diff --git a/.gitmodules b/.gitmodules index 550a1db7..7ed0a278 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "phobos"] path = runtime/phobos url = git://github.com/ldc-developers/phobos.git +[submodule "tests/d2/dmd-testsuite"] + path = tests/d2/dmd-testsuite + url = git://github.com/ldc-developers/dmd-testsuite.git diff --git a/dmd2/aggregate.h b/dmd2/aggregate.h index 46af2b3d..6deae43e 100644 --- a/dmd2/aggregate.h +++ b/dmd2/aggregate.h @@ -67,7 +67,6 @@ 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 int hasUnions; // set if aggregate has overlapping fields VarDeclarations fields; // VarDeclaration fields enum Sizeok sizeok; // set when structsize contains valid data @@ -96,17 +95,18 @@ struct AggregateDeclaration : ScopeDsymbol #ifdef IN_GCC Expressions *attributes; // GCC decl/type attributes - FuncDeclarations methods; // flat list of all methods for debug information #endif + Expression *getRTInfo; // pointer to GC info generated by object.RTInfo(this) + AggregateDeclaration(Loc loc, Identifier *id); void semantic2(Scope *sc); 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 @@ -165,8 +165,14 @@ struct StructDeclaration : AggregateDeclaration FuncDeclaration *xeq; // TypeInfo_Struct.xopEquals static FuncDeclaration *xerreq; // object.xopEquals + + structalign_t alignment; // alignment applied outside of the struct #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); @@ -175,6 +181,7 @@ struct StructDeclaration : AggregateDeclaration char *mangle(); const char *kind(); void finalizeSize(Scope *sc); + bool isPOD(); #if DMDV1 Expression *cloneMembers(); #endif diff --git a/dmd2/aliasthis.c b/dmd2/aliasthis.c index 0f6ff452..b26731b9 100644 --- a/dmd2/aliasthis.c +++ b/dmd2/aliasthis.c @@ -18,6 +18,7 @@ #include "aggregate.h" #include "dsymbol.h" #include "mtype.h" +#include "declaration.h" #if DMDV2 @@ -78,9 +79,32 @@ void AliasThis::semantic(Scope *sc) ::error(loc, "%s is not a member of %s", s->toChars(), ad->toChars()); else ::error(loc, "undefined identifier %s", ident->toChars()); + return; } else if (ad->aliasthis && s != ad->aliasthis) error("there can be only one alias this"); + + /* disable the alias this conversion so the implicit conversion check + * doesn't use it. + */ + /* This should use ad->aliasthis directly, but with static foreach and templates + * ad->type->sym might be different to ad. + */ + AggregateDeclaration *ad2 = ad->type->toDsymbol(NULL)->isAggregateDeclaration(); + Dsymbol *save = ad2->aliasthis; + ad2->aliasthis = NULL; + + if (Declaration *d = s->isDeclaration()) + { + Type *t = d->type; + assert(t); + if (ad->type->implicitConvTo(t)) + { + ::error(loc, "alias this is not reachable as %s already converts to %s", ad->toChars(), t->toChars()); + } + } + + ad2->aliasthis = save; ad->aliasthis = s; } else diff --git a/dmd2/argtypes.c b/dmd2/argtypes.c index 3f1d3620..ffa38a86 100644 --- a/dmd2/argtypes.c +++ b/dmd2/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; @@ -124,23 +131,39 @@ TypeTuple *TypeBasic::toArgTypes() return t; } +#if DMDV2 TypeTuple *TypeVector::toArgTypes() { - return new TypeTuple(Type::tfloat64); + 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() @@ -150,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/dmd2/arrayop.c b/dmd2/arrayop.c index ed685c18..bac8391a 100644 --- a/dmd2/arrayop.c +++ b/dmd2/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 @@ -142,7 +142,6 @@ Expression *BinExp::arrayOp(Scope *sc) buf.writestring(type->toBasetype()->nextOf()->toBasetype()->deco); #endif - size_t namelen = buf.offset; buf.writeByte(0); char *name = buf.toChars(); Identifier *ident = Lexer::idPool(name); @@ -349,7 +348,7 @@ Expression *BinExp::arrayOp(Scope *sc) Initializer *init = new ExpInitializer(0, new IntegerExp(0, 0, Type::tsize_t)); Dsymbol *d = new VarDeclaration(0, Type::tsize_t, Id::p, init); Statement *s1 = new ForStatement(0, - new DeclarationStatement(0, d), + new ExpStatement(0, d), new CmpExp(TOKlt, 0, new IdentifierExp(0, Id::p), new ArrayLengthExp(0, new IdentifierExp(0, p->ident))), new PostExp(TOKplusplus, 0, new IdentifierExp(0, Id::p)), new ExpStatement(0, loopbody)); @@ -357,7 +356,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 @@ -413,6 +412,23 @@ Expression *BinExp::arrayOp(Scope *sc) return e; } +Expression *BinAssignExp::arrayOp(Scope *sc) +{ + //printf("BinAssignExp::arrayOp() %s\n", toChars()); + + /* Check that the elements of e1 can be assigned to + */ + Type *tn = e1->type->toBasetype()->nextOf(); + + if (tn && (!tn->isMutable() || !tn->isAssignable())) + { + error("slice %s is not mutable", e1->toChars()); + return new ErrorExp(); + } + + return BinExp::arrayOp(sc); +} + /****************************************** * Construct the identifier for the array operation function, * and build the argument list to pass to it. diff --git a/dmd2/artistic.txt b/dmd2/artistic.txt index cd17757e..cae432b7 100644 --- a/dmd2/artistic.txt +++ b/dmd2/artistic.txt @@ -1,117 +1,117 @@ - - - - - The "Artistic License" - - Preamble - -The intent of this document is to state the conditions under which a -Package may be copied, such that the Copyright Holder maintains some -semblance of artistic control over the development of the package, -while giving the users of the package the right to use and distribute -the Package in a more-or-less customary fashion, plus the right to make -reasonable modifications. - -Definitions: - - "Package" refers to the collection of files distributed by the - Copyright Holder, and derivatives of that collection of files - created through textual modification. - - "Standard Version" refers to such a Package if it has not been - modified, or has been modified in accordance with the wishes - of the Copyright Holder as specified below. - - "Copyright Holder" is whoever is named in the copyright or - copyrights for the package. - - "You" is you, if you're thinking about copying or distributing - this Package. - - "Reasonable copying fee" is whatever you can justify on the - basis of media cost, duplication charges, time of people involved, - and so on. (You will not be required to justify it to the - Copyright Holder, but only to the computing community at large - as a market that must bear the fee.) - - "Freely Available" means that no fee is charged for the item - itself, though there may be fees involved in handling the item. - It also means that recipients of the item may redistribute it - under the same conditions they received it. - -1. You may make and give away verbatim copies of the source form of the -Standard Version of this Package without restriction, provided that you -duplicate all of the original copyright notices and associated disclaimers. - -2. You may apply bug fixes, portability fixes and other modifications -derived from the Public Domain or from the Copyright Holder. A Package -modified in such a way shall still be considered the Standard Version. - -3. You may otherwise modify your copy of this Package in any way, provided -that you insert a prominent notice in each changed file stating how and -when you changed that file, and provided that you do at least ONE of the -following: - - a) place your modifications in the Public Domain or otherwise make them - Freely Available, such as by posting said modifications to Usenet or - an equivalent medium, or placing the modifications on a major archive - site such as uunet.uu.net, or by allowing the Copyright Holder to include - your modifications in the Standard Version of the Package. - - b) use the modified Package only within your corporation or organization. - - c) rename any non-standard executables so the names do not conflict - with standard executables, which must also be provided, and provide - a separate manual page for each non-standard executable that clearly - documents how it differs from the Standard Version. - - d) make other distribution arrangements with the Copyright Holder. - -4. You may distribute the programs of this Package in object code or -executable form, provided that you do at least ONE of the following: - - a) distribute a Standard Version of the executables and library files, - together with instructions (in the manual page or equivalent) on where - to get the Standard Version. - - b) accompany the distribution with the machine-readable source of - the Package with your modifications. - - c) give non-standard executables non-standard names, and clearly - document the differences in manual pages (or equivalent), together - with instructions on where to get the Standard Version. - - d) make other distribution arrangements with the Copyright Holder. - -5. You may charge a reasonable copying fee for any distribution of this -Package. You may charge any fee you choose for support of this -Package. You may not charge a fee for this Package itself. However, -you may distribute this Package in aggregate with other (possibly -commercial) programs as part of a larger (possibly commercial) software -distribution provided that you do not advertise this Package as a -product of your own. You may embed this Package's interpreter within -an executable of yours (by linking); this shall be construed as a mere -form of aggregation, provided that the complete Standard Version of the -interpreter is so embedded. - -6. The source code and object code supplied as input to or produced as -output from the programs of this Package do not automatically fall -under the copyright of this Package, but belong to whoever generated -them, and may be sold commercially, and may be aggregated with this -Package. - -7. Aggregation of this Package with a commercial distribution is always -permitted provided that the use of this Package is embedded; that is, -when no overt attempt is made to make this Package's interfaces visible -to the end user of the commercial distribution. Such use shall not be -construed as a distribution of this Package. - -8. The name of the Copyright Holder may not be used to endorse or promote -products derived from this software without specific prior written permission. - -9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED -WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - - The End + + + + + The "Artistic License" + + Preamble + +The intent of this document is to state the conditions under which a +Package may be copied, such that the Copyright Holder maintains some +semblance of artistic control over the development of the package, +while giving the users of the package the right to use and distribute +the Package in a more-or-less customary fashion, plus the right to make +reasonable modifications. + +Definitions: + + "Package" refers to the collection of files distributed by the + Copyright Holder, and derivatives of that collection of files + created through textual modification. + + "Standard Version" refers to such a Package if it has not been + modified, or has been modified in accordance with the wishes + of the Copyright Holder as specified below. + + "Copyright Holder" is whoever is named in the copyright or + copyrights for the package. + + "You" is you, if you're thinking about copying or distributing + this Package. + + "Reasonable copying fee" is whatever you can justify on the + basis of media cost, duplication charges, time of people involved, + and so on. (You will not be required to justify it to the + Copyright Holder, but only to the computing community at large + as a market that must bear the fee.) + + "Freely Available" means that no fee is charged for the item + itself, though there may be fees involved in handling the item. + It also means that recipients of the item may redistribute it + under the same conditions they received it. + +1. You may make and give away verbatim copies of the source form of the +Standard Version of this Package without restriction, provided that you +duplicate all of the original copyright notices and associated disclaimers. + +2. You may apply bug fixes, portability fixes and other modifications +derived from the Public Domain or from the Copyright Holder. A Package +modified in such a way shall still be considered the Standard Version. + +3. You may otherwise modify your copy of this Package in any way, provided +that you insert a prominent notice in each changed file stating how and +when you changed that file, and provided that you do at least ONE of the +following: + + a) place your modifications in the Public Domain or otherwise make them + Freely Available, such as by posting said modifications to Usenet or + an equivalent medium, or placing the modifications on a major archive + site such as uunet.uu.net, or by allowing the Copyright Holder to include + your modifications in the Standard Version of the Package. + + b) use the modified Package only within your corporation or organization. + + c) rename any non-standard executables so the names do not conflict + with standard executables, which must also be provided, and provide + a separate manual page for each non-standard executable that clearly + documents how it differs from the Standard Version. + + d) make other distribution arrangements with the Copyright Holder. + +4. You may distribute the programs of this Package in object code or +executable form, provided that you do at least ONE of the following: + + a) distribute a Standard Version of the executables and library files, + together with instructions (in the manual page or equivalent) on where + to get the Standard Version. + + b) accompany the distribution with the machine-readable source of + the Package with your modifications. + + c) give non-standard executables non-standard names, and clearly + document the differences in manual pages (or equivalent), together + with instructions on where to get the Standard Version. + + d) make other distribution arrangements with the Copyright Holder. + +5. You may charge a reasonable copying fee for any distribution of this +Package. You may charge any fee you choose for support of this +Package. You may not charge a fee for this Package itself. However, +you may distribute this Package in aggregate with other (possibly +commercial) programs as part of a larger (possibly commercial) software +distribution provided that you do not advertise this Package as a +product of your own. You may embed this Package's interpreter within +an executable of yours (by linking); this shall be construed as a mere +form of aggregation, provided that the complete Standard Version of the +interpreter is so embedded. + +6. The source code and object code supplied as input to or produced as +output from the programs of this Package do not automatically fall +under the copyright of this Package, but belong to whoever generated +them, and may be sold commercially, and may be aggregated with this +Package. + +7. Aggregation of this Package with a commercial distribution is always +permitted provided that the use of this Package is embedded; that is, +when no overt attempt is made to make this Package's interfaces visible +to the end user of the commercial distribution. Such use shall not be +construed as a distribution of this Package. + +8. The name of the Copyright Holder may not be used to endorse or promote +products derived from this software without specific prior written permission. + +9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + The End diff --git a/dmd2/attrib.c b/dmd2/attrib.c index 776565d0..a21213f9 100644 --- a/dmd2/attrib.c +++ b/dmd2/attrib.c @@ -11,6 +11,7 @@ #include #include #include +#include // memcpy() #include "rmem.h" @@ -37,7 +38,7 @@ extern void obj_includelib(const char *name); #if IN_DMD -void obj_startaddress(Symbol *s); +bool obj_startaddress(Symbol *s); #endif @@ -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) { @@ -760,7 +761,10 @@ void AlignDeclaration::semantic(Scope *sc) void AlignDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { - buf->printf("align (%d)", salign); + if (salign == STRUCTALIGN_DEFAULT) + buf->printf("align"); + else + buf->printf("align (%d)", salign); AttribDeclaration::toCBuffer(buf, hgs); } @@ -938,7 +942,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) @@ -977,8 +981,8 @@ void PragmaDeclaration::semantic(Scope *sc) Expression *e = (*args)[i]; e = e->semantic(sc); - if (e->op != TOKerror) - e = e->optimize(WANTvalue | WANTinterpret); + if (e->op != TOKerror && e->op != TOKtype) + e = e->ctfeInterpret(); if (e->op == TOKerror) { errorSupplemental(loc, "while evaluating pragma(msg, %s)", (*args)[i]->toChars()); return; @@ -1004,7 +1008,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; @@ -1022,7 +1026,7 @@ void PragmaDeclaration::semantic(Scope *sc) } goto Lnodecl; } -#if IN_GCC +#ifdef IN_GCC else if (ident == Id::GNU_asm) { if (! args || args->dim != 2) @@ -1046,7 +1050,7 @@ void PragmaDeclaration::semantic(Scope *sc) e = (*args)[1]; e = e->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); + e = e->ctfeInterpret(); e = e->toString(); if (e && ((StringExp *)e)->sz == 1) s = ((StringExp *)e); @@ -1068,7 +1072,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()) @@ -1105,7 +1109,7 @@ void PragmaDeclaration::semantic(Scope *sc) unsigned errors_save = global.errors; e = e->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); + e = e->ctfeInterpret(); if (i == 0) printf(" ("); else @@ -1175,21 +1179,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 - /* 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 (!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); + } } #if DMDV2 else if (ident == Id::startaddress) @@ -1406,6 +1408,31 @@ Dsymbol *StaticIfDeclaration::syntaxCopy(Dsymbol *s) return dd; } +Dsymbols *StaticIfDeclaration::include(Scope *sc, ScopeDsymbol *sd) +{ + //printf("StaticIfDeclaration::include(sc = %p) scope = %p\n", sc, scope); + + if (condition->inc == 0) + { + Dsymbols *d = ConditionalDeclaration::include(sc, sd); + + // Set the scopes lazily. + if (scope && d) + { + for (size_t i = 0; i < d->dim; i++) + { + Dsymbol *s = (*d)[i]; + + s->setScope(sc); + } + } + return d; + } + else + { + return ConditionalDeclaration::include(sc, sd); + } +} int StaticIfDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) { @@ -1512,7 +1539,7 @@ void CompileDeclaration::compileIt(Scope *sc) //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/dmd2/attrib.h b/dmd2/attrib.h index 6762d338..aa8d0447 100644 --- a/dmd2/attrib.h +++ b/dmd2/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); @@ -122,7 +122,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); @@ -178,6 +178,7 @@ struct StaticIfDeclaration : ConditionalDeclaration StaticIfDeclaration(Condition *condition, Dsymbols *decl, Dsymbols *elsedecl); Dsymbol *syntaxCopy(Dsymbol *s); + Dsymbols *include(Scope *sc, ScopeDsymbol *s); int addMember(Scope *sc, ScopeDsymbol *s, int memnum); void semantic(Scope *sc); void importAll(Scope *sc); diff --git a/dmd2/builtin.c b/dmd2/builtin.c index 0c8a780a..c1494b5f 100644 --- a/dmd2/builtin.c +++ b/dmd2/builtin.c @@ -10,9 +10,9 @@ #include #include +#include // strcmp() #include - #include "mars.h" #include "declaration.h" #include "attrib.h" @@ -44,10 +44,10 @@ enum BUILTIN FuncDeclaration::isBuiltin() { static const char FeZe [] = "FNaNbNfeZe"; // @safe pure nothrow real function(real) static const char FeZe2[] = "FNaNbNeeZe"; // @trusted pure nothrow real function(real) - static const char FuintZint[] = "FNaNbkZi"; // pure nothrow int function(uint) - static const char FuintZuint[] = "FNaNbkZk"; // pure nothrow uint function(uint) + static const char FuintZint[] = "FNaNbNfkZi"; // @safe pure nothrow int function(uint) + static const char FuintZuint[] = "FNaNbNfkZk"; // @safe pure nothrow uint function(uint) static const char FulongZulong[] = "FNaNbkZk"; // pure nothrow int function(ulong) - static const char FulongZint[] = "FNaNbmZi"; // pure nothrow int function(uint) + static const char FulongZint[] = "FNaNbNfmZi"; // @safe pure nothrow int function(uint) static const char FrealrealZreal [] = "FNaNbNfeeZe"; // @safe pure nothrow real function(real, real) static const char FrealZlong [] = "FNaNbNfeZl"; // @safe pure nothrow long function(real) @@ -167,7 +167,7 @@ uinteger_t eval_bswap(Expression *arg0) Expression *eval_builtin(Loc loc, enum BUILTIN builtin, Expressions *arguments) { assert(arguments && arguments->dim); - Expression *arg0 = arguments->tdata()[0]; + Expression *arg0 = (*arguments)[0]; Expression *e = NULL; switch (builtin) { diff --git a/dmd2/canthrow.c b/dmd2/canthrow.c index 885b241a..27992b08 100644 --- a/dmd2/canthrow.c +++ b/dmd2/canthrow.c @@ -42,6 +42,7 @@ struct CanThrow int Expression::canThrow(bool mustNotThrow) { + //printf("Expression::canThrow(%d) %s\n", mustNotThrow, toChars()); CanThrow ct; ct.can = FALSE; ct.mustnot = mustNotThrow; @@ -132,7 +133,7 @@ int Dsymbol_canThrow(Dsymbol *s, bool mustNotThrow) { for (size_t i = 0; i < decl->dim; i++) { - s = decl->tdata()[i]; + s = (*decl)[i]; if (Dsymbol_canThrow(s, mustNotThrow)) return 1; } @@ -165,7 +166,7 @@ int Dsymbol_canThrow(Dsymbol *s, bool mustNotThrow) { for (size_t i = 0; i < tm->members->dim; i++) { - Dsymbol *sm = tm->members->tdata()[i]; + Dsymbol *sm = (*tm->members)[i]; if (Dsymbol_canThrow(sm, mustNotThrow)) return 1; } @@ -174,7 +175,7 @@ int Dsymbol_canThrow(Dsymbol *s, bool mustNotThrow) else if ((td = s->isTupleDeclaration()) != NULL) { for (size_t i = 0; i < td->objects->dim; i++) - { Object *o = td->objects->tdata()[i]; + { Object *o = (*td->objects)[i]; if (o->dyncast() == DYNCAST_EXPRESSION) { Expression *eo = (Expression *)o; if (eo->op == TOKdsymbol) diff --git a/dmd2/cast.c b/dmd2/cast.c index 0db05863..02e1f8b5 100644 --- a/dmd2/cast.c +++ b/dmd2/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" @@ -36,9 +37,10 @@ Expression *Expression::implicitCastTo(Scope *sc, Type *t) MATCH match = implicitConvTo(t); if (match) - { TY tyfrom = type->toBasetype()->ty; - TY tyto = t->toBasetype()->ty; + { #if DMDV1 + TY tyfrom = type->toBasetype()->ty; + TY tyto = t->toBasetype()->ty; if (global.params.warnings && Type::impcnvWarn[tyfrom][tyto] && op != TOKint64) @@ -138,7 +140,7 @@ Expression *ErrorExp::implicitCastTo(Scope *sc, Type *t) Expression *FuncExp::implicitCastTo(Scope *sc, Type *t) { //printf("FuncExp::implicitCastTo type = %p %s, t = %s\n", type, type ? type->toChars() : NULL, t->toChars()); - return inferType(t); + return inferType(t)->Expression::implicitCastTo(sc, t); } /******************************************* @@ -215,6 +217,7 @@ MATCH IntegerExp::implicitConvTo(Type *t) TY ty = type->toBasetype()->ty; TY toty = t->toBasetype()->ty; + TY oldty = ty; if (m == MATCHnomatch && t->ty == Tenum) goto Lno; @@ -282,6 +285,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) @@ -293,6 +298,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; @@ -319,11 +327,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; @@ -540,19 +543,28 @@ MATCH ArrayLiteralExp::implicitConvTo(Type *t) if ((tb->ty == Tarray || tb->ty == Tsarray) && (typeb->ty == Tarray || typeb->ty == Tsarray)) { + Type *typen = typeb->nextOf()->toBasetype(); + if (tb->ty == Tsarray) { TypeSArray *tsa = (TypeSArray *)tb; if (elements->dim != tsa->dim->toInteger()) result = MATCHnomatch; } - 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 + Type *telement = tb->nextOf(); + if (!elements->dim) + { if (typen->ty != Tvoid) + result = typen->implicitConvTo(telement); + } + else + { for (size_t i = 0; i < elements->dim; i++) + { Expression *e = (*elements)[i]; + 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) @@ -560,25 +572,46 @@ MATCH ArrayLiteralExp::implicitConvTo(Type *t) return result; } + 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; + } else return Expression::implicitConvTo(t); } MATCH AssocArrayLiteralExp::implicitConvTo(Type *t) -{ MATCH result = MATCHexact; - +{ Type *typeb = type->toBasetype(); Type *tb = t->toBasetype(); if (tb->ty == Taarray && typeb->ty == Taarray) { + MATCH result = MATCHexact; for (size_t i = 0; i < keys->dim; i++) - { Expression *e = keys->tdata()[i]; + { Expression *e = (*keys)[i]; MATCH m = (MATCH)e->implicitConvTo(((TypeAArray *)tb)->index); if (m < result) result = m; // remember worst match if (result == MATCHnomatch) break; // no need to check for worse - e = values->tdata()[i]; + e = (*values)[i]; m = (MATCH)e->implicitConvTo(tb->nextOf()); if (m < result) result = m; // remember worst match @@ -905,6 +938,9 @@ Expression *Expression::castTo(Scope *sc, Type *t) } else if (tb->ty == Tvector && typeb->ty != Tvector) { + //printf("test1 e = %s, e->type = %s, tb = %s\n", e->toChars(), e->type->toChars(), tb->toChars()); + TypeVector *tv = (TypeVector *)tb; + e = new CastExp(loc, e, tv->elementType()); e = new VectorExp(loc, e, tb); e = e->semantic(sc); return e; @@ -1372,9 +1408,9 @@ Expression *TupleExp::castTo(Scope *sc, Type *t) { TupleExp *e = (TupleExp *)copy(); e->exps = (Expressions *)exps->copy(); for (size_t i = 0; i < e->exps->dim; i++) - { Expression *ex = e->exps->tdata()[i]; + { Expression *ex = (*e->exps)[i]; ex = ex->castTo(sc, t); - e->exps->tdata()[i] = ex; + (*e->exps)[i] = ex; } return e; } @@ -1420,6 +1456,28 @@ Expression *ArrayLiteralExp::castTo(Scope *sc, Type *t) e->type = tp; } } + 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; + } L1: return e->Expression::castTo(sc, t); } @@ -1439,13 +1497,13 @@ Expression *AssocArrayLiteralExp::castTo(Scope *sc, Type *t) e->values = (Expressions *)values->copy(); assert(keys->dim == values->dim); for (size_t i = 0; i < keys->dim; i++) - { Expression *ex = values->tdata()[i]; + { Expression *ex = (*values)[i]; ex = ex->castTo(sc, tb->nextOf()); - e->values->tdata()[i] = ex; + (*e->values)[i] = ex; - ex = keys->tdata()[i]; + ex = (*keys)[i]; ex = ex->castTo(sc, ((TypeAArray *)tb)->index); - e->keys->tdata()[i] = ex; + (*e->keys)[i] = ex; } e->type = t; return e; @@ -1688,7 +1746,7 @@ Expression *FuncExp::inferType(Type *to, int flag, TemplateParameters *tparams) { if (to->ty == Tdelegate || to->ty == Tpointer && to->nextOf()->ty == Tfunction) - { treq = to; + { fd->treq = to; } return this; } @@ -1714,6 +1772,8 @@ Expression *FuncExp::inferType(Type *to, int flag, TemplateParameters *tparams) { TypeFunction *tfv = (TypeFunction *)t; TypeFunction *tfl = (TypeFunction *)fd->type; + //printf("\ttfv = %s\n", tfv->toChars()); + //printf("\ttfl = %s\n", tfl->toChars()); size_t dim = Parameter::dim(tfl->parameters); if (Parameter::dim(tfv->parameters) == dim && @@ -1740,6 +1800,13 @@ Expression *FuncExp::inferType(Type *to, int flag, TemplateParameters *tparams) } } + // Set target of return type inference + assert(td->onemember); + FuncLiteralDeclaration *fld = td->onemember->isFuncLiteralDeclaration(); + assert(fld); + if (!fld->type->nextOf() && tfv->next) + fld->treq = tfv; + TemplateInstance *ti = new TemplateInstance(loc, td, tiargs); e = (new ScopeExp(loc, ti))->semantic(td->scope); if (e->op == TOKfunction) @@ -1759,14 +1826,12 @@ Expression *FuncExp::inferType(Type *to, int flag, TemplateParameters *tparams) to->ty == Tdelegate) { Type *typen = type->nextOf(); - assert(typen->deco); - //if (typen->covariant(to->nextOf()) == 1) + if (typen->deco) { FuncExp *fe = (FuncExp *)copy(); fe->tok = TOKdelegate; fe->type = (new TypeDelegate(typen))->merge(); e = fe; - //e = fe->Expression::implicitCastTo(sc, to); } } else @@ -1879,7 +1944,7 @@ bool isVoidArrayLiteral(Expression *e, Type *other) while (e->op == TOKarrayliteral && e->type->ty == Tarray && (((ArrayLiteralExp *)e)->elements->dim == 1)) { - e = ((ArrayLiteralExp *)e)->elements->tdata()[0]; + e = (*((ArrayLiteralExp *)e)->elements)[0]; if (other->ty == Tsarray || other->ty == Tarray) other = other->nextOf(); else @@ -1910,6 +1975,7 @@ int typeMerge(Scope *sc, Expression *e, Type **pt, Expression **pe1, Expression //printf("typeMerge() %s op %s\n", (*pe1)->toChars(), (*pe2)->toChars()); //e->dump(0); + MATCH m; Expression *e1 = *pe1; Expression *e2 = *pe2; @@ -2110,10 +2176,20 @@ Lagain: */ goto Lx2; } - else if ((t1->ty == Tsarray || t1->ty == Tarray) && t1->implicitConvTo(t2)) + else if ((t1->ty == Tsarray || t1->ty == Tarray) && + (m = t1->implicitConvTo(t2)) != MATCHnomatch) { if (t1->ty == Tsarray && e2->op == TOKarrayliteral) goto Lt1; + if (m == MATCHconst && + (e->op == TOKaddass || e->op == TOKminass || e->op == TOKmulass || + e->op == TOKdivass || e->op == TOKmodass || e->op == TOKpowass || + e->op == TOKandass || e->op == TOKorass || e->op == TOKxorass) + ) + { // Don't make the lvalue const + t = t2; + goto Lret; + } goto Lt2; } else if ((t2->ty == Tsarray || t2->ty == Tarray) && t2->implicitConvTo(t1)) diff --git a/dmd2/class.c b/dmd2/class.c index 25644248..6721e925 100644 --- a/dmd2/class.c +++ b/dmd2/class.c @@ -11,6 +11,7 @@ #include #include #include +#include // mem{cpy|set}() #include "root.h" #include "rmem.h" @@ -177,6 +178,12 @@ ClassDeclaration::ClassDeclaration(Loc loc, Identifier *id, BaseClasses *basecla Type::typeinfowild->error("%s", msg); Type::typeinfowild = this; } + + if (id == Id::TypeInfo_Vector) + { if (Type::typeinfovector) + Type::typeinfovector->error("%s", msg); + Type::typeinfovector = this; + } #endif } @@ -241,9 +248,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); @@ -292,10 +299,6 @@ void ClassDeclaration::semantic(Scope *sc) scope = NULL; } unsigned dprogress_save = Module::dprogress; -#ifdef IN_GCC - methods.setDim(0); -#endif - int errors = global.gaggedErrors; if (sc->stc & STCdeprecated) @@ -308,7 +311,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(); @@ -333,7 +336,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) @@ -403,7 +406,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) @@ -432,7 +435,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()); } @@ -464,22 +467,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; @@ -535,7 +536,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()) { @@ -614,8 +617,7 @@ void ClassDeclaration::semantic(Scope *sc) } sc->protection = PROTpublic; sc->explicitProtection = 0; - sc->structalign = 8; - structalign = sc->structalign; + sc->structalign = STRUCTALIGN_DEFAULT; if (baseClass) { sc->offset = baseClass->structsize; alignsize = baseClass->alignsize; @@ -642,9 +644,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); } } @@ -682,7 +685,7 @@ void ClassDeclaration::semantic(Scope *sc) fields.setDim(0); structsize = 0; alignsize = 0; - structalign = 0; +// structalign = 0; sc = sc->pop(); @@ -757,7 +760,7 @@ void ClassDeclaration::semantic(Scope *sc) BaseClass *b = (*vtblInterfaces)[i]; unsigned thissize = PTRSIZE; - alignmember(structalign, thissize, &sc->offset); + alignmember(STRUCTALIGN_DEFAULT, thissize, &sc->offset); assert(b->offset == 0); b->offset = sc->offset; @@ -774,9 +777,12 @@ void ClassDeclaration::semantic(Scope *sc) } structsize = sc->offset; #if IN_LLVM - if (global.params.is64bit) - structsize = (structsize + structalign - 1) & ~(structalign - 1); + if (sc->structalign == STRUCTALIGN_DEFAULT) + structsize = (structsize + alignsize - 1) & ~(alignsize - 1); + else + structsize = (structsize + sc->structalign - 1) & ~(sc->structalign - 1); #endif + sizeok = SIZEOKdone; Module::dprogress++; @@ -788,7 +794,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); } @@ -813,7 +819,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(','); @@ -827,7 +833,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); @@ -862,7 +868,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; @@ -908,7 +914,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; } @@ -946,7 +952,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) { @@ -1011,7 +1017,7 @@ int ClassDeclaration::isFuncHidden(FuncDeclaration *fd) if (os) { for (size_t i = 0; i < os->a.dim; i++) - { Dsymbol *s2 = os->a.tdata()[i]; + { Dsymbol *s2 = os->a[i]; FuncDeclaration *f2 = s2->isFuncDeclaration(); if (f2 && overloadApply(f2, &isf, fd)) return 0; @@ -1054,9 +1060,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 @@ -1068,6 +1076,15 @@ FuncDeclaration *ClassDeclaration::findFunc(Identifier *ident, TypeFunction *tf) goto Lfdmatch; } + { + int m1 = (tf->mod == fd ->type->mod) ? MATCHexact : MATCHnomatch; + int m2 = (tf->mod == fdmatch->type->mod) ? MATCHexact : MATCHnomatch; + if (m1 > m2) + goto Lfd; + else if (m1 < m2) + goto Lfdmatch; + } + { // The way of definition: non-mixin > mixin int m1 = fd ->parent->isClassDeclaration() ? MATCHexact : MATCHnomatch; @@ -1158,7 +1175,7 @@ int ClassDeclaration::isAbstract() return TRUE; for (size_t i = 1; i < vtbl.dim; i++) { - FuncDeclaration *fd = vtbl.tdata()[i]->isFuncDeclaration(); + FuncDeclaration *fd = vtbl[i]->isFuncDeclaration(); //printf("\tvtbl[%d] = %p\n", i, fd); if (!fd || fd->isAbstract()) @@ -1266,7 +1283,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(); @@ -1294,7 +1311,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) @@ -1312,7 +1329,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()); } @@ -1373,7 +1390,7 @@ void InterfaceDeclaration::semantic(Scope *sc) { vtbl.reserve(d - 1); for (size_t j = 1; j < d; j++) - vtbl.push(b->base->vtbl.tdata()[j]); + vtbl.push(b->base->vtbl[j]); } } else @@ -1401,10 +1418,10 @@ void InterfaceDeclaration::semantic(Scope *sc) sc->linkage = LINKwindows; else if (isCPPinterface()) sc->linkage = LINKcpp; - sc->structalign = 8; + sc->structalign = STRUCTALIGN_DEFAULT; sc->protection = PROTpublic; sc->explicitProtection = 0; - structalign = sc->structalign; +// structalign = sc->structalign; sc->offset = PTRSIZE * 2; structsize = sc->offset; inuse++; @@ -1426,7 +1443,7 @@ void InterfaceDeclaration::semantic(Scope *sc) for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = members->tdata()[i]; + Dsymbol *s = (*members)[i]; s->semantic(sc); } @@ -1526,7 +1543,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; } @@ -1610,7 +1627,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 = base->vtbl.tdata()[j]->isFuncDeclaration(); + FuncDeclaration *ifd = base->vtbl[j]->isFuncDeclaration(); FuncDeclaration *fd; TypeFunction *tf; @@ -1647,7 +1664,7 @@ int BaseClass::fillVtbl(ClassDeclaration *cd, FuncDeclarations *vtbl, int newins fd = NULL; } if (vtbl) - vtbl->tdata()[j] = fd; + (*vtbl)[j] = fd; } return result; diff --git a/dmd2/clone.c b/dmd2/clone.c index d0b22c40..bfd167ae 100644 --- a/dmd2/clone.c +++ b/dmd2/clone.c @@ -45,7 +45,7 @@ int StructDeclaration::needOpAssign() */ for (size_t i = 0; i < fields.dim; i++) { - Dsymbol *s = fields.tdata()[i]; + Dsymbol *s = fields[i]; VarDeclaration *v = s->isVarDeclaration(); assert(v && v->storage_class & STCfield); if (v->storage_class & STCref) @@ -153,7 +153,7 @@ FuncDeclaration *StructDeclaration::buildOpAssign(Scope *sc) //printf("\tmemberwise copy\n"); for (size_t i = 0; i < fields.dim; i++) { - Dsymbol *s = fields.tdata()[i]; + Dsymbol *s = fields[i]; VarDeclaration *v = s->isVarDeclaration(); assert(v && v->storage_class & STCfield); // this.v = s.v; @@ -214,7 +214,7 @@ int StructDeclaration::needOpEquals() */ for (size_t i = 0; i < fields.dim; i++) { - Dsymbol *s = fields.tdata()[i]; + Dsymbol *s = fields[i]; VarDeclaration *v = s->isVarDeclaration(); assert(v && v->storage_class & STCfield); if (v->storage_class & STCref) @@ -304,7 +304,7 @@ FuncDeclaration *StructDeclaration::buildOpEquals(Scope *sc) //printf("\tmemberwise compare\n"); for (size_t i = 0; i < fields.dim; i++) { - Dsymbol *s = fields.tdata()[i]; + Dsymbol *s = fields[i]; VarDeclaration *v = s->isVarDeclaration(); assert(v && v->storage_class & STCfield); if (v->storage_class & STCref) @@ -513,13 +513,13 @@ FuncDeclaration *StructDeclaration::buildPostBlit(Scope *sc) for (size_t i = 0; i < fields.dim; i++) { - Dsymbol *s = fields.tdata()[i]; + Dsymbol *s = fields[i]; VarDeclaration *v = s->isVarDeclaration(); assert(v && v->storage_class & STCfield); if (v->storage_class & STCref) continue; Type *tv = v->type->toBasetype(); - dinteger_t dim = (tv->ty == Tsarray ? 1 : 0); + dinteger_t dim = 1; while (tv->ty == Tsarray) { TypeSArray *ta = (TypeSArray *)tv; dim *= ((TypeSArray *)tv)->dim->toInteger(); @@ -528,7 +528,7 @@ FuncDeclaration *StructDeclaration::buildPostBlit(Scope *sc) if (tv->ty == Tstruct) { TypeStruct *ts = (TypeStruct *)tv; StructDeclaration *sd = ts->sym; - if (sd->postblit) + if (sd->postblit && dim) { stc |= sd->postblit->storage_class & STCdisable; @@ -542,7 +542,7 @@ FuncDeclaration *StructDeclaration::buildPostBlit(Scope *sc) Expression *ex = new ThisExp(0); ex = new DotVarExp(0, ex, v, 0); - if (dim == 0) + if (v->type->toBasetype()->ty == Tstruct) { // this.v.postblit() ex = new DotVarExp(0, ex, sd->postblit, 0); ex = new CallExp(0, ex); @@ -581,12 +581,12 @@ FuncDeclaration *StructDeclaration::buildPostBlit(Scope *sc) return NULL; case 1: - return postblits.tdata()[0]; + return postblits[0]; default: e = NULL; for (size_t i = 0; i < postblits.dim; i++) - { FuncDeclaration *fd = postblits.tdata()[i]; + { FuncDeclaration *fd = postblits[i]; stc |= fd->storage_class & STCdisable; if (stc & STCdisable) { @@ -625,13 +625,13 @@ FuncDeclaration *AggregateDeclaration::buildDtor(Scope *sc) #if DMDV2 for (size_t i = 0; i < fields.dim; i++) { - Dsymbol *s = fields.tdata()[i]; + Dsymbol *s = fields[i]; VarDeclaration *v = s->isVarDeclaration(); assert(v && v->storage_class & STCfield); if (v->storage_class & STCref) continue; Type *tv = v->type->toBasetype(); - dinteger_t dim = (tv->ty == Tsarray ? 1 : 0); + dinteger_t dim = 1; while (tv->ty == Tsarray) { TypeSArray *ta = (TypeSArray *)tv; dim *= ((TypeSArray *)tv)->dim->toInteger(); @@ -640,14 +640,14 @@ FuncDeclaration *AggregateDeclaration::buildDtor(Scope *sc) if (tv->ty == Tstruct) { TypeStruct *ts = (TypeStruct *)tv; StructDeclaration *sd = ts->sym; - if (sd->dtor) + if (sd->dtor && dim) { Expression *ex; // this.v ex = new ThisExp(0); ex = new DotVarExp(0, ex, v, 0); - if (dim == 0) + if (v->type->toBasetype()->ty == Tstruct) { // this.v.dtor() ex = new DotVarExp(0, ex, sd->dtor, 0); ex = new CallExp(0, ex); @@ -686,12 +686,12 @@ FuncDeclaration *AggregateDeclaration::buildDtor(Scope *sc) return NULL; case 1: - return dtors.tdata()[0]; + return dtors[0]; default: e = NULL; for (size_t i = 0; i < dtors.dim; i++) - { FuncDeclaration *fd = dtors.tdata()[i]; + { FuncDeclaration *fd = dtors[i]; Expression *ex = new ThisExp(0); ex = new DotVarExp(0, ex, fd, 0); ex = new CallExp(0, ex); diff --git a/dmd2/cond.c b/dmd2/cond.c index afce513e..f54fd467 100644 --- a/dmd2/cond.c +++ b/dmd2/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/dmd2/constfold.c b/dmd2/constfold.c index 887aa515..b114885e 100644 --- a/dmd2/constfold.c +++ b/dmd2/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__ @@ -621,7 +622,7 @@ Expression *Pow(Type *type, Expression *e1, Expression *e2) // Special case: call sqrt directly. Expressions args; args.setDim(1); - args.tdata()[0] = e1; + args[0] = e1; e = eval_builtin(loc, BUILTINsqrt, &args); if (!e) e = EXP_CANT_INTERPRET; @@ -1290,7 +1291,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); @@ -1374,7 +1375,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; @@ -1392,7 +1393,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; @@ -1407,12 +1408,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; @@ -1483,7 +1484,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; } @@ -1512,7 +1513,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); } } @@ -1525,7 +1526,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; @@ -1549,6 +1550,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) @@ -1666,7 +1709,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; @@ -1684,7 +1727,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/dmd2/cppmangle.c b/dmd2/cppmangle.c index 915bb23c..f29eaa83 100644 --- a/dmd2/cppmangle.c +++ b/dmd2/cppmangle.c @@ -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 @@ -9,6 +9,7 @@ // See the included readme.txt for details. #include +#include #include #include "mars.h" @@ -69,7 +70,7 @@ int CppMangleState::substitute(OutBuffer *buf, void *p) { for (size_t i = 0; i < components.dim; i++) { - if (p == components.tdata()[i]) + if (p == components[i]) { /* Sequence is S_, S0_, .., S9_, SA_, ..., SZ_, S10_, ... */ @@ -88,7 +89,7 @@ int CppMangleState::exist(void *p) { for (size_t i = 0; i < components.dim; i++) { - if (p == components.tdata()[i]) + if (p == components[i]) { return 1; } @@ -160,7 +161,7 @@ char *cpp_mangle(Dsymbol *s) cms.components.setDim(0); OutBuffer buf; -#if MACHOBJ +#if TARGET_OSX buf.writestring("__Z"); #else buf.writestring("_Z"); @@ -417,7 +418,7 @@ void Parameter::argsCppMangle(OutBuffer *buf, CppMangleState *cms, Parameters *a if (arguments) { for (size_t i = 0; i < arguments->dim; i++) - { Parameter *arg = arguments->tdata()[i]; + { Parameter *arg = (*arguments)[i]; Type *t = arg->type; if (arg->storageClass & (STCout | STCref)) t = t->referenceTo(); diff --git a/dmd2/declaration.c b/dmd2/declaration.c index 8b5f5eab..d82248c6 100644 --- a/dmd2/declaration.c +++ b/dmd2/declaration.c @@ -122,6 +122,18 @@ void Declaration::checkModify(Loc loc, Scope *sc, Type *t) } #endif +Dsymbol *Declaration::search(Loc loc, Identifier *ident, int flags) +{ + Dsymbol *s = Dsymbol::search(loc, ident, flags); + if (!s && type) + { + s = type->toDsymbol(NULL); + if (s) + s = s->search(loc, ident, flags); + } + return s; +} + /********************************* TupleDeclaration ****************************/ @@ -159,7 +171,7 @@ Type *TupleDeclaration::getType() /* It's only a type tuple if all the Object's are types */ for (size_t i = 0; i < objects->dim; i++) - { Object *o = objects->tdata()[i]; + { Object *o = (*objects)[i]; if (o->dyncast() != DYNCAST_TYPE) { @@ -176,7 +188,7 @@ Type *TupleDeclaration::getType() OutBuffer buf; int hasdeco = 1; for (size_t i = 0; i < types->dim; i++) - { Type *t = types->tdata()[i]; + { Type *t = (*types)[i]; //printf("type = %s\n", t->toChars()); #if 0 @@ -187,7 +199,7 @@ Type *TupleDeclaration::getType() #else Parameter *arg = new Parameter(0, t, NULL, NULL); #endif - args->tdata()[i] = arg; + (*args)[i] = arg; if (!t->deco) hasdeco = 0; } @@ -204,7 +216,7 @@ int TupleDeclaration::needThis() { //printf("TupleDeclaration::needThis(%s)\n", toChars()); for (size_t i = 0; i < objects->dim; i++) - { Object *o = objects->tdata()[i]; + { Object *o = (*objects)[i]; if (o->dyncast() == DYNCAST_EXPRESSION) { Expression *e = (Expression *)o; if (e->op == TOKdsymbol) @@ -336,7 +348,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; @@ -557,6 +569,17 @@ void AliasDeclaration::semantic(Scope *sc) s->parent = sc->parent; } } + OverloadSet *o = s->toAlias()->isOverloadSet(); + if (o) + { + if (overnext) + { + o->push(overnext); + overnext = NULL; + s = o; + s->parent = sc->parent; + } + } if (overnext) ScopeDsymbol::multiplyDefined(0, this, overnext); if (s == this) @@ -619,7 +642,9 @@ const char *AliasDeclaration::kind() Type *AliasDeclaration::getType() { - return type; + if (type) + return type; + return toAlias()->getType(); } Dsymbol *AliasDeclaration::toAlias() @@ -632,7 +657,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; @@ -845,6 +872,14 @@ void VarDeclaration::semantic(Scope *sc) this->parent = sc->parent; //printf("this = %p, parent = %p, '%s'\n", this, parent, parent->toChars()); protection = sc->protection; + + /* If scope's alignment is the default, use the type's alignment, + * otherwise the scope overrrides. + */ + alignment = sc->structalign; + if (alignment == STRUCTALIGN_DEFAULT) + alignment = type->alignment(); // use type's alignment + //printf("sc->stc = %x\n", sc->stc); //printf("storage_class = x%x\n", storage_class); @@ -931,7 +966,7 @@ void VarDeclaration::semantic(Scope *sc) for (size_t pos = 0; pos < iexps->dim; pos++) { Lexpand1: - Expression *e = iexps->tdata()[pos]; + Expression *e = (*iexps)[pos]; Parameter *arg = Parameter::getNth(tt->arguments, pos); arg->type = arg->type->semantic(loc, sc); //printf("[%d] iexps->dim = %d, ", pos, iexps->dim); @@ -1028,7 +1063,7 @@ Lnomatch: Expression *einit = ie; if (ie && ie->op == TOKtuple) - { einit = ((TupleExp *)ie)->exps->tdata()[i]; + { einit = (*((TupleExp *)ie)->exps)[i]; } Initializer *ti = init; if (einit) @@ -1051,7 +1086,7 @@ Lnomatch: } #endif Expression *e = new DsymbolExp(loc, v); - exps->tdata()[i] = e; + (*exps)[i] = e; } TupleDeclaration *v2 = new TupleDeclaration(loc, ident, exps); v2->isexp = 1; @@ -1091,7 +1126,7 @@ Lnomatch: } else if (storage_class & STCfinal) { - error("final cannot be applied to variable"); + error("final cannot be applied to variable, perhaps you meant const?"); } if (storage_class & (STCstatic | STCextern | STCmanifest | STCtemplateparameter | STCtls | STCgshared | STCctfe)) @@ -1114,7 +1149,6 @@ Lnomatch: #endif { storage_class |= STCfield; - alignment = sc->structalign; #if DMDV2 if (tb->ty == Tstruct && ((TypeStruct *)tb)->sym->noDefaultCtor || tb->ty == Tclass && ((TypeClass *)tb)->sym->noDefaultCtor) @@ -1244,6 +1278,19 @@ Lnomatch: init = new ExpInitializer(loc, e); goto Ldtor; } + else if (type->ty == Tstruct && + (((TypeStruct *)type)->sym->isnested)) + { + /* Nested struct requires valid enclosing frame pointer. + * In StructLiteralExp::toElem(), it's calculated. + */ + Expression *e = type->defaultInitLiteral(loc); + Expression *e1 = new VarExp(loc, this); + e = new ConstructExp(loc, e1, e); + e = e->semantic(sc); + init = new ExpInitializer(loc, e); + goto Ldtor; + } else if (type->ty == Ttypedef) { TypeTypedef *td = (TypeTypedef *)type; if (td->sym->init) @@ -1313,7 +1360,8 @@ Lnomatch: Expression *e = init->toExpression(); if (!e) { - init = init->semantic(sc, type, 0); // Don't need to interpret + // Run semantic, but 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"); @@ -1395,16 +1443,26 @@ Lnomatch: { e = new ConstructExp(loc, new VarExp(loc, this), new IntegerExp(loc, 0, Type::tint32)); } + else if (sd->isNested()) + { e = new AssignExp(loc, new VarExp(loc, this), t->defaultInitLiteral(loc)); + e->op = TOKblit; + } else { e = new AssignExp(loc, new VarExp(loc, this), t->defaultInit(loc)); e->op = TOKblit; } e->type = t; - (*pinit) = new CommaExp(loc, e, (*pinit)); - /* Replace __ctmp being constructed with e1 + /* Replace __ctmp being constructed with e1. + * We need to copy constructor call expression, + * because it may be used in other place. */ - dve->e1 = e1; + DotVarExp *dvx = (DotVarExp *)dve->copy(); + dvx->e1 = e1; + CallExp *cx = (CallExp *)ce->copy(); + cx->e1 = dvx; + + (*pinit) = new CommaExp(loc, e, cx); (*pinit) = (*pinit)->semantic(sc); goto Ldtor; } @@ -1466,7 +1524,7 @@ Lnomatch: } else { - init = init->semantic(sc, type, WANTinterpret); + init = init->semantic(sc, type, INITinterpret); } } else if (storage_class & (STCconst | STCimmutable | STCmanifest) || @@ -1537,7 +1595,7 @@ Lnomatch: } 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 @@ -1552,7 +1610,7 @@ Lnomatch: else if (ei) { if (isDataseg() || (storage_class & STCmanifest)) - e = e->optimize(WANTvalue | WANTinterpret); + e = e->ctfeInterpret(); else e = e->optimize(WANTvalue); switch (e->op) @@ -1639,7 +1697,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--; } sem = Semantic2Done; @@ -1710,9 +1768,8 @@ 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 - offset = AggregateDeclaration::placeField(poffset, memsize, memalignsize, memalign, + offset = AggregateDeclaration::placeField(poffset, memsize, memalignsize, alignment, &ad->structsize, &ad->alignsize, isunion); //printf("\t%s: alignsize = %d\n", toChars(), alignsize); @@ -1831,28 +1888,8 @@ void VarDeclaration::checkNestedReference(Scope *sc, Loc loc) // The current function FuncDeclaration *fdthis = sc->parent->isFuncDeclaration(); - if (fdv && fdthis && fdv != fdthis && fdthis->ident != Id::ensure && fdthis->ident != Id::require) + if (fdv && fdthis && fdv != fdthis) { - /* __ensure is always called directly, - * so it never becomes closure. - */ - - //printf("\tfdv = %s\n", fdv->toChars()); - //printf("\tfdthis = %s\n", fdthis->toChars()); - - if (loc.filename) - fdthis->getLevel(loc, sc, fdv); - - // Function literals from fdthis to fdv must be delegates - for (Dsymbol *s = fdthis; s && s != fdv; s = s->toParent2()) - { - // function literal has reference to enclosing scope is delegate - if (FuncLiteralDeclaration *fld = s->isFuncLiteralDeclaration()) - { - fld->tok = TOKdelegate; - } - } - // Add fdthis to nestedrefs[] if not already there for (size_t i = 0; 1; i++) { @@ -1865,23 +1902,46 @@ void VarDeclaration::checkNestedReference(Scope *sc, Loc loc) break; } - // Add this to fdv->closureVars[] if not already there - for (size_t i = 0; 1; i++) + if (fdthis->ident != Id::ensure) { - if (i == fdv->closureVars.dim) - { - fdv->closureVars.push(this); - break; - } - if (fdv->closureVars[i] == this) - break; - } + /* __ensure is always called directly, + * so it never becomes closure. + */ - //printf("fdthis is %s\n", fdthis->toChars()); - //printf("var %s in function %s is nested ref\n", toChars(), fdv->toChars()); - // __dollar creates problems because it isn't a real variable Bugzilla 3326 - if (ident == Id::dollar) - ::error(loc, "cannnot use $ inside a function literal"); + //printf("\tfdv = %s\n", fdv->toChars()); + //printf("\tfdthis = %s\n", fdthis->toChars()); + + if (loc.filename) + fdthis->getLevel(loc, sc, fdv); + + // Function literals from fdthis to fdv must be delegates + for (Dsymbol *s = fdthis; s && s != fdv; s = s->toParent2()) + { + // function literal has reference to enclosing scope is delegate + if (FuncLiteralDeclaration *fld = s->isFuncLiteralDeclaration()) + { + fld->tok = TOKdelegate; + } + } + + // Add this to fdv->closureVars[] if not already there + for (size_t i = 0; 1; i++) + { + if (i == fdv->closureVars.dim) + { + fdv->closureVars.push(this); + break; + } + if (fdv->closureVars[i] == this) + break; + } + + //printf("fdthis is %s\n", fdthis->toChars()); + //printf("var %s in function %s is nested ref\n", toChars(), fdv->toChars()); + // __dollar creates problems because it isn't a real variable Bugzilla 3326 + if (ident == Id::dollar) + ::error(loc, "cannnot use $ inside a function literal"); + } } } } @@ -2353,7 +2413,7 @@ TypeInfoAssociativeArrayDeclaration::TypeInfoAssociativeArrayDeclaration(Type *t TypeInfoVectorDeclaration::TypeInfoVectorDeclaration(Type *tinfo) : TypeInfoDeclaration(tinfo, 0) { - if (!Type::typeinfoarray) + if (!Type::typeinfovector) { ObjectNotFound(Id::TypeInfo_Vector); } diff --git a/dmd2/declaration.h b/dmd2/declaration.h index 66d87567..fff2ef8f 100644 --- a/dmd2/declaration.h +++ b/dmd2/declaration.h @@ -101,6 +101,12 @@ enum PURE; #define STCdisable 0x2000000000LL // for functions that are not callable #define STCresult 0x4000000000LL // for result variables passed to out contracts #define STCnodefaultctor 0x8000000000LL // must be set inside constructor +#define STCtemp 0x10000000000LL // temporary variable introduced by inlining + // and used only in backend process, so it's rvalue + +#ifdef BUG6652 +#define STCbug6652 0x800000000000LL // +#endif struct Match { @@ -136,7 +142,7 @@ struct Declaration : Dsymbol enum LINK linkage; int inuse; // used to detect cycles -#if IN_GCC +#ifdef IN_GCC Expressions *attributes; // GCC decl/type attributes #endif @@ -148,6 +154,8 @@ struct Declaration : Dsymbol unsigned size(Loc loc); void checkModify(Loc loc, Scope *sc, Type *t); + Dsymbol *search(Loc loc, Identifier *ident, int flags); + void emitComment(Scope *sc); void toJsonBuffer(OutBuffer *buf); void toDocBuffer(OutBuffer *buf); @@ -288,7 +296,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 @@ -710,7 +718,7 @@ enum BUILTIN BUILTINbsr, // core.bitop.bsr BUILTINbsf, // core.bitop.bsf BUILTINbswap, // core.bitop.bswap -#if IN_GCC +#ifdef IN_GCC BUILTINgcc, // GCC builtin #endif }; @@ -738,12 +746,14 @@ 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 VarDeclaration *vthis; // 'this' parameter (member and nested) VarDeclaration *v_arguments; // '_arguments' parameter -#if IN_GCC +#ifdef IN_GCC + VarDeclaration *v_arguments_var; // '_arguments' variable VarDeclaration *v_argptr; // '_argptr' variable #endif VarDeclaration *v_argsave; // save area for args passed in registers for variadic functions @@ -861,6 +871,7 @@ struct FuncDeclaration : Declaration void checkNestedReference(Scope *sc, Loc loc); int needsClosure(); int hasNestedFrameRefs(); + void buildResultVar(); Statement *mergeFrequire(Statement *, Expressions *params = 0); Statement *mergeFensure(Statement *, Expressions *params = 0); Parameters *getParameters(int *pvarargs); @@ -941,6 +952,7 @@ struct FuncAliasDeclaration : FuncDeclaration struct FuncLiteralDeclaration : FuncDeclaration { enum TOK tok; // TOKfunction or TOKdelegate + Type *treq; // target of return type inference FuncLiteralDeclaration(Loc loc, Loc endloc, Type *type, enum TOK tok, ForeachStatement *fes); diff --git a/dmd2/delegatize.c b/dmd2/delegatize.c index b08892f1..b6014892 100644 --- a/dmd2/delegatize.c +++ b/dmd2/delegatize.c @@ -20,6 +20,10 @@ #include "aggregate.h" #include "scope.h" +#if IN_LLVM +#include "init.h" +#endif + /******************************************** * Convert from expression to delegate that returns the expression, * i.e. convert: @@ -110,6 +114,36 @@ int lambdaCheckForNestedRef(Expression *e, void *param) */ switch (e->op) { +#if IN_LLVM + // We also need to consider the initializers of VarDeclarations in + // DeclarationExps, such as generated for postblit invocation for + // function parameters. + // + // Without this check, e.g. the nested reference to a in the delegate + // create for the lazy argument is not picked up in the following case: + // --- + // struct HasPostblit { this(this) {} } + // struct Foo { HasPostblit _data; } + // void receiver(Foo) {} + // void lazyFunc(E)(lazy E e) { e(); } + // void test() { Foo a; lazyFunc(receiver(a)); } + // --- + case TOKdeclaration: + { DeclarationExp *de = (DeclarationExp *)e; + if (VarDeclaration *vd = de->declaration->isVarDeclaration()) + { + if (vd->init) + { + if (ExpInitializer* ei = vd->init->isExpInitializer()) + { + ei->exp->apply(&lambdaCheckForNestedRef, sc); + } + // TODO: Other classes of initializers? + } + } + break; + } +#endif case TOKsymoff: { SymOffExp *se = (SymOffExp *)e; VarDeclaration *v = se->var->isVarDeclaration(); diff --git a/dmd2/dmd_msc.vcproj b/dmd2/dmd_msc.vcproj index 94a9e4f9..1d27f7e3 100644 --- a/dmd2/dmd_msc.vcproj +++ b/dmd2/dmd_msc.vcproj @@ -1,7 +1,7 @@ + + + + + + + + + + + + - - - - + RelativePath=".\root\dmgcmem.c" > - - - - + RelativePath=".\root\man.c" > + + + + + + + + + + + + + + + + + + @@ -1656,7 +1718,7 @@ @@ -1667,7 +1729,7 @@ @@ -1678,7 +1740,7 @@ diff --git a/dmd2/doc.c b/dmd2/doc.c index 094d5947..e9631c42 100644 --- a/dmd2/doc.c +++ b/dmd2/doc.c @@ -1,2229 +1,2230 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -// This implements the Ddoc capability. - -#include -#include -#include -#include -#include - -#include "rmem.h" -#include "root.h" - -#include "mars.h" -#include "dsymbol.h" -#include "macro.h" -#include "template.h" -#include "lexer.h" -#include "aggregate.h" -#include "declaration.h" -#include "enum.h" -#include "id.h" -#include "module.h" -#include "scope.h" -#include "hdrgen.h" -#include "doc.h" -#include "mtype.h" -#include "utf.h" - -struct Escape -{ - const char *strings[256]; - - static const char *escapeChar(unsigned c); -}; - -struct Section -{ - unsigned char *name; - unsigned namelen; - - unsigned char *body; - unsigned bodylen; - - int nooutput; - - virtual void write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf); -}; - -struct ParamSection : Section -{ - void write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf); -}; - -struct MacroSection : Section -{ - void write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf); -}; - -typedef ArrayBase
Sections; - -struct DocComment -{ - Sections sections; // Section*[] - - Section *summary; - Section *copyright; - Section *macros; - Macro **pmacrotable; - Escape **pescapetable; - - DocComment(); - - static DocComment *parse(Scope *sc, Dsymbol *s, unsigned char *comment); - static void parseMacros(Escape **pescapetable, Macro **pmacrotable, unsigned char *m, unsigned mlen); - static void parseEscapes(Escape **pescapetable, unsigned char *textstart, unsigned textlen); - - void parseSections(unsigned char *comment); - void writeSections(Scope *sc, Dsymbol *s, OutBuffer *buf); -}; - - -int cmp(const char *stringz, void *s, size_t slen); -int icmp(const char *stringz, void *s, size_t slen); -int isDitto(unsigned char *comment); -unsigned char *skipwhitespace(unsigned char *p); -unsigned skiptoident(OutBuffer *buf, size_t i); -unsigned skippastident(OutBuffer *buf, size_t i); -unsigned skippastURL(OutBuffer *buf, size_t i); -void highlightText(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset); -void highlightCode(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset); -void highlightCode2(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset); -Parameter *isFunctionParameter(Dsymbol *s, unsigned char *p, unsigned len); - -int isIdStart(unsigned char *p); -int isIdTail(unsigned char *p); -int utfStride(unsigned char *p); - -static unsigned char ddoc_default[] = "\ -DDOC = \n\ - \n\ - $(TITLE)\n\ - \n\ -

$(TITLE)

\n\ - $(BODY)\n\ -
$(SMALL Page generated by $(LINK2 http://www.digitalmars.com/d/2.0/ddoc.html, Ddoc). $(COPYRIGHT))\n\ - \n\ -\n\ -B = $0\n\ -I = $0\n\ -U = $0\n\ -P =

$0

\n\ -DL =
$0
\n\ -DT =
$0
\n\ -DD =
$0
\n\ -TABLE = $0
\n\ -TR = $0\n\ -TH = $0\n\ -TD = $0\n\ -OL =
    $0
\n\ -UL =
    $0
\n\ -LI =
  • $0
  • \n\ -BIG = $0\n\ -SMALL = $0\n\ -BR =
    \n\ -LINK = $0\n\ -LINK2 = $+\n\ -LPAREN= (\n\ -RPAREN= )\n\ -DOLLAR= $\n\ -\n\ -RED = $0\n\ -BLUE = $0\n\ -GREEN = $0\n\ -YELLOW =$0\n\ -BLACK = $0\n\ -WHITE = $0\n\ -\n\ -D_CODE =
    $0
    \n\ -D_COMMENT = $(GREEN $0)\n\ -D_STRING = $(RED $0)\n\ -D_KEYWORD = $(BLUE $0)\n\ -D_PSYMBOL = $(U $0)\n\ -D_PARAM = $(I $0)\n\ -\n\ -DDOC_COMMENT = \n\ -DDOC_DECL = $(DT $(BIG $0))\n\ -DDOC_DECL_DD = $(DD $0)\n\ -DDOC_DITTO = $(BR)$0\n\ -DDOC_SECTIONS = $0\n\ -DDOC_SUMMARY = $0$(BR)$(BR)\n\ -DDOC_DESCRIPTION = $0$(BR)$(BR)\n\ -DDOC_AUTHORS = $(B Authors:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_BUGS = $(RED BUGS:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_COPYRIGHT = $(B Copyright:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_DATE = $(B Date:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_DEPRECATED = $(RED Deprecated:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_EXAMPLES = $(B Examples:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_HISTORY = $(B History:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_LICENSE = $(B License:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_RETURNS = $(B Returns:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_SEE_ALSO = $(B See Also:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_STANDARDS = $(B Standards:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_THROWS = $(B Throws:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_VERSION = $(B Version:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_SECTION_H = $(B $0)$(BR)\n\ -DDOC_SECTION = $0$(BR)$(BR)\n\ -DDOC_MEMBERS = $(DL $0)\n\ -DDOC_MODULE_MEMBERS = $(DDOC_MEMBERS $0)\n\ -DDOC_CLASS_MEMBERS = $(DDOC_MEMBERS $0)\n\ -DDOC_STRUCT_MEMBERS = $(DDOC_MEMBERS $0)\n\ -DDOC_ENUM_MEMBERS = $(DDOC_MEMBERS $0)\n\ -DDOC_TEMPLATE_MEMBERS = $(DDOC_MEMBERS $0)\n\ -DDOC_PARAMS = $(B Params:)$(BR)\n$(TABLE $0)$(BR)\n\ -DDOC_PARAM_ROW = $(TR $0)\n\ -DDOC_PARAM_ID = $(TD $0)\n\ -DDOC_PARAM_DESC = $(TD $0)\n\ -DDOC_BLANKLINE = $(BR)$(BR)\n\ -\n\ -DDOC_PSYMBOL = $(U $0)\n\ -DDOC_KEYWORD = $(B $0)\n\ -DDOC_PARAM = $(I $0)\n\ -\n\ -ESCAPES = //>/\n\ - /&/&/\n\ -"; - -static char ddoc_decl_s[] = "$(DDOC_DECL "; -static char ddoc_decl_e[] = ")\n"; - -static char ddoc_decl_dd_s[] = "$(DDOC_DECL_DD "; -static char ddoc_decl_dd_e[] = ")\n"; - - -/**************************************************** - */ - -void Module::gendocfile() -{ - static OutBuffer mbuf; - static int mbuf_done; - - OutBuffer buf; - - //printf("Module::gendocfile()\n"); - - if (!mbuf_done) // if not already read the ddoc files - { mbuf_done = 1; - - // Use our internal default - mbuf.write(ddoc_default, sizeof(ddoc_default) - 1); - - // Override with DDOCFILE specified in the sc.ini file - char *p = getenv("DDOCFILE"); - if (p) - global.params.ddocfiles->shift(p); - - // 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); - File file(&f); - file.readv(); - // BUG: convert file contents to UTF-8 before use - - //printf("file: '%.*s'\n", file.len, file.buffer); - mbuf.write(file.buffer, file.len); - } - } - DocComment::parseMacros(&escapetable, ¯otable, mbuf.data, mbuf.offset); - - Scope *sc = Scope::createGlobal(this); // create root scope - sc->docbuf = &buf; - - DocComment *dc = DocComment::parse(sc, this, comment); - dc->pmacrotable = ¯otable; - dc->pescapetable = &escapetable; - - // Generate predefined macros - - // Set the title to be the name of the module - { const char *p = toPrettyChars(); - Macro::define(¯otable, (unsigned char *)"TITLE", 5, (unsigned char *)p, strlen(p)); - } - - // Set time macros - { time_t t; - time(&t); - char *p = ctime(&t); - p = mem.strdup(p); - Macro::define(¯otable, (unsigned char *)"DATETIME", 8, (unsigned char *)p, strlen(p)); - Macro::define(¯otable, (unsigned char *)"YEAR", 4, (unsigned char *)p + 20, 4); - } - - char *srcfilename = srcfile->toChars(); - Macro::define(¯otable, (unsigned char *)"SRCFILENAME", 11, (unsigned char *)srcfilename, strlen(srcfilename)); - - char *docfilename = docfile->toChars(); - Macro::define(¯otable, (unsigned char *)"DOCFILENAME", 11, (unsigned char *)docfilename, strlen(docfilename)); - - if (dc->copyright) - { - dc->copyright->nooutput = 1; - Macro::define(¯otable, (unsigned char *)"COPYRIGHT", 9, dc->copyright->body, dc->copyright->bodylen); - } - - buf.printf("$(DDOC_COMMENT Generated by Ddoc from %s)\n", srcfile->toChars()); - if (isDocFile) - { - size_t commentlen = strlen((char *)comment); - if (dc->macros) - { - commentlen = dc->macros->name - comment; - dc->macros->write(dc, sc, this, sc->docbuf); - } - sc->docbuf->write(comment, commentlen); - highlightText(NULL, this, sc->docbuf, 0); - } - else - { - dc->writeSections(sc, this, sc->docbuf); - emitMemberComments(sc); - } - - //printf("BODY= '%.*s'\n", buf.offset, buf.data); - Macro::define(¯otable, (unsigned char *)"BODY", 4, buf.data, buf.offset); - - OutBuffer buf2; - buf2.writestring("$(DDOC)\n"); - unsigned end = buf2.offset; - macrotable->expand(&buf2, 0, &end, NULL, 0); - -#if 1 - /* Remove all the escape sequences from buf2, - * and make CR-LF the newline. - */ - { - buf.setsize(0); - buf.reserve(buf2.offset); - unsigned char *p = buf2.data; - for (unsigned j = 0; j < buf2.offset; j++) - { - unsigned char c = p[j]; - if (c == 0xFF && j + 1 < buf2.offset) - { - j++; - continue; - } - if (c == '\n') - buf.writeByte('\r'); - else if (c == '\r') - { - buf.writestring("\r\n"); - if (j + 1 < buf2.offset && p[j + 1] == '\n') - { - j++; - } - continue; - } - buf.writeByte(c); - } - } - - // Transfer image to file - assert(docfile); - docfile->setbuffer(buf.data, buf.offset); - docfile->ref = 1; - char *pt = FileName::path(docfile->toChars()); - if (*pt) - FileName::ensurePathExists(pt); - mem.free(pt); - docfile->writev(); -#else - /* Remove all the escape sequences from buf2 - */ - { unsigned i = 0; - unsigned char *p = buf2.data; - for (unsigned j = 0; j < buf2.offset; j++) - { - if (p[j] == 0xFF && j + 1 < buf2.offset) - { - j++; - continue; - } - p[i] = p[j]; - i++; - } - buf2.setsize(i); - } - - // Transfer image to file - docfile->setbuffer(buf2.data, buf2.offset); - docfile->ref = 1; - char *pt = FileName::path(docfile->toChars()); - if (*pt) - FileName::ensurePathExists(pt); - mem.free(pt); - docfile->writev(); -#endif -} - -/**************************************************** - * Having unmatched parentheses can hose the output of Ddoc, - * as the macros depend on properly nested parentheses. - * This function replaces all ( with $(LPAREN) and ) with $(RPAREN) - * to preserve text literally. This also means macros in the - * text won't be expanded. - */ -void escapeDdocString(OutBuffer *buf, unsigned start) -{ - for (unsigned u = start; u < buf->offset; u++) - { - unsigned char c = buf->data[u]; - switch(c) - { - case '$': - buf->remove(u, 1); - buf->insert(u, "$(DOLLAR)", 9); - u += 8; - break; - - case '(': - buf->remove(u, 1); //remove the ( - buf->insert(u, "$(LPAREN)", 9); //insert this instead - u += 8; //skip over newly inserted macro - break; - - case ')': - buf->remove(u, 1); //remove the ) - buf->insert(u, "$(RPAREN)", 9); //insert this instead - u += 8; //skip over newly inserted macro - break; - } - } -} - -/**************************************************** - * Having unmatched parentheses can hose the output of Ddoc, - * as the macros depend on properly nested parentheses. - - * Fix by replacing unmatched ( with $(LPAREN) and unmatched ) with $(RPAREN). - */ -void escapeStrayParenthesis(OutBuffer *buf, unsigned start, Loc loc) -{ - unsigned par_open = 0; - - for (unsigned u = start; u < buf->offset; u++) - { - unsigned char c = buf->data[u]; - switch(c) - { - case '(': - par_open++; - break; - - case ')': - if (par_open == 0) - { - //stray ')' - if (global.params.warnings) - warning(loc, "Ddoc: Stray ')'. This may cause incorrect Ddoc output." - " Use $(RPAREN) instead for unpaired right parentheses."); - buf->remove(u, 1); //remove the ) - buf->insert(u, "$(RPAREN)", 9); //insert this instead - u += 8; //skip over newly inserted macro - } - else - par_open--; - break; -#if 0 - // For this to work, loc must be set to the beginning of the passed - // text which is currently not possible - // (loc is set to the Loc of the Dsymbol) - case '\n': - loc.linnum++; - break; -#endif - } - } - - if (par_open) // if any unmatched lparens - { par_open = 0; - for (unsigned u = buf->offset; u > start;) - { u--; - unsigned char c = buf->data[u]; - switch(c) - { - case ')': - par_open++; - break; - - case '(': - if (par_open == 0) - { - //stray '(' - if (global.params.warnings) - warning(loc, "Ddoc: Stray '('. This may cause incorrect Ddoc output." - " Use $(LPAREN) instead for unpaired left parentheses."); - buf->remove(u, 1); //remove the ( - buf->insert(u, "$(LPAREN)", 9); //insert this instead - } - else - par_open--; - break; - } - } - } -} - -/******************************* emitComment **********************************/ - -/* - * Emit doc comment to documentation file - */ - -void Dsymbol::emitDitto(Scope *sc) -{ - //printf("Dsymbol::emitDitto() %s %s\n", kind(), toChars()); - OutBuffer *buf = sc->docbuf; - unsigned o; - OutBuffer b; - - b.writestring("$(DDOC_DITTO "); - o = b.offset; - toDocBuffer(&b); - //printf("b: '%.*s'\n", b.offset, b.data); - /* If 'this' is a function template, then highlightCode() was - * already run by FuncDeclaration::toDocbuffer(). - */ - TemplateDeclaration *td; - if (parent && - (td = parent->isTemplateDeclaration()) != NULL && - td->onemember == this) - { - } - else - highlightCode(sc, this, &b, o); - b.writeByte(')'); - buf->spread(sc->lastoffset, b.offset); - memcpy(buf->data + sc->lastoffset, b.data, b.offset); - sc->lastoffset += b.offset; -} - -void ScopeDsymbol::emitMemberComments(Scope *sc) -{ - //printf("ScopeDsymbol::emitMemberComments() %s\n", toChars()); - OutBuffer *buf = sc->docbuf; - - if (members) - { const char *m = "$(DDOC_MEMBERS \n"; - - if (isModule()) - m = "$(DDOC_MODULE_MEMBERS \n"; - else if (isClassDeclaration()) - m = "$(DDOC_CLASS_MEMBERS \n"; - else if (isStructDeclaration()) - m = "$(DDOC_STRUCT_MEMBERS \n"; - else if (isEnumDeclaration()) - m = "$(DDOC_ENUM_MEMBERS \n"; - else if (isTemplateDeclaration()) - m = "$(DDOC_TEMPLATE_MEMBERS \n"; - - unsigned offset1 = buf->offset; // save starting offset - buf->writestring(m); - unsigned offset2 = buf->offset; // to see if we write anything - sc = sc->push(this); - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = (*members)[i]; - //printf("\ts = '%s'\n", s->toChars()); - s->emitComment(sc); - } - sc->pop(); - if (buf->offset == offset2) - { - /* Didn't write out any members, so back out last write - */ - buf->offset = offset1; - } - else - buf->writestring(")\n"); - } -} - -void emitProtection(OutBuffer *buf, PROT prot) -{ - const char *p; - - switch (prot) - { - case PROTpackage: p = "package"; break; - case PROTprotected: p = "protected"; break; - case PROTexport: p = "export"; break; - default: p = NULL; break; - } - if (p) - buf->printf("%s ", p); -} - -void Dsymbol::emitComment(Scope *sc) { } -void InvariantDeclaration::emitComment(Scope *sc) { } -#if DMDV2 -void PostBlitDeclaration::emitComment(Scope *sc) { } -#endif -void DtorDeclaration::emitComment(Scope *sc) { } -void StaticCtorDeclaration::emitComment(Scope *sc) { } -void StaticDtorDeclaration::emitComment(Scope *sc) { } -void ClassInfoDeclaration::emitComment(Scope *sc) { } -void ModuleInfoDeclaration::emitComment(Scope *sc) { } -void TypeInfoDeclaration::emitComment(Scope *sc) { } - - -void Declaration::emitComment(Scope *sc) -{ - //printf("Declaration::emitComment(%p '%s'), comment = '%s'\n", this, toChars(), comment); - //printf("type = %p\n", type); - - if (protection == PROTprivate || !ident || - (!type && !isCtorDeclaration() && !isAliasDeclaration())) - return; - if (!comment) - return; - - OutBuffer *buf = sc->docbuf; - DocComment *dc = DocComment::parse(sc, this, comment); - unsigned o; - - if (!dc) - { - emitDitto(sc); - return; - } - dc->pmacrotable = &sc->module->macrotable; - - buf->writestring(ddoc_decl_s); - o = buf->offset; - toDocBuffer(buf); - highlightCode(sc, this, buf, o); - sc->lastoffset = buf->offset; - buf->writestring(ddoc_decl_e); - - buf->writestring(ddoc_decl_dd_s); - dc->writeSections(sc, this, buf); - buf->writestring(ddoc_decl_dd_e); -} - -void AggregateDeclaration::emitComment(Scope *sc) -{ - //printf("AggregateDeclaration::emitComment() '%s'\n", toChars()); - if (prot() == PROTprivate) - return; - if (!comment) - return; - - OutBuffer *buf = sc->docbuf; - DocComment *dc = DocComment::parse(sc, this, comment); - - if (!dc) - { - emitDitto(sc); - return; - } - dc->pmacrotable = &sc->module->macrotable; - - buf->writestring(ddoc_decl_s); - toDocBuffer(buf); - sc->lastoffset = buf->offset; - buf->writestring(ddoc_decl_e); - - buf->writestring(ddoc_decl_dd_s); - dc->writeSections(sc, this, buf); - emitMemberComments(sc); - buf->writestring(ddoc_decl_dd_e); -} - -void TemplateDeclaration::emitComment(Scope *sc) -{ - //printf("TemplateDeclaration::emitComment() '%s', kind = %s\n", toChars(), kind()); - if (prot() == PROTprivate) - return; - - unsigned char *com = comment; - int hasmembers = 1; - - Dsymbol *ss = this; - - if (onemember) - { - ss = onemember->isAggregateDeclaration(); - if (!ss) - { - ss = onemember->isFuncDeclaration(); - if (ss) - { hasmembers = 0; - if (com != ss->comment) - com = Lexer::combineComments(com, ss->comment); - } - else - ss = this; - } - } - - if (!com) - return; - - OutBuffer *buf = sc->docbuf; - DocComment *dc = DocComment::parse(sc, this, com); - unsigned o; - - if (!dc) - { - ss->emitDitto(sc); - return; - } - dc->pmacrotable = &sc->module->macrotable; - - buf->writestring(ddoc_decl_s); - o = buf->offset; - ss->toDocBuffer(buf); - if (ss == this) - highlightCode(sc, this, buf, o); - sc->lastoffset = buf->offset; - buf->writestring(ddoc_decl_e); - - buf->writestring(ddoc_decl_dd_s); - dc->writeSections(sc, this, buf); - if (hasmembers) - ((ScopeDsymbol *)ss)->emitMemberComments(sc); - buf->writestring(ddoc_decl_dd_e); -} - -void EnumDeclaration::emitComment(Scope *sc) -{ - if (prot() == PROTprivate) - return; -// if (!comment) - { if (isAnonymous() && members) - { - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = (*members)[i]; - s->emitComment(sc); - } - return; - } - } - if (!comment) - return; - if (isAnonymous()) - return; - - OutBuffer *buf = sc->docbuf; - DocComment *dc = DocComment::parse(sc, this, comment); - - if (!dc) - { - emitDitto(sc); - return; - } - dc->pmacrotable = &sc->module->macrotable; - - buf->writestring(ddoc_decl_s); - toDocBuffer(buf); - sc->lastoffset = buf->offset; - buf->writestring(ddoc_decl_e); - - buf->writestring(ddoc_decl_dd_s); - dc->writeSections(sc, this, buf); - emitMemberComments(sc); - buf->writestring(ddoc_decl_dd_e); -} - -void EnumMember::emitComment(Scope *sc) -{ - //printf("EnumMember::emitComment(%p '%s'), comment = '%s'\n", this, toChars(), comment); - if (prot() == PROTprivate) - return; - if (!comment) - return; - - OutBuffer *buf = sc->docbuf; - DocComment *dc = DocComment::parse(sc, this, comment); - unsigned o; - - if (!dc) - { - emitDitto(sc); - return; - } - dc->pmacrotable = &sc->module->macrotable; - - buf->writestring(ddoc_decl_s); - o = buf->offset; - toDocBuffer(buf); - highlightCode(sc, this, buf, o); - sc->lastoffset = buf->offset; - buf->writestring(ddoc_decl_e); - - buf->writestring(ddoc_decl_dd_s); - dc->writeSections(sc, this, buf); - buf->writestring(ddoc_decl_dd_e); -} - -/******************************* toDocBuffer **********************************/ - -void Dsymbol::toDocBuffer(OutBuffer *buf) -{ - //printf("Dsymbol::toDocbuffer() %s\n", toChars()); - HdrGenState hgs; - - hgs.ddoc = 1; - toCBuffer(buf, &hgs); -} - -void prefix(OutBuffer *buf, Dsymbol *s) -{ - if (s->isDeprecated()) - buf->writestring("deprecated "); - Declaration *d = s->isDeclaration(); - if (d) - { - emitProtection(buf, d->protection); - if (d->isAbstract()) - buf->writestring("abstract "); - if (d->isStatic()) - buf->writestring("static "); - if (d->isConst()) - buf->writestring("const "); -#if DMDV2 - if (d->isImmutable()) - buf->writestring("immutable "); -#endif - if (d->isFinal()) - buf->writestring("final "); - if (d->isSynchronized()) - buf->writestring("synchronized "); - } -} - -void declarationToDocBuffer(Declaration *decl, OutBuffer *buf, TemplateDeclaration *td) -{ - //printf("declarationToDocBuffer() %s, originalType = %s, td = %s\n", decl->toChars(), decl->originalType ? decl->originalType->toChars() : "--", td ? td->toChars() : "--"); - if (decl->ident) - { - prefix(buf, decl); - - if (decl->type) - { HdrGenState hgs; - hgs.ddoc = 1; - Type *origType = decl->originalType ? decl->originalType : decl->type; - if (origType->ty == Tfunction) - { - TypeFunction *attrType = (TypeFunction*)(decl->ident == Id::ctor ? origType : decl->type); - ((TypeFunction*)origType)->toCBufferWithAttributes(buf, decl->ident, &hgs, attrType, td); - } - else - origType->toCBuffer(buf, decl->ident, &hgs); - } - else - buf->writestring(decl->ident->toChars()); - buf->writestring(";\n"); - } -} - -void Declaration::toDocBuffer(OutBuffer *buf) -{ - declarationToDocBuffer(this, buf, NULL); -} - -void AliasDeclaration::toDocBuffer(OutBuffer *buf) -{ - //printf("AliasDeclaration::toDocbuffer() %s\n", toChars()); - if (ident) - { - if (isDeprecated()) - buf->writestring("deprecated "); - - emitProtection(buf, protection); - buf->writestring("alias "); - buf->writestring(toChars()); - buf->writestring(";\n"); - } -} - - -void TypedefDeclaration::toDocBuffer(OutBuffer *buf) -{ - if (ident) - { - if (isDeprecated()) - buf->writestring("deprecated "); - - emitProtection(buf, protection); - buf->writestring("typedef "); - buf->writestring(toChars()); - buf->writestring(";\n"); - } -} - - -void FuncDeclaration::toDocBuffer(OutBuffer *buf) -{ - //printf("FuncDeclaration::toDocbuffer() %s\n", toChars()); - if (ident) - { - TemplateDeclaration *td; - - if (parent && - (td = parent->isTemplateDeclaration()) != NULL && - td->onemember == this) - { /* It's a function template - */ - unsigned o = buf->offset; - - declarationToDocBuffer(this, buf, td); - - highlightCode(NULL, this, buf, o); - } - else - { - Declaration::toDocBuffer(buf); - } - } -} - -#if DMDV1 -void CtorDeclaration::toDocBuffer(OutBuffer *buf) -{ - HdrGenState hgs; - - buf->writestring("this"); - Parameter::argsToCBuffer(buf, &hgs, arguments, varargs); - buf->writestring(";\n"); -} -#endif - -void AggregateDeclaration::toDocBuffer(OutBuffer *buf) -{ - if (ident) - { -#if 0 - emitProtection(buf, protection); -#endif - buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); - buf->writestring(";\n"); - } -} - -void StructDeclaration::toDocBuffer(OutBuffer *buf) -{ - //printf("StructDeclaration::toDocbuffer() %s\n", toChars()); - if (ident) - { -#if 0 - emitProtection(buf, protection); -#endif - TemplateDeclaration *td; - - if (parent && - (td = parent->isTemplateDeclaration()) != NULL && - td->onemember == this) - { unsigned o = buf->offset; - td->toDocBuffer(buf); - highlightCode(NULL, this, buf, o); - } - else - { - buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); - } - buf->writestring(";\n"); - } -} - -void ClassDeclaration::toDocBuffer(OutBuffer *buf) -{ - //printf("ClassDeclaration::toDocbuffer() %s\n", toChars()); - if (ident) - { -#if 0 - emitProtection(buf, protection); -#endif - TemplateDeclaration *td; - - if (parent && - (td = parent->isTemplateDeclaration()) != NULL && - td->onemember == this) - { unsigned o = buf->offset; - td->toDocBuffer(buf); - highlightCode(NULL, this, buf, o); - } - else - { - if (isAbstract()) - buf->writestring("abstract "); - buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); - } - int any = 0; - for (size_t i = 0; i < baseclasses->dim; i++) - { BaseClass *bc = (*baseclasses)[i]; - - if (bc->protection == PROTprivate) - continue; - if (bc->base && bc->base->ident == Id::Object) - continue; - - if (any) - buf->writestring(", "); - else - { buf->writestring(": "); - any = 1; - } - emitProtection(buf, bc->protection); - if (bc->base) - { - buf->writestring(bc->base->toPrettyChars()); - } - else - { - HdrGenState hgs; - bc->type->toCBuffer(buf, NULL, &hgs); - } - } - buf->writestring(";\n"); - } -} - - -void EnumDeclaration::toDocBuffer(OutBuffer *buf) -{ - if (ident) - { - buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); - buf->writestring(";\n"); - } -} - -void EnumMember::toDocBuffer(OutBuffer *buf) -{ - if (ident) - { - buf->writestring(toChars()); - } -} - - -/********************************* 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); - if (sc->lastdc && isDitto(comment)) - return NULL; - - DocComment *dc = new DocComment(); - if (!comment) - return dc; - - dc->parseSections(comment); - - for (size_t i = 0; i < dc->sections.dim; i++) - { Section *sec = dc->sections[i]; - - if (icmp("copyright", sec->name, sec->namelen) == 0) - { - dc->copyright = sec; - } - if (icmp("macros", sec->name, sec->namelen) == 0) - { - dc->macros = sec; - } - } - - sc->lastdc = dc; - return dc; -} - -/***************************************** - * Parse next paragraph out of *pcomment. - * Update *pcomment to point past paragraph. - * Returns NULL if no more paragraphs. - * If paragraph ends in 'identifier:', - * then (*pcomment)[0 .. idlen] is the identifier. - */ - -void DocComment::parseSections(unsigned char *comment) -{ unsigned char *p; - unsigned char *pstart; - unsigned char *pend; - unsigned char *idstart; - unsigned idlen; - - unsigned char *name = NULL; - unsigned namelen = 0; - - //printf("parseSections('%s')\n", comment); - p = comment; - while (*p) - { - p = skipwhitespace(p); - pstart = p; - pend = p; - - /* Find end of section, which is ended by one of: - * 'identifier:' (but not inside a code section) - * '\0' - */ - idlen = 0; - int inCode = 0; - while (1) - { - // Check for start/end of a code section - if (*p == '-') - { - int numdash = 0; - while (*p == '-') - { - ++numdash; - p++; - } - // BUG: handle UTF PS and LS too - if (!*p || *p == '\r' || *p == '\n' && numdash >= 3) - inCode ^= 1; - pend = p; - } - - if (!inCode && isIdStart(p)) - { - unsigned char *q = p + utfStride(p); - while (isIdTail(q)) - q += utfStride(q); - if (*q == ':') // identifier: ends it - { idlen = q - p; - idstart = p; - for (pend = p; pend > pstart; pend--) - { if (pend[-1] == '\n') - break; - } - p = q + 1; - break; - } - } - while (1) - { - if (!*p) - goto L1; - if (*p == '\n') - { p++; - if (*p == '\n' && !summary && !namelen && !inCode) - { - pend = p; - p++; - goto L1; - } - break; - } - p++; - pend = p; - } - p = skipwhitespace(p); - } - L1: - - if (namelen || pstart < pend) - { - Section *s; - if (icmp("Params", name, namelen) == 0) - s = new ParamSection(); - else if (icmp("Macros", name, namelen) == 0) - s = new MacroSection(); - else - s = new Section(); - s->name = name; - s->namelen = namelen; - s->body = pstart; - s->bodylen = pend - pstart; - s->nooutput = 0; - - //printf("Section: '%.*s' = '%.*s'\n", s->namelen, s->name, s->bodylen, s->body); - - sections.push(s); - - if (!summary && !namelen) - summary = s; - } - - if (idlen) - { name = idstart; - namelen = idlen; - } - else - { name = NULL; - namelen = 0; - if (!*p) - break; - } - } -} - -void DocComment::writeSections(Scope *sc, Dsymbol *s, OutBuffer *buf) -{ - //printf("DocComment::writeSections()\n"); - if (sections.dim) - { - buf->writestring("$(DDOC_SECTIONS \n"); - for (size_t i = 0; i < sections.dim; i++) - { Section *sec = sections[i]; - - if (sec->nooutput) - continue; - //printf("Section: '%.*s' = '%.*s'\n", sec->namelen, sec->name, sec->bodylen, sec->body); - if (sec->namelen || i) - sec->write(this, sc, s, buf); - else - { - buf->writestring("$(DDOC_SUMMARY "); - unsigned o = buf->offset; - buf->write(sec->body, sec->bodylen); - escapeStrayParenthesis(buf, o, s->loc); - highlightText(sc, s, buf, o); - buf->writestring(")\n"); - } - } - buf->writestring(")\n"); - } - else - { - buf->writestring("$(DDOC_BLANKLINE)\n"); - } -} - -/*************************************************** - */ - -void Section::write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf) -{ - if (namelen) - { - static const char *table[] = - { "AUTHORS", "BUGS", "COPYRIGHT", "DATE", - "DEPRECATED", "EXAMPLES", "HISTORY", "LICENSE", - "RETURNS", "SEE_ALSO", "STANDARDS", "THROWS", - "VERSION" }; - - for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++) - { - if (icmp(table[i], name, namelen) == 0) - { - buf->printf("$(DDOC_%s ", table[i]); - goto L1; - } - } - - buf->writestring("$(DDOC_SECTION "); - // Replace _ characters with spaces - buf->writestring("$(DDOC_SECTION_H "); - unsigned o = buf->offset; - for (unsigned u = 0; u < namelen; u++) - { unsigned char c = name[u]; - buf->writeByte((c == '_') ? ' ' : c); - } - escapeStrayParenthesis(buf, o, s->loc); - buf->writestring(":)\n"); - } - else - { - buf->writestring("$(DDOC_DESCRIPTION "); - } - L1: - unsigned o = buf->offset; - buf->write(body, bodylen); - escapeStrayParenthesis(buf, o, s->loc); - highlightText(sc, s, buf, o); - buf->writestring(")\n"); -} - -/*************************************************** - */ - -void ParamSection::write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf) -{ - unsigned char *p = body; - unsigned len = bodylen; - unsigned char *pend = p + len; - - unsigned char *tempstart; - unsigned templen; - - unsigned char *namestart; - unsigned namelen = 0; // !=0 if line continuation - - unsigned char *textstart; - unsigned textlen; - - unsigned o; - Parameter *arg; - - buf->writestring("$(DDOC_PARAMS \n"); - while (p < pend) - { - // Skip to start of macro - while (1) - { - switch (*p) - { - case ' ': - case '\t': - p++; - continue; - - case '\n': - p++; - goto Lcont; - - default: - if (isIdStart(p)) - break; - if (namelen) - goto Ltext; // continuation of prev macro - goto Lskipline; - } - break; - } - tempstart = p; - - while (isIdTail(p)) - p += utfStride(p); - templen = p - tempstart; - - while (*p == ' ' || *p == '\t') - p++; - - if (*p != '=') - { if (namelen) - goto Ltext; // continuation of prev macro - goto Lskipline; - } - p++; - - if (namelen) - { // Output existing param - - L1: - //printf("param '%.*s' = '%.*s'\n", namelen, namestart, textlen, textstart); - HdrGenState hgs; - buf->writestring("$(DDOC_PARAM_ROW "); - buf->writestring("$(DDOC_PARAM_ID "); - o = buf->offset; - arg = isFunctionParameter(s, namestart, namelen); - if (arg && arg->type && arg->ident) - arg->type->toCBuffer(buf, arg->ident, &hgs); - else - buf->write(namestart, namelen); - escapeStrayParenthesis(buf, o, s->loc); - highlightCode(sc, s, buf, o); - buf->writestring(")\n"); - - buf->writestring("$(DDOC_PARAM_DESC "); - o = buf->offset; - buf->write(textstart, textlen); - escapeStrayParenthesis(buf, o, s->loc); - highlightText(sc, s, buf, o); - buf->writestring(")"); - buf->writestring(")\n"); - namelen = 0; - if (p >= pend) - break; - } - - namestart = tempstart; - namelen = templen; - - while (*p == ' ' || *p == '\t') - p++; - textstart = p; - - Ltext: - while (*p != '\n') - p++; - textlen = p - textstart; - p++; - - Lcont: - continue; - - Lskipline: - // Ignore this line - while (*p++ != '\n') - ; - } - if (namelen) - goto L1; // write out last one - buf->writestring(")\n"); -} - -/*************************************************** - */ - -void MacroSection::write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf) -{ - //printf("MacroSection::write()\n"); - DocComment::parseMacros(dc->pescapetable, dc->pmacrotable, body, bodylen); -} - -/************************************************ - * Parse macros out of Macros: section. - * Macros are of the form: - * name1 = value1 - * - * name2 = value2 - */ - -void DocComment::parseMacros(Escape **pescapetable, Macro **pmacrotable, unsigned char *m, unsigned mlen) -{ - unsigned char *p = m; - unsigned len = mlen; - unsigned char *pend = p + len; - - unsigned char *tempstart; - unsigned templen; - - unsigned char *namestart; - unsigned namelen = 0; // !=0 if line continuation - - unsigned char *textstart; - unsigned textlen; - - while (p < pend) - { - // Skip to start of macro - while (1) - { - if (p >= pend) - goto Ldone; - switch (*p) - { - case ' ': - case '\t': - p++; - continue; - - case '\n': - p++; - goto Lcont; - - default: - if (isIdStart(p)) - break; - if (namelen) - goto Ltext; // continuation of prev macro - goto Lskipline; - } - break; - } - tempstart = p; - - while (1) - { - if (p >= pend) - goto Ldone; - if (!isIdTail(p)) - break; - p += utfStride(p); - } - templen = p - tempstart; - - while (1) - { - if (p >= pend) - goto Ldone; - if (!(*p == ' ' || *p == '\t')) - break; - p++; - } - - if (*p != '=') - { if (namelen) - goto Ltext; // continuation of prev macro - goto Lskipline; - } - p++; - if (p >= pend) - goto Ldone; - - if (namelen) - { // Output existing macro - L1: - //printf("macro '%.*s' = '%.*s'\n", namelen, namestart, textlen, textstart); - if (icmp("ESCAPES", namestart, namelen) == 0) - parseEscapes(pescapetable, textstart, textlen); - else - Macro::define(pmacrotable, namestart, namelen, textstart, textlen); - namelen = 0; - if (p >= pend) - break; - } - - namestart = tempstart; - namelen = templen; - - while (p < pend && (*p == ' ' || *p == '\t')) - p++; - textstart = p; - - Ltext: - while (p < pend && *p != '\n') - p++; - textlen = p - textstart; - - // Remove trailing \r if there is one - if (p > m && p[-1] == '\r') - textlen--; - - p++; - //printf("p = %p, pend = %p\n", p, pend); - - Lcont: - continue; - - Lskipline: - // Ignore this line - while (p < pend && *p++ != '\n') - ; - } -Ldone: - if (namelen) - goto L1; // write out last one -} - -/************************************** - * Parse escapes of the form: - * /c/string/ - * where c is a single character. - * Multiple escapes can be separated - * by whitespace and/or commas. - */ - -void DocComment::parseEscapes(Escape **pescapetable, unsigned char *textstart, unsigned textlen) -{ Escape *escapetable = *pescapetable; - - if (!escapetable) - { escapetable = new Escape; - *pescapetable = escapetable; - } - unsigned char *p = textstart; - unsigned char *pend = p + textlen; - - while (1) - { - while (1) - { - if (p + 4 >= pend) - return; - if (!(*p == ' ' || *p == '\t' || *p == '\n' || *p == ',')) - break; - p++; - } - if (p[0] != '/' || p[2] != '/') - return; - unsigned char c = p[1]; - p += 3; - unsigned char *start = p; - while (1) - { - if (p >= pend) - return; - if (*p == '/') - break; - p++; - } - size_t len = p - start; - char *s = (char *)memcpy(mem.malloc(len + 1), start, len); - s[len] = 0; - escapetable->strings[c] = s; - //printf("%c = '%s'\n", c, s); - p++; - } -} - - -/****************************************** - * Compare 0-terminated string with length terminated string. - * Return < 0, ==0, > 0 - */ - -int cmp(const char *stringz, void *s, size_t slen) -{ - size_t len1 = strlen(stringz); - - if (len1 != slen) - return len1 - slen; - return memcmp(stringz, s, slen); -} - -int icmp(const char *stringz, void *s, size_t slen) -{ - size_t len1 = strlen(stringz); - - if (len1 != slen) - return len1 - slen; - return memicmp(stringz, (char *)s, slen); -} - -/***************************************** - * Return !=0 if comment consists entirely of "ditto". - */ - -int isDitto(unsigned char *comment) -{ - if (comment) - { - unsigned char *p = skipwhitespace(comment); - - if (memicmp((char *)p, "ditto", 5) == 0 && *skipwhitespace(p + 5) == 0) - return 1; - } - return 0; -} - -/********************************************** - * Skip white space. - */ - -unsigned char *skipwhitespace(unsigned char *p) -{ - for (; 1; p++) - { switch (*p) - { - case ' ': - case '\t': - case '\n': - continue; - } - break; - } - return p; -} - - -/************************************************ - * Scan forward to one of: - * start of identifier - * beginning of next line - * end of buf - */ - -unsigned skiptoident(OutBuffer *buf, size_t i) -{ - while (i < buf->offset) - { dchar_t c; - - size_t oi = i; - if (utf_decodeChar((unsigned char *)buf->data, buf->offset, &i, &c)) - /* Ignore UTF errors, but still consume input - */ - break; - if (c >= 0x80) - { - if (!isUniAlpha(c)) - continue; - } - else if (!(isalpha(c) || c == '_' || c == '\n')) - continue; - i = oi; - break; - } - return i; -} - -/************************************************ - * Scan forward past end of identifier. - */ - -unsigned skippastident(OutBuffer *buf, size_t i) -{ - while (i < buf->offset) - { dchar_t c; - - size_t oi = i; - if (utf_decodeChar((unsigned char *)buf->data, buf->offset, &i, &c)) - /* Ignore UTF errors, but still consume input - */ - break; - if (c >= 0x80) - { - if (isUniAlpha(c)) - continue; - } - else if (isalnum(c) || c == '_') - continue; - i = oi; - break; - } - return i; -} - - -/************************************************ - * Scan forward past URL starting at i. - * We don't want to highlight parts of a URL. - * Returns: - * i if not a URL - * index just past it if it is a URL - */ - -unsigned skippastURL(OutBuffer *buf, size_t i) -{ unsigned length = buf->offset - i; - unsigned char *p = &buf->data[i]; - unsigned j; - unsigned sawdot = 0; - - if (length > 7 && memicmp((char *)p, "http://", 7) == 0) - { - j = 7; - } - else if (length > 8 && memicmp((char *)p, "https://", 8) == 0) - { - j = 8; - } - else - goto Lno; - - for (; j < length; j++) - { unsigned char c = p[j]; - if (isalnum(c)) - continue; - if (c == '-' || c == '_' || c == '?' || - c == '=' || c == '%' || c == '&' || - c == '/' || c == '+' || c == '#' || - c == '~') - continue; - if (c == '.') - { - sawdot = 1; - continue; - } - break; - } - if (sawdot) - return i + j; - -Lno: - return i; -} - - -/**************************************************** - */ - -int isKeyword(unsigned char *p, unsigned len) -{ - static const char *table[] = { "true", "false", "null" }; - - for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++) - { - if (cmp(table[i], p, len) == 0) - return 1; - } - return 0; -} - -/**************************************************** - */ - -Parameter *isFunctionParameter(Dsymbol *s, unsigned char *p, unsigned len) -{ - FuncDeclaration *f = s->isFuncDeclaration(); - - /* f->type may be NULL for template members. - */ - if (f && f->type) - { - TypeFunction *tf; - if (f->originalType) - { - tf = (TypeFunction *)f->originalType; - } - else - tf = (TypeFunction *)f->type; - - if (tf->parameters) - { - for (size_t k = 0; k < tf->parameters->dim; k++) - { Parameter *arg = (*tf->parameters)[k]; - - if (arg->ident && cmp(arg->ident->toChars(), p, len) == 0) - { - return arg; - } - } - } - } - return NULL; -} - -/************************************************** - * Highlight text section. - */ - -void highlightText(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset) -{ - //printf("highlightText()\n"); - const char *sid = s->ident->toChars(); - FuncDeclaration *f = s->isFuncDeclaration(); - unsigned char *p; - const char *se; - - int leadingBlank = 1; - int inCode = 0; - int inComment = 0; // in comment - unsigned iCodeStart; // start of code section - - unsigned iLineStart = offset; - - for (unsigned i = offset; i < buf->offset; i++) - { unsigned char c = buf->data[i]; - - Lcont: - switch (c) - { - case ' ': - case '\t': - break; - - case '\n': - if (sc && !inCode && i == iLineStart && i + 1 < buf->offset) // if "\n\n" - { - static char blankline[] = "$(DDOC_BLANKLINE)\n"; - - i = buf->insert(i, blankline, sizeof(blankline) - 1); - } - leadingBlank = 1; - iLineStart = i + 1; - break; - - case '<': - leadingBlank = 0; - if (inCode) - break; - p = &buf->data[i]; - - // Skip over comments - if (p[1] == '!' && p[2] == '-' && p[3] == '-') - { unsigned j = i + 4; - p += 4; - while (1) - { - if (j == buf->offset) - goto L1; - if (p[0] == '-' && p[1] == '-' && p[2] == '>') - { - i = j + 2; // place on closing '>' - break; - } - j++; - p++; - } - break; - } - - // Skip over HTML tag - if (isalpha(p[1]) || (p[1] == '/' && isalpha(p[2]))) - { unsigned j = i + 2; - p += 2; - while (1) - { - if (j == buf->offset) - goto L1; - if (p[0] == '>') - { - i = j; // place on closing '>' - break; - } - j++; - p++; - } - break; - } - - L1: - // Replace '<' with '<' character entity - se = Escape::escapeChar('<'); - if (se) - { size_t len = strlen(se); - buf->remove(i, 1); - i = buf->insert(i, se, len); - i--; // point to ';' - } - break; - - case '>': - leadingBlank = 0; - if (inCode) - break; - // Replace '>' with '>' character entity - se = Escape::escapeChar('>'); - if (se) - { size_t len = strlen(se); - buf->remove(i, 1); - i = buf->insert(i, se, len); - i--; // point to ';' - } - break; - - case '&': - leadingBlank = 0; - if (inCode) - break; - p = &buf->data[i]; - if (p[1] == '#' || isalpha(p[1])) - break; // already a character entity - // Replace '&' with '&' character entity - se = Escape::escapeChar('&'); - if (se) - { size_t len = strlen(se); - buf->remove(i, 1); - i = buf->insert(i, se, len); - i--; // point to ';' - } - break; - - case '-': - /* A line beginning with --- delimits a code section. - * inCode tells us if it is start or end of a code section. - */ - if (leadingBlank) - { int istart = i; - int eollen = 0; - - leadingBlank = 0; - while (1) - { - ++i; - if (i >= buf->offset) - break; - c = buf->data[i]; - if (c == '\n') - { eollen = 1; - break; - } - if (c == '\r') - { - eollen = 1; - if (i + 1 >= buf->offset) - break; - if (buf->data[i + 1] == '\n') - { eollen = 2; - break; - } - } - // BUG: handle UTF PS and LS too - if (c != '-') - goto Lcont; - } - if (i - istart < 3) - goto Lcont; - - // We have the start/end of a code section - - // Remove the entire --- line, including blanks and \n - buf->remove(iLineStart, i - iLineStart + eollen); - i = iLineStart; - - if (inCode && (i <= iCodeStart)) - { // Empty code section, just remove it completely. - inCode = 0; - break; - } - - if (inCode) - { - inCode = 0; - // The code section is from iCodeStart to i - OutBuffer codebuf; - - codebuf.write(buf->data + iCodeStart, i - iCodeStart); - codebuf.writeByte(0); - highlightCode2(sc, s, &codebuf, 0); - buf->remove(iCodeStart, i - iCodeStart); - i = buf->insert(iCodeStart, codebuf.data, codebuf.offset); - i = buf->insert(i, ")\n", 2); - i--; - } - else - { static char pre[] = "$(D_CODE \n"; - - inCode = 1; - i = buf->insert(i, pre, sizeof(pre) - 1); - iCodeStart = i; - i--; // place i on > - leadingBlank = true; - } - } - break; - - default: - leadingBlank = 0; - if (sc && !inCode && isIdStart(&buf->data[i])) - { unsigned j; - - j = skippastident(buf, i); - if (j > i) - { - unsigned k = skippastURL(buf, i); - if (k > i) - { i = k - 1; - break; - } - - if (buf->data[i] == '_') // leading '_' means no highlight - { - buf->remove(i, 1); - i = j - 1; - } - else - { - if (cmp(sid, buf->data + i, j - i) == 0) - { - i = buf->bracket(i, "$(DDOC_PSYMBOL ", j, ")") - 1; - break; - } - else if (isKeyword(buf->data + i, j - i)) - { - i = buf->bracket(i, "$(DDOC_KEYWORD ", j, ")") - 1; - break; - } - else - { - if (f && isFunctionParameter(f, buf->data + i, j - i)) - { - //printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j); - i = buf->bracket(i, "$(DDOC_PARAM ", j, ")") - 1; - break; - } - } - i = j - 1; - } - } - } - break; - } - } - if (inCode) - s->error("unmatched --- in DDoc comment"); - ; -} - -/************************************************** - * Highlight code for DDOC section. - */ - -void highlightCode(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset) -{ - char *sid = s->ident->toChars(); - FuncDeclaration *f = s->isFuncDeclaration(); - - //printf("highlightCode(s = '%s', kind = %s)\n", sid, s->kind()); - for (unsigned i = offset; i < buf->offset; i++) - { unsigned char c = buf->data[i]; - const char *se; - - se = Escape::escapeChar(c); - if (se) - { - size_t len = strlen(se); - buf->remove(i, 1); - i = buf->insert(i, se, len); - i--; // point to ';' - } - else if (isIdStart(&buf->data[i])) - { unsigned j; - - j = skippastident(buf, i); - if (j > i) - { - if (cmp(sid, buf->data + i, j - i) == 0) - { - i = buf->bracket(i, "$(DDOC_PSYMBOL ", j, ")") - 1; - continue; - } - else if (f) - { - if (isFunctionParameter(f, buf->data + i, j - i)) - { - //printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j); - i = buf->bracket(i, "$(DDOC_PARAM ", j, ")") - 1; - continue; - } - } - i = j - 1; - } - } - } -} - -/**************************************** - */ - -void highlightCode3(OutBuffer *buf, unsigned char *p, unsigned char *pend) -{ - for (; p < pend; p++) - { const char *s = Escape::escapeChar(*p); - if (s) - buf->writestring(s); - else - buf->writeByte(*p); - } -} - -/************************************************** - * Highlight code for CODE section. - */ - - -void highlightCode2(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset) -{ - char *sid = s->ident->toChars(); - FuncDeclaration *f = s->isFuncDeclaration(); - unsigned errorsave = global.errors; - Lexer lex(NULL, buf->data, 0, buf->offset - 1, 0, 1); - Token tok; - OutBuffer res; - unsigned char *lastp = buf->data; - const char *highlight; - - //printf("highlightCode2('%.*s')\n", buf->offset - 1, buf->data); - res.reserve(buf->offset); - while (1) - { - lex.scan(&tok); - highlightCode3(&res, lastp, tok.ptr); - highlight = NULL; - switch (tok.value) - { - case TOKidentifier: - if (!sc) - break; - if (cmp(sid, tok.ptr, lex.p - tok.ptr) == 0) - { - highlight = "$(D_PSYMBOL "; - break; - } - else if (f) - { - if (isFunctionParameter(f, tok.ptr, lex.p - tok.ptr)) - { - //printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j); - highlight = "$(D_PARAM "; - break; - } - } - break; - - case TOKcomment: - highlight = "$(D_COMMENT "; - break; - - case TOKstring: - highlight = "$(D_STRING "; - break; - - default: - if (tok.isKeyword()) - highlight = "$(D_KEYWORD "; - break; - } - if (highlight) - res.writestring(highlight); - highlightCode3(&res, tok.ptr, lex.p); - if (highlight) - res.writeByte(')'); - if (tok.value == TOKeof) - break; - lastp = lex.p; - } - buf->setsize(offset); - buf->write(&res); - global.errors = errorsave; -} - -/*************************************** - * Find character string to replace c with. - */ - -const char *Escape::escapeChar(unsigned c) -{ const char *s; - - switch (c) - { - case '<': - s = "<"; - break; - case '>': - s = ">"; - break; - case '&': - s = "&"; - break; - default: - s = NULL; - break; - } - return s; -} - -/**************************************** - * Determine if p points to the start of an identifier. - */ - -int isIdStart(unsigned char *p) -{ - unsigned c = *p; - if (isalpha(c) || c == '_') - return 1; - if (c >= 0x80) - { size_t i = 0; - if (utf_decodeChar(p, 4, &i, &c)) - return 0; // ignore errors - if (isUniAlpha(c)) - return 1; - } - return 0; -} - -/**************************************** - * Determine if p points to the rest of an identifier. - */ - -int isIdTail(unsigned char *p) -{ - unsigned c = *p; - if (isalnum(c) || c == '_') - return 1; - if (c >= 0x80) - { size_t i = 0; - if (utf_decodeChar(p, 4, &i, &c)) - return 0; // ignore errors - if (isUniAlpha(c)) - return 1; - } - return 0; -} - -/***************************************** - * Return number of bytes in UTF character. - */ - -int utfStride(unsigned char *p) -{ - unsigned c = *p; - if (c < 0x80) - return 1; - size_t i = 0; - utf_decodeChar(p, 4, &i, &c); // ignore errors, but still consume input - return i; -} + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2012 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +// This implements the Ddoc capability. + +#include +#include +#include +#include +#include + +#include "rmem.h" +#include "root.h" + +#if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ +#include "gnuc.h" +#endif + +#include "mars.h" +#include "dsymbol.h" +#include "macro.h" +#include "template.h" +#include "lexer.h" +#include "aggregate.h" +#include "declaration.h" +#include "enum.h" +#include "id.h" +#include "module.h" +#include "scope.h" +#include "hdrgen.h" +#include "doc.h" +#include "mtype.h" +#include "utf.h" + +struct Escape +{ + const char *strings[256]; + + static const char *escapeChar(unsigned c); +}; + +struct Section +{ + unsigned char *name; + unsigned namelen; + + unsigned char *body; + unsigned bodylen; + + int nooutput; + + virtual void write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf); +}; + +struct ParamSection : Section +{ + void write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf); +}; + +struct MacroSection : Section +{ + void write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf); +}; + +typedef ArrayBase
    Sections; + +struct DocComment +{ + Sections sections; // Section*[] + + Section *summary; + Section *copyright; + Section *macros; + Macro **pmacrotable; + Escape **pescapetable; + + 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); + static void parseEscapes(Escape **pescapetable, unsigned char *textstart, unsigned textlen); + + void parseSections(unsigned char *comment); + void writeSections(Scope *sc, Dsymbol *s, OutBuffer *buf); +}; + + +int cmp(const char *stringz, void *s, size_t slen); +int icmp(const char *stringz, void *s, size_t slen); +int isDitto(unsigned char *comment); +unsigned char *skipwhitespace(unsigned char *p); +unsigned skiptoident(OutBuffer *buf, size_t i); +unsigned skippastident(OutBuffer *buf, size_t i); +unsigned skippastURL(OutBuffer *buf, size_t i); +void highlightText(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset); +void highlightCode(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset); +void highlightCode2(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset); +Parameter *isFunctionParameter(Dsymbol *s, unsigned char *p, unsigned len); + +int isIdStart(unsigned char *p); +int isIdTail(unsigned char *p); +int utfStride(unsigned char *p); + +static unsigned char ddoc_default[] = "\ +DDOC = \n\ + \n\ + $(TITLE)\n\ + \n\ +

    $(TITLE)

    \n\ + $(BODY)\n\ +
    $(SMALL Page generated by $(LINK2 http://www.digitalmars.com/d/2.0/ddoc.html, Ddoc). $(COPYRIGHT))\n\ + \n\ +\n\ +B = $0\n\ +I = $0\n\ +U = $0\n\ +P =

    $0

    \n\ +DL =
    $0
    \n\ +DT =
    $0
    \n\ +DD =
    $0
    \n\ +TABLE = $0
    \n\ +TR = $0\n\ +TH = $0\n\ +TD = $0\n\ +OL =
      $0
    \n\ +UL =
      $0
    \n\ +LI =
  • $0
  • \n\ +BIG = $0\n\ +SMALL = $0\n\ +BR =
    \n\ +LINK = $0\n\ +LINK2 = $+\n\ +LPAREN= (\n\ +RPAREN= )\n\ +DOLLAR= $\n\ +\n\ +RED = $0\n\ +BLUE = $0\n\ +GREEN = $0\n\ +YELLOW =$0\n\ +BLACK = $0\n\ +WHITE = $0\n\ +\n\ +D_CODE =
    $0
    \n\ +D_COMMENT = $(GREEN $0)\n\ +D_STRING = $(RED $0)\n\ +D_KEYWORD = $(BLUE $0)\n\ +D_PSYMBOL = $(U $0)\n\ +D_PARAM = $(I $0)\n\ +\n\ +DDOC_COMMENT = \n\ +DDOC_DECL = $(DT $(BIG $0))\n\ +DDOC_DECL_DD = $(DD $0)\n\ +DDOC_DITTO = $(BR)$0\n\ +DDOC_SECTIONS = $0\n\ +DDOC_SUMMARY = $0$(BR)$(BR)\n\ +DDOC_DESCRIPTION = $0$(BR)$(BR)\n\ +DDOC_AUTHORS = $(B Authors:)$(BR)\n$0$(BR)$(BR)\n\ +DDOC_BUGS = $(RED BUGS:)$(BR)\n$0$(BR)$(BR)\n\ +DDOC_COPYRIGHT = $(B Copyright:)$(BR)\n$0$(BR)$(BR)\n\ +DDOC_DATE = $(B Date:)$(BR)\n$0$(BR)$(BR)\n\ +DDOC_DEPRECATED = $(RED Deprecated:)$(BR)\n$0$(BR)$(BR)\n\ +DDOC_EXAMPLES = $(B Examples:)$(BR)\n$0$(BR)$(BR)\n\ +DDOC_HISTORY = $(B History:)$(BR)\n$0$(BR)$(BR)\n\ +DDOC_LICENSE = $(B License:)$(BR)\n$0$(BR)$(BR)\n\ +DDOC_RETURNS = $(B Returns:)$(BR)\n$0$(BR)$(BR)\n\ +DDOC_SEE_ALSO = $(B See Also:)$(BR)\n$0$(BR)$(BR)\n\ +DDOC_STANDARDS = $(B Standards:)$(BR)\n$0$(BR)$(BR)\n\ +DDOC_THROWS = $(B Throws:)$(BR)\n$0$(BR)$(BR)\n\ +DDOC_VERSION = $(B Version:)$(BR)\n$0$(BR)$(BR)\n\ +DDOC_SECTION_H = $(B $0)$(BR)\n\ +DDOC_SECTION = $0$(BR)$(BR)\n\ +DDOC_MEMBERS = $(DL $0)\n\ +DDOC_MODULE_MEMBERS = $(DDOC_MEMBERS $0)\n\ +DDOC_CLASS_MEMBERS = $(DDOC_MEMBERS $0)\n\ +DDOC_STRUCT_MEMBERS = $(DDOC_MEMBERS $0)\n\ +DDOC_ENUM_MEMBERS = $(DDOC_MEMBERS $0)\n\ +DDOC_TEMPLATE_MEMBERS = $(DDOC_MEMBERS $0)\n\ +DDOC_PARAMS = $(B Params:)$(BR)\n$(TABLE $0)$(BR)\n\ +DDOC_PARAM_ROW = $(TR $0)\n\ +DDOC_PARAM_ID = $(TD $0)\n\ +DDOC_PARAM_DESC = $(TD $0)\n\ +DDOC_BLANKLINE = $(BR)$(BR)\n\ +\n\ +DDOC_PSYMBOL = $(U $0)\n\ +DDOC_KEYWORD = $(B $0)\n\ +DDOC_PARAM = $(I $0)\n\ +\n\ +ESCAPES = //>/\n\ + /&/&/\n\ +"; + +static char ddoc_decl_s[] = "$(DDOC_DECL "; +static char ddoc_decl_e[] = ")\n"; + +static char ddoc_decl_dd_s[] = "$(DDOC_DECL_DD "; +static char ddoc_decl_dd_e[] = ")\n"; + + +/**************************************************** + */ + +void Module::gendocfile() +{ + static OutBuffer mbuf; + static int mbuf_done; + + OutBuffer buf; + + //printf("Module::gendocfile()\n"); + + if (!mbuf_done) // if not already read the ddoc files + { mbuf_done = 1; + + // Use our internal default + mbuf.write(ddoc_default, sizeof(ddoc_default) - 1); + + // Override with DDOCFILE specified in the sc.ini file + char *p = getenv("DDOCFILE"); + if (p) + global.params.ddocfiles->shift(p); + + // 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)[i], 0); + File file(&f); + file.readv(); + // BUG: convert file contents to UTF-8 before use + + //printf("file: '%.*s'\n", file.len, file.buffer); + mbuf.write(file.buffer, file.len); + } + } + DocComment::parseMacros(&escapetable, ¯otable, mbuf.data, mbuf.offset); + + Scope *sc = Scope::createGlobal(this); // create root scope + sc->docbuf = &buf; + + DocComment *dc = DocComment::parse(sc, this, comment); + dc->pmacrotable = ¯otable; + dc->pescapetable = &escapetable; + + // Generate predefined macros + + // Set the title to be the name of the module + { const char *p = toPrettyChars(); + Macro::define(¯otable, (unsigned char *)"TITLE", 5, (unsigned char *)p, strlen(p)); + } + + // Set time macros + { time_t t; + time(&t); + char *p = ctime(&t); + p = mem.strdup(p); + Macro::define(¯otable, (unsigned char *)"DATETIME", 8, (unsigned char *)p, strlen(p)); + Macro::define(¯otable, (unsigned char *)"YEAR", 4, (unsigned char *)p + 20, 4); + } + + char *srcfilename = srcfile->toChars(); + Macro::define(¯otable, (unsigned char *)"SRCFILENAME", 11, (unsigned char *)srcfilename, strlen(srcfilename)); + + char *docfilename = docfile->toChars(); + Macro::define(¯otable, (unsigned char *)"DOCFILENAME", 11, (unsigned char *)docfilename, strlen(docfilename)); + + if (dc->copyright) + { + dc->copyright->nooutput = 1; + Macro::define(¯otable, (unsigned char *)"COPYRIGHT", 9, dc->copyright->body, dc->copyright->bodylen); + } + + buf.printf("$(DDOC_COMMENT Generated by Ddoc from %s)\n", srcfile->toChars()); + if (isDocFile) + { + size_t commentlen = strlen((char *)comment); + if (dc->macros) + { + commentlen = dc->macros->name - comment; + dc->macros->write(dc, sc, this, sc->docbuf); + } + sc->docbuf->write(comment, commentlen); + highlightText(NULL, this, sc->docbuf, 0); + } + else + { + dc->writeSections(sc, this, sc->docbuf); + emitMemberComments(sc); + } + + //printf("BODY= '%.*s'\n", buf.offset, buf.data); + Macro::define(¯otable, (unsigned char *)"BODY", 4, buf.data, buf.offset); + + OutBuffer buf2; + buf2.writestring("$(DDOC)\n"); + unsigned end = buf2.offset; + macrotable->expand(&buf2, 0, &end, NULL, 0); + +#if 1 + /* Remove all the escape sequences from buf2, + * and make CR-LF the newline. + */ + { + buf.setsize(0); + buf.reserve(buf2.offset); + unsigned char *p = buf2.data; + for (unsigned j = 0; j < buf2.offset; j++) + { + unsigned char c = p[j]; + if (c == 0xFF && j + 1 < buf2.offset) + { + j++; + continue; + } + if (c == '\n') + buf.writeByte('\r'); + else if (c == '\r') + { + buf.writestring("\r\n"); + if (j + 1 < buf2.offset && p[j + 1] == '\n') + { + j++; + } + continue; + } + buf.writeByte(c); + } + } + + // Transfer image to file + assert(docfile); + docfile->setbuffer(buf.data, buf.offset); + docfile->ref = 1; + char *pt = FileName::path(docfile->toChars()); + if (*pt) + FileName::ensurePathExists(pt); + mem.free(pt); + docfile->writev(); +#else + /* Remove all the escape sequences from buf2 + */ + { unsigned i = 0; + unsigned char *p = buf2.data; + for (unsigned j = 0; j < buf2.offset; j++) + { + if (p[j] == 0xFF && j + 1 < buf2.offset) + { + j++; + continue; + } + p[i] = p[j]; + i++; + } + buf2.setsize(i); + } + + // Transfer image to file + docfile->setbuffer(buf2.data, buf2.offset); + docfile->ref = 1; + char *pt = FileName::path(docfile->toChars()); + if (*pt) + FileName::ensurePathExists(pt); + mem.free(pt); + docfile->writev(); +#endif +} + +/**************************************************** + * Having unmatched parentheses can hose the output of Ddoc, + * as the macros depend on properly nested parentheses. + * This function replaces all ( with $(LPAREN) and ) with $(RPAREN) + * to preserve text literally. This also means macros in the + * text won't be expanded. + */ +void escapeDdocString(OutBuffer *buf, unsigned start) +{ + for (unsigned u = start; u < buf->offset; u++) + { + unsigned char c = buf->data[u]; + switch(c) + { + case '$': + buf->remove(u, 1); + buf->insert(u, "$(DOLLAR)", 9); + u += 8; + break; + + case '(': + buf->remove(u, 1); //remove the ( + buf->insert(u, "$(LPAREN)", 9); //insert this instead + u += 8; //skip over newly inserted macro + break; + + case ')': + buf->remove(u, 1); //remove the ) + buf->insert(u, "$(RPAREN)", 9); //insert this instead + u += 8; //skip over newly inserted macro + break; + } + } +} + +/**************************************************** + * Having unmatched parentheses can hose the output of Ddoc, + * as the macros depend on properly nested parentheses. + + * Fix by replacing unmatched ( with $(LPAREN) and unmatched ) with $(RPAREN). + */ +void escapeStrayParenthesis(OutBuffer *buf, unsigned start, Loc loc) +{ + unsigned par_open = 0; + + for (unsigned u = start; u < buf->offset; u++) + { + unsigned char c = buf->data[u]; + switch(c) + { + case '(': + par_open++; + break; + + case ')': + if (par_open == 0) + { + //stray ')' + if (global.params.warnings) + warning(loc, "Ddoc: Stray ')'. This may cause incorrect Ddoc output." + " Use $(RPAREN) instead for unpaired right parentheses."); + buf->remove(u, 1); //remove the ) + buf->insert(u, "$(RPAREN)", 9); //insert this instead + u += 8; //skip over newly inserted macro + } + else + par_open--; + break; +#if 0 + // For this to work, loc must be set to the beginning of the passed + // text which is currently not possible + // (loc is set to the Loc of the Dsymbol) + case '\n': + loc.linnum++; + break; +#endif + } + } + + if (par_open) // if any unmatched lparens + { par_open = 0; + for (unsigned u = buf->offset; u > start;) + { u--; + unsigned char c = buf->data[u]; + switch(c) + { + case ')': + par_open++; + break; + + case '(': + if (par_open == 0) + { + //stray '(' + if (global.params.warnings) + warning(loc, "Ddoc: Stray '('. This may cause incorrect Ddoc output." + " Use $(LPAREN) instead for unpaired left parentheses."); + buf->remove(u, 1); //remove the ( + buf->insert(u, "$(LPAREN)", 9); //insert this instead + } + else + par_open--; + break; + } + } + } +} + +/******************************* emitComment **********************************/ + +/* + * Emit doc comment to documentation file + */ + +void Dsymbol::emitDitto(Scope *sc) +{ + //printf("Dsymbol::emitDitto() %s %s\n", kind(), toChars()); + OutBuffer *buf = sc->docbuf; + unsigned o; + OutBuffer b; + + b.writestring("$(DDOC_DITTO "); + o = b.offset; + toDocBuffer(&b); + //printf("b: '%.*s'\n", b.offset, b.data); + /* If 'this' is a function template, then highlightCode() was + * already run by FuncDeclaration::toDocbuffer(). + */ + TemplateDeclaration *td; + if (parent && + (td = parent->isTemplateDeclaration()) != NULL && + td->onemember == this) + { + } + else + highlightCode(sc, this, &b, o); + b.writeByte(')'); + buf->spread(sc->lastoffset, b.offset); + memcpy(buf->data + sc->lastoffset, b.data, b.offset); + sc->lastoffset += b.offset; +} + +void ScopeDsymbol::emitMemberComments(Scope *sc) +{ + //printf("ScopeDsymbol::emitMemberComments() %s\n", toChars()); + OutBuffer *buf = sc->docbuf; + + if (members) + { const char *m = "$(DDOC_MEMBERS \n"; + + if (isModule()) + m = "$(DDOC_MODULE_MEMBERS \n"; + else if (isClassDeclaration()) + m = "$(DDOC_CLASS_MEMBERS \n"; + else if (isStructDeclaration()) + m = "$(DDOC_STRUCT_MEMBERS \n"; + else if (isEnumDeclaration()) + m = "$(DDOC_ENUM_MEMBERS \n"; + else if (isTemplateDeclaration()) + m = "$(DDOC_TEMPLATE_MEMBERS \n"; + + unsigned offset1 = buf->offset; // save starting offset + buf->writestring(m); + unsigned offset2 = buf->offset; // to see if we write anything + sc = sc->push(this); + for (size_t i = 0; i < members->dim; i++) + { + Dsymbol *s = (*members)[i]; + //printf("\ts = '%s'\n", s->toChars()); + s->emitComment(sc); + } + sc->pop(); + if (buf->offset == offset2) + { + /* Didn't write out any members, so back out last write + */ + buf->offset = offset1; + } + else + buf->writestring(")\n"); + } +} + +void emitProtection(OutBuffer *buf, PROT prot) +{ + const char *p; + + switch (prot) + { + case PROTpackage: p = "package"; break; + case PROTprotected: p = "protected"; break; + case PROTexport: p = "export"; break; + default: p = NULL; break; + } + if (p) + buf->printf("%s ", p); +} + +void Dsymbol::emitComment(Scope *sc) { } +void InvariantDeclaration::emitComment(Scope *sc) { } +#if DMDV2 +void PostBlitDeclaration::emitComment(Scope *sc) { } +#endif +void DtorDeclaration::emitComment(Scope *sc) { } +void StaticCtorDeclaration::emitComment(Scope *sc) { } +void StaticDtorDeclaration::emitComment(Scope *sc) { } +void ClassInfoDeclaration::emitComment(Scope *sc) { } +void ModuleInfoDeclaration::emitComment(Scope *sc) { } +void TypeInfoDeclaration::emitComment(Scope *sc) { } + + +void Declaration::emitComment(Scope *sc) +{ + //printf("Declaration::emitComment(%p '%s'), comment = '%s'\n", this, toChars(), comment); + //printf("type = %p\n", type); + + if (protection == PROTprivate || !ident || + (!type && !isCtorDeclaration() && !isAliasDeclaration())) + return; + if (!comment) + return; + + OutBuffer *buf = sc->docbuf; + DocComment *dc = DocComment::parse(sc, this, comment); + unsigned o; + + if (!dc) + { + emitDitto(sc); + return; + } + dc->pmacrotable = &sc->module->macrotable; + + buf->writestring(ddoc_decl_s); + o = buf->offset; + toDocBuffer(buf); + highlightCode(sc, this, buf, o); + sc->lastoffset = buf->offset; + buf->writestring(ddoc_decl_e); + + buf->writestring(ddoc_decl_dd_s); + dc->writeSections(sc, this, buf); + buf->writestring(ddoc_decl_dd_e); +} + +void AggregateDeclaration::emitComment(Scope *sc) +{ + //printf("AggregateDeclaration::emitComment() '%s'\n", toChars()); + if (prot() == PROTprivate) + return; + if (!comment) + return; + + OutBuffer *buf = sc->docbuf; + DocComment *dc = DocComment::parse(sc, this, comment); + + if (!dc) + { + emitDitto(sc); + return; + } + dc->pmacrotable = &sc->module->macrotable; + + buf->writestring(ddoc_decl_s); + toDocBuffer(buf); + sc->lastoffset = buf->offset; + buf->writestring(ddoc_decl_e); + + buf->writestring(ddoc_decl_dd_s); + dc->writeSections(sc, this, buf); + emitMemberComments(sc); + buf->writestring(ddoc_decl_dd_e); +} + +void TemplateDeclaration::emitComment(Scope *sc) +{ + //printf("TemplateDeclaration::emitComment() '%s', kind = %s\n", toChars(), kind()); + if (prot() == PROTprivate) + return; + + unsigned char *com = comment; + int hasmembers = 1; + + Dsymbol *ss = this; + + if (onemember) + { + ss = onemember->isAggregateDeclaration(); + if (!ss) + { + ss = onemember->isFuncDeclaration(); + if (ss) + { hasmembers = 0; + if (com != ss->comment) + com = Lexer::combineComments(com, ss->comment); + } + else + ss = this; + } + } + + if (!com) + return; + + OutBuffer *buf = sc->docbuf; + DocComment *dc = DocComment::parse(sc, this, com); + unsigned o; + + if (!dc) + { + ss->emitDitto(sc); + return; + } + dc->pmacrotable = &sc->module->macrotable; + + buf->writestring(ddoc_decl_s); + o = buf->offset; + ss->toDocBuffer(buf); + if (ss == this) + highlightCode(sc, this, buf, o); + sc->lastoffset = buf->offset; + buf->writestring(ddoc_decl_e); + + buf->writestring(ddoc_decl_dd_s); + dc->writeSections(sc, this, buf); + if (hasmembers) + ((ScopeDsymbol *)ss)->emitMemberComments(sc); + buf->writestring(ddoc_decl_dd_e); +} + +void EnumDeclaration::emitComment(Scope *sc) +{ + if (prot() == PROTprivate) + return; +// if (!comment) + { if (isAnonymous() && members) + { + for (size_t i = 0; i < members->dim; i++) + { + Dsymbol *s = (*members)[i]; + s->emitComment(sc); + } + return; + } + } + if (!comment) + return; + if (isAnonymous()) + return; + + OutBuffer *buf = sc->docbuf; + DocComment *dc = DocComment::parse(sc, this, comment); + + if (!dc) + { + emitDitto(sc); + return; + } + dc->pmacrotable = &sc->module->macrotable; + + buf->writestring(ddoc_decl_s); + toDocBuffer(buf); + sc->lastoffset = buf->offset; + buf->writestring(ddoc_decl_e); + + buf->writestring(ddoc_decl_dd_s); + dc->writeSections(sc, this, buf); + emitMemberComments(sc); + buf->writestring(ddoc_decl_dd_e); +} + +void EnumMember::emitComment(Scope *sc) +{ + //printf("EnumMember::emitComment(%p '%s'), comment = '%s'\n", this, toChars(), comment); + if (prot() == PROTprivate) + return; + if (!comment) + return; + + OutBuffer *buf = sc->docbuf; + DocComment *dc = DocComment::parse(sc, this, comment); + unsigned o; + + if (!dc) + { + emitDitto(sc); + return; + } + dc->pmacrotable = &sc->module->macrotable; + + buf->writestring(ddoc_decl_s); + o = buf->offset; + toDocBuffer(buf); + highlightCode(sc, this, buf, o); + sc->lastoffset = buf->offset; + buf->writestring(ddoc_decl_e); + + buf->writestring(ddoc_decl_dd_s); + dc->writeSections(sc, this, buf); + buf->writestring(ddoc_decl_dd_e); +} + +/******************************* toDocBuffer **********************************/ + +void Dsymbol::toDocBuffer(OutBuffer *buf) +{ + //printf("Dsymbol::toDocbuffer() %s\n", toChars()); + HdrGenState hgs; + + hgs.ddoc = 1; + toCBuffer(buf, &hgs); +} + +void prefix(OutBuffer *buf, Dsymbol *s) +{ + if (s->isDeprecated()) + buf->writestring("deprecated "); + Declaration *d = s->isDeclaration(); + if (d) + { + emitProtection(buf, d->protection); + if (d->isAbstract()) + buf->writestring("abstract "); + if (d->isStatic()) + buf->writestring("static "); + if (d->isConst()) + buf->writestring("const "); +#if DMDV2 + if (d->isImmutable()) + buf->writestring("immutable "); +#endif + if (d->isFinal()) + buf->writestring("final "); + if (d->isSynchronized()) + buf->writestring("synchronized "); + } +} + +void declarationToDocBuffer(Declaration *decl, OutBuffer *buf, TemplateDeclaration *td) +{ + //printf("declarationToDocBuffer() %s, originalType = %s, td = %s\n", decl->toChars(), decl->originalType ? decl->originalType->toChars() : "--", td ? td->toChars() : "--"); + if (decl->ident) + { + prefix(buf, decl); + + if (decl->type) + { HdrGenState hgs; + hgs.ddoc = 1; + Type *origType = decl->originalType ? decl->originalType : decl->type; + if (origType->ty == Tfunction) + { + TypeFunction *attrType = (TypeFunction*)(decl->ident == Id::ctor ? origType : decl->type); + ((TypeFunction*)origType)->toCBufferWithAttributes(buf, decl->ident, &hgs, attrType, td); + } + else + origType->toCBuffer(buf, decl->ident, &hgs); + } + else + buf->writestring(decl->ident->toChars()); + buf->writestring(";\n"); + } +} + +void Declaration::toDocBuffer(OutBuffer *buf) +{ + declarationToDocBuffer(this, buf, NULL); +} + +void AliasDeclaration::toDocBuffer(OutBuffer *buf) +{ + //printf("AliasDeclaration::toDocbuffer() %s\n", toChars()); + if (ident) + { + if (isDeprecated()) + buf->writestring("deprecated "); + + emitProtection(buf, protection); + buf->writestring("alias "); + buf->writestring(toChars()); + buf->writestring(";\n"); + } +} + + +void TypedefDeclaration::toDocBuffer(OutBuffer *buf) +{ + if (ident) + { + if (isDeprecated()) + buf->writestring("deprecated "); + + emitProtection(buf, protection); + buf->writestring("typedef "); + buf->writestring(toChars()); + buf->writestring(";\n"); + } +} + + +void FuncDeclaration::toDocBuffer(OutBuffer *buf) +{ + //printf("FuncDeclaration::toDocbuffer() %s\n", toChars()); + if (ident) + { + TemplateDeclaration *td; + + if (parent && + (td = parent->isTemplateDeclaration()) != NULL && + td->onemember == this) + { /* It's a function template + */ + unsigned o = buf->offset; + + declarationToDocBuffer(this, buf, td); + + highlightCode(NULL, this, buf, o); + } + else + { + Declaration::toDocBuffer(buf); + } + } +} + +#if DMDV1 +void CtorDeclaration::toDocBuffer(OutBuffer *buf) +{ + HdrGenState hgs; + + buf->writestring("this"); + Parameter::argsToCBuffer(buf, &hgs, arguments, varargs); + buf->writestring(";\n"); +} +#endif + +void AggregateDeclaration::toDocBuffer(OutBuffer *buf) +{ + if (ident) + { +#if 0 + emitProtection(buf, protection); +#endif + buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); + buf->writestring(";\n"); + } +} + +void StructDeclaration::toDocBuffer(OutBuffer *buf) +{ + //printf("StructDeclaration::toDocbuffer() %s\n", toChars()); + if (ident) + { +#if 0 + emitProtection(buf, protection); +#endif + TemplateDeclaration *td; + + if (parent && + (td = parent->isTemplateDeclaration()) != NULL && + td->onemember == this) + { unsigned o = buf->offset; + td->toDocBuffer(buf); + highlightCode(NULL, this, buf, o); + } + else + { + buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); + } + buf->writestring(";\n"); + } +} + +void ClassDeclaration::toDocBuffer(OutBuffer *buf) +{ + //printf("ClassDeclaration::toDocbuffer() %s\n", toChars()); + if (ident) + { +#if 0 + emitProtection(buf, protection); +#endif + TemplateDeclaration *td; + + if (parent && + (td = parent->isTemplateDeclaration()) != NULL && + td->onemember == this) + { unsigned o = buf->offset; + td->toDocBuffer(buf); + highlightCode(NULL, this, buf, o); + } + else + { + if (isAbstract()) + buf->writestring("abstract "); + buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); + } + int any = 0; + for (size_t i = 0; i < baseclasses->dim; i++) + { BaseClass *bc = (*baseclasses)[i]; + + if (bc->protection == PROTprivate) + continue; + if (bc->base && bc->base->ident == Id::Object) + continue; + + if (any) + buf->writestring(", "); + else + { buf->writestring(": "); + any = 1; + } + emitProtection(buf, bc->protection); + if (bc->base) + { + buf->writestring(bc->base->toPrettyChars()); + } + else + { + HdrGenState hgs; + bc->type->toCBuffer(buf, NULL, &hgs); + } + } + buf->writestring(";\n"); + } +} + + +void EnumDeclaration::toDocBuffer(OutBuffer *buf) +{ + if (ident) + { + buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); + buf->writestring(";\n"); + } +} + +void EnumMember::toDocBuffer(OutBuffer *buf) +{ + if (ident) + { + buf->writestring(toChars()); + } +} + + +/********************************* DocComment *********************************/ + +DocComment *DocComment::parse(Scope *sc, Dsymbol *s, unsigned char *comment) +{ + //printf("parse(%s): '%s'\n", s->toChars(), comment); + if (sc->lastdc && isDitto(comment)) + return NULL; + + DocComment *dc = new DocComment(); + if (!comment) + return dc; + + dc->parseSections(comment); + + for (size_t i = 0; i < dc->sections.dim; i++) + { Section *sec = dc->sections[i]; + + if (icmp("copyright", sec->name, sec->namelen) == 0) + { + dc->copyright = sec; + } + if (icmp("macros", sec->name, sec->namelen) == 0) + { + dc->macros = sec; + } + } + + sc->lastdc = dc; + return dc; +} + +/***************************************** + * Parse next paragraph out of *pcomment. + * Update *pcomment to point past paragraph. + * Returns NULL if no more paragraphs. + * If paragraph ends in 'identifier:', + * then (*pcomment)[0 .. idlen] is the identifier. + */ + +void DocComment::parseSections(unsigned char *comment) +{ unsigned char *p; + unsigned char *pstart; + unsigned char *pend; + unsigned char *idstart; + unsigned idlen; + + unsigned char *name = NULL; + unsigned namelen = 0; + + //printf("parseSections('%s')\n", comment); + p = comment; + while (*p) + { + p = skipwhitespace(p); + pstart = p; + pend = p; + + /* Find end of section, which is ended by one of: + * 'identifier:' (but not inside a code section) + * '\0' + */ + idlen = 0; + int inCode = 0; + while (1) + { + // Check for start/end of a code section + if (*p == '-') + { + int numdash = 0; + while (*p == '-') + { + ++numdash; + p++; + } + // BUG: handle UTF PS and LS too + if (!*p || *p == '\r' || *p == '\n' && numdash >= 3) + inCode ^= 1; + pend = p; + } + + if (!inCode && isIdStart(p)) + { + unsigned char *q = p + utfStride(p); + while (isIdTail(q)) + q += utfStride(q); + if (*q == ':') // identifier: ends it + { idlen = q - p; + idstart = p; + for (pend = p; pend > pstart; pend--) + { if (pend[-1] == '\n') + break; + } + p = q + 1; + break; + } + } + while (1) + { + if (!*p) + goto L1; + if (*p == '\n') + { p++; + if (*p == '\n' && !summary && !namelen && !inCode) + { + pend = p; + p++; + goto L1; + } + break; + } + p++; + pend = p; + } + p = skipwhitespace(p); + } + L1: + + if (namelen || pstart < pend) + { + Section *s; + if (icmp("Params", name, namelen) == 0) + s = new ParamSection(); + else if (icmp("Macros", name, namelen) == 0) + s = new MacroSection(); + else + s = new Section(); + s->name = name; + s->namelen = namelen; + s->body = pstart; + s->bodylen = pend - pstart; + s->nooutput = 0; + + //printf("Section: '%.*s' = '%.*s'\n", s->namelen, s->name, s->bodylen, s->body); + + sections.push(s); + + if (!summary && !namelen) + summary = s; + } + + if (idlen) + { name = idstart; + namelen = idlen; + } + else + { name = NULL; + namelen = 0; + if (!*p) + break; + } + } +} + +void DocComment::writeSections(Scope *sc, Dsymbol *s, OutBuffer *buf) +{ + //printf("DocComment::writeSections()\n"); + if (sections.dim) + { + buf->writestring("$(DDOC_SECTIONS \n"); + for (size_t i = 0; i < sections.dim; i++) + { Section *sec = sections[i]; + + if (sec->nooutput) + continue; + //printf("Section: '%.*s' = '%.*s'\n", sec->namelen, sec->name, sec->bodylen, sec->body); + if (sec->namelen || i) + sec->write(this, sc, s, buf); + else + { + buf->writestring("$(DDOC_SUMMARY "); + unsigned o = buf->offset; + buf->write(sec->body, sec->bodylen); + escapeStrayParenthesis(buf, o, s->loc); + highlightText(sc, s, buf, o); + buf->writestring(")\n"); + } + } + buf->writestring(")\n"); + } + else + { + buf->writestring("$(DDOC_BLANKLINE)\n"); + } +} + +/*************************************************** + */ + +void Section::write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf) +{ + if (namelen) + { + static const char *table[] = + { "AUTHORS", "BUGS", "COPYRIGHT", "DATE", + "DEPRECATED", "EXAMPLES", "HISTORY", "LICENSE", + "RETURNS", "SEE_ALSO", "STANDARDS", "THROWS", + "VERSION" }; + + for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++) + { + if (icmp(table[i], name, namelen) == 0) + { + buf->printf("$(DDOC_%s ", table[i]); + goto L1; + } + } + + buf->writestring("$(DDOC_SECTION "); + // Replace _ characters with spaces + buf->writestring("$(DDOC_SECTION_H "); + unsigned o = buf->offset; + for (unsigned u = 0; u < namelen; u++) + { unsigned char c = name[u]; + buf->writeByte((c == '_') ? ' ' : c); + } + escapeStrayParenthesis(buf, o, s->loc); + buf->writestring(":)\n"); + } + else + { + buf->writestring("$(DDOC_DESCRIPTION "); + } + L1: + unsigned o = buf->offset; + buf->write(body, bodylen); + escapeStrayParenthesis(buf, o, s->loc); + highlightText(sc, s, buf, o); + buf->writestring(")\n"); +} + +/*************************************************** + */ + +void ParamSection::write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf) +{ + unsigned char *p = body; + unsigned len = bodylen; + unsigned char *pend = p + len; + + unsigned char *tempstart; + unsigned templen; + + unsigned char *namestart; + unsigned namelen = 0; // !=0 if line continuation + + unsigned char *textstart; + unsigned textlen; + + unsigned o; + Parameter *arg; + + buf->writestring("$(DDOC_PARAMS \n"); + while (p < pend) + { + // Skip to start of macro + while (1) + { + switch (*p) + { + case ' ': + case '\t': + p++; + continue; + + case '\n': + p++; + goto Lcont; + + default: + if (isIdStart(p)) + break; + if (namelen) + goto Ltext; // continuation of prev macro + goto Lskipline; + } + break; + } + tempstart = p; + + while (isIdTail(p)) + p += utfStride(p); + templen = p - tempstart; + + while (*p == ' ' || *p == '\t') + p++; + + if (*p != '=') + { if (namelen) + goto Ltext; // continuation of prev macro + goto Lskipline; + } + p++; + + if (namelen) + { // Output existing param + + L1: + //printf("param '%.*s' = '%.*s'\n", namelen, namestart, textlen, textstart); + HdrGenState hgs; + buf->writestring("$(DDOC_PARAM_ROW "); + buf->writestring("$(DDOC_PARAM_ID "); + o = buf->offset; + arg = isFunctionParameter(s, namestart, namelen); + if (arg && arg->type && arg->ident) + arg->type->toCBuffer(buf, arg->ident, &hgs); + else + buf->write(namestart, namelen); + escapeStrayParenthesis(buf, o, s->loc); + highlightCode(sc, s, buf, o); + buf->writestring(")\n"); + + buf->writestring("$(DDOC_PARAM_DESC "); + o = buf->offset; + buf->write(textstart, textlen); + escapeStrayParenthesis(buf, o, s->loc); + highlightText(sc, s, buf, o); + buf->writestring(")"); + buf->writestring(")\n"); + namelen = 0; + if (p >= pend) + break; + } + + namestart = tempstart; + namelen = templen; + + while (*p == ' ' || *p == '\t') + p++; + textstart = p; + + Ltext: + while (*p != '\n') + p++; + textlen = p - textstart; + p++; + + Lcont: + continue; + + Lskipline: + // Ignore this line + while (*p++ != '\n') + ; + } + if (namelen) + goto L1; // write out last one + buf->writestring(")\n"); +} + +/*************************************************** + */ + +void MacroSection::write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf) +{ + //printf("MacroSection::write()\n"); + DocComment::parseMacros(dc->pescapetable, dc->pmacrotable, body, bodylen); +} + +/************************************************ + * Parse macros out of Macros: section. + * Macros are of the form: + * name1 = value1 + * + * name2 = value2 + */ + +void DocComment::parseMacros(Escape **pescapetable, Macro **pmacrotable, unsigned char *m, unsigned mlen) +{ + unsigned char *p = m; + unsigned len = mlen; + unsigned char *pend = p + len; + + unsigned char *tempstart; + unsigned templen; + + unsigned char *namestart; + unsigned namelen = 0; // !=0 if line continuation + + unsigned char *textstart; + unsigned textlen; + + while (p < pend) + { + // Skip to start of macro + while (1) + { + if (p >= pend) + goto Ldone; + switch (*p) + { + case ' ': + case '\t': + p++; + continue; + + case '\n': + p++; + goto Lcont; + + default: + if (isIdStart(p)) + break; + if (namelen) + goto Ltext; // continuation of prev macro + goto Lskipline; + } + break; + } + tempstart = p; + + while (1) + { + if (p >= pend) + goto Ldone; + if (!isIdTail(p)) + break; + p += utfStride(p); + } + templen = p - tempstart; + + while (1) + { + if (p >= pend) + goto Ldone; + if (!(*p == ' ' || *p == '\t')) + break; + p++; + } + + if (*p != '=') + { if (namelen) + goto Ltext; // continuation of prev macro + goto Lskipline; + } + p++; + if (p >= pend) + goto Ldone; + + if (namelen) + { // Output existing macro + L1: + //printf("macro '%.*s' = '%.*s'\n", namelen, namestart, textlen, textstart); + if (icmp("ESCAPES", namestart, namelen) == 0) + parseEscapes(pescapetable, textstart, textlen); + else + Macro::define(pmacrotable, namestart, namelen, textstart, textlen); + namelen = 0; + if (p >= pend) + break; + } + + namestart = tempstart; + namelen = templen; + + while (p < pend && (*p == ' ' || *p == '\t')) + p++; + textstart = p; + + Ltext: + while (p < pend && *p != '\n') + p++; + textlen = p - textstart; + + // Remove trailing \r if there is one + if (p > m && p[-1] == '\r') + textlen--; + + p++; + //printf("p = %p, pend = %p\n", p, pend); + + Lcont: + continue; + + Lskipline: + // Ignore this line + while (p < pend && *p++ != '\n') + ; + } +Ldone: + if (namelen) + goto L1; // write out last one +} + +/************************************** + * Parse escapes of the form: + * /c/string/ + * where c is a single character. + * Multiple escapes can be separated + * by whitespace and/or commas. + */ + +void DocComment::parseEscapes(Escape **pescapetable, unsigned char *textstart, unsigned textlen) +{ Escape *escapetable = *pescapetable; + + if (!escapetable) + { escapetable = new Escape; + *pescapetable = escapetable; + } + unsigned char *p = textstart; + unsigned char *pend = p + textlen; + + while (1) + { + while (1) + { + if (p + 4 >= pend) + return; + if (!(*p == ' ' || *p == '\t' || *p == '\n' || *p == ',')) + break; + p++; + } + if (p[0] != '/' || p[2] != '/') + return; + unsigned char c = p[1]; + p += 3; + unsigned char *start = p; + while (1) + { + if (p >= pend) + return; + if (*p == '/') + break; + p++; + } + size_t len = p - start; + char *s = (char *)memcpy(mem.malloc(len + 1), start, len); + s[len] = 0; + escapetable->strings[c] = s; + //printf("%c = '%s'\n", c, s); + p++; + } +} + + +/****************************************** + * Compare 0-terminated string with length terminated string. + * Return < 0, ==0, > 0 + */ + +int cmp(const char *stringz, void *s, size_t slen) +{ + size_t len1 = strlen(stringz); + + if (len1 != slen) + return len1 - slen; + return memcmp(stringz, s, slen); +} + +int icmp(const char *stringz, void *s, size_t slen) +{ + size_t len1 = strlen(stringz); + + if (len1 != slen) + return len1 - slen; + return memicmp(stringz, (char *)s, slen); +} + +/***************************************** + * Return !=0 if comment consists entirely of "ditto". + */ + +int isDitto(unsigned char *comment) +{ + if (comment) + { + unsigned char *p = skipwhitespace(comment); + + if (memicmp((char *)p, "ditto", 5) == 0 && *skipwhitespace(p + 5) == 0) + return 1; + } + return 0; +} + +/********************************************** + * Skip white space. + */ + +unsigned char *skipwhitespace(unsigned char *p) +{ + for (; 1; p++) + { switch (*p) + { + case ' ': + case '\t': + case '\n': + continue; + } + break; + } + return p; +} + + +/************************************************ + * Scan forward to one of: + * start of identifier + * beginning of next line + * end of buf + */ + +unsigned skiptoident(OutBuffer *buf, size_t i) +{ + while (i < buf->offset) + { dchar_t c; + + size_t oi = i; + if (utf_decodeChar((unsigned char *)buf->data, buf->offset, &i, &c)) + /* Ignore UTF errors, but still consume input + */ + break; + if (c >= 0x80) + { + if (!isUniAlpha(c)) + continue; + } + else if (!(isalpha(c) || c == '_' || c == '\n')) + continue; + i = oi; + break; + } + return i; +} + +/************************************************ + * Scan forward past end of identifier. + */ + +unsigned skippastident(OutBuffer *buf, size_t i) +{ + while (i < buf->offset) + { dchar_t c; + + size_t oi = i; + if (utf_decodeChar((unsigned char *)buf->data, buf->offset, &i, &c)) + /* Ignore UTF errors, but still consume input + */ + break; + if (c >= 0x80) + { + if (isUniAlpha(c)) + continue; + } + else if (isalnum(c) || c == '_') + continue; + i = oi; + break; + } + return i; +} + + +/************************************************ + * Scan forward past URL starting at i. + * We don't want to highlight parts of a URL. + * Returns: + * i if not a URL + * index just past it if it is a URL + */ + +unsigned skippastURL(OutBuffer *buf, size_t i) +{ unsigned length = buf->offset - i; + unsigned char *p = &buf->data[i]; + unsigned j; + unsigned sawdot = 0; + + if (length > 7 && memicmp((char *)p, "http://", 7) == 0) + { + j = 7; + } + else if (length > 8 && memicmp((char *)p, "https://", 8) == 0) + { + j = 8; + } + else + goto Lno; + + for (; j < length; j++) + { unsigned char c = p[j]; + if (isalnum(c)) + continue; + if (c == '-' || c == '_' || c == '?' || + c == '=' || c == '%' || c == '&' || + c == '/' || c == '+' || c == '#' || + c == '~') + continue; + if (c == '.') + { + sawdot = 1; + continue; + } + break; + } + if (sawdot) + return i + j; + +Lno: + return i; +} + + +/**************************************************** + */ + +int isKeyword(unsigned char *p, unsigned len) +{ + static const char *table[] = { "true", "false", "null" }; + + for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++) + { + if (cmp(table[i], p, len) == 0) + return 1; + } + return 0; +} + +/**************************************************** + */ + +Parameter *isFunctionParameter(Dsymbol *s, unsigned char *p, unsigned len) +{ + FuncDeclaration *f = s->isFuncDeclaration(); + + /* f->type may be NULL for template members. + */ + if (f && f->type) + { + TypeFunction *tf; + if (f->originalType) + { + tf = (TypeFunction *)f->originalType; + } + else + tf = (TypeFunction *)f->type; + + if (tf->parameters) + { + for (size_t k = 0; k < tf->parameters->dim; k++) + { Parameter *arg = (*tf->parameters)[k]; + + if (arg->ident && cmp(arg->ident->toChars(), p, len) == 0) + { + return arg; + } + } + } + } + return NULL; +} + +/************************************************** + * Highlight text section. + */ + +void highlightText(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset) +{ + //printf("highlightText()\n"); + const char *sid = s->ident->toChars(); + FuncDeclaration *f = s->isFuncDeclaration(); + unsigned char *p; + const char *se; + + int leadingBlank = 1; + int inCode = 0; + //int inComment = 0; // in comment + unsigned iCodeStart; // start of code section + + unsigned iLineStart = offset; + + for (unsigned i = offset; i < buf->offset; i++) + { unsigned char c = buf->data[i]; + + Lcont: + switch (c) + { + case ' ': + case '\t': + break; + + case '\n': + if (sc && !inCode && i == iLineStart && i + 1 < buf->offset) // if "\n\n" + { + static char blankline[] = "$(DDOC_BLANKLINE)\n"; + + i = buf->insert(i, blankline, sizeof(blankline) - 1); + } + leadingBlank = 1; + iLineStart = i + 1; + break; + + case '<': + leadingBlank = 0; + if (inCode) + break; + p = &buf->data[i]; + + // Skip over comments + if (p[1] == '!' && p[2] == '-' && p[3] == '-') + { unsigned j = i + 4; + p += 4; + while (1) + { + if (j == buf->offset) + goto L1; + if (p[0] == '-' && p[1] == '-' && p[2] == '>') + { + i = j + 2; // place on closing '>' + break; + } + j++; + p++; + } + break; + } + + // Skip over HTML tag + if (isalpha(p[1]) || (p[1] == '/' && isalpha(p[2]))) + { unsigned j = i + 2; + p += 2; + while (1) + { + if (j == buf->offset) + goto L1; + if (p[0] == '>') + { + i = j; // place on closing '>' + break; + } + j++; + p++; + } + break; + } + + L1: + // Replace '<' with '<' character entity + se = Escape::escapeChar('<'); + if (se) + { size_t len = strlen(se); + buf->remove(i, 1); + i = buf->insert(i, se, len); + i--; // point to ';' + } + break; + + case '>': + leadingBlank = 0; + if (inCode) + break; + // Replace '>' with '>' character entity + se = Escape::escapeChar('>'); + if (se) + { size_t len = strlen(se); + buf->remove(i, 1); + i = buf->insert(i, se, len); + i--; // point to ';' + } + break; + + case '&': + leadingBlank = 0; + if (inCode) + break; + p = &buf->data[i]; + if (p[1] == '#' || isalpha(p[1])) + break; // already a character entity + // Replace '&' with '&' character entity + se = Escape::escapeChar('&'); + if (se) + { size_t len = strlen(se); + buf->remove(i, 1); + i = buf->insert(i, se, len); + i--; // point to ';' + } + break; + + case '-': + /* A line beginning with --- delimits a code section. + * inCode tells us if it is start or end of a code section. + */ + if (leadingBlank) + { int istart = i; + int eollen = 0; + + leadingBlank = 0; + while (1) + { + ++i; + if (i >= buf->offset) + break; + c = buf->data[i]; + if (c == '\n') + { eollen = 1; + break; + } + if (c == '\r') + { + eollen = 1; + if (i + 1 >= buf->offset) + break; + if (buf->data[i + 1] == '\n') + { eollen = 2; + break; + } + } + // BUG: handle UTF PS and LS too + if (c != '-') + goto Lcont; + } + if (i - istart < 3) + goto Lcont; + + // We have the start/end of a code section + + // Remove the entire --- line, including blanks and \n + buf->remove(iLineStart, i - iLineStart + eollen); + i = iLineStart; + + if (inCode && (i <= iCodeStart)) + { // Empty code section, just remove it completely. + inCode = 0; + break; + } + + if (inCode) + { + inCode = 0; + // The code section is from iCodeStart to i + OutBuffer codebuf; + + codebuf.write(buf->data + iCodeStart, i - iCodeStart); + codebuf.writeByte(0); + highlightCode2(sc, s, &codebuf, 0); + buf->remove(iCodeStart, i - iCodeStart); + i = buf->insert(iCodeStart, codebuf.data, codebuf.offset); + i = buf->insert(i, ")\n", 2); + i--; + } + else + { static char pre[] = "$(D_CODE \n"; + + inCode = 1; + i = buf->insert(i, pre, sizeof(pre) - 1); + iCodeStart = i; + i--; // place i on > + leadingBlank = true; + } + } + break; + + default: + leadingBlank = 0; + if (sc && !inCode && isIdStart(&buf->data[i])) + { unsigned j; + + j = skippastident(buf, i); + if (j > i) + { + unsigned k = skippastURL(buf, i); + if (k > i) + { i = k - 1; + break; + } + + if (buf->data[i] == '_') // leading '_' means no highlight + { + buf->remove(i, 1); + i = j - 1; + } + else + { + if (cmp(sid, buf->data + i, j - i) == 0) + { + i = buf->bracket(i, "$(DDOC_PSYMBOL ", j, ")") - 1; + break; + } + else if (isKeyword(buf->data + i, j - i)) + { + i = buf->bracket(i, "$(DDOC_KEYWORD ", j, ")") - 1; + break; + } + else + { + if (f && isFunctionParameter(f, buf->data + i, j - i)) + { + //printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j); + i = buf->bracket(i, "$(DDOC_PARAM ", j, ")") - 1; + break; + } + } + i = j - 1; + } + } + } + break; + } + } + if (inCode) + s->error("unmatched --- in DDoc comment"); + ; +} + +/************************************************** + * Highlight code for DDOC section. + */ + +void highlightCode(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset) +{ + char *sid = s->ident->toChars(); + FuncDeclaration *f = s->isFuncDeclaration(); + + //printf("highlightCode(s = '%s', kind = %s)\n", sid, s->kind()); + for (unsigned i = offset; i < buf->offset; i++) + { unsigned char c = buf->data[i]; + const char *se; + + se = Escape::escapeChar(c); + if (se) + { + size_t len = strlen(se); + buf->remove(i, 1); + i = buf->insert(i, se, len); + i--; // point to ';' + } + else if (isIdStart(&buf->data[i])) + { unsigned j; + + j = skippastident(buf, i); + if (j > i) + { + if (cmp(sid, buf->data + i, j - i) == 0) + { + i = buf->bracket(i, "$(DDOC_PSYMBOL ", j, ")") - 1; + continue; + } + else if (f) + { + if (isFunctionParameter(f, buf->data + i, j - i)) + { + //printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j); + i = buf->bracket(i, "$(DDOC_PARAM ", j, ")") - 1; + continue; + } + } + i = j - 1; + } + } + } +} + +/**************************************** + */ + +void highlightCode3(OutBuffer *buf, unsigned char *p, unsigned char *pend) +{ + for (; p < pend; p++) + { const char *s = Escape::escapeChar(*p); + if (s) + buf->writestring(s); + else + buf->writeByte(*p); + } +} + +/************************************************** + * Highlight code for CODE section. + */ + + +void highlightCode2(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset) +{ + char *sid = s->ident->toChars(); + FuncDeclaration *f = s->isFuncDeclaration(); + unsigned errorsave = global.errors; + Lexer lex(NULL, buf->data, 0, buf->offset - 1, 0, 1); + Token tok; + OutBuffer res; + unsigned char *lastp = buf->data; + const char *highlight; + + //printf("highlightCode2('%.*s')\n", buf->offset - 1, buf->data); + res.reserve(buf->offset); + while (1) + { + lex.scan(&tok); + highlightCode3(&res, lastp, tok.ptr); + highlight = NULL; + switch (tok.value) + { + case TOKidentifier: + if (!sc) + break; + if (cmp(sid, tok.ptr, lex.p - tok.ptr) == 0) + { + highlight = "$(D_PSYMBOL "; + break; + } + else if (f) + { + if (isFunctionParameter(f, tok.ptr, lex.p - tok.ptr)) + { + //printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j); + highlight = "$(D_PARAM "; + break; + } + } + break; + + case TOKcomment: + highlight = "$(D_COMMENT "; + break; + + case TOKstring: + highlight = "$(D_STRING "; + break; + + default: + if (tok.isKeyword()) + highlight = "$(D_KEYWORD "; + break; + } + if (highlight) + res.writestring(highlight); + highlightCode3(&res, tok.ptr, lex.p); + if (highlight) + res.writeByte(')'); + if (tok.value == TOKeof) + break; + lastp = lex.p; + } + buf->setsize(offset); + buf->write(&res); + global.errors = errorsave; +} + +/*************************************** + * Find character string to replace c with. + */ + +const char *Escape::escapeChar(unsigned c) +{ const char *s; + + switch (c) + { + case '<': + s = "<"; + break; + case '>': + s = ">"; + break; + case '&': + s = "&"; + break; + default: + s = NULL; + break; + } + return s; +} + +/**************************************** + * Determine if p points to the start of an identifier. + */ + +int isIdStart(unsigned char *p) +{ + unsigned c = *p; + if (isalpha(c) || c == '_') + return 1; + if (c >= 0x80) + { size_t i = 0; + if (utf_decodeChar(p, 4, &i, &c)) + return 0; // ignore errors + if (isUniAlpha(c)) + return 1; + } + return 0; +} + +/**************************************** + * Determine if p points to the rest of an identifier. + */ + +int isIdTail(unsigned char *p) +{ + unsigned c = *p; + if (isalnum(c) || c == '_') + return 1; + if (c >= 0x80) + { size_t i = 0; + if (utf_decodeChar(p, 4, &i, &c)) + return 0; // ignore errors + if (isUniAlpha(c)) + return 1; + } + return 0; +} + +/***************************************** + * Return number of bytes in UTF character. + */ + +int utfStride(unsigned char *p) +{ + unsigned c = *p; + if (c < 0x80) + return 1; + size_t i = 0; + utf_decodeChar(p, 4, &i, &c); // ignore errors, but still consume input + return i; +} diff --git a/dmd2/dsymbol.c b/dmd2/dsymbol.c index ef23de74..fdc799ed 100644 --- a/dmd2/dsymbol.c +++ b/dmd2/dsymbol.c @@ -1,1528 +1,1501 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include - -#include "rmem.h" -#include "speller.h" -#include "aav.h" - -#include "mars.h" -#include "dsymbol.h" -#include "aggregate.h" -#include "identifier.h" -#include "module.h" -#include "mtype.h" -#include "expression.h" -#include "statement.h" -#include "declaration.h" -#include "id.h" -#include "scope.h" -#include "init.h" -#include "import.h" -#include "template.h" -#include "attrib.h" -#if IN_LLVM -#include "../gen/pragma.h" -#endif - -/****************************** Dsymbol ******************************/ - -Dsymbol::Dsymbol() -{ - //printf("Dsymbol::Dsymbol(%p)\n", this); - this->ident = NULL; - this->c_ident = NULL; - this->parent = NULL; -#if IN_DMD - this->csym = NULL; - this->isym = NULL; -#endif - this->loc = 0; - this->comment = NULL; - this->scope = NULL; - this->errors = false; - -#if IN_LLVM - this->llvmInternal = LLVMnone; - this->irsym = NULL; -#endif -} - -Dsymbol::Dsymbol(Identifier *ident) -{ - //printf("Dsymbol::Dsymbol(%p, ident)\n", this); - this->ident = ident; - this->c_ident = NULL; - this->parent = NULL; -#if IN_DMD - this->csym = NULL; - this->isym = NULL; -#endif - this->loc = 0; - this->comment = NULL; - this->scope = NULL; - this->errors = false; - -#if IN_LLVM - this->llvmInternal = LLVMnone; - this->irsym = NULL; -#endif -} - -int Dsymbol::equals(Object *o) -{ Dsymbol *s; - - if (this == o) - return TRUE; - s = (Dsymbol *)(o); - // Overload sets don't have an ident - if (s && ident && s->ident && ident->equals(s->ident)) - return TRUE; - return FALSE; -} - -/************************************** - * Copy the syntax. - * Used for template instantiations. - * If s is NULL, allocate the new object, otherwise fill it in. - */ - -Dsymbol *Dsymbol::syntaxCopy(Dsymbol *s) -{ - print(); - printf("%s %s\n", kind(), toChars()); - assert(0); - return NULL; -} - -/************************************** - * Determine if this symbol is only one. - * Returns: - * FALSE, *ps = NULL: There are 2 or more symbols - * TRUE, *ps = NULL: There are zero symbols - * TRUE, *ps = symbol: The one and only one symbol - */ - -int Dsymbol::oneMember(Dsymbol **ps, Identifier *ident) -{ - //printf("Dsymbol::oneMember()\n"); - *ps = this; - return TRUE; -} - -/***************************************** - * Same as Dsymbol::oneMember(), but look at an array of Dsymbols. - */ - -int Dsymbol::oneMembers(Dsymbols *members, Dsymbol **ps, Identifier *ident) -{ - //printf("Dsymbol::oneMembers() %d\n", members ? members->dim : 0); - Dsymbol *s = NULL; - - if (members) - { - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *sx = (*members)[i]; - - int x = sx->oneMember(ps, ident); - //printf("\t[%d] kind %s = %d, s = %p\n", i, sx->kind(), x, *ps); - if (!x) - { - //printf("\tfalse 1\n"); - assert(*ps == NULL); - return FALSE; - } - if (*ps) - { - if (ident) - { - if (!(*ps)->ident || !(*ps)->ident->equals(ident)) - continue; - } - if (!s) - s = *ps; - else if (s->isOverloadable() && (*ps)->isOverloadable()) - ; // keep head of overload set - else // more than one symbol - { *ps = NULL; - //printf("\tfalse 2\n"); - return FALSE; - } - } - } - } - *ps = s; // s is the one symbol, NULL if none - //printf("\ttrue\n"); - return TRUE; -} - -/***************************************** - * Is Dsymbol a variable that contains pointers? - */ - -int Dsymbol::hasPointers() -{ - //printf("Dsymbol::hasPointers() %s\n", toChars()); - return 0; -} - -bool Dsymbol::hasStaticCtorOrDtor() -{ - //printf("Dsymbol::hasStaticCtorOrDtor() %s\n", toChars()); - return FALSE; -} - -void Dsymbol::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion) -{ -} - -char *Dsymbol::toChars() -{ - return ident ? ident->toChars() : (char *)"__anonymous"; -} - -const char *Dsymbol::toPrettyChars() -{ Dsymbol *p; - char *s; - char *q; - size_t len; - - //printf("Dsymbol::toPrettyChars() '%s'\n", toChars()); - if (!parent) - return toChars(); - - len = 0; - for (p = this; p; p = p->parent) - len += strlen(p->toChars()) + 1; - - s = (char *)mem.malloc(len); - q = s + len - 1; - *q = 0; - for (p = this; p; p = p->parent) - { - char *t = p->toChars(); - len = strlen(t); - q -= len; - memcpy(q, t, len); - if (q == s) - break; - q--; -#if TARGET_NET - if (AggregateDeclaration* ad = p->isAggregateDeclaration()) - { - if (ad->isNested() && p->parent && p->parent->isAggregateDeclaration()) - { - *q = '/'; - continue; - } - } -#endif - *q = '.'; - } - return s; -} - -char *Dsymbol::locToChars() -{ - OutBuffer buf; - - if (!loc.filename) // avoid bug 5861. - { - Module *m = getModule(); - - if (m && m->srcfile) - loc.filename = m->srcfile->toChars(); - } - return loc.toChars(); -} - -const char *Dsymbol::kind() -{ - return "symbol"; -} - -/********************************* - * If this symbol is really an alias for another, - * return that other. - */ - -Dsymbol *Dsymbol::toAlias() -{ - return this; -} - -Dsymbol *Dsymbol::toParent() -{ - return parent ? parent->pastMixin() : NULL; -} - -Dsymbol *Dsymbol::pastMixin() -{ - Dsymbol *s = this; - - //printf("Dsymbol::pastMixin() %s\n", toChars()); - while (s && s->isTemplateMixin()) - s = s->parent; - return s; -} - -/********************************** - * Use this instead of toParent() when looking for the - * 'this' pointer of the enclosing function/class. - */ - -Dsymbol *Dsymbol::toParent2() -{ - Dsymbol *s = parent; - while (s && s->isTemplateInstance()) - s = s->parent; - return s; -} - -TemplateInstance *Dsymbol::inTemplateInstance() -{ - for (Dsymbol *parent = this->parent; parent; parent = parent->parent) - { - TemplateInstance *ti = parent->isTemplateInstance(); - if (ti) - return ti; - } - return NULL; -} - -// Check if this function is a member of a template which has only been -// instantiated speculatively, eg from inside is(typeof()). -// Return the speculative template instance it is part of, -// or NULL if not speculative. -TemplateInstance *Dsymbol::isSpeculative() -{ - Dsymbol * par = parent; - while (par) - { - TemplateInstance *ti = par->isTemplateInstance(); - if (ti && ti->speculative) - return ti; - par = par->toParent(); - } - return NULL; -} - -int Dsymbol::isAnonymous() -{ - return ident ? 0 : 1; -} - -/************************************* - * Set scope for future semantic analysis so we can - * deal better with forward references. - */ - -void Dsymbol::setScope(Scope *sc) -{ - //printf("Dsymbol::setScope() %p %s, %p stc = %llx\n", this, toChars(), sc, sc->stc); - if (!sc->nofree) - sc->setNoFree(); // may need it even after semantic() finishes - scope = sc; -} - -void Dsymbol::importAll(Scope *sc) -{ -} - -/************************************* - * Does semantic analysis on the public face of declarations. - */ - -void Dsymbol::semantic0(Scope *sc) -{ -} - -void Dsymbol::semantic(Scope *sc) -{ - error("%p has no semantic routine", this); -} - -/************************************* - * Does semantic analysis on initializers and members of aggregates. - */ - -void Dsymbol::semantic2(Scope *sc) -{ - // Most Dsymbols have no further semantic analysis needed -} - -/************************************* - * Does semantic analysis on function bodies. - */ - -void Dsymbol::semantic3(Scope *sc) -{ - // Most Dsymbols have no further semantic analysis needed -} - -/************************************* - * Look for function inlining possibilities. - */ - -void Dsymbol::inlineScan() -{ - // Most Dsymbols aren't functions -} - -/********************************************* - * Search for ident as member of s. - * Input: - * flags: 1 don't find private members - * 2 don't give error messages - * 4 return NULL if ambiguous - * Returns: - * NULL if not found - */ - -Dsymbol *Dsymbol::search(Loc loc, Identifier *ident, int flags) -{ - //printf("Dsymbol::search(this=%p,%s, ident='%s')\n", this, toChars(), ident->toChars()); - return NULL; -} - -/*************************************************** - * Search for symbol with correct spelling. - */ - -void *symbol_search_fp(void *arg, const char *seed) -{ - /* If not in the lexer's string table, it certainly isn't in the symbol table. - * Doing this first is a lot faster. - */ - size_t len = strlen(seed); - if (!len) - return NULL; - StringValue *sv = Lexer::stringtable.lookup(seed, len); - if (!sv) - return NULL; - Identifier *id = (Identifier *)sv->ptrvalue; - assert(id); - - Dsymbol *s = (Dsymbol *)arg; - Module::clearCache(); - return s->search(0, id, 4|2); -} - -Dsymbol *Dsymbol::search_correct(Identifier *ident) -{ - if (global.gag) - return NULL; // don't do it for speculative compiles; too time consuming - - return (Dsymbol *)speller(ident->toChars(), &symbol_search_fp, this, idchars); -} - -/*************************************** - * Search for identifier id as a member of 'this'. - * id may be a template instance. - * Returns: - * symbol found, NULL if not - */ - -Dsymbol *Dsymbol::searchX(Loc loc, Scope *sc, Identifier *id) -{ - //printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident->toChars()); - Dsymbol *s = toAlias(); - Dsymbol *sm; - - switch (id->dyncast()) - { - case DYNCAST_IDENTIFIER: - sm = s->search(loc, id, 0); - break; - - case DYNCAST_DSYMBOL: - { // It's a template instance - //printf("\ttemplate instance id\n"); - Dsymbol *st = (Dsymbol *)id; - TemplateInstance *ti = st->isTemplateInstance(); - id = ti->name; - sm = s->search(loc, id, 0); - if (!sm) - { - sm = s->search_correct(id); - if (sm) - error("template identifier '%s' is not a member of '%s %s', did you mean '%s %s'?", - id->toChars(), s->kind(), s->toChars(), sm->kind(), sm->toChars()); - else - error("template identifier '%s' is not a member of '%s %s'", - id->toChars(), s->kind(), s->toChars()); - return NULL; - } - sm = sm->toAlias(); - TemplateDeclaration *td = sm->isTemplateDeclaration(); - if (!td) - { - error("%s is not a template, it is a %s", id->toChars(), sm->kind()); - return NULL; - } - ti->tempdecl = td; - if (!ti->semanticRun) - ti->semantic(sc); - sm = ti->toAlias(); - break; - } - - default: - assert(0); - } - return sm; -} - -int Dsymbol::overloadInsert(Dsymbol *s) -{ - //printf("Dsymbol::overloadInsert('%s')\n", s->toChars()); - return FALSE; -} - -void Dsymbol::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(toChars()); -} - -unsigned Dsymbol::size(Loc loc) -{ - error("Dsymbol '%s' has no size\n", toChars()); - return 0; -} - -int Dsymbol::isforwardRef() -{ - return FALSE; -} - -AggregateDeclaration *Dsymbol::isThis() -{ - return NULL; -} - -AggregateDeclaration *Dsymbol::isAggregateMember() // are we a member of an aggregate? -{ - Dsymbol *parent = toParent(); - if (parent && parent->isAggregateDeclaration()) - return (AggregateDeclaration *)parent; - return NULL; -} - -ClassDeclaration *Dsymbol::isClassMember() // are we a member of a class? -{ - AggregateDeclaration *ad = isAggregateMember(); - return ad ? ad->isClassDeclaration() : NULL; -} - -void Dsymbol::defineRef(Dsymbol *s) -{ - assert(0); -} - -int Dsymbol::isExport() -{ - return FALSE; -} - -int Dsymbol::isImportedSymbol() -{ - return FALSE; -} - -int Dsymbol::isDeprecated() -{ - return FALSE; -} - -#if DMDV2 -int Dsymbol::isOverloadable() -{ - return 0; -} - -int Dsymbol::hasOverloads() -{ - return 0; -} -#endif - -LabelDsymbol *Dsymbol::isLabel() // is this a LabelDsymbol()? -{ - return NULL; -} - -AggregateDeclaration *Dsymbol::isMember() // is this a member of an AggregateDeclaration? -{ - //printf("Dsymbol::isMember() %s\n", toChars()); - Dsymbol *parent = toParent(); - //printf("parent is %s %s\n", parent->kind(), parent->toChars()); - return parent ? parent->isAggregateDeclaration() : NULL; -} - -Type *Dsymbol::getType() -{ - return NULL; -} - -int Dsymbol::needThis() -{ - return FALSE; -} - -int Dsymbol::apply(Dsymbol_apply_ft_t fp, void *param) -{ - return (*fp)(this, param); -} - -int Dsymbol::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) -{ - //printf("Dsymbol::addMember('%s')\n", toChars()); - //printf("Dsymbol::addMember(this = %p, '%s' scopesym = '%s')\n", this, toChars(), sd->toChars()); - //printf("Dsymbol::addMember(this = %p, '%s' sd = %p, sd->symtab = %p)\n", this, toChars(), sd, sd->symtab); - parent = sd; - if (!isAnonymous()) // no name, so can't add it to symbol table - { - if (!sd->symtabInsert(this)) // if name is already defined - { - Dsymbol *s2; - - s2 = sd->symtab->lookup(ident); - if (!s2->overloadInsert(this)) - { - sd->multiplyDefined(0, this, s2); - } - } - if (sd->isAggregateDeclaration() || sd->isEnumDeclaration()) - { - if (ident == Id::__sizeof || ident == Id::__xalignof || ident == Id::mangleof) - error(".%s property cannot be redefined", ident->toChars()); - } - return 1; - } - return 0; -} - -void Dsymbol::error(const char *format, ...) -{ - //printf("Dsymbol::error()\n"); - if (!loc.filename) // avoid bug 5861. - { - Module *m = getModule(); - - if (m && m->srcfile) - loc.filename = m->srcfile->toChars(); - } - va_list ap; - va_start(ap, format); - verror(loc, format, ap); - va_end(ap); -} - -void Dsymbol::error(Loc loc, const char *format, ...) -{ - va_list ap; - va_start(ap, format); - verror(loc, format, ap); - 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()) - { - // Don't complain if we're inside a deprecated symbol's scope - for (Dsymbol *sp = sc->parent; sp; sp = sp->parent) - { if (sp->isDeprecated()) - goto L1; - } - - for (Scope *sc2 = sc; sc2; sc2 = sc2->enclosing) - { - if (sc2->scopesym && sc2->scopesym->isDeprecated()) - goto L1; - - // If inside a StorageClassDeclaration that is deprecated - if (sc2->stc & STCdeprecated) - goto L1; - } - - error(loc, "is deprecated"); - } - - L1: - Declaration *d = isDeclaration(); - if (d && d->storage_class & STCdisable) - { - if (!(sc->func && sc->func->storage_class & STCdisable)) - { - if (d->ident == Id::cpctor && d->toParent()) - d->toParent()->error(loc, "is not copyable because it is annotated with @disable"); - else - error(loc, "is not callable because it is annotated with @disable"); - } - } -} - -/********************************** - * Determine which Module a Dsymbol is in. - */ - -Module *Dsymbol::getModule() -{ - //printf("Dsymbol::getModule()\n"); - TemplateDeclaration *td = getFuncTemplateDecl(this); - if (td) - return td->getModule(); - - Dsymbol *s = this; - while (s) - { - //printf("\ts = %s '%s'\n", s->kind(), s->toPrettyChars()); - Module *m = s->isModule(); - if (m) - return m; - s = s->parent; - } - return NULL; -} - -/********************************** - * Determine which Module a Dsymbol is in, as far as access rights go. - */ - -Module *Dsymbol::getAccessModule() -{ - //printf("Dsymbol::getAccessModule()\n"); - TemplateDeclaration *td = getFuncTemplateDecl(this); - if (td) - return td->getAccessModule(); - - Dsymbol *s = this; - while (s) - { - //printf("\ts = %s '%s'\n", s->kind(), s->toPrettyChars()); - Module *m = s->isModule(); - if (m) - return m; - TemplateInstance *ti = s->isTemplateInstance(); - if (ti && ti->isnested) - /* Because of local template instantiation, the parent isn't where the access - * rights come from - it's the template declaration - */ - s = ti->tempdecl; - else - s = s->parent; - } - return NULL; -} - -/************************************* - */ - -enum PROT Dsymbol::prot() -{ - return PROTpublic; -} - -/************************************* - * Do syntax copy of an array of Dsymbol's. - */ - - -Dsymbols *Dsymbol::arraySyntaxCopy(Dsymbols *a) -{ - - Dsymbols *b = NULL; - if (a) - { - b = a->copy(); - for (size_t i = 0; i < b->dim; i++) - { - Dsymbol *s = (*b)[i]; - - s = s->syntaxCopy(NULL); - (*b)[i] = s; - } - } - return b; -} - - -/**************************************** - * Add documentation comment to Dsymbol. - * Ignore NULL comments. - */ - -void Dsymbol::addComment(unsigned char *comment) -{ - //if (comment) - //printf("adding comment '%s' to symbol %p '%s'\n", comment, this, toChars()); - - if (!this->comment) - this->comment = comment; -#if 1 - else if (comment && strcmp((char *)comment, (char *)this->comment)) - { // Concatenate the two - this->comment = Lexer::combineComments(this->comment, comment); - } -#endif -} - -/********************************* OverloadSet ****************************/ - -#if DMDV2 -OverloadSet::OverloadSet() - : Dsymbol() -{ -} - -void OverloadSet::push(Dsymbol *s) -{ - a.push(s); -} - -const char *OverloadSet::kind() -{ - return "overloadset"; -} -#endif - - -/********************************* ScopeDsymbol ****************************/ - -ScopeDsymbol::ScopeDsymbol() - : Dsymbol() -{ - members = NULL; - symtab = NULL; - imports = NULL; - prots = NULL; -} - -ScopeDsymbol::ScopeDsymbol(Identifier *id) - : Dsymbol(id) -{ - members = NULL; - symtab = NULL; - imports = NULL; - prots = NULL; -} - -Dsymbol *ScopeDsymbol::syntaxCopy(Dsymbol *s) -{ - //printf("ScopeDsymbol::syntaxCopy('%s')\n", toChars()); - - ScopeDsymbol *sd; - if (s) - sd = (ScopeDsymbol *)s; - else - sd = new ScopeDsymbol(ident); - sd->members = arraySyntaxCopy(members); - return sd; -} - -Dsymbol *ScopeDsymbol::search(Loc loc, Identifier *ident, int flags) -{ - //printf("%s->ScopeDsymbol::search(ident='%s', flags=x%x)\n", toChars(), ident->toChars(), flags); - //if (strcmp(ident->toChars(),"c") == 0) *(char*)0=0; - - // Look in symbols declared in this module - Dsymbol *s = symtab ? symtab->lookup(ident) : NULL; - //printf("\ts = %p, imports = %p, %d\n", s, imports, imports ? imports->dim : 0); - // hide the aliases generated by selective or renamed private imports - if (s && flags & 1) - if (AliasDeclaration* ad = s->isAliasDeclaration()) - // may be a private alias to a function that is overloaded. these - // are sorted out during overload resolution, accept them here - if (ad->importprot == PROTprivate && !ad->aliassym->isFuncAliasDeclaration()) - s = NULL; - - if (s) - { - //printf("\ts = '%s.%s'\n",toChars(),s->toChars()); - } - else if (imports) - { - OverloadSet *a = NULL; - - // Look in imported modules - for (size_t i = 0; i < imports->dim; i++) - { Dsymbol *ss = (*imports)[i]; - Dsymbol *s2; - - // If private import, don't search it - if (flags & 1 && prots[i] == PROTprivate) - continue; - - //printf("\tscanning import '%s', prots = %d, isModule = %p, isImport = %p\n", ss->toChars(), prots[i], ss->isModule(), ss->isImport()); - /* Don't find private members if ss is a module - */ - s2 = ss->search(loc, ident, ss->isModule() ? 1 : 0); - if (!s) - s = s2; - else if (s2 && s != s2) - { - if (s->toAlias() == s2->toAlias()) - { - /* After following aliases, we found the same - * symbol, so it's not an ambiguity. But if one - * alias is deprecated or less accessible, prefer - * the other. - */ - if (s->isDeprecated() || - s2->prot() > s->prot() && s2->prot() != PROTnone) - s = s2; - } - else - { - /* Two imports of the same module should be regarded as - * the same. - */ - Import *i1 = s->isImport(); - Import *i2 = s2->isImport(); - if (!(i1 && i2 && - (i1->mod == i2->mod || - (!i1->parent->isImport() && !i2->parent->isImport() && - i1->ident->equals(i2->ident)) - ) - ) - ) - { - /* If both s2 and s are overloadable (though we only - * need to check s once) - */ - if (s2->isOverloadable() && (a || s->isOverloadable())) - { if (!a) - a = new OverloadSet(); - /* Don't add to a[] if s2 is alias of previous sym - */ - for (size_t j = 0; j < a->a.dim; j++) - { Dsymbol *s3 = a->a[j]; - if (s2->toAlias() == s3->toAlias()) - { - if (s3->isDeprecated() || - s2->prot() > s3->prot() && s2->prot() != PROTnone) - a->a[j] = s2; - goto Lcontinue; - } - } - a->push(s2); - Lcontinue: - continue; - } - if (flags & 4) // if return NULL on ambiguity - return NULL; - if (!(flags & 2)) - ScopeDsymbol::multiplyDefined(loc, s, s2); - break; - } - } - } - } - - /* Build special symbol if we had multiple finds - */ - if (a) - { assert(s); - a->push(s); - s = a; - } - - if (s) - { - Declaration *d = s->isDeclaration(); - if (d && d->protection == PROTprivate && - !d->parent->isTemplateMixin() && - !(flags & 2)) - error(loc, "%s is private", d->toPrettyChars()); - } - } - return s; -} - -void ScopeDsymbol::importScope(Dsymbol *s, enum PROT protection) -{ - //printf("%s->ScopeDsymbol::importScope(%s, %d)\n", toChars(), s->toChars(), protection); - - // No circular or redundant import's - if (s != this) - { - if (!imports) - imports = new Dsymbols(); - else - { - for (size_t i = 0; i < imports->dim; i++) - { Dsymbol *ss = (*imports)[i]; - if (ss == s) // if already imported - { - if (protection > prots[i]) - prots[i] = protection; // upgrade access - return; - } - } - } - imports->push(s); - prots = (unsigned char *)mem.realloc(prots, imports->dim * sizeof(prots[0])); - prots[imports->dim - 1] = protection; - } -} - -int ScopeDsymbol::isforwardRef() -{ - return (members == NULL); -} - -void ScopeDsymbol::defineRef(Dsymbol *s) -{ - ScopeDsymbol *ss; - - ss = s->isScopeDsymbol(); - members = ss->members; - ss->members = NULL; -} - -void ScopeDsymbol::multiplyDefined(Loc loc, Dsymbol *s1, Dsymbol *s2) -{ -#if 0 - printf("ScopeDsymbol::multiplyDefined()\n"); - printf("s1 = %p, '%s' kind = '%s', parent = %s\n", s1, s1->toChars(), s1->kind(), s1->parent ? s1->parent->toChars() : ""); - printf("s2 = %p, '%s' kind = '%s', parent = %s\n", s2, s2->toChars(), s2->kind(), s2->parent ? s2->parent->toChars() : ""); -#endif - if (loc.filename) - { ::error(loc, "%s at %s conflicts with %s at %s", - s1->toPrettyChars(), - s1->locToChars(), - s2->toPrettyChars(), - s2->locToChars()); - } - else - { - s1->error(loc, "conflicts with %s %s at %s", - s2->kind(), - s2->toPrettyChars(), - s2->locToChars()); - } -} - -Dsymbol *ScopeDsymbol::nameCollision(Dsymbol *s) -{ - Dsymbol *sprev; - - // Look to see if we are defining a forward referenced symbol - - sprev = symtab->lookup(s->ident); - assert(sprev); - if (s->equals(sprev)) // if the same symbol - { - if (s->isforwardRef()) // if second declaration is a forward reference - return sprev; - if (sprev->isforwardRef()) - { - sprev->defineRef(s); // copy data from s into sprev - return sprev; - } - } - multiplyDefined(0, s, sprev); - return sprev; -} - -const char *ScopeDsymbol::kind() -{ - return "ScopeDsymbol"; -} - -Dsymbol *ScopeDsymbol::symtabInsert(Dsymbol *s) -{ - return symtab->insert(s); -} - -/**************************************** - * Return true if any of the members are static ctors or static dtors, or if - * any members have members that are. - */ - -bool ScopeDsymbol::hasStaticCtorOrDtor() -{ - if (members) - { - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *member = (*members)[i]; - - if (member->hasStaticCtorOrDtor()) - return TRUE; - } - } - return FALSE; -} - -/*************************************** - * Determine number of Dsymbols, folding in AttribDeclaration members. - */ - -#if DMDV2 -static int dimDg(void *ctx, size_t n, Dsymbol *) -{ - ++*(size_t *)ctx; - return 0; -} - -size_t ScopeDsymbol::dim(Dsymbols *members) -{ - size_t n = 0; - foreach(NULL, members, &dimDg, &n); - return n; -} -#endif - -/*************************************** - * Get nth Dsymbol, folding in AttribDeclaration members. - * Returns: - * Dsymbol* nth Dsymbol - * NULL not found, *pn gets incremented by the number - * of Dsymbols - */ - -#if DMDV2 -struct GetNthSymbolCtx -{ - size_t nth; - Dsymbol *sym; -}; - -static int getNthSymbolDg(void *ctx, size_t n, Dsymbol *sym) -{ - GetNthSymbolCtx *p = (GetNthSymbolCtx *)ctx; - if (n == p->nth) - { p->sym = sym; - return 1; - } - return 0; -} - -Dsymbol *ScopeDsymbol::getNth(Dsymbols *members, size_t nth, size_t *pn) -{ - GetNthSymbolCtx ctx = { nth, NULL }; - int res = foreach(NULL, members, &getNthSymbolDg, &ctx); - return res ? ctx.sym : NULL; -} -#endif - -/*************************************** - * Expands attribute declarations in members in depth first - * order. Calls dg(void *ctx, size_t symidx, Dsymbol *sym) for each - * member. - * If dg returns !=0, stops and returns that value else returns 0. - * Use this function to avoid the O(N + N^2/2) complexity of - * calculating dim and calling N times getNth. - */ - -#if DMDV2 -int ScopeDsymbol::foreach(Scope *sc, Dsymbols *members, ScopeDsymbol::ForeachDg dg, void *ctx, size_t *pn) -{ - assert(dg); - if (!members) - return 0; - - size_t n = pn ? *pn : 0; // take over index - int result = 0; - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = (*members)[i]; - - if (AttribDeclaration *a = s->isAttribDeclaration()) - result = foreach(sc, a->include(sc, NULL), dg, ctx, &n); - else if (TemplateMixin *tm = s->isTemplateMixin()) - result = foreach(sc, tm->members, dg, ctx, &n); - else if (s->isTemplateInstance()) - ; - else - result = dg(ctx, n++, s); - - if (result) - break; - } - - if (pn) - *pn = n; // update index - return result; -} -#endif - -/******************************************* - * Look for member of the form: - * const(MemberInfo)[] getMembers(string); - * Returns NULL if not found - */ - -#if DMDV2 -FuncDeclaration *ScopeDsymbol::findGetMembers() -{ - Dsymbol *s = search_function(this, Id::getmembers); - FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL; - -#if 0 // Finish - static TypeFunction *tfgetmembers; - - if (!tfgetmembers) - { - Scope sc; - Parameters *arguments = new Parameters; - Parameters *arg = new Parameter(STCin, Type::tchar->constOf()->arrayOf(), NULL, NULL); - arguments->push(arg); - - Type *tret = NULL; - tfgetmembers = new TypeFunction(arguments, tret, 0, LINKd); - tfgetmembers = (TypeFunction *)tfgetmembers->semantic(0, &sc); - } - if (fdx) - fdx = fdx->overloadExactMatch(tfgetmembers); -#endif - if (fdx && fdx->isVirtual()) - fdx = NULL; - - return fdx; -} -#endif - - -/****************************** WithScopeSymbol ******************************/ - -WithScopeSymbol::WithScopeSymbol(WithStatement *withstate) - : ScopeDsymbol() -{ - this->withstate = withstate; -} - -Dsymbol *WithScopeSymbol::search(Loc loc, Identifier *ident, int flags) -{ - // Acts as proxy to the with class declaration - return withstate->exp->type->toDsymbol(NULL)->search(loc, ident, 0); -} - -/****************************** ArrayScopeSymbol ******************************/ - -ArrayScopeSymbol::ArrayScopeSymbol(Scope *sc, Expression *e) - : ScopeDsymbol() -{ - assert(e->op == TOKindex || e->op == TOKslice || e->op == TOKarray); - exp = e; - type = NULL; - td = NULL; - this->sc = sc; -} - -ArrayScopeSymbol::ArrayScopeSymbol(Scope *sc, TypeTuple *t) - : ScopeDsymbol() -{ - exp = NULL; - type = t; - td = NULL; - this->sc = sc; -} - -ArrayScopeSymbol::ArrayScopeSymbol(Scope *sc, TupleDeclaration *s) - : ScopeDsymbol() -{ - exp = NULL; - type = NULL; - td = s; - this->sc = sc; -} - -Dsymbol *ArrayScopeSymbol::search(Loc loc, Identifier *ident, int flags) -{ - //printf("ArrayScopeSymbol::search('%s', flags = %d)\n", ident->toChars(), flags); - if (ident == Id::length || ident == Id::dollar) - { VarDeclaration **pvar; - Expression *ce; - - if (ident == Id::length && !global.params.useDeprecated) - error("using 'length' inside [ ] is deprecated, use '$' instead"); - - L1: - - if (td) - { /* $ gives the number of elements in the tuple - */ - VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL); - Expression *e = new IntegerExp(0, td->objects->dim, Type::tsize_t); - v->init = new ExpInitializer(0, e); - v->storage_class |= STCstatic | STCconst; - v->semantic(sc); - return v; - } - - if (type) - { /* $ gives the number of type entries in the type tuple - */ - VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL); - Expression *e = new IntegerExp(0, type->arguments->dim, Type::tsize_t); - v->init = new ExpInitializer(0, e); - v->storage_class |= STCstatic | STCconst; - v->semantic(sc); - return v; - } - - if (exp->op == TOKindex) - { /* array[index] where index is some function of $ - */ - IndexExp *ie = (IndexExp *)exp; - - pvar = &ie->lengthVar; - ce = ie->e1; - } - else if (exp->op == TOKslice) - { /* array[lwr .. upr] where lwr or upr is some function of $ - */ - SliceExp *se = (SliceExp *)exp; - - pvar = &se->lengthVar; - ce = se->e1; - } - else if (exp->op == TOKarray) - { /* array[e0, e1, e2, e3] where e0, e1, e2 are some function of $ - * $ is a opDollar!(dim)() where dim is the dimension(0,1,2,...) - */ - ArrayExp *ae = (ArrayExp *)exp; - AggregateDeclaration *ad = NULL; - - Type *t = ae->e1->type->toBasetype(); - if (t->ty == Tclass) - { - ad = ((TypeClass *)t)->sym; - } - else if (t->ty == Tstruct) - { - ad = ((TypeStruct *)t)->sym; - } - assert(ad); - - Dsymbol *dsym = search_function(ad, Id::opDollar); - if (!dsym) // no dollar exists -- search in higher scope - return NULL; - VarDeclaration *v = ae->lengthVar; - if (!v) - { // $ is lazily initialized. Create it now. - TemplateDeclaration *td = dsym->isTemplateDeclaration(); - if (td) - { // Instantiate opDollar!(dim) with the index as a template argument - Objects *tdargs = new Objects(); - tdargs->setDim(1); - - Expression *x = new IntegerExp(0, ae->currentDimension, Type::tsize_t); - x = x->semantic(sc); - tdargs->data[0] = x; - - //TemplateInstance *ti = new TemplateInstance(loc, td, tdargs); - //ti->semantic(sc); - - DotTemplateInstanceExp *dte = new DotTemplateInstanceExp(loc, ae->e1, td->ident, tdargs); - - v = new VarDeclaration(loc, NULL, Id::dollar, new ExpInitializer(0, dte)); - } - else - { /* opDollar exists, but it's a function, not a template. - * This is acceptable ONLY for single-dimension indexing. - * Note that it's impossible to have both template & function opDollar, - * because both take no arguments. - */ - if (ae->arguments->dim != 1) { - ae->error("%s only defines opDollar for one dimension", ad->toChars()); - return NULL; - } - FuncDeclaration *fd = dsym->isFuncDeclaration(); - assert(fd); - Expression * x = new DotVarExp(loc, ae->e1, fd); - - v = new VarDeclaration(loc, NULL, Id::dollar, new ExpInitializer(0, x)); - } - v->semantic(sc); - ae->lengthVar = v; - } - return v; - } - else - /* Didn't find $, look in enclosing scope(s). - */ - return NULL; - - /* If we are indexing into an array that is really a type - * tuple, rewrite this as an index into a type tuple and - * try again. - */ - if (ce->op == TOKtype) - { - Type *t = ((TypeExp *)ce)->type; - if (t->ty == Ttuple) - { type = (TypeTuple *)t; - goto L1; - } - } - - /* *pvar is lazily initialized, so if we refer to $ - * multiple times, it gets set only once. - */ - if (!*pvar) // if not already initialized - { /* Create variable v and set it to the value of $ - */ - VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL); - if (ce->op == TOKtuple) - { /* It is for an expression tuple, so the - * length will be a const. - */ - Expression *e = new IntegerExp(0, ((TupleExp *)ce)->exps->dim, Type::tsize_t); - v->init = new ExpInitializer(0, e); - v->storage_class |= STCstatic | STCconst; - } - else - { /* For arrays, $ will either be a compile-time constant - * (in which case its value in set during constant-folding), - * or a variable (in which case an expression is created in - * toir.c). - */ - VoidInitializer *e = new VoidInitializer(0); - e->type = Type::tsize_t; - v->init = e; - } - *pvar = v; - } - (*pvar)->semantic(sc); - return (*pvar); - } - return NULL; -} - - -/****************************** DsymbolTable ******************************/ - -DsymbolTable::DsymbolTable() -{ -#if STRINGTABLE - tab = new StringTable; - tab->init(); -#else - tab = NULL; -#endif -} - -DsymbolTable::~DsymbolTable() -{ -#if STRINGTABLE - delete tab; -#endif -} - -Dsymbol *DsymbolTable::lookup(Identifier *ident) -{ -#if STRINGTABLE -#ifdef DEBUG - assert(ident); - assert(tab); -#endif - //printf("DsymbolTable::lookup(%s)\n", (char*)ident->string); - StringValue *sv = tab->lookup((char*)ident->string, ident->len); - return (Dsymbol *)(sv ? sv->ptrvalue : NULL); -#else - //printf("DsymbolTable::lookup(%s)\n", (char*)ident->string); - return (Dsymbol *)_aaGetRvalue(tab, ident); -#endif -} - -Dsymbol *DsymbolTable::insert(Dsymbol *s) -{ - //printf("DsymbolTable::insert(this = %p, '%s')\n", this, s->ident->toChars()); - Identifier *ident = s->ident; -#if STRINGTABLE -#ifdef DEBUG - assert(ident); - assert(tab); -#endif - StringValue *sv = tab->insert(ident->toChars(), ident->len); - if (!sv) - return NULL; // already in table - sv->ptrvalue = s; - return s; -#else - Dsymbol **ps = (Dsymbol **)_aaGet(&tab, ident); - if (*ps) - return NULL; // already in table - *ps = s; - return s; -#endif -} - -Dsymbol *DsymbolTable::insert(Identifier *ident, Dsymbol *s) -{ - //printf("DsymbolTable::insert()\n"); -#if STRINGTABLE - StringValue *sv = tab->insert(ident->toChars(), ident->len); - if (!sv) - return NULL; // already in table - sv->ptrvalue = s; - return s; -#else - Dsymbol **ps = (Dsymbol **)_aaGet(&tab, ident); - if (*ps) - return NULL; // already in table - *ps = s; - return s; -#endif -} - -Dsymbol *DsymbolTable::update(Dsymbol *s) -{ - Identifier *ident = s->ident; -#if STRINGTABLE - StringValue *sv = tab->update(ident->toChars(), ident->len); - sv->ptrvalue = s; - return s; -#else - Dsymbol **ps = (Dsymbol **)_aaGet(&tab, ident); - *ps = s; - return s; -#endif -} - - - - + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2012 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#include +#include +#include + +#include "rmem.h" +#include "speller.h" +#include "aav.h" + +#include "mars.h" +#include "dsymbol.h" +#include "aggregate.h" +#include "identifier.h" +#include "module.h" +#include "mtype.h" +#include "expression.h" +#include "statement.h" +#include "declaration.h" +#include "id.h" +#include "scope.h" +#include "init.h" +#include "import.h" +#include "template.h" +#include "attrib.h" +#if IN_LLVM +#include "../gen/pragma.h" +#endif + +/****************************** Dsymbol ******************************/ + +Dsymbol::Dsymbol() +{ + //printf("Dsymbol::Dsymbol(%p)\n", this); + this->ident = NULL; + this->c_ident = NULL; + this->parent = NULL; +#if IN_DMD + this->csym = NULL; + this->isym = NULL; +#endif + this->loc = 0; + this->comment = NULL; + this->scope = NULL; + this->errors = false; + +#if IN_LLVM + this->llvmInternal = LLVMnone; + this->irsym = NULL; +#endif +} + +Dsymbol::Dsymbol(Identifier *ident) +{ + //printf("Dsymbol::Dsymbol(%p, ident)\n", this); + this->ident = ident; + this->c_ident = NULL; + this->parent = NULL; +#if IN_DMD + this->csym = NULL; + this->isym = NULL; +#endif + this->loc = 0; + this->comment = NULL; + this->scope = NULL; + this->errors = false; + +#if IN_LLVM + this->llvmInternal = LLVMnone; + this->irsym = NULL; +#endif +} + +int Dsymbol::equals(Object *o) +{ Dsymbol *s; + + if (this == o) + return TRUE; + s = (Dsymbol *)(o); + // Overload sets don't have an ident + if (s && ident && s->ident && ident->equals(s->ident)) + return TRUE; + return FALSE; +} + +/************************************** + * Copy the syntax. + * Used for template instantiations. + * If s is NULL, allocate the new object, otherwise fill it in. + */ + +Dsymbol *Dsymbol::syntaxCopy(Dsymbol *s) +{ + print(); + printf("%s %s\n", kind(), toChars()); + assert(0); + return NULL; +} + +/************************************** + * Determine if this symbol is only one. + * Returns: + * FALSE, *ps = NULL: There are 2 or more symbols + * TRUE, *ps = NULL: There are zero symbols + * TRUE, *ps = symbol: The one and only one symbol + */ + +int Dsymbol::oneMember(Dsymbol **ps, Identifier *ident) +{ + //printf("Dsymbol::oneMember()\n"); + *ps = this; + return TRUE; +} + +/***************************************** + * Same as Dsymbol::oneMember(), but look at an array of Dsymbols. + */ + +int Dsymbol::oneMembers(Dsymbols *members, Dsymbol **ps, Identifier *ident) +{ + //printf("Dsymbol::oneMembers() %d\n", members ? members->dim : 0); + Dsymbol *s = NULL; + + if (members) + { + for (size_t i = 0; i < members->dim; i++) + { Dsymbol *sx = (*members)[i]; + + int x = sx->oneMember(ps, ident); + //printf("\t[%d] kind %s = %d, s = %p\n", i, sx->kind(), x, *ps); + if (!x) + { + //printf("\tfalse 1\n"); + assert(*ps == NULL); + return FALSE; + } + if (*ps) + { + if (ident) + { + if (!(*ps)->ident || !(*ps)->ident->equals(ident)) + continue; + } + if (!s) + s = *ps; + else if (s->isOverloadable() && (*ps)->isOverloadable()) + ; // keep head of overload set + else // more than one symbol + { *ps = NULL; + //printf("\tfalse 2\n"); + return FALSE; + } + } + } + } + *ps = s; // s is the one symbol, NULL if none + //printf("\ttrue\n"); + return TRUE; +} + +/***************************************** + * Is Dsymbol a variable that contains pointers? + */ + +int Dsymbol::hasPointers() +{ + //printf("Dsymbol::hasPointers() %s\n", toChars()); + return 0; +} + +bool Dsymbol::hasStaticCtorOrDtor() +{ + //printf("Dsymbol::hasStaticCtorOrDtor() %s\n", toChars()); + return FALSE; +} + +void Dsymbol::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion) +{ +} + +char *Dsymbol::toChars() +{ + return ident ? ident->toChars() : (char *)"__anonymous"; +} + +const char *Dsymbol::toPrettyChars() +{ Dsymbol *p; + char *s; + char *q; + size_t len; + + //printf("Dsymbol::toPrettyChars() '%s'\n", toChars()); + if (!parent) + return toChars(); + + len = 0; + for (p = this; p; p = p->parent) + len += strlen(p->toChars()) + 1; + + s = (char *)mem.malloc(len); + q = s + len - 1; + *q = 0; + for (p = this; p; p = p->parent) + { + char *t = p->toChars(); + len = strlen(t); + q -= len; + memcpy(q, t, len); + if (q == s) + break; + q--; +#if TARGET_NET + if (AggregateDeclaration* ad = p->isAggregateDeclaration()) + { + if (ad->isNested() && p->parent && p->parent->isAggregateDeclaration()) + { + *q = '/'; + continue; + } + } +#endif + *q = '.'; + } + return s; +} + +char *Dsymbol::locToChars() +{ + OutBuffer buf; + + if (!loc.filename) // avoid bug 5861. + { + Module *m = getModule(); + + if (m && m->srcfile) + loc.filename = m->srcfile->toChars(); + } + return loc.toChars(); +} + +const char *Dsymbol::kind() +{ + return "symbol"; +} + +/********************************* + * If this symbol is really an alias for another, + * return that other. + */ + +Dsymbol *Dsymbol::toAlias() +{ + return this; +} + +Dsymbol *Dsymbol::toParent() +{ + return parent ? parent->pastMixin() : NULL; +} + +Dsymbol *Dsymbol::pastMixin() +{ + Dsymbol *s = this; + + //printf("Dsymbol::pastMixin() %s\n", toChars()); + while (s && s->isTemplateMixin()) + s = s->parent; + return s; +} + +/********************************** + * Use this instead of toParent() when looking for the + * 'this' pointer of the enclosing function/class. + */ + +Dsymbol *Dsymbol::toParent2() +{ + Dsymbol *s = parent; + while (s && s->isTemplateInstance()) + s = s->parent; + return s; +} + +TemplateInstance *Dsymbol::inTemplateInstance() +{ + for (Dsymbol *parent = this->parent; parent; parent = parent->parent) + { + TemplateInstance *ti = parent->isTemplateInstance(); + if (ti) + return ti; + } + return NULL; +} + +// Check if this function is a member of a template which has only been +// instantiated speculatively, eg from inside is(typeof()). +// Return the speculative template instance it is part of, +// or NULL if not speculative. +TemplateInstance *Dsymbol::isSpeculative() +{ + Dsymbol * par = parent; + while (par) + { + TemplateInstance *ti = par->isTemplateInstance(); + if (ti && ti->speculative) + return ti; + par = par->toParent(); + } + return NULL; +} + +int Dsymbol::isAnonymous() +{ + return ident ? 0 : 1; +} + +/************************************* + * Set scope for future semantic analysis so we can + * deal better with forward references. + */ + +void Dsymbol::setScope(Scope *sc) +{ + //printf("Dsymbol::setScope() %p %s, %p stc = %llx\n", this, toChars(), sc, sc->stc); + if (!sc->nofree) + sc->setNoFree(); // may need it even after semantic() finishes + scope = sc; +} + +void Dsymbol::importAll(Scope *sc) +{ +} + +/************************************* + * Does semantic analysis on the public face of declarations. + */ + +void Dsymbol::semantic0(Scope *sc) +{ +} + +void Dsymbol::semantic(Scope *sc) +{ + error("%p has no semantic routine", this); +} + +/************************************* + * Does semantic analysis on initializers and members of aggregates. + */ + +void Dsymbol::semantic2(Scope *sc) +{ + // Most Dsymbols have no further semantic analysis needed +} + +/************************************* + * Does semantic analysis on function bodies. + */ + +void Dsymbol::semantic3(Scope *sc) +{ + // Most Dsymbols have no further semantic analysis needed +} + +/************************************* + * Look for function inlining possibilities. + */ + +void Dsymbol::inlineScan() +{ + // Most Dsymbols aren't functions +} + +/********************************************* + * Search for ident as member of s. + * Input: + * flags: 1 don't find private members + * 2 don't give error messages + * 4 return NULL if ambiguous + * Returns: + * NULL if not found + */ + +Dsymbol *Dsymbol::search(Loc loc, Identifier *ident, int flags) +{ + //printf("Dsymbol::search(this=%p,%s, ident='%s')\n", this, toChars(), ident->toChars()); + return NULL; +} + +/*************************************************** + * Search for symbol with correct spelling. + */ + +void *symbol_search_fp(void *arg, const char *seed) +{ + /* If not in the lexer's string table, it certainly isn't in the symbol table. + * Doing this first is a lot faster. + */ + size_t len = strlen(seed); + if (!len) + return NULL; + StringValue *sv = Lexer::stringtable.lookup(seed, len); + if (!sv) + return NULL; + Identifier *id = (Identifier *)sv->ptrvalue; + assert(id); + + Dsymbol *s = (Dsymbol *)arg; + Module::clearCache(); + return s->search(0, id, 4|2); +} + +Dsymbol *Dsymbol::search_correct(Identifier *ident) +{ + if (global.gag) + return NULL; // don't do it for speculative compiles; too time consuming + + return (Dsymbol *)speller(ident->toChars(), &symbol_search_fp, this, idchars); +} + +/*************************************** + * Search for identifier id as a member of 'this'. + * id may be a template instance. + * Returns: + * symbol found, NULL if not + */ + +Dsymbol *Dsymbol::searchX(Loc loc, Scope *sc, Identifier *id) +{ + //printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident->toChars()); + Dsymbol *s = toAlias(); + Dsymbol *sm; + + switch (id->dyncast()) + { + case DYNCAST_IDENTIFIER: + sm = s->search(loc, id, 0); + break; + + case DYNCAST_DSYMBOL: + { // It's a template instance + //printf("\ttemplate instance id\n"); + Dsymbol *st = (Dsymbol *)id; + TemplateInstance *ti = st->isTemplateInstance(); + id = ti->name; + sm = s->search(loc, id, 0); + if (!sm) + { + sm = s->search_correct(id); + if (sm) + error("template identifier '%s' is not a member of '%s %s', did you mean '%s %s'?", + id->toChars(), s->kind(), s->toChars(), sm->kind(), sm->toChars()); + else + error("template identifier '%s' is not a member of '%s %s'", + id->toChars(), s->kind(), s->toChars()); + return NULL; + } + sm = sm->toAlias(); + TemplateDeclaration *td = sm->isTemplateDeclaration(); + if (!td) + { + error("%s is not a template, it is a %s", id->toChars(), sm->kind()); + return NULL; + } + ti->tempdecl = td; + if (!ti->semanticRun) + ti->semantic(sc); + sm = ti->toAlias(); + break; + } + + default: + assert(0); + } + return sm; +} + +int Dsymbol::overloadInsert(Dsymbol *s) +{ + //printf("Dsymbol::overloadInsert('%s')\n", s->toChars()); + return FALSE; +} + +void Dsymbol::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring(toChars()); +} + +unsigned Dsymbol::size(Loc loc) +{ + error("Dsymbol '%s' has no size\n", toChars()); + return 0; +} + +int Dsymbol::isforwardRef() +{ + return FALSE; +} + +AggregateDeclaration *Dsymbol::isThis() +{ + return NULL; +} + +AggregateDeclaration *Dsymbol::isAggregateMember() // are we a member of an aggregate? +{ + Dsymbol *parent = toParent(); + if (parent && parent->isAggregateDeclaration()) + return (AggregateDeclaration *)parent; + return NULL; +} + +ClassDeclaration *Dsymbol::isClassMember() // are we a member of a class? +{ + AggregateDeclaration *ad = isAggregateMember(); + return ad ? ad->isClassDeclaration() : NULL; +} + +void Dsymbol::defineRef(Dsymbol *s) +{ + assert(0); +} + +int Dsymbol::isExport() +{ + return FALSE; +} + +int Dsymbol::isImportedSymbol() +{ + return FALSE; +} + +int Dsymbol::isDeprecated() +{ + return FALSE; +} + +#if DMDV2 +int Dsymbol::isOverloadable() +{ + return 0; +} + +int Dsymbol::hasOverloads() +{ + return 0; +} +#endif + +LabelDsymbol *Dsymbol::isLabel() // is this a LabelDsymbol()? +{ + return NULL; +} + +AggregateDeclaration *Dsymbol::isMember() // is this a member of an AggregateDeclaration? +{ + //printf("Dsymbol::isMember() %s\n", toChars()); + Dsymbol *parent = toParent(); + //printf("parent is %s %s\n", parent->kind(), parent->toChars()); + return parent ? parent->isAggregateDeclaration() : NULL; +} + +Type *Dsymbol::getType() +{ + return NULL; +} + +int Dsymbol::needThis() +{ + return FALSE; +} + +int Dsymbol::apply(Dsymbol_apply_ft_t fp, void *param) +{ + return (*fp)(this, param); +} + +int Dsymbol::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) +{ + //printf("Dsymbol::addMember('%s')\n", toChars()); + //printf("Dsymbol::addMember(this = %p, '%s' scopesym = '%s')\n", this, toChars(), sd->toChars()); + //printf("Dsymbol::addMember(this = %p, '%s' sd = %p, sd->symtab = %p)\n", this, toChars(), sd, sd->symtab); + parent = sd; + if (!isAnonymous()) // no name, so can't add it to symbol table + { + if (!sd->symtabInsert(this)) // if name is already defined + { + Dsymbol *s2; + + s2 = sd->symtab->lookup(ident); + if (!s2->overloadInsert(this)) + { + sd->multiplyDefined(0, this, s2); + } + } + if (sd->isAggregateDeclaration() || sd->isEnumDeclaration()) + { + if (ident == Id::__sizeof || ident == Id::__xalignof || ident == Id::mangleof) + error(".%s property cannot be redefined", ident->toChars()); + } + return 1; + } + return 0; +} + +void Dsymbol::error(const char *format, ...) +{ + //printf("Dsymbol::error()\n"); + if (!loc.filename) // avoid bug 5861. + { + Module *m = getModule(); + + if (m && m->srcfile) + loc.filename = m->srcfile->toChars(); + } + va_list ap; + va_start(ap, format); + verror(loc, format, ap, kind(), toPrettyChars()); + va_end(ap); +} + +void Dsymbol::error(Loc loc, const char *format, ...) +{ + va_list ap; + va_start(ap, format); + verror(loc, format, ap, kind(), toPrettyChars()); + va_end(ap); +} + +void Dsymbol::checkDeprecated(Loc loc, Scope *sc) +{ + if (!global.params.useDeprecated && isDeprecated()) + { + // Don't complain if we're inside a deprecated symbol's scope + for (Dsymbol *sp = sc->parent; sp; sp = sp->parent) + { if (sp->isDeprecated()) + goto L1; + } + + for (Scope *sc2 = sc; sc2; sc2 = sc2->enclosing) + { + if (sc2->scopesym && sc2->scopesym->isDeprecated()) + goto L1; + + // If inside a StorageClassDeclaration that is deprecated + if (sc2->stc & STCdeprecated) + goto L1; + } + + error(loc, "is deprecated"); + } + + L1: + Declaration *d = isDeclaration(); + if (d && d->storage_class & STCdisable) + { + if (!(sc->func && sc->func->storage_class & STCdisable)) + { + if (d->ident == Id::cpctor && d->toParent()) + d->toParent()->error(loc, "is not copyable because it is annotated with @disable"); + else + error(loc, "is not callable because it is annotated with @disable"); + } + } +} + +/********************************** + * Determine which Module a Dsymbol is in. + */ + +Module *Dsymbol::getModule() +{ + //printf("Dsymbol::getModule()\n"); + TemplateDeclaration *td = getFuncTemplateDecl(this); + if (td) + return td->getModule(); + + Dsymbol *s = this; + while (s) + { + //printf("\ts = %s '%s'\n", s->kind(), s->toPrettyChars()); + Module *m = s->isModule(); + if (m) + return m; + s = s->parent; + } + return NULL; +} + +/********************************** + * Determine which Module a Dsymbol is in, as far as access rights go. + */ + +Module *Dsymbol::getAccessModule() +{ + //printf("Dsymbol::getAccessModule()\n"); + TemplateDeclaration *td = getFuncTemplateDecl(this); + if (td) + return td->getAccessModule(); + + Dsymbol *s = this; + while (s) + { + //printf("\ts = %s '%s'\n", s->kind(), s->toPrettyChars()); + Module *m = s->isModule(); + if (m) + return m; + TemplateInstance *ti = s->isTemplateInstance(); + if (ti && ti->isnested) + /* Because of local template instantiation, the parent isn't where the access + * rights come from - it's the template declaration + */ + s = ti->tempdecl; + else + s = s->parent; + } + return NULL; +} + +/************************************* + */ + +enum PROT Dsymbol::prot() +{ + return PROTpublic; +} + +/************************************* + * Do syntax copy of an array of Dsymbol's. + */ + + +Dsymbols *Dsymbol::arraySyntaxCopy(Dsymbols *a) +{ + + Dsymbols *b = NULL; + if (a) + { + b = a->copy(); + for (size_t i = 0; i < b->dim; i++) + { + Dsymbol *s = (*b)[i]; + + s = s->syntaxCopy(NULL); + (*b)[i] = s; + } + } + return b; +} + + +/**************************************** + * Add documentation comment to Dsymbol. + * Ignore NULL comments. + */ + +void Dsymbol::addComment(unsigned char *comment) +{ + //if (comment) + //printf("adding comment '%s' to symbol %p '%s'\n", comment, this, toChars()); + + if (!this->comment) + this->comment = comment; +#if 1 + else if (comment && strcmp((char *)comment, (char *)this->comment)) + { // Concatenate the two + this->comment = Lexer::combineComments(this->comment, comment); + } +#endif +} + +/********************************* OverloadSet ****************************/ + +#if DMDV2 +OverloadSet::OverloadSet() + : Dsymbol() +{ +} + +void OverloadSet::push(Dsymbol *s) +{ + a.push(s); +} + +const char *OverloadSet::kind() +{ + return "overloadset"; +} +#endif + + +/********************************* ScopeDsymbol ****************************/ + +ScopeDsymbol::ScopeDsymbol() + : Dsymbol() +{ + members = NULL; + symtab = NULL; + imports = NULL; + prots = NULL; +} + +ScopeDsymbol::ScopeDsymbol(Identifier *id) + : Dsymbol(id) +{ + members = NULL; + symtab = NULL; + imports = NULL; + prots = NULL; +} + +Dsymbol *ScopeDsymbol::syntaxCopy(Dsymbol *s) +{ + //printf("ScopeDsymbol::syntaxCopy('%s')\n", toChars()); + + ScopeDsymbol *sd; + if (s) + sd = (ScopeDsymbol *)s; + else + sd = new ScopeDsymbol(ident); + sd->members = arraySyntaxCopy(members); + return sd; +} + +Dsymbol *ScopeDsymbol::search(Loc loc, Identifier *ident, int flags) +{ + //printf("%s->ScopeDsymbol::search(ident='%s', flags=x%x)\n", toChars(), ident->toChars(), flags); + //if (strcmp(ident->toChars(),"c") == 0) *(char*)0=0; + + // Look in symbols declared in this module + Dsymbol *s = symtab ? symtab->lookup(ident) : NULL; + //printf("\ts = %p, imports = %p, %d\n", s, imports, imports ? imports->dim : 0); + // hide the aliases generated by selective or renamed private imports + if (s && flags & 1) + if (AliasDeclaration* ad = s->isAliasDeclaration()) + // may be a private alias to a function that is overloaded. these + // are sorted out during overload resolution, accept them here + if (ad->importprot == PROTprivate && !ad->aliassym->isFuncAliasDeclaration()) + s = NULL; + + if (s) + { + //printf("\ts = '%s.%s'\n",toChars(),s->toChars()); + } + else if (imports) + { + OverloadSet *a = NULL; + + // Look in imported modules + for (size_t i = 0; i < imports->dim; i++) + { Dsymbol *ss = (*imports)[i]; + Dsymbol *s2; + + // If private import, don't search it + if (flags & 1 && prots[i] == PROTprivate) + continue; + + //printf("\tscanning import '%s', prots = %d, isModule = %p, isImport = %p\n", ss->toChars(), prots[i], ss->isModule(), ss->isImport()); + /* Don't find private members if ss is a module + */ + s2 = ss->search(loc, ident, ss->isModule() ? 1 : 0); + if (!s) + s = s2; + else if (s2 && s != s2) + { + if (s->toAlias() == s2->toAlias() || + s->getType() == s2->getType() && s->getType()) + { + /* After following aliases, we found the same + * symbol, so it's not an ambiguity. But if one + * alias is deprecated or less accessible, prefer + * the other. + */ + if (s->isDeprecated() || + s2->prot() > s->prot() && s2->prot() != PROTnone) + s = s2; + } + else + { + /* Two imports of the same module should be regarded as + * the same. + */ + Import *i1 = s->isImport(); + Import *i2 = s2->isImport(); + if (!(i1 && i2 && + (i1->mod == i2->mod || + (!i1->parent->isImport() && !i2->parent->isImport() && + i1->ident->equals(i2->ident)) + ) + ) + ) + { + /* If both s2 and s are overloadable (though we only + * need to check s once) + */ + if (s2->isOverloadable() && (a || s->isOverloadable())) + { if (!a) + a = new OverloadSet(); + /* Don't add to a[] if s2 is alias of previous sym + */ + for (size_t j = 0; j < a->a.dim; j++) + { Dsymbol *s3 = a->a[j]; + if (s2->toAlias() == s3->toAlias()) + { + if (s3->isDeprecated() || + s2->prot() > s3->prot() && s2->prot() != PROTnone) + a->a[j] = s2; + goto Lcontinue; + } + } + a->push(s2); + Lcontinue: + continue; + } + if (flags & 4) // if return NULL on ambiguity + return NULL; + if (!(flags & 2)) + ScopeDsymbol::multiplyDefined(loc, s, s2); + break; + } + } + } + } + + /* Build special symbol if we had multiple finds + */ + if (a) + { assert(s); + a->push(s); + s = a; + } + + if (s) + { + Declaration *d = s->isDeclaration(); + if (d && d->protection == PROTprivate && + !d->parent->isTemplateMixin() && + !(flags & 2)) + error(loc, "%s is private", d->toPrettyChars()); + } + } + return s; +} + +void ScopeDsymbol::importScope(Dsymbol *s, enum PROT protection) +{ + //printf("%s->ScopeDsymbol::importScope(%s, %d)\n", toChars(), s->toChars(), protection); + + // No circular or redundant import's + if (s != this) + { + if (!imports) + imports = new Dsymbols(); + else + { + for (size_t i = 0; i < imports->dim; i++) + { Dsymbol *ss = (*imports)[i]; + if (ss == s) // if already imported + { + if (protection > prots[i]) + prots[i] = protection; // upgrade access + return; + } + } + } + imports->push(s); + prots = (unsigned char *)mem.realloc(prots, imports->dim * sizeof(prots[0])); + prots[imports->dim - 1] = protection; + } +} + +int ScopeDsymbol::isforwardRef() +{ + return (members == NULL); +} + +void ScopeDsymbol::defineRef(Dsymbol *s) +{ + ScopeDsymbol *ss; + + ss = s->isScopeDsymbol(); + members = ss->members; + ss->members = NULL; +} + +void ScopeDsymbol::multiplyDefined(Loc loc, Dsymbol *s1, Dsymbol *s2) +{ +#if 0 + printf("ScopeDsymbol::multiplyDefined()\n"); + printf("s1 = %p, '%s' kind = '%s', parent = %s\n", s1, s1->toChars(), s1->kind(), s1->parent ? s1->parent->toChars() : ""); + printf("s2 = %p, '%s' kind = '%s', parent = %s\n", s2, s2->toChars(), s2->kind(), s2->parent ? s2->parent->toChars() : ""); +#endif + if (loc.filename) + { ::error(loc, "%s at %s conflicts with %s at %s", + s1->toPrettyChars(), + s1->locToChars(), + s2->toPrettyChars(), + s2->locToChars()); + } + else + { + s1->error(loc, "conflicts with %s %s at %s", + s2->kind(), + s2->toPrettyChars(), + s2->locToChars()); + } +} + +Dsymbol *ScopeDsymbol::nameCollision(Dsymbol *s) +{ + Dsymbol *sprev; + + // Look to see if we are defining a forward referenced symbol + + sprev = symtab->lookup(s->ident); + assert(sprev); + if (s->equals(sprev)) // if the same symbol + { + if (s->isforwardRef()) // if second declaration is a forward reference + return sprev; + if (sprev->isforwardRef()) + { + sprev->defineRef(s); // copy data from s into sprev + return sprev; + } + } + multiplyDefined(0, s, sprev); + return sprev; +} + +const char *ScopeDsymbol::kind() +{ + return "ScopeDsymbol"; +} + +Dsymbol *ScopeDsymbol::symtabInsert(Dsymbol *s) +{ + return symtab->insert(s); +} + +/**************************************** + * Return true if any of the members are static ctors or static dtors, or if + * any members have members that are. + */ + +bool ScopeDsymbol::hasStaticCtorOrDtor() +{ + if (members) + { + for (size_t i = 0; i < members->dim; i++) + { Dsymbol *member = (*members)[i]; + + if (member->hasStaticCtorOrDtor()) + return TRUE; + } + } + return FALSE; +} + +/*************************************** + * Determine number of Dsymbols, folding in AttribDeclaration members. + */ + +#if DMDV2 +static int dimDg(void *ctx, size_t n, Dsymbol *) +{ + ++*(size_t *)ctx; + return 0; +} + +size_t ScopeDsymbol::dim(Dsymbols *members) +{ + size_t n = 0; + foreach(NULL, members, &dimDg, &n); + return n; +} +#endif + +/*************************************** + * Get nth Dsymbol, folding in AttribDeclaration members. + * Returns: + * Dsymbol* nth Dsymbol + * NULL not found, *pn gets incremented by the number + * of Dsymbols + */ + +#if DMDV2 +struct GetNthSymbolCtx +{ + size_t nth; + Dsymbol *sym; +}; + +static int getNthSymbolDg(void *ctx, size_t n, Dsymbol *sym) +{ + GetNthSymbolCtx *p = (GetNthSymbolCtx *)ctx; + if (n == p->nth) + { p->sym = sym; + return 1; + } + return 0; +} + +Dsymbol *ScopeDsymbol::getNth(Dsymbols *members, size_t nth, size_t *pn) +{ + GetNthSymbolCtx ctx = { nth, NULL }; + int res = foreach(NULL, members, &getNthSymbolDg, &ctx); + return res ? ctx.sym : NULL; +} +#endif + +/*************************************** + * Expands attribute declarations in members in depth first + * order. Calls dg(void *ctx, size_t symidx, Dsymbol *sym) for each + * member. + * If dg returns !=0, stops and returns that value else returns 0. + * Use this function to avoid the O(N + N^2/2) complexity of + * calculating dim and calling N times getNth. + */ + +#if DMDV2 +int ScopeDsymbol::foreach(Scope *sc, Dsymbols *members, ScopeDsymbol::ForeachDg dg, void *ctx, size_t *pn) +{ + assert(dg); + if (!members) + return 0; + + size_t n = pn ? *pn : 0; // take over index + int result = 0; + for (size_t i = 0; i < members->dim; i++) + { Dsymbol *s = (*members)[i]; + + if (AttribDeclaration *a = s->isAttribDeclaration()) + result = foreach(sc, a->include(sc, NULL), dg, ctx, &n); + else if (TemplateMixin *tm = s->isTemplateMixin()) + result = foreach(sc, tm->members, dg, ctx, &n); + else if (s->isTemplateInstance()) + ; + else if (s->isUnitTestDeclaration()) + ; + else + result = dg(ctx, n++, s); + + if (result) + break; + } + + if (pn) + *pn = n; // update index + return result; +} +#endif + +/******************************************* + * Look for member of the form: + * const(MemberInfo)[] getMembers(string); + * Returns NULL if not found + */ + +#if DMDV2 +FuncDeclaration *ScopeDsymbol::findGetMembers() +{ + Dsymbol *s = search_function(this, Id::getmembers); + FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL; + +#if 0 // Finish + static TypeFunction *tfgetmembers; + + if (!tfgetmembers) + { + Scope sc; + Parameters *arguments = new Parameters; + Parameters *arg = new Parameter(STCin, Type::tchar->constOf()->arrayOf(), NULL, NULL); + arguments->push(arg); + + Type *tret = NULL; + tfgetmembers = new TypeFunction(arguments, tret, 0, LINKd); + tfgetmembers = (TypeFunction *)tfgetmembers->semantic(0, &sc); + } + if (fdx) + fdx = fdx->overloadExactMatch(tfgetmembers); +#endif + if (fdx && fdx->isVirtual()) + fdx = NULL; + + return fdx; +} +#endif + + +/****************************** WithScopeSymbol ******************************/ + +WithScopeSymbol::WithScopeSymbol(WithStatement *withstate) + : ScopeDsymbol() +{ + this->withstate = withstate; +} + +Dsymbol *WithScopeSymbol::search(Loc loc, Identifier *ident, int flags) +{ + // Acts as proxy to the with class declaration + return withstate->exp->type->toDsymbol(NULL)->search(loc, ident, 0); +} + +/****************************** ArrayScopeSymbol ******************************/ + +ArrayScopeSymbol::ArrayScopeSymbol(Scope *sc, Expression *e) + : ScopeDsymbol() +{ + assert(e->op == TOKindex || e->op == TOKslice || e->op == TOKarray); + exp = e; + type = NULL; + td = NULL; + this->sc = sc; +} + +ArrayScopeSymbol::ArrayScopeSymbol(Scope *sc, TypeTuple *t) + : ScopeDsymbol() +{ + exp = NULL; + type = t; + td = NULL; + this->sc = sc; +} + +ArrayScopeSymbol::ArrayScopeSymbol(Scope *sc, TupleDeclaration *s) + : ScopeDsymbol() +{ + exp = NULL; + type = NULL; + td = s; + this->sc = sc; +} + +Dsymbol *ArrayScopeSymbol::search(Loc loc, Identifier *ident, int flags) +{ + //printf("ArrayScopeSymbol::search('%s', flags = %d)\n", ident->toChars(), flags); + if (ident == Id::length || ident == Id::dollar) + { VarDeclaration **pvar; + Expression *ce; + + if (ident == Id::length && !global.params.useDeprecated) + error("using 'length' inside [ ] is deprecated, use '$' instead"); + + L1: + + if (td) + { /* $ gives the number of elements in the tuple + */ + VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL); + Expression *e = new IntegerExp(0, td->objects->dim, Type::tsize_t); + v->init = new ExpInitializer(0, e); + v->storage_class |= STCstatic | STCconst; + v->semantic(sc); + return v; + } + + if (type) + { /* $ gives the number of type entries in the type tuple + */ + VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL); + Expression *e = new IntegerExp(0, type->arguments->dim, Type::tsize_t); + v->init = new ExpInitializer(0, e); + v->storage_class |= STCstatic | STCconst; + v->semantic(sc); + return v; + } + + if (exp->op == TOKindex) + { /* array[index] where index is some function of $ + */ + IndexExp *ie = (IndexExp *)exp; + + pvar = &ie->lengthVar; + ce = ie->e1; + } + else if (exp->op == TOKslice) + { /* array[lwr .. upr] where lwr or upr is some function of $ + */ + SliceExp *se = (SliceExp *)exp; + + pvar = &se->lengthVar; + ce = se->e1; + } + else if (exp->op == TOKarray) + { /* array[e0, e1, e2, e3] where e0, e1, e2 are some function of $ + * $ is a opDollar!(dim)() where dim is the dimension(0,1,2,...) + */ + ArrayExp *ae = (ArrayExp *)exp; + AggregateDeclaration *ad = NULL; + + Type *t = ae->e1->type->toBasetype(); + if (t->ty == Tclass) + { + ad = ((TypeClass *)t)->sym; + } + else if (t->ty == Tstruct) + { + ad = ((TypeStruct *)t)->sym; + } + assert(ad); + + Dsymbol *dsym = search_function(ad, Id::opDollar); + if (!dsym) // no dollar exists -- search in higher scope + return NULL; + VarDeclaration *v = ae->lengthVar; + if (!v) + { // $ is lazily initialized. Create it now. + TemplateDeclaration *td = dsym->isTemplateDeclaration(); + if (td) + { // Instantiate opDollar!(dim) with the index as a template argument + Objects *tdargs = new Objects(); + tdargs->setDim(1); + + Expression *x = new IntegerExp(0, ae->currentDimension, Type::tsize_t); + x = x->semantic(sc); + tdargs->data[0] = x; + + //TemplateInstance *ti = new TemplateInstance(loc, td, tdargs); + //ti->semantic(sc); + + DotTemplateInstanceExp *dte = new DotTemplateInstanceExp(loc, ae->e1, td->ident, tdargs); + + v = new VarDeclaration(loc, NULL, Id::dollar, new ExpInitializer(0, dte)); + } + else + { /* opDollar exists, but it's a function, not a template. + * This is acceptable ONLY for single-dimension indexing. + * Note that it's impossible to have both template & function opDollar, + * because both take no arguments. + */ + if (ae->arguments->dim != 1) { + ae->error("%s only defines opDollar for one dimension", ad->toChars()); + return NULL; + } + FuncDeclaration *fd = dsym->isFuncDeclaration(); + assert(fd); + Expression * x = new DotVarExp(loc, ae->e1, fd); + + v = new VarDeclaration(loc, NULL, Id::dollar, new ExpInitializer(0, x)); + } + v->semantic(sc); + ae->lengthVar = v; + } + return v; + } + else + /* Didn't find $, look in enclosing scope(s). + */ + return NULL; + + /* If we are indexing into an array that is really a type + * tuple, rewrite this as an index into a type tuple and + * try again. + */ + if (ce->op == TOKtype) + { + Type *t = ((TypeExp *)ce)->type; + if (t->ty == Ttuple) + { type = (TypeTuple *)t; + goto L1; + } + } + + /* *pvar is lazily initialized, so if we refer to $ + * multiple times, it gets set only once. + */ + if (!*pvar) // if not already initialized + { /* Create variable v and set it to the value of $ + */ + VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL); + if (ce->op == TOKtuple) + { /* It is for an expression tuple, so the + * length will be a const. + */ + Expression *e = new IntegerExp(0, ((TupleExp *)ce)->exps->dim, Type::tsize_t); + v->init = new ExpInitializer(0, e); + v->storage_class |= STCstatic | STCconst; + } + else + { /* For arrays, $ will either be a compile-time constant + * (in which case its value in set during constant-folding), + * or a variable (in which case an expression is created in + * toir.c). + */ + 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; + } + (*pvar)->semantic(sc); + return (*pvar); + } + return NULL; +} + + +/****************************** DsymbolTable ******************************/ + +DsymbolTable::DsymbolTable() +{ +#if STRINGTABLE + tab = new StringTable; + tab->init(); +#else + tab = NULL; +#endif +} + +DsymbolTable::~DsymbolTable() +{ +#if STRINGTABLE + delete tab; +#endif +} + +Dsymbol *DsymbolTable::lookup(Identifier *ident) +{ +#if STRINGTABLE +#ifdef DEBUG + assert(ident); + assert(tab); +#endif + //printf("DsymbolTable::lookup(%s)\n", (char*)ident->string); + StringValue *sv = tab->lookup((char*)ident->string, ident->len); + return (Dsymbol *)(sv ? sv->ptrvalue : NULL); +#else + //printf("DsymbolTable::lookup(%s)\n", (char*)ident->string); + return (Dsymbol *)_aaGetRvalue(tab, ident); +#endif +} + +Dsymbol *DsymbolTable::insert(Dsymbol *s) +{ + //printf("DsymbolTable::insert(this = %p, '%s')\n", this, s->ident->toChars()); + Identifier *ident = s->ident; +#if STRINGTABLE +#ifdef DEBUG + assert(ident); + assert(tab); +#endif + StringValue *sv = tab->insert(ident->toChars(), ident->len); + if (!sv) + return NULL; // already in table + sv->ptrvalue = s; + return s; +#else + Dsymbol **ps = (Dsymbol **)_aaGet(&tab, ident); + if (*ps) + return NULL; // already in table + *ps = s; + return s; +#endif +} + +Dsymbol *DsymbolTable::insert(Identifier *ident, Dsymbol *s) +{ + //printf("DsymbolTable::insert()\n"); +#if STRINGTABLE + StringValue *sv = tab->insert(ident->toChars(), ident->len); + if (!sv) + return NULL; // already in table + sv->ptrvalue = s; + return s; +#else + Dsymbol **ps = (Dsymbol **)_aaGet(&tab, ident); + if (*ps) + return NULL; // already in table + *ps = s; + return s; +#endif +} + +Dsymbol *DsymbolTable::update(Dsymbol *s) +{ + Identifier *ident = s->ident; +#if STRINGTABLE + StringValue *sv = tab->update(ident->toChars(), ident->len); + sv->ptrvalue = s; + return s; +#else + Dsymbol **ps = (Dsymbol **)_aaGet(&tab, ident); + *ps = s; + return s; +#endif +} + + + + diff --git a/dmd2/dsymbol.h b/dmd2/dsymbol.h index b895d9a2..47f97f2a 100644 --- a/dmd2/dsymbol.h +++ b/dmd2/dsymbol.h @@ -1,396 +1,395 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_DSYMBOL_H -#define DMD_DSYMBOL_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "root.h" -#include "stringtable.h" - -#include "mars.h" -#include "arraytypes.h" - -#if IN_LLVM -#if defined(_MSC_VER) -#undef min -#undef max -#endif -#include "../ir/irdsymbol.h" -#endif - -struct Identifier; -struct Scope; -struct DsymbolTable; -struct Declaration; -struct ThisDeclaration; -struct TupleDeclaration; -struct TypedefDeclaration; -struct AliasDeclaration; -struct AggregateDeclaration; -struct EnumDeclaration; -struct ClassDeclaration; -struct InterfaceDeclaration; -struct StructDeclaration; -struct UnionDeclaration; -struct FuncDeclaration; -struct FuncAliasDeclaration; -struct FuncLiteralDeclaration; -struct CtorDeclaration; -struct PostBlitDeclaration; -struct DtorDeclaration; -struct StaticCtorDeclaration; -struct StaticDtorDeclaration; -struct SharedStaticCtorDeclaration; -struct SharedStaticDtorDeclaration; -struct InvariantDeclaration; -struct UnitTestDeclaration; -struct NewDeclaration; -struct VarDeclaration; -struct AttribDeclaration; -#if IN_DMD -struct Symbol; -#endif -struct Package; -struct Module; -struct Import; -struct Type; -struct TypeTuple; -struct WithStatement; -struct LabelDsymbol; -struct ScopeDsymbol; -struct TemplateDeclaration; -struct TemplateInstance; -struct TemplateMixin; -struct EnumMember; -struct ScopeDsymbol; -struct WithScopeSymbol; -struct ArrayScopeSymbol; -struct StaticStructInitDeclaration; -struct Expression; -struct DeleteDeclaration; -struct HdrGenState; -struct OverloadSet; -struct AA; -#if TARGET_NET -struct PragmaScope; -#endif -#if IN_LLVM -struct TypeInfoDeclaration; -struct ClassInfoDeclaration; -#endif - -#if IN_GCC -union tree_node; -typedef union tree_node TYPE; -#else -struct TYPE; -#endif - -#if IN_LLVM -class Ir; -class IrSymbol; -namespace llvm -{ - class Value; -} -#endif -#if IN_DMD -// Back end -struct Classsym; -#endif - -enum PROT -{ - PROTundefined, - PROTnone, // no access - PROTprivate, - PROTpackage, - PROTprotected, - PROTpublic, - PROTexport, -}; - -/* State of symbol in winding its way through the passes of the compiler - */ -enum PASS -{ - PASSinit, // initial state - PASSsemantic, // semantic() started - PASSsemanticdone, // semantic() done - PASSsemantic2, // semantic2() run - PASSsemantic3, // semantic3() started - PASSsemantic3done, // semantic3() done - PASSobj, // toObjFile() run -}; - -typedef int (*Dsymbol_apply_ft_t)(Dsymbol *, void *); - -struct Dsymbol : Object -{ - Identifier *ident; - Identifier *c_ident; - Dsymbol *parent; -#if IN_DMD - Symbol *csym; // symbol for code generator - Symbol *isym; // import version of csym -#endif - unsigned char *comment; // documentation comment for this Dsymbol - Loc loc; // where defined - Scope *scope; // !=NULL means context to use for semantic() - bool errors; // this symbol failed to pass semantic() - - Dsymbol(); - Dsymbol(Identifier *); - char *toChars(); - char *locToChars(); - int equals(Object *o); - 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 *getAccessModule(); - Dsymbol *pastMixin(); - Dsymbol *toParent(); - Dsymbol *toParent2(); - TemplateInstance *inTemplateInstance(); - TemplateInstance *isSpeculative(); - - int dyncast() { return DYNCAST_DSYMBOL; } // kludge for template.isSymbol() - - static Dsymbols *arraySyntaxCopy(Dsymbols *a); - - virtual const char *toPrettyChars(); - virtual const char *kind(); - virtual Dsymbol *toAlias(); // resolve real symbol - virtual int apply(Dsymbol_apply_ft_t fp, void *param); - virtual int addMember(Scope *sc, ScopeDsymbol *s, int memnum); - virtual void setScope(Scope *sc); - virtual void importAll(Scope *sc); - virtual void semantic0(Scope *sc); - virtual void semantic(Scope *sc); - virtual void semantic2(Scope *sc); - virtual void semantic3(Scope *sc); - virtual void inlineScan(); - virtual Dsymbol *search(Loc loc, Identifier *ident, int flags); - Dsymbol *search_correct(Identifier *id); - Dsymbol *searchX(Loc loc, Scope *sc, Identifier *id); - virtual int overloadInsert(Dsymbol *s); - char *toHChars(); - virtual void toHBuffer(OutBuffer *buf, HdrGenState *hgs); - virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - virtual void toDocBuffer(OutBuffer *buf); - virtual void toJsonBuffer(OutBuffer *buf); - virtual unsigned size(Loc loc); - virtual int isforwardRef(); - virtual void defineRef(Dsymbol *s); - virtual AggregateDeclaration *isThis(); // is a 'this' required to access the member - AggregateDeclaration *isAggregateMember(); // are we a member of an aggregate? - ClassDeclaration *isClassMember(); // are we a member of a class? - virtual int isExport(); // is Dsymbol exported? - virtual int isImportedSymbol(); // is Dsymbol imported? - virtual int isDeprecated(); // is Dsymbol deprecated? -#if DMDV2 - virtual int isOverloadable(); - virtual int hasOverloads(); -#endif - virtual LabelDsymbol *isLabel(); // is this a LabelDsymbol? - virtual AggregateDeclaration *isMember(); // is this symbol a member of an AggregateDeclaration? - virtual Type *getType(); // is this a type? - virtual char *mangle(); - virtual int needThis(); // need a 'this' pointer? - virtual enum PROT prot(); - virtual Dsymbol *syntaxCopy(Dsymbol *s); // copy only syntax trees - virtual int oneMember(Dsymbol **ps, Identifier *ident); - static int oneMembers(Dsymbols *members, Dsymbol **ps, Identifier *ident = NULL); - virtual void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion); - virtual int hasPointers(); - virtual bool hasStaticCtorOrDtor(); - virtual void addLocalClass(ClassDeclarations *) { } - virtual void checkCtorConstInit() { } - - virtual void addComment(unsigned char *comment); - virtual void emitComment(Scope *sc); - void emitDitto(Scope *sc); - -#if IN_DMD - // Backend - - virtual Symbol *toSymbol(); // to backend symbol - virtual void toObjFile(int multiobj); // compile to .obj file - virtual int cvMember(unsigned char *p); // emit cv debug info for member - - Symbol *toImport(); // to backend import symbol - static Symbol *toImport(Symbol *s); // to backend import symbol - - Symbol *toSymbolX(const char *prefix, int sclass, TYPE *t, const char *suffix); // helper -#endif - - // Eliminate need for dynamic_cast - virtual Package *isPackage() { return NULL; } - virtual Module *isModule() { return NULL; } - virtual EnumMember *isEnumMember() { return NULL; } - virtual TemplateDeclaration *isTemplateDeclaration() { return NULL; } - virtual TemplateInstance *isTemplateInstance() { return NULL; } - virtual TemplateMixin *isTemplateMixin() { return NULL; } - virtual Declaration *isDeclaration() { return NULL; } - virtual ThisDeclaration *isThisDeclaration() { return NULL; } - virtual TupleDeclaration *isTupleDeclaration() { return NULL; } - virtual TypedefDeclaration *isTypedefDeclaration() { return NULL; } - virtual AliasDeclaration *isAliasDeclaration() { return NULL; } - virtual AggregateDeclaration *isAggregateDeclaration() { return NULL; } - virtual FuncDeclaration *isFuncDeclaration() { return NULL; } - virtual FuncAliasDeclaration *isFuncAliasDeclaration() { return NULL; } - virtual FuncLiteralDeclaration *isFuncLiteralDeclaration() { return NULL; } - virtual CtorDeclaration *isCtorDeclaration() { return NULL; } - virtual PostBlitDeclaration *isPostBlitDeclaration() { return NULL; } - virtual DtorDeclaration *isDtorDeclaration() { return NULL; } - virtual StaticCtorDeclaration *isStaticCtorDeclaration() { return NULL; } - virtual StaticDtorDeclaration *isStaticDtorDeclaration() { return NULL; } - virtual SharedStaticCtorDeclaration *isSharedStaticCtorDeclaration() { return NULL; } - virtual SharedStaticDtorDeclaration *isSharedStaticDtorDeclaration() { return NULL; } - virtual InvariantDeclaration *isInvariantDeclaration() { return NULL; } - virtual UnitTestDeclaration *isUnitTestDeclaration() { return NULL; } - virtual NewDeclaration *isNewDeclaration() { return NULL; } - virtual VarDeclaration *isVarDeclaration() { return NULL; } - virtual ClassDeclaration *isClassDeclaration() { return NULL; } - virtual StructDeclaration *isStructDeclaration() { return NULL; } - virtual UnionDeclaration *isUnionDeclaration() { return NULL; } - virtual InterfaceDeclaration *isInterfaceDeclaration() { return NULL; } - virtual ScopeDsymbol *isScopeDsymbol() { return NULL; } - virtual WithScopeSymbol *isWithScopeSymbol() { return NULL; } - virtual ArrayScopeSymbol *isArrayScopeSymbol() { return NULL; } - virtual Import *isImport() { return NULL; } - virtual EnumDeclaration *isEnumDeclaration() { return NULL; } - virtual DeleteDeclaration *isDeleteDeclaration() { return NULL; } - virtual StaticStructInitDeclaration *isStaticStructInitDeclaration() { return NULL; } - virtual AttribDeclaration *isAttribDeclaration() { return NULL; } - virtual OverloadSet *isOverloadSet() { return NULL; } - virtual TypeInfoDeclaration* isTypeInfoDeclaration() { return NULL; } - virtual ClassInfoDeclaration* isClassInfoDeclaration() { return NULL; } -#if TARGET_NET - virtual PragmaScope* isPragmaScope() { return NULL; } -#endif -#if IN_LLVM - /// Codegen traversal - virtual void codegen(Ir* ir); - - // llvm stuff - int llvmInternal; - - IrDsymbol ir; - IrSymbol* irsym; -#endif -}; - -// Dsymbol that generates a scope - -struct ScopeDsymbol : Dsymbol -{ - Dsymbols *members; // all Dsymbol's in this scope - DsymbolTable *symtab; // members[] sorted into table - - Dsymbols *imports; // imported Dsymbol's - unsigned char *prots; // array of PROT, one for each import - - ScopeDsymbol(); - ScopeDsymbol(Identifier *id); - Dsymbol *syntaxCopy(Dsymbol *s); - Dsymbol *search(Loc loc, Identifier *ident, int flags); - void importScope(Dsymbol *s, enum PROT protection); - int isforwardRef(); - void defineRef(Dsymbol *s); - static void multiplyDefined(Loc loc, Dsymbol *s1, Dsymbol *s2); - Dsymbol *nameCollision(Dsymbol *s); - const char *kind(); - FuncDeclaration *findGetMembers(); - virtual Dsymbol *symtabInsert(Dsymbol *s); - bool hasStaticCtorOrDtor(); - - void emitMemberComments(Scope *sc); - - static size_t dim(Dsymbols *members); - static Dsymbol *getNth(Dsymbols *members, size_t nth, size_t *pn = NULL); - - typedef int (*ForeachDg)(void *ctx, size_t idx, Dsymbol *s); - static int foreach(Scope *sc, Dsymbols *members, ForeachDg dg, void *ctx, size_t *pn=NULL); - - ScopeDsymbol *isScopeDsymbol() { return this; } -}; - -// With statement scope - -struct WithScopeSymbol : ScopeDsymbol -{ - WithStatement *withstate; - - WithScopeSymbol(WithStatement *withstate); - Dsymbol *search(Loc loc, Identifier *ident, int flags); - - WithScopeSymbol *isWithScopeSymbol() { return this; } -}; - -// Array Index/Slice scope - -struct ArrayScopeSymbol : ScopeDsymbol -{ - Expression *exp; // IndexExp or SliceExp - TypeTuple *type; // for tuple[length] - TupleDeclaration *td; // for tuples of objects - Scope *sc; - - ArrayScopeSymbol(Scope *sc, Expression *e); - ArrayScopeSymbol(Scope *sc, TypeTuple *t); - ArrayScopeSymbol(Scope *sc, TupleDeclaration *td); - Dsymbol *search(Loc loc, Identifier *ident, int flags); - - ArrayScopeSymbol *isArrayScopeSymbol() { return this; } -}; - -// Overload Sets - -#if DMDV2 -struct OverloadSet : Dsymbol -{ - Dsymbols a; // array of Dsymbols - - OverloadSet(); - void push(Dsymbol *s); - OverloadSet *isOverloadSet() { return this; } - const char *kind(); -}; -#endif - -// Table of Dsymbol's - -struct DsymbolTable : Object -{ - AA *tab; - - DsymbolTable(); - ~DsymbolTable(); - - // Look up Identifier. Return Dsymbol if found, NULL if not. - Dsymbol *lookup(Identifier *ident); - - // Insert Dsymbol in table. Return NULL if already there. - Dsymbol *insert(Dsymbol *s); - - // Look for Dsymbol in table. If there, return it. If not, insert s and return that. - Dsymbol *update(Dsymbol *s); - Dsymbol *insert(Identifier *ident, Dsymbol *s); // when ident and s are not the same -}; - -#endif /* DMD_DSYMBOL_H */ + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2012 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#ifndef DMD_DSYMBOL_H +#define DMD_DSYMBOL_H + +#ifdef __DMC__ +#pragma once +#endif /* __DMC__ */ + +#include "root.h" +#include "stringtable.h" + +#include "mars.h" +#include "arraytypes.h" + +#if IN_LLVM +#if defined(_MSC_VER) +#undef min +#undef max +#endif +#include "../ir/irdsymbol.h" +#endif + +struct Identifier; +struct Scope; +struct DsymbolTable; +struct Declaration; +struct ThisDeclaration; +struct TupleDeclaration; +struct TypedefDeclaration; +struct AliasDeclaration; +struct AggregateDeclaration; +struct EnumDeclaration; +struct ClassDeclaration; +struct InterfaceDeclaration; +struct StructDeclaration; +struct UnionDeclaration; +struct FuncDeclaration; +struct FuncAliasDeclaration; +struct FuncLiteralDeclaration; +struct CtorDeclaration; +struct PostBlitDeclaration; +struct DtorDeclaration; +struct StaticCtorDeclaration; +struct StaticDtorDeclaration; +struct SharedStaticCtorDeclaration; +struct SharedStaticDtorDeclaration; +struct InvariantDeclaration; +struct UnitTestDeclaration; +struct NewDeclaration; +struct VarDeclaration; +struct AttribDeclaration; +#if IN_DMD +struct Symbol; +#endif +struct Package; +struct Module; +struct Import; +struct Type; +struct TypeTuple; +struct WithStatement; +struct LabelDsymbol; +struct ScopeDsymbol; +struct TemplateDeclaration; +struct TemplateInstance; +struct TemplateMixin; +struct EnumMember; +struct ScopeDsymbol; +struct WithScopeSymbol; +struct ArrayScopeSymbol; +struct StaticStructInitDeclaration; +struct Expression; +struct DeleteDeclaration; +struct HdrGenState; +struct OverloadSet; +struct AA; +#if TARGET_NET +struct PragmaScope; +#endif +#if IN_LLVM +struct TypeInfoDeclaration; +struct ClassInfoDeclaration; +#endif + +#ifdef IN_GCC +union tree_node; +typedef union tree_node TYPE; +#else +struct TYPE; +#endif + +#if IN_LLVM +class Ir; +class IrSymbol; +namespace llvm +{ + class Value; +} +#endif +#if IN_DMD +// Back end +struct Classsym; +#endif + +enum PROT +{ + PROTundefined, + PROTnone, // no access + PROTprivate, + PROTpackage, + PROTprotected, + PROTpublic, + PROTexport, +}; + +/* State of symbol in winding its way through the passes of the compiler + */ +enum PASS +{ + PASSinit, // initial state + PASSsemantic, // semantic() started + PASSsemanticdone, // semantic() done + PASSsemantic2, // semantic2() run + PASSsemantic3, // semantic3() started + PASSsemantic3done, // semantic3() done + PASSobj, // toObjFile() run +}; + +typedef int (*Dsymbol_apply_ft_t)(Dsymbol *, void *); + +struct Dsymbol : Object +{ + Identifier *ident; + Identifier *c_ident; + Dsymbol *parent; +#if IN_DMD + Symbol *csym; // symbol for code generator + Symbol *isym; // import version of csym +#endif + unsigned char *comment; // documentation comment for this Dsymbol + Loc loc; // where defined + Scope *scope; // !=NULL means context to use for semantic() + bool errors; // this symbol failed to pass semantic() + + Dsymbol(); + Dsymbol(Identifier *); + char *toChars(); + char *locToChars(); + int equals(Object *o); + int isAnonymous(); + void error(Loc loc, const char *format, ...) IS_PRINTF(3); + void error(const char *format, ...) IS_PRINTF(2); + void checkDeprecated(Loc loc, Scope *sc); + Module *getModule(); // module where declared + Module *getAccessModule(); + Dsymbol *pastMixin(); + Dsymbol *toParent(); + Dsymbol *toParent2(); + TemplateInstance *inTemplateInstance(); + TemplateInstance *isSpeculative(); + + int dyncast() { return DYNCAST_DSYMBOL; } // kludge for template.isSymbol() + + static Dsymbols *arraySyntaxCopy(Dsymbols *a); + + virtual const char *toPrettyChars(); + virtual const char *kind(); + virtual Dsymbol *toAlias(); // resolve real symbol + virtual int apply(Dsymbol_apply_ft_t fp, void *param); + virtual int addMember(Scope *sc, ScopeDsymbol *s, int memnum); + virtual void setScope(Scope *sc); + virtual void importAll(Scope *sc); + virtual void semantic0(Scope *sc); + virtual void semantic(Scope *sc); + virtual void semantic2(Scope *sc); + virtual void semantic3(Scope *sc); + virtual void inlineScan(); + virtual Dsymbol *search(Loc loc, Identifier *ident, int flags); + Dsymbol *search_correct(Identifier *id); + Dsymbol *searchX(Loc loc, Scope *sc, Identifier *id); + virtual int overloadInsert(Dsymbol *s); + char *toHChars(); + virtual void toHBuffer(OutBuffer *buf, HdrGenState *hgs); + virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + virtual void toDocBuffer(OutBuffer *buf); + virtual void toJsonBuffer(OutBuffer *buf); + virtual unsigned size(Loc loc); + virtual int isforwardRef(); + virtual void defineRef(Dsymbol *s); + virtual AggregateDeclaration *isThis(); // is a 'this' required to access the member + AggregateDeclaration *isAggregateMember(); // are we a member of an aggregate? + ClassDeclaration *isClassMember(); // are we a member of a class? + virtual int isExport(); // is Dsymbol exported? + virtual int isImportedSymbol(); // is Dsymbol imported? + virtual int isDeprecated(); // is Dsymbol deprecated? +#if DMDV2 + virtual int isOverloadable(); + virtual int hasOverloads(); +#endif + virtual LabelDsymbol *isLabel(); // is this a LabelDsymbol? + virtual AggregateDeclaration *isMember(); // is this symbol a member of an AggregateDeclaration? + virtual Type *getType(); // is this a type? + virtual char *mangle(); + virtual int needThis(); // need a 'this' pointer? + virtual enum PROT prot(); + virtual Dsymbol *syntaxCopy(Dsymbol *s); // copy only syntax trees + virtual int oneMember(Dsymbol **ps, Identifier *ident); + static int oneMembers(Dsymbols *members, Dsymbol **ps, Identifier *ident = NULL); + virtual void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion); + virtual int hasPointers(); + virtual bool hasStaticCtorOrDtor(); + virtual void addLocalClass(ClassDeclarations *) { } + virtual void checkCtorConstInit() { } + + virtual void addComment(unsigned char *comment); + virtual void emitComment(Scope *sc); + void emitDitto(Scope *sc); + +#if IN_DMD + // Backend + + virtual Symbol *toSymbol(); // to backend symbol + virtual void toObjFile(int multiobj); // compile to .obj file + virtual int cvMember(unsigned char *p); // emit cv debug info for member + + Symbol *toImport(); // to backend import symbol + static Symbol *toImport(Symbol *s); // to backend import symbol + + Symbol *toSymbolX(const char *prefix, int sclass, TYPE *t, const char *suffix); // helper +#endif + + // Eliminate need for dynamic_cast + virtual Package *isPackage() { return NULL; } + virtual Module *isModule() { return NULL; } + virtual EnumMember *isEnumMember() { return NULL; } + virtual TemplateDeclaration *isTemplateDeclaration() { return NULL; } + virtual TemplateInstance *isTemplateInstance() { return NULL; } + virtual TemplateMixin *isTemplateMixin() { return NULL; } + virtual Declaration *isDeclaration() { return NULL; } + virtual ThisDeclaration *isThisDeclaration() { return NULL; } + virtual TupleDeclaration *isTupleDeclaration() { return NULL; } + virtual TypedefDeclaration *isTypedefDeclaration() { return NULL; } + virtual AliasDeclaration *isAliasDeclaration() { return NULL; } + virtual AggregateDeclaration *isAggregateDeclaration() { return NULL; } + virtual FuncDeclaration *isFuncDeclaration() { return NULL; } + virtual FuncAliasDeclaration *isFuncAliasDeclaration() { return NULL; } + virtual FuncLiteralDeclaration *isFuncLiteralDeclaration() { return NULL; } + virtual CtorDeclaration *isCtorDeclaration() { return NULL; } + virtual PostBlitDeclaration *isPostBlitDeclaration() { return NULL; } + virtual DtorDeclaration *isDtorDeclaration() { return NULL; } + virtual StaticCtorDeclaration *isStaticCtorDeclaration() { return NULL; } + virtual StaticDtorDeclaration *isStaticDtorDeclaration() { return NULL; } + virtual SharedStaticCtorDeclaration *isSharedStaticCtorDeclaration() { return NULL; } + virtual SharedStaticDtorDeclaration *isSharedStaticDtorDeclaration() { return NULL; } + virtual InvariantDeclaration *isInvariantDeclaration() { return NULL; } + virtual UnitTestDeclaration *isUnitTestDeclaration() { return NULL; } + virtual NewDeclaration *isNewDeclaration() { return NULL; } + virtual VarDeclaration *isVarDeclaration() { return NULL; } + virtual ClassDeclaration *isClassDeclaration() { return NULL; } + virtual StructDeclaration *isStructDeclaration() { return NULL; } + virtual UnionDeclaration *isUnionDeclaration() { return NULL; } + virtual InterfaceDeclaration *isInterfaceDeclaration() { return NULL; } + virtual ScopeDsymbol *isScopeDsymbol() { return NULL; } + virtual WithScopeSymbol *isWithScopeSymbol() { return NULL; } + virtual ArrayScopeSymbol *isArrayScopeSymbol() { return NULL; } + virtual Import *isImport() { return NULL; } + virtual EnumDeclaration *isEnumDeclaration() { return NULL; } + virtual DeleteDeclaration *isDeleteDeclaration() { return NULL; } + virtual StaticStructInitDeclaration *isStaticStructInitDeclaration() { return NULL; } + virtual AttribDeclaration *isAttribDeclaration() { return NULL; } + virtual OverloadSet *isOverloadSet() { return NULL; } + virtual TypeInfoDeclaration* isTypeInfoDeclaration() { return NULL; } + virtual ClassInfoDeclaration* isClassInfoDeclaration() { return NULL; } +#if TARGET_NET + virtual PragmaScope* isPragmaScope() { return NULL; } +#endif +#if IN_LLVM + /// Codegen traversal + virtual void codegen(Ir* ir); + + // llvm stuff + int llvmInternal; + + IrDsymbol ir; + IrSymbol* irsym; +#endif +}; + +// Dsymbol that generates a scope + +struct ScopeDsymbol : Dsymbol +{ + Dsymbols *members; // all Dsymbol's in this scope + DsymbolTable *symtab; // members[] sorted into table + + Dsymbols *imports; // imported Dsymbol's + unsigned char *prots; // array of PROT, one for each import + + ScopeDsymbol(); + ScopeDsymbol(Identifier *id); + Dsymbol *syntaxCopy(Dsymbol *s); + Dsymbol *search(Loc loc, Identifier *ident, int flags); + void importScope(Dsymbol *s, enum PROT protection); + int isforwardRef(); + void defineRef(Dsymbol *s); + static void multiplyDefined(Loc loc, Dsymbol *s1, Dsymbol *s2); + Dsymbol *nameCollision(Dsymbol *s); + const char *kind(); + FuncDeclaration *findGetMembers(); + virtual Dsymbol *symtabInsert(Dsymbol *s); + bool hasStaticCtorOrDtor(); + + void emitMemberComments(Scope *sc); + + static size_t dim(Dsymbols *members); + static Dsymbol *getNth(Dsymbols *members, size_t nth, size_t *pn = NULL); + + typedef int (*ForeachDg)(void *ctx, size_t idx, Dsymbol *s); + static int foreach(Scope *sc, Dsymbols *members, ForeachDg dg, void *ctx, size_t *pn=NULL); + + ScopeDsymbol *isScopeDsymbol() { return this; } +}; + +// With statement scope + +struct WithScopeSymbol : ScopeDsymbol +{ + WithStatement *withstate; + + WithScopeSymbol(WithStatement *withstate); + Dsymbol *search(Loc loc, Identifier *ident, int flags); + + WithScopeSymbol *isWithScopeSymbol() { return this; } +}; + +// Array Index/Slice scope + +struct ArrayScopeSymbol : ScopeDsymbol +{ + Expression *exp; // IndexExp or SliceExp + TypeTuple *type; // for tuple[length] + TupleDeclaration *td; // for tuples of objects + Scope *sc; + + ArrayScopeSymbol(Scope *sc, Expression *e); + ArrayScopeSymbol(Scope *sc, TypeTuple *t); + ArrayScopeSymbol(Scope *sc, TupleDeclaration *td); + Dsymbol *search(Loc loc, Identifier *ident, int flags); + + ArrayScopeSymbol *isArrayScopeSymbol() { return this; } +}; + +// Overload Sets + +#if DMDV2 +struct OverloadSet : Dsymbol +{ + Dsymbols a; // array of Dsymbols + + OverloadSet(); + void push(Dsymbol *s); + OverloadSet *isOverloadSet() { return this; } + const char *kind(); +}; +#endif + +// Table of Dsymbol's + +struct DsymbolTable : Object +{ + AA *tab; + + DsymbolTable(); + ~DsymbolTable(); + + // Look up Identifier. Return Dsymbol if found, NULL if not. + Dsymbol *lookup(Identifier *ident); + + // Insert Dsymbol in table. Return NULL if already there. + Dsymbol *insert(Dsymbol *s); + + // Look for Dsymbol in table. If there, return it. If not, insert s and return that. + Dsymbol *update(Dsymbol *s); + Dsymbol *insert(Identifier *ident, Dsymbol *s); // when ident and s are not the same +}; + +#endif /* DMD_DSYMBOL_H */ diff --git a/dmd2/dump.c b/dmd2/dump.c index c9e4f5ff..e0d43186 100644 --- a/dmd2/dump.c +++ b/dmd2/dump.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 @@ -36,7 +36,7 @@ void dumpExpressions(int i, Expressions *exps) if (exps) { for (size_t j = 0; j < exps->dim; j++) - { Expression *e = exps->tdata()[j]; + { Expression *e = (*exps)[j]; indent(i); printf("(\n"); e->dump(i + 2); diff --git a/dmd2/enum.c b/dmd2/enum.c index a09a7e93..93fc79c4 100644 --- a/dmd2/enum.c +++ b/dmd2/enum.c @@ -185,11 +185,11 @@ void EnumDeclaration::semantic(Scope *sc) { assert(e->dyncast() == DYNCAST_EXPRESSION); e = e->semantic(sce); - e = e->optimize(WANTvalue | WANTinterpret); + e = e->ctfeInterpret(); if (memtype) { e = e->implicitCastTo(sce, memtype); - e = e->optimize(WANTvalue | WANTinterpret); + e = e->ctfeInterpret(); if (!isAnonymous()) e = e->castTo(sce, type); t = memtype; @@ -197,7 +197,7 @@ void EnumDeclaration::semantic(Scope *sc) else if (em->type) { e = e->implicitCastTo(sce, em->type); - e = e->optimize(WANTvalue | WANTinterpret); + e = e->ctfeInterpret(); assert(isAnonymous()); t = e->type; } @@ -214,7 +214,7 @@ void EnumDeclaration::semantic(Scope *sc) t = Type::tint32; e = new IntegerExp(em->loc, 0, Type::tint32); e = e->implicitCastTo(sce, t); - e = e->optimize(WANTvalue | WANTinterpret); + e = e->ctfeInterpret(); if (!isAnonymous()) e = e->castTo(sce, type); } @@ -225,7 +225,7 @@ void EnumDeclaration::semantic(Scope *sc) { emax = t->getProperty(0, Id::max); emax = emax->semantic(sce); - emax = emax->optimize(WANTvalue | WANTinterpret); + emax = emax->ctfeInterpret(); } // Set value to (elast + 1). @@ -233,7 +233,7 @@ void EnumDeclaration::semantic(Scope *sc) assert(elast); e = new EqualExp(TOKequal, em->loc, elast, emax); e = e->semantic(sce); - e = e->optimize(WANTvalue | WANTinterpret); + e = e->ctfeInterpret(); if (e->toInteger()) error("overflow of enum value %s", elast->toChars()); @@ -241,14 +241,14 @@ void EnumDeclaration::semantic(Scope *sc) e = new AddExp(em->loc, elast, new IntegerExp(em->loc, 1, Type::tint32)); e = e->semantic(sce); e = e->castTo(sce, elast->type); - e = e->optimize(WANTvalue | WANTinterpret); + e = e->ctfeInterpret(); if (t->isfloating()) { // Check that e != elast (not always true for floats) Expression *etest = new EqualExp(TOKequal, em->loc, e, elast); etest = etest->semantic(sce); - etest = etest->optimize(WANTvalue | WANTinterpret); + etest = etest->ctfeInterpret(); if (etest->toInteger()) error("enum member %s has inexact value, due to loss of precision", em->toChars()); } @@ -298,13 +298,13 @@ void EnumDeclaration::semantic(Scope *sc) // Compute if(e < minval) ec = new CmpExp(TOKlt, em->loc, e, minval); ec = ec->semantic(sce); - ec = ec->optimize(WANTvalue | WANTinterpret); + ec = ec->ctfeInterpret(); if (ec->toInteger()) minval = e; ec = new CmpExp(TOKgt, em->loc, e, maxval); ec = ec->semantic(sce); - ec = ec->optimize(WANTvalue | WANTinterpret); + ec = ec->ctfeInterpret(); if (ec->toInteger()) maxval = e; } diff --git a/dmd2/enum.h b/dmd2/enum.h index c13d90ca..1c7d5e9d 100644 --- a/dmd2/enum.h +++ b/dmd2/enum.h @@ -42,7 +42,7 @@ struct EnumDeclaration : ScopeDsymbol int isdeprecated; int isdone; // 0: not done // 1: semantic() successfully completed -#if IN_GCC +#ifdef IN_GCC Expressions *attributes; // GCC decl/type attributes #endif diff --git a/dmd2/expression.c b/dmd2/expression.c index 6fd1d480..c898cdb9 100644 --- a/dmd2/expression.c +++ b/dmd2/expression.c @@ -1,4 +1,3 @@ - // Compiler implementation of the D programming language // Copyright (c) 1999-2012 by Digital Mars // All Rights Reserved @@ -116,6 +115,7 @@ Expression *getRightThis(Loc loc, Scope *sc, AggregateDeclaration *ad, e1 = new DotVarExp(loc, e1, tcd->vthis); e1->type = tcd->vthis->type; + e1->type = e1->type->addMod(t->mod); // Do not call checkNestedRef() //e1 = e1->semantic(sc); @@ -151,6 +151,7 @@ Expression *getRightThis(Loc loc, Scope *sc, AggregateDeclaration *ad, } if (s && s->isClassDeclaration()) { e1->type = s->isClassDeclaration()->type; + e1->type = e1->type->addMod(t->mod); if (n > 1) e1 = e1->semantic(sc); } @@ -570,14 +571,14 @@ int expandAliasThisTuples(Expressions *exps, int starti) for (size_t u = starti; u < exps->dim; u++) { - Expression *exp = exps->tdata()[u]; + Expression *exp = (*exps)[u]; TupleDeclaration *td = isAliasThisTuple(exp); if (td) { exps->remove(u); for (size_t i = 0; iobjects->dim; ++i) { - Expression *e = isExpression(td->objects->tdata()[i]); + Expression *e = isExpression((*td->objects)[i]); assert(e); assert(e->op == TOKdsymbol); DsymbolExp *se = (DsymbolExp *)e; @@ -592,7 +593,7 @@ int expandAliasThisTuples(Expressions *exps, int starti) printf("expansion ->\n"); for (size_t i = 0; idim; ++i) { - Expression *e = exps->tdata()[i]; + Expression *e = (*exps)[i]; printf("\texps[%d] e = %s %s\n", i, Token::tochars[e->op], e->toChars()); } #endif @@ -738,6 +739,12 @@ void preFunctionParameters(Loc loc, Scope *sc, Expressions *exps) { Expression *arg = (*exps)[i]; arg = resolveProperties(sc, arg); +#if 0 + if (arg->op == TOKtype) + { arg->error("%s is not an expression", arg->toChars()); + arg = new ErrorExp(); + } +#endif (*exps)[i] = arg; //arg->rvalue(); @@ -794,24 +801,41 @@ void valueNoDtor(Expression *e) #if DMDV2 Expression *callCpCtor(Loc loc, Scope *sc, Expression *e, int noscope) { - Type *tb = e->type->toBasetype(); - assert(tb->ty == Tstruct); - StructDeclaration *sd = ((TypeStruct *)tb)->sym; - if (sd->cpctor) + if (e->op == TOKarrayliteral) { - /* Create a variable tmp, and replace the argument e with: - * (tmp = e),tmp - * and let AssignExp() handle the construction. - * This is not the most efficent, ideally tmp would be constructed - * directly onto the stack. - */ - Identifier *idtmp = Lexer::uniqueId("__cpcttmp"); - VarDeclaration *tmp = new VarDeclaration(loc, tb, idtmp, new ExpInitializer(0, e)); - tmp->storage_class |= STCctfe; - tmp->noscope = noscope; - Expression *ae = new DeclarationExp(loc, tmp); - e = new CommaExp(loc, ae, new VarExp(loc, tmp)); - e = e->semantic(sc); + ArrayLiteralExp *ae = (ArrayLiteralExp *)e; + for (size_t i = 0; i < ae->elements->dim; i++) + { + ae->elements->tdata()[i] = + callCpCtor(loc, sc, ae->elements->tdata()[i], noscope); + } + e = ae->semantic(sc); + return e; + } + + Type *tb = e->type->toBasetype(); + Type *tv = tb; + while (tv->ty == Tsarray) + tv = tv->nextOf()->toBasetype(); + if (tv->ty == Tstruct) + { + StructDeclaration *sd = ((TypeStruct *)tv)->sym; + if (sd->cpctor) + { + /* Create a variable tmp, and replace the argument e with: + * (tmp = e),tmp + * and let AssignExp() handle the construction. + * This is not the most efficent, ideally tmp would be constructed + * directly onto the stack. + */ + Identifier *idtmp = Lexer::uniqueId("__cpcttmp"); + VarDeclaration *tmp = new VarDeclaration(loc, tb, idtmp, new ExpInitializer(0, e)); + tmp->storage_class |= STCctfe; + tmp->noscope = noscope; + Expression *ae = new DeclarationExp(loc, tmp); + e = new CommaExp(loc, ae, new VarExp(loc, tmp)); + e = e->semantic(sc); + } } return e; } @@ -825,6 +849,8 @@ Expression *callCpCtor(Loc loc, Scope *sc, Expression *e, int noscope) * 3. do default promotions on arguments corresponding to ... * 4. add hidden _arguments[] argument * 5. call copy constructor for struct value arguments + * Input: + * fd the function being called, NULL if called indirectly * Returns: * return type from function */ @@ -877,7 +903,7 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, Expression *arg; if (i < nargs) - arg = arguments->tdata()[i]; + arg = (*arguments)[i]; else arg = NULL; @@ -887,7 +913,7 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, if (!arg) { - if (!p->defaultArg) + if (!p->defaultArg || !fd) { if (tf->varargs == 2 && i + 1 == nparams) goto L2; @@ -908,7 +934,7 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, if (tf->varargs == 2 && i + 1 == nparams && pt->nextOf()) pt = pt->nextOf(); arg = arg->inferType(pt, 2); - arguments->tdata()[i] = arg; + (*arguments)[i] = arg; } if (tf->varargs == 2 && i + 1 == nparams) @@ -958,7 +984,7 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, c->type = v->type; for (size_t u = i; u < nargs; u++) - { Expression *a = arguments->tdata()[u]; + { Expression *a = (*arguments)[u]; if (tret && !((TypeArray *)tb)->next->equals(a->type)) a = a->toDelegate(sc, tret); @@ -982,7 +1008,7 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, Expressions *args = new Expressions(); args->setDim(nargs - i); for (size_t u = i; u < nargs; u++) - args->tdata()[u - i] = arguments->tdata()[u]; + (*args)[u - i] = (*arguments)[u]; arg = new NewExp(loc, NULL, NULL, p->type, args); break; } @@ -996,7 +1022,7 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, arg = arg->semantic(sc); //printf("\targ = '%s'\n", arg->toChars()); arguments->setDim(i + 1); - arguments->tdata()[i] = arg; + (*arguments)[i] = arg; nargs = i + 1; done = 1; } @@ -1032,7 +1058,7 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, assert(nargs >= nparams); for (size_t i = 0; i < nargs; i++) { - Expression *arg = arguments->tdata()[i]; + Expression *arg = (*arguments)[i]; assert(arg); if (i < nparams) @@ -1097,45 +1123,50 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, { arg = arg->modifiableLvalue(sc, arg); } - - Type *tb = arg->type->toBasetype(); -// LDC we don't want this! -#if !IN_LLVM -#if !SARRAYVALUE - // Convert static arrays to pointers - if (tb->ty == Tsarray) - { - arg = arg->checkToPointer(); + else if (p->storageClass & STClazy) + { // Convert lazy argument to a delegate + arg = arg->toDelegate(sc, p->type); } -#endif -#endif -#if DMDV2 - if (tb->ty == Tstruct && !(p->storageClass & (STCref | STCout))) + else { - if (arg->op == TOKcall) + Type *tb = arg->type->toBasetype(); + if (arg->op == TOKarrayliteral) { - /* The struct value returned from the function is transferred - * to the function, so the callee should not call the destructor - * on it. - */ - valueNoDtor(arg); - } - else - { /* Not transferring it, so call the copy constructor - */ arg = callCpCtor(loc, sc, arg, 1); } - } + else if (tb->ty == Tsarray) + { +#if !SARRAYVALUE && !IN_LLVM + // Convert static arrays to pointers + arg = arg->checkToPointer(); +#else + // call copy constructor of each element + arg = callCpCtor(loc, sc, arg, 1); #endif + } +#if DMDV2 + else if (tb->ty == Tstruct) + { + if (arg->op == TOKcall && !arg->isLvalue()) + { + /* The struct value returned from the function is transferred + * to the function, so the callee should not call the destructor + * on it. + */ + valueNoDtor(arg); + } + else + { /* Not transferring it, so call the copy constructor + */ + arg = callCpCtor(loc, sc, arg, 1); + } + } +#endif + } //printf("arg: %s\n", arg->toChars()); //printf("type: %s\n", arg->type->toChars()); - // Convert lazy argument to a delegate - if (p->storageClass & STClazy) - { - arg = arg->toDelegate(sc, p->type); - } #if DMDV2 /* Look for arguments that cannot 'escape' from the called * function. @@ -1253,7 +1284,7 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, } arg = arg->optimize(WANTvalue); L3: - arguments->tdata()[i] = arg; + (*arguments)[i] = arg; } #if !IN_LLVM @@ -1434,13 +1465,16 @@ void Expression::print() } char *Expression::toChars() -{ OutBuffer *buf; +{ HdrGenState hgs; - memset(&hgs, 0, sizeof(hgs)); - buf = new OutBuffer(); - toCBuffer(buf, &hgs); - return buf->toChars(); + + OutBuffer buf; + toCBuffer(&buf, &hgs); + buf.writeByte(0); + char *p = (char *)buf.data; + buf.data = NULL; + return p; } void Expression::error(const char *format, ...) @@ -1548,12 +1582,12 @@ void Expression::toMangleBuffer(OutBuffer *buf) /*************************************** * Return !=0 if expression is an lvalue. */ -#if DMDV2 + int Expression::isLvalue() { return 0; } -#endif + /******************************* * Give error if we're not an lvalue. @@ -1934,7 +1968,7 @@ Expressions *Expression::arraySyntaxCopy(Expressions *exps) if (e) e = e->syntaxCopy(); - a->tdata()[i] = e; + (*a)[i] = e; } } return a; @@ -2814,12 +2848,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) { @@ -2854,7 +2888,7 @@ AggregateDeclaration *isAggregate(Type *t); Expression *DsymbolExp::semantic(Scope *sc) { #if LOGSEMANTIC - printf("DsymbolExp::semantic('%s')\n", s->toChars()); + printf("DsymbolExp::semantic(%s %s)\n", s->kind(), s->toChars()); #endif Lagain: @@ -2872,7 +2906,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); @@ -3038,6 +3072,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; @@ -3050,6 +3102,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; @@ -3085,12 +3139,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) { @@ -3187,12 +3241,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) { @@ -3404,20 +3458,6 @@ int StringExp::equals(Object *o) return FALSE; } -char *StringExp::toChars() -{ - OutBuffer buf; - HdrGenState hgs; - char *p; - - memset(&hgs, 0, sizeof(hgs)); - toCBuffer(&buf, &hgs); - buf.writeByte(0); - p = (char *)buf.data; - buf.data = NULL; - return p; -} - Expression *StringExp::semantic(Scope *sc) { #if LOGSEMANTIC @@ -3625,7 +3665,7 @@ int StringExp::isBool(int result) return result ? TRUE : FALSE; } -#if DMDV2 + int StringExp::isLvalue() { /* string literal is rvalue in default, but @@ -3633,7 +3673,7 @@ int StringExp::isLvalue() */ return 0; } -#endif + Expression *StringExp::toLvalue(Scope *sc, Expression *e) { @@ -3783,6 +3823,7 @@ ArrayLiteralExp::ArrayLiteralExp(Loc loc, Expression *e) { elements = new Expressions; elements->push(e); + this->ownedByCtfe = false; } Expression *ArrayLiteralExp::syntaxCopy() @@ -3838,10 +3879,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); @@ -3849,7 +3890,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; } @@ -3868,7 +3910,7 @@ void ArrayLiteralExp::toMangleBuffer(OutBuffer *buf) size_t dim = elements ? elements->dim : 0; buf->printf("A%zu", dim); for (size_t i = 0; i < dim; i++) - { Expression *e = elements->tdata()[i]; + { Expression *e = (*elements)[i]; e->toMangleBuffer(buf); } } @@ -3937,8 +3979,8 @@ void AssocArrayLiteralExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writeByte('['); for (size_t i = 0; i < keys->dim; i++) - { Expression *key = keys->tdata()[i]; - Expression *value = values->tdata()[i]; + { Expression *key = (*keys)[i]; + Expression *value = (*values)[i]; if (i) buf->writeByte(','); @@ -3954,8 +3996,8 @@ void AssocArrayLiteralExp::toMangleBuffer(OutBuffer *buf) size_t dim = keys->dim; buf->printf("A%zu", dim); for (size_t i = 0; i < dim; i++) - { Expression *key = keys->tdata()[i]; - Expression *value = values->tdata()[i]; + { Expression *key = (*keys)[i]; + Expression *value = (*values)[i]; key->toMangleBuffer(buf); value->toMangleBuffer(buf); @@ -4008,7 +4050,7 @@ Expression *StructLiteralExp::semantic(Scope *sc) expandTuples(elements); size_t offset = 0; for (size_t i = 0; i < elements->dim; i++) - { e = elements->tdata()[i]; + { e = (*elements)[i]; if (!e) continue; @@ -4022,7 +4064,7 @@ Expression *StructLiteralExp::semantic(Scope *sc) error("more initializers than fields (%d) of %s", nfields, sd->toChars()); return new ErrorExp(); } - Dsymbol *s = sd->fields.tdata()[i]; + Dsymbol *s = sd->fields[i]; VarDeclaration *v = s->isVarDeclaration(); assert(v); if (v->offset < offset) @@ -4043,13 +4085,13 @@ Expression *StructLiteralExp::semantic(Scope *sc) e = e->implicitCastTo(sc, telem); - elements->tdata()[i] = e; + (*elements)[i] = e; } /* Fill out remainder of elements[] with default initializers for fields[] */ for (size_t i = elements->dim; i < nfields; i++) - { Dsymbol *s = sd->fields.tdata()[i]; + { Dsymbol *s = sd->fields[i]; VarDeclaration *v = s->isVarDeclaration(); assert(v); assert(!v->isThisDeclaration()); @@ -4072,7 +4114,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. @@ -4124,7 +4166,7 @@ Expression *StructLiteralExp::getField(Type *type, unsigned offset) { //printf("\ti = %d\n", i); assert(i < elements->dim); - e = elements->tdata()[i]; + e = (*elements)[i]; if (e) { //printf("e = %s, e->type = %s\n", e->toChars(), e->type->toChars()); @@ -4138,7 +4180,7 @@ Expression *StructLiteralExp::getField(Type *type, unsigned offset) Expressions *z = new Expressions; z->setDim(length); for (int q = 0; q < length; ++q) - z->tdata()[q] = e->copy(); + (*z)[q] = e->copy(); e = new ArrayLiteralExp(loc, z); e->type = type; } @@ -4165,13 +4207,13 @@ int StructLiteralExp::getFieldIndex(Type *type, unsigned offset) { 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); if (offset == v->offset && type->size() == v->type->size()) - { Expression *e = elements->tdata()[i]; + { Expression *e = (*elements)[i]; if (e) { return i; @@ -4196,7 +4238,7 @@ void StructLiteralExp::toMangleBuffer(OutBuffer *buf) size_t dim = elements ? elements->dim : 0; buf->printf("S%zu", dim); for (size_t i = 0; i < dim; i++) - { Expression *e = elements->tdata()[i]; + { Expression *e = (*elements)[i]; if (e) e->toMangleBuffer(buf); else @@ -4239,8 +4281,32 @@ Expression *TypeExp::syntaxCopy() Expression *TypeExp::semantic(Scope *sc) { //printf("TypeExp::semantic(%s)\n", type->toChars()); - type = type->semantic(loc, sc); - return this; + Expression *e; + Type *t; + Dsymbol *s; + + type->resolve(loc, sc, &e, &t, &s); + if (e) + { + //printf("e = %s %s\n", Token::toChars(e->op), e->toChars()); + e = e->semantic(sc); + } + else if (t) + { + //printf("t = %d %s\n", t->ty, t->toChars()); + type = t->semantic(loc, sc); + e = this; + } + else if (s) + { + //printf("s = %s %s\n", s->kind(), s->toChars()); + e = new DsymbolExp(loc, s, s->hasOverloads()); + e = e->semantic(sc); + } + else + assert(0); + + return e; } int TypeExp::rvalue() @@ -4289,6 +4355,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) @@ -4302,7 +4370,7 @@ Lagain: e = new DotVarExp(loc, e, s->isDeclaration()); } else - e = new DsymbolExp(loc, s); + e = new DsymbolExp(loc, s, s->hasOverloads()); e = e->semantic(sc); //printf("-1ScopeExp::semantic()\n"); return e; @@ -4425,6 +4493,13 @@ Lagain: sc = sc->push(cdthis); type = newtype->semantic(loc, sc); sc = sc->pop(); + + if (!MODimplicitConv(thisexp->type->mod, newtype->mod)) + { + error("nested type %s should have the same or weaker constancy as enclosing type %s", + newtype->toChars(), thisexp->type->toChars()); + goto Lerr; + } } else { @@ -4459,7 +4534,7 @@ Lagain: else if (cd->isAbstract()) { error("cannot create instance of abstract class %s", cd->toChars()); for (size_t i = 0; i < cd->vtbl.dim; i++) - { FuncDeclaration *fd = cd->vtbl.tdata()[i]->isFuncDeclaration(); + { FuncDeclaration *fd = cd->vtbl[i]->isFuncDeclaration(); if (fd && fd->isAbstract()) error("function %s is abstract", fd->toChars()); } @@ -4712,7 +4787,7 @@ Lagain: goto Lerr; } - Expression *arg = arguments->tdata()[i]; + Expression *arg = (*arguments)[i]; arg = resolveProperties(sc, arg); arg = arg->implicitCastTo(sc, Type::tsize_t); arg = arg->optimize(WANTvalue); @@ -4720,7 +4795,7 @@ Lagain: { error("negative array index %s", arg->toChars()); goto Lerr; } - arguments->tdata()[i] = arg; + (*arguments)[i] = arg; tb = ((TypeDArray *)tb)->next->toBasetype(); } } @@ -5018,14 +5093,14 @@ void VarExp::checkEscapeRef() } } -#if DMDV2 + int VarExp::isLvalue() { - if (var->storage_class & STClazy) + if (var->storage_class & (STClazy | STCtemp)) return 0; return 1; } -#endif + Expression *VarExp::toLvalue(Scope *sc, Expression *e) { @@ -5049,6 +5124,16 @@ Expression *VarExp::modifiableLvalue(Scope *sc, Expression *e) //if (type && type->toBasetype()->ty == Tsarray) //error("cannot change reference to static array '%s'", var->toChars()); +#if (BUG6652 == 1) + VarDeclaration *v = var->isVarDeclaration(); + if (v && (v->storage_class & STCbug6652) && global.params.warnings) + warning("Variable modified in foreach body requires ref storage class"); +#elif (BUG6652 == 2) + VarDeclaration *v = var->isVarDeclaration(); + if (v && (v->storage_class & STCbug6652) && !global.params.useDeprecated) + error("Variable modified in foreach body requires ref storage class"); +#endif + var->checkModify(loc, sc, type); // See if this expression is a modifiable lvalue (i.e. not const) @@ -5098,7 +5183,7 @@ TupleExp::TupleExp(Loc loc, TupleDeclaration *tup) exps->reserve(tup->objects->dim); for (size_t i = 0; i < tup->objects->dim; i++) - { Object *o = tup->objects->tdata()[i]; + { Object *o = (*tup->objects)[i]; if (o->dyncast() == DYNCAST_EXPRESSION) { Expression *e = (Expression *)o; @@ -5202,7 +5287,6 @@ FuncExp::FuncExp(Loc loc, FuncLiteralDeclaration *fd, TemplateDeclaration *td) this->fd = fd; this->td = td; tok = fd->tok; // save original kind of function/delegate/(infer) - treq = NULL; } Expression *FuncExp::syntaxCopy() @@ -5215,36 +5299,41 @@ Expression *FuncExp::semantic(Scope *sc) { #if LOGSEMANTIC printf("FuncExp::semantic(%s)\n", toChars()); - if (treq) printf(" treq = %s\n", treq->toChars()); + if (fd->treq) printf(" treq = %s\n", fd->treq->toChars()); #endif if (!type || type == Type::tvoid) { - if (treq) - treq = treq->semantic(loc, sc); + /* fd->treq might be incomplete type, + * so should not semantic it. + * void foo(T)(T delegate(int) dg){} + * foo(a=>a); // in IFTI, treq == T delegate(int) + */ + //if (fd->treq) + // fd->treq = fd->treq->semantic(loc, sc); // Set target of return type inference - if (treq && !fd->type->nextOf()) + if (fd->treq && !fd->type->nextOf()) { TypeFunction *tfv = NULL; - if (treq->ty == Tdelegate || - (treq->ty == Tpointer && treq->nextOf()->ty == Tfunction)) - tfv = (TypeFunction *)treq->nextOf(); + if (fd->treq->ty == Tdelegate || + (fd->treq->ty == Tpointer && fd->treq->nextOf()->ty == Tfunction)) + tfv = (TypeFunction *)fd->treq->nextOf(); if (tfv) { TypeFunction *tfl = (TypeFunction *)fd->type; tfl->next = tfv->nextOf(); } } - //printf("td = %p, treq = %p\n", td, treq); + //printf("td = %p, treq = %p\n", td, fd->treq); if (td) { assert(td->parameters && td->parameters->dim); td->semantic(sc); type = Type::tvoid; // temporary type - if (!treq) // defer type determination + if (!fd->treq) // defer type determination return this; - return inferType(treq); + return inferType(fd->treq); } unsigned olderrors = global.errors; @@ -5273,14 +5362,32 @@ Expression *FuncExp::semantic(Scope *sc) // Type is a "delegate to" or "pointer to" the function literal if ((fd->isNested() && fd->tok == TOKdelegate) || - (tok == TOKreserved && treq && treq->ty == Tdelegate)) + (tok == TOKreserved && fd->treq && fd->treq->ty == Tdelegate)) { type = new TypeDelegate(fd->type); type = type->semantic(loc, sc); + + fd->tok = TOKdelegate; } else { - type = fd->type->pointerTo(); + type = new TypePointer(fd->type); + type = type->semantic(loc, sc); + //type = fd->type->pointerTo(); + + /* A lambda expression deduced to function pointer might become + * to a delegate literal implicitly. + * + * auto foo(void function() fp) { return 1; } + * assert(foo({}) == 1); + * + * So, should keep fd->tok == TOKreserve if fd->treq == NULL. + */ + if (fd->treq && fd->treq->ty == Tpointer) + { // change to non-nested + fd->tok = TOKfunction; + fd->vthis = NULL; + } } fd->tookAddressOf++; } @@ -5293,7 +5400,7 @@ Expression *FuncExp::semantic(Scope *sc, Expressions *arguments) if ((!type || type == Type::tvoid) && td && arguments && arguments->dim) { for (size_t k = 0; k < arguments->dim; k++) - { Expression *checkarg = arguments->tdata()[k]; + { Expression *checkarg = (*arguments)[k]; if (checkarg->op == TOKerror) return checkarg; } @@ -5303,6 +5410,12 @@ Expression *FuncExp::semantic(Scope *sc, Expressions *arguments) TypeFunction *tfl = (TypeFunction *)fd->type; size_t dim = Parameter::dim(tfl->parameters); + if (arguments->dim < dim) + { // Default arguments are always typed, so they don't need inference. + Parameter *p = Parameter::getNth(tfl->parameters, arguments->dim); + if (p->defaultArg) + dim = arguments->dim; + } if ((!tfl->varargs && arguments->dim == dim) || ( tfl->varargs && arguments->dim >= dim)) @@ -5379,7 +5492,7 @@ Expression *DeclarationExp::semantic(Scope *sc) if (ad) { if (ad->decl && ad->decl->dim == 1) - s = ad->decl->tdata()[0]; + s = (*ad->decl)[0]; } if (s->isVarDeclaration()) @@ -5570,7 +5683,7 @@ void TraitsExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) for (size_t i = 0; i < args->dim; i++) { buf->writeByte(','); - Object *oarg = args->tdata()[i]; + Object *oarg = (*args)[i]; ObjectToCBuffer(buf, hgs, oarg); } } @@ -5623,8 +5736,8 @@ Expression *IsExp::syntaxCopy() p = new TemplateParameters(); p->setDim(parameters->dim); for (size_t i = 0; i < p->dim; i++) - { TemplateParameter *tp = parameters->tdata()[i]; - p->tdata()[i] = tp->syntaxCopy(); + { TemplateParameter *tp = (*parameters)[i]; + (*p)[i] = tp->syntaxCopy(); } } @@ -5734,7 +5847,7 @@ Expression *IsExp::semantic(Scope *sc) Parameters *args = new Parameters; args->reserve(cd->baseclasses->dim); for (size_t i = 0; i < cd->baseclasses->dim; i++) - { BaseClass *b = cd->baseclasses->tdata()[i]; + { BaseClass *b = (*cd->baseclasses)[i]; args->push(new Parameter(STCin, b->type, NULL, NULL)); } tded = new TypeTuple(args); @@ -5754,6 +5867,7 @@ Expression *IsExp::semantic(Scope *sc) break; case TOKfunction: + case TOKparameters: { if (targ->ty != Tfunction) goto Lno; @@ -5769,7 +5883,9 @@ Expression *IsExp::semantic(Scope *sc) for (size_t i = 0; i < dim; i++) { Parameter *arg = Parameter::getNth(params, i); assert(arg && arg->type); - args->push(new Parameter(arg->storageClass, arg->type, NULL, NULL)); + args->push(new Parameter(arg->storageClass, arg->type, + (tok2 == TOKparameters) ? arg->ident : NULL, + (tok2 == TOKparameters) ? arg->defaultArg : NULL)); } tded = new TypeTuple(args); break; @@ -5831,13 +5947,13 @@ Expression *IsExp::semantic(Scope *sc) } else { - tded = (Type *)dedtypes.tdata()[0]; + tded = (Type *)dedtypes[0]; if (!tded) tded = targ; #if DMDV2 Objects tiargs; tiargs.setDim(1); - tiargs.tdata()[0] = targ; + tiargs[0] = targ; /* Declare trailing parameters */ @@ -5936,7 +6052,7 @@ void IsExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) for (size_t i = 1; i < parameters->dim; i++) { buf->writeByte(','); - TemplateParameter *tp = parameters->tdata()[i]; + TemplateParameter *tp = (*parameters)[i]; tp->toCBuffer(buf, hgs); } } @@ -6342,7 +6458,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()); @@ -6384,7 +6500,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; @@ -6576,8 +6692,30 @@ Expression *DotIdExp::semantic(Scope *sc, int flag) } } +// Type *t1save = e1->type; + UnaExp::semantic(sc); +#if 0 + /* + * Identify typeof(var).stringof and use the original type of var, if possible + */ + if (ident == Id::stringof && e1->op == TOKtype && t1save && t1save->ty == Ttypeof) + { TypeTypeof *t = (TypeTypeof *)t1save; + if (t->exp->op == TOKvar) + { + Type *ot = ((VarExp *)t->exp)->var->originalType; + if (ot) + { + char *s = ((VarExp *)t->exp)->var->originalType->toChars(); + e = new StringExp(loc, s, strlen(s), 'c'); + e = e->semantic(sc); + return e; + } + } + } +#endif + if (ident == Id::mangleof) { // symbol.mangleof Dsymbol *ds; @@ -6918,7 +7056,7 @@ Expression *DotVarExp::semantic(Scope *sc) exps->reserve(tup->objects->dim); for (size_t i = 0; i < tup->objects->dim; i++) - { Object *o = tup->objects->tdata()[i]; + { Object *o = (*tup->objects)[i]; if (o->dyncast() != DYNCAST_EXPRESSION) { error("%s is not an expression", o->toChars()); @@ -7003,12 +7141,12 @@ Lerr: return new ErrorExp(); } -#if DMDV2 + int DotVarExp::isLvalue() { return 1; } -#endif + Expression *DotVarExp::toLvalue(Scope *sc, Expression *e) { @@ -7153,15 +7291,31 @@ Expression *DotTemplateInstanceExp::semantic(Scope *sc, int flag) #endif UnaExp::semantic(sc); - Expression *e = new DotIdExp(loc, e1, ti->name); + if (e1->op == TOKerror) + return e1; - if (e1->op == TOKimport && ((ScopeExp *)e1)->sds->isModule()) - e = ((DotIdExp *)e)->semantic(sc, 1); + Expression *e; + DotIdExp *die = new DotIdExp(loc, e1, ti->name); + + if (flag || !e1->type || e1->op == TOKtype || + e1->op == TOKimport && ((ScopeExp *)e1)->sds->isModule()) + { + e = die->semantic(sc, 1); + } else { + Type *t1b = e1->type->toBasetype(); + if ((t1b->ty == Tarray || t1b->ty == Tsarray || t1b->ty == Taarray || + t1b->ty == Tnull || t1b->isTypeBasic() && t1b->ty != Tvoid)) + { + /* No built-in type has templatized property, so can short cut. + */ + return resolveUFCSProperties(sc, this); + } + unsigned errors = global.startGagging(); - e = ((DotIdExp *)e)->semantic(sc, 1); - if (global.endGagging(errors) && !flag) + e = die->semantic(sc, 1); + if (global.endGagging(errors)) { return resolveUFCSProperties(sc, this); } @@ -7367,7 +7521,7 @@ CallExp::CallExp(Loc loc, Expression *e, Expression *earg1) Expressions *arguments = new Expressions(); if (earg1) { arguments->setDim(1); - arguments->tdata()[0] = earg1; + (*arguments)[0] = earg1; } this->arguments = arguments; } @@ -7377,8 +7531,8 @@ CallExp::CallExp(Loc loc, Expression *e, Expression *earg1, Expression *earg2) { Expressions *arguments = new Expressions(); arguments->setDim(2); - arguments->tdata()[0] = earg1; - arguments->tdata()[1] = earg2; + (*arguments)[0] = earg1; + (*arguments)[1] = earg2; this->arguments = arguments; } @@ -7391,162 +7545,128 @@ Expression *CallExp::syntaxCopy() Expression *CallExp::resolveUFCS(Scope *sc) { - Expression *e = NULL; - DotIdExp *dotid; - DotTemplateInstanceExp *dotti; + Expression *e; Identifier *ident; + Objects *tiargs; if (e1->op == TOKdot) { - dotid = (DotIdExp *)e1; - ident = dotid->ident; - e = dotid->e1 = dotid->e1->semantic(sc); - if (e->op == TOKdotexp) - return NULL; - e = resolveProperties(sc, e); + DotIdExp *die = (DotIdExp *)e1; + e = (die->e1 = die->e1->semantic(sc)); + ident = die->ident; + tiargs = NULL; } else if (e1->op == TOKdotti) { - dotti = (DotTemplateInstanceExp *)e1; - ident = dotti->ti->name; - e = dotti->e1 = dotti->e1->semantic(sc); - if (e->op == TOKdotexp) - return NULL; - e = resolveProperties(sc, e); + DotTemplateInstanceExp *dti = (DotTemplateInstanceExp *)e1; + e = (dti->e1 = dti->e1->semantic(sc)); + ident = dti->ti->name; + tiargs = dti->ti->tiargs; } + else + return NULL; - if (e && e->type) + if (e->op == TOKerror || !e->type) + return NULL; + + if (e->op == TOKtype || e->op == TOKimport || e->op == TOKdotexp) + return NULL; + + e = resolveProperties(sc, e); + + Type *t = e->type->toBasetype(); + //printf("resolveUCSS %s, e = %s, %s, %s\n", + // toChars(), Token::toChars(e->op), t->toChars(), e->toChars()); + if (t->ty == Taarray) { - if (e->op == TOKtype || e->op == TOKimport) + if (tiargs) + { + goto Lshift; + } + else if (ident == Id::remove) + { + /* Transform: + * aa.remove(arg) into delete aa[arg] + */ + if (!arguments || arguments->dim != 1) + { error("expected key as argument to aa.remove()"); + return new ErrorExp(); + } + if (!e->type->isMutable()) + { const char *p = NULL; + if (e->type->isConst()) + p = "const"; + else if (e->type->isImmutable()) + p = "immutable"; + else + p = "inout"; + error("cannot remove key from %s associative array %s", p, e->toChars()); + return new ErrorExp(); + } + Expression *key = (*arguments)[0]; + key = key->semantic(sc); + key = resolveProperties(sc, key); + + TypeAArray *taa = (TypeAArray *)t; + key = key->implicitCastTo(sc, taa->index); + + if (!key->rvalue()) + return new ErrorExp(); + + return new RemoveExp(loc, e, key); + } + else if (ident == Id::apply || ident == Id::applyReverse) + { return NULL; - //printf("resolveUCSS %s, e->op = %s\n", toChars(), Token::toChars(e->op)); - AggregateDeclaration *ad; - Expression *esave = e; -Lagain: - Type *t = e->type->toBasetype(); - if (t->ty == Tpointer) - { Type *tn = t->nextOf(); - if (tn->ty == Tclass || tn->ty == Tstruct) - { - e = new PtrExp(e->loc, e); - e = e->semantic(sc); - t = e->type->toBasetype(); - } } - if (t->ty == Tclass) - { - ad = ((TypeClass *)t)->sym; - goto L1; - } - else if (t->ty == Tstruct) - { - ad = ((TypeStruct *)t)->sym; - L1: - if (ad->search(loc, ident, 0)) + else + { TypeAArray *taa = (TypeAArray *)t; + assert(taa->ty == Taarray); + StructDeclaration *sd = taa->getImpl(); + Dsymbol *s = sd->search(0, ident, 2); + if (s) return NULL; - if (ad->aliasthis) - { - e = resolveAliasThis(sc, e); - goto Lagain; - } - if (ad->search(loc, Id::opDot, 0)) - { - e = new DotIdExp(e->loc, e, Id::opDot); - e = e->semantic(sc); - e = resolveProperties(sc, e); - goto Lagain; - } - if (ad->search(loc, Id::opDispatch, 0)) - return NULL; - e = esave; goto Lshift; } - else if ((t->isTypeBasic() && t->ty != Tvoid) || - t->ty == Tenum || t->ty == Tnull) - { - goto Lshift; - } - else if (t->ty == Taarray && e1->op == TOKdot) - { - if (ident == Id::remove) - { - /* Transform: - * aa.remove(arg) into delete aa[arg] - */ - if (!arguments || arguments->dim != 1) - { error("expected key as argument to aa.remove()"); - return new ErrorExp(); - } - if (!e->type->isMutable()) - { const char *p = NULL; - if (e->type->isConst()) - p = "const"; - else if (e->type->isImmutable()) - p = "immutable"; - else - p = "inout"; - error("cannot remove key from %s associative array %s", p, e->toChars()); - return new ErrorExp(); - } - Expression *key = arguments->tdata()[0]; - key = key->semantic(sc); - key = resolveProperties(sc, key); - - TypeAArray *taa = (TypeAArray *)t; - key = key->implicitCastTo(sc, taa->index); - - if (!key->rvalue()) - return new ErrorExp(); - - return new RemoveExp(loc, e, key); - } - else if (ident == Id::apply || ident == Id::applyReverse) - { - return NULL; - } - else - { TypeAArray *taa = (TypeAArray *)t; - assert(taa->ty == Taarray); - StructDeclaration *sd = taa->getImpl(); - Dsymbol *s = sd->search(0, ident, 2); - if (s) - return NULL; - goto Lshift; - } - } - else if (t->ty == Tarray || t->ty == Tsarray) - { + } + else if (t->ty == Tarray || t->ty == Tsarray || + t->ty == Tnull || t->isTypeBasic() && t->ty != Tvoid) + { + /* In basic, built-in types don't have normal and templatized + * member functions. So can short cut. + */ Lshift: - if (!arguments) - arguments = new Expressions(); - arguments->shift(e); - if (e1->op == TOKdot) - { - /* Transform: - * array.id(args) into .id(array,args) - */ -#if DMDV2 - e1 = new DotIdExp(dotid->loc, - new IdentifierExp(dotid->loc, Id::empty), - ident); -#else - e1 = new IdentifierExp(dotid->loc, ident); -#endif - } - else if (e1->op == TOKdotti) - { - /* Transform: - * array.foo!(tiargs)(args) into .foo!(tiargs)(array,args) - */ -#if DMDV2 - e1 = new DotTemplateInstanceExp(dotti->loc, - new IdentifierExp(dotti->loc, Id::empty), - dotti->ti->name, dotti->ti->tiargs); -#else - e1 = new ScopeExp(dotti->loc, dotti->ti); -#endif - } - //printf("-> this = %s\n", toChars()); + if (!arguments) + arguments = new Expressions(); + arguments->shift(e); + if (!tiargs) + { + /* Transform: + * array.id(args) into .id(array,args) + */ + e1 = new DotIdExp(e1->loc, + new IdentifierExp(e1->loc, Id::empty), + ident); + } + else + { + /* Transform: + * array.foo!(tiargs)(args) into .foo!(tiargs)(array,args) + */ + e1 = new DotTemplateInstanceExp(e1->loc, + new IdentifierExp(e1->loc, Id::empty), + ident, tiargs); + } + } + else + { + DotIdExp *die = new DotIdExp(e->loc, e, ident); + + unsigned errors = global.startGagging(); + Expression *ex = die->semantic(sc, 1); + if (global.endGagging(errors)) + { + goto Lshift; } } return NULL; @@ -7568,7 +7688,7 @@ Expression *CallExp::semantic(Scope *sc) #if 0 if (arguments && arguments->dim) { - Expression *earg = arguments->tdata()[0]; + Expression *earg = (*arguments)[0]; earg->print(); if (earg->type) earg->type->print(); } @@ -7836,7 +7956,13 @@ Lagain: goto L1; // overload of opCall, therefore it's a call if (e1->op != TOKtype) - { error("%s %s does not overload ()", ad->kind(), ad->toChars()); + { + if (ad->aliasthis) + { + e1 = resolveAliasThis(sc, e1); + goto Lagain; + } + error("%s %s does not overload ()", ad->kind(), ad->toChars()); return new ErrorExp(); } @@ -7867,7 +7993,7 @@ Lagain: if (arguments && arguments->dim) { for (size_t k = 0; k < arguments->dim; k++) - { Expression *checkarg = arguments->tdata()[k]; + { Expression *checkarg = (*arguments)[k]; if (checkarg->op == TOKerror) return checkarg; } @@ -7880,7 +8006,7 @@ Lagain: if (targsi && targsi->dim) { for (size_t k = 0; k < targsi->dim; k++) - { Object *o = targsi->tdata()[k]; + { Object *o = (*targsi)[k]; if (isError(o)) return new ErrorExp(); } @@ -7894,13 +8020,23 @@ Lagain: AggregateDeclaration *ad; UnaExp *ue = (UnaExp *)(e1); + Expression *ue1 = ue->e1; + VarDeclaration *v; + if (ue1->op == TOKvar && + (v = ((VarExp *)ue1)->var->isVarDeclaration()) != NULL && + v->needThis()) + { + ue->e1 = new TypeExp(ue1->loc, ue1->type); + ue1 = NULL; + } + if (e1->op == TOKdotvar) { // Do overload resolution dve = (DotVarExp *)(e1); f = dve->var->isFuncDeclaration(); assert(f); - f = f->overloadResolve(loc, ue->e1, arguments); + f = f->overloadResolve(loc, ue1, arguments); ad = f->toParent()->isAggregateDeclaration(); } @@ -7911,7 +8047,7 @@ Lagain: if (!arguments) // Should fix deduceFunctionTemplate() so it works on NULL argument arguments = new Expressions(); - f = td->deduceFunctionTemplate(sc, loc, targsi, ue->e1, arguments); + f = td->deduceFunctionTemplate(sc, loc, targsi, ue1, arguments); if (!f) return new ErrorExp(); ad = td->toParent()->isAggregateDeclaration(); @@ -7960,6 +8096,7 @@ Lagain: { e1 = new DotVarExp(loc, dte->e1, f); e1 = e1->semantic(sc); + ue = (UnaExp *)e1; } #if 0 printf("ue->e1 = %s\n", ue->e1->toChars()); @@ -8115,7 +8252,7 @@ Lagain: FuncDeclaration *f = NULL; Dsymbol *s = NULL; for (size_t i = 0; i < eo->vars->a.dim; i++) - { s = eo->vars->a.tdata()[i]; + { s = eo->vars->a[i]; FuncDeclaration *f2 = s->isFuncDeclaration(); if (f2) { @@ -8157,7 +8294,17 @@ Lagain: { TypeFunction *tf; const char *p; - if (t1->ty == Tdelegate) + if (e1->op == TOKfunction) + { + // function literal that direct called is always inferred. + assert(((FuncExp *)e1)->fd); + f = ((FuncExp *)e1)->fd; + tf = (TypeFunction *)f->type; + p = "function literal"; + + f->checkNestedReference(sc, loc); + } + else if (t1->ty == Tdelegate) { TypeDelegate *td = (TypeDelegate *)t1; assert(td->next->ty == Tfunction); tf = (TypeFunction *)(td->next); @@ -8222,7 +8369,7 @@ Lagain: else buf.writeByte(')'); - //printf("tf = %s, args = %s\n", tf->deco, arguments->tdata()[0]->type->deco); + //printf("tf = %s, args = %s\n", tf->deco, (*arguments)[0]->type->deco); ::error(loc, "%s %s %s is not callable using argument types %s", p, e1->toChars(), Parameter::argsTypesToChars(tf->parameters, tf->varargs), buf.toChars()); @@ -8306,10 +8453,12 @@ Lagain: } -#if DMDV2 + int CallExp::isLvalue() { Type *tb = e1->type->toBasetype(); + if (tb->ty == Tdelegate || tb->ty == Tpointer) + tb = tb->nextOf(); if (tb->ty == Tfunction && ((TypeFunction *)tb)->isref) { if (e1->op == TOKdotvar) @@ -8319,7 +8468,7 @@ int CallExp::isLvalue() } return 0; } -#endif + Expression *CallExp::toLvalue(Scope *sc, Expression *e) { @@ -8404,8 +8553,10 @@ Expression *AddrExp::semantic(Scope *sc) m = sc->module; #endif UnaExp::semantic(sc); + Expression *olde1 = e1; if (e1->type == Type::terror) return new ErrorExp(); + int wasCond = e1->op == TOKquestion; e1 = e1->toLvalue(sc, NULL); if (e1->op == TOKerror) return e1; @@ -8515,6 +8666,24 @@ Expression *AddrExp::semantic(Scope *sc) } } } + else if (wasCond) + { + /* a ? b : c was transformed to *(a ? &b : &c), but we still + * need to do safety checks + */ + assert(e1->op == TOKstar); + PtrExp *pe = (PtrExp *)e1; + assert(pe->e1->op == TOKquestion); + CondExp *ce = (CondExp *)pe->e1; + assert(ce->e1->op == TOKaddress); + assert(ce->e2->op == TOKaddress); + + // Re-run semantic on the address expressions only + ce->e1->type = NULL; + ce->e1 = ce->e1->semantic(sc); + ce->e2->type = NULL; + ce->e2 = ce->e2->semantic(sc); + } return optimize(WANTvalue); } return this; @@ -8576,12 +8745,12 @@ Expression *PtrExp::semantic(Scope *sc) return this; } -#if DMDV2 + int PtrExp::isLvalue() { return 1; } -#endif + void PtrExp::checkEscapeRef() { @@ -8992,6 +9161,12 @@ Expression *CastExp::semantic(Scope *sc) { return new VectorExp(loc, e1, to); } + + if (tob->isintegral() && t1b->ty == Tarray && + !global.params.useDeprecated) + { + error("casting %s to %s is deprecated", e1->type->toChars(), to->toChars()); + } } else if (!to) { error("cannot cast tuple"); @@ -9122,7 +9297,7 @@ VectorExp::VectorExp(Loc loc, Expression *e, Type *t) : UnaExp(loc, TOKvector, sizeof(VectorExp), e) { assert(t->ty == Tvector); - to = t; + to = (TypeVector *)t; dim = ~0; } @@ -9295,8 +9470,8 @@ Lagain: 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(); @@ -9384,12 +9559,12 @@ void SliceExp::checkEscapeRef() e1->checkEscapeRef(); } -#if DMDV2 + int SliceExp::isLvalue() { return 1; } -#endif + Expression *SliceExp::toLvalue(Scope *sc, Expression *e) { @@ -9540,6 +9715,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) @@ -9548,7 +9725,7 @@ Expression *ArrayExp::semantic(Scope *sc) { error("only one index allowed to index %s", t1->toChars()); goto Lerr; } - e = new IndexExp(loc, e1, arguments->tdata()[0]); + e = new IndexExp(loc, e1, (*arguments)[0]); return e->semantic(sc); } @@ -9563,14 +9740,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) { @@ -9652,12 +9829,12 @@ void CommaExp::checkEscapeRef() e2->checkEscapeRef(); } -#if DMDV2 + int CommaExp::isLvalue() { return e2->isLvalue(); } -#endif + Expression *CommaExp::toLvalue(Scope *sc, Expression *e) { @@ -9736,7 +9913,7 @@ Expression *IndexExp::semantic(Scope *sc) if (e2->type == Type::terror) goto Lerr; if (e2->type->ty == Ttuple && ((TupleExp *)e2)->exps->dim == 1) // bug 4444 fix - e2 = ((TupleExp *)e2)->exps->tdata()[0]; + e2 = (*((TupleExp *)e2)->exps)[0]; if (t1->ty == Tsarray || t1->ty == Tarray || t1->ty == Ttuple) sc = sc->pop(); @@ -9787,7 +9964,7 @@ Expression *IndexExp::semantic(Scope *sc) case Ttuple: { e2 = e2->implicitCastTo(sc, Type::tsize_t); - e2 = e2->optimize(WANTvalue | WANTinterpret); + e2 = e2->ctfeInterpret(); uinteger_t index = e2->toUInteger(); size_t length; TupleExp *te; @@ -9844,12 +10021,12 @@ Lerr: return new ErrorExp(); } -#if DMDV2 + int IndexExp::isLvalue() { return 1; } -#endif + Expression *IndexExp::toLvalue(Scope *sc, Expression *e) { @@ -10064,7 +10241,7 @@ Expression *AssignExp::semantic(Scope *sc) { Expression *e = new DotIdExp(loc, ae->e1, Id::indexass); // Deal with $ for (size_t i = 0; i < ae->arguments->dim; i++) - { Expression *x = ae->arguments->tdata()[i]; + { Expression *x = (*ae->arguments)[i]; // Create scope for '$' variable for this dimension ArrayScopeSymbol *sym = new ArrayScopeSymbol(sc, ae); sym->loc = loc; @@ -10082,7 +10259,7 @@ Expression *AssignExp::semantic(Scope *sc) x = new CommaExp(0, av, x); x->semantic(sc); } - ae->arguments->tdata()[i] = x; + (*ae->arguments)[i] = x; sc = sc->pop(); } Expressions *a = (Expressions *)ae->arguments->copy(); @@ -10104,7 +10281,7 @@ Expression *AssignExp::semantic(Scope *sc) return new ErrorExp(); } - e = new CallExp(loc, e, ae->arguments->tdata()[0], e2); + e = new CallExp(loc, e, (*ae->arguments)[0], e2); e = e->semantic(sc); return e; } @@ -10385,7 +10562,7 @@ Ltupleassign: for (size_t u = 0; u < iexps->dim ; u++) { Lexpand: - Expression *e = iexps->tdata()[u]; + Expression *e = (*iexps)[u]; Parameter *arg = Parameter::getNth(tt->arguments, u); //printf("[%d] iexps->dim = %d, ", u, iexps->dim); @@ -10401,7 +10578,7 @@ Ltupleassign: goto Lnomatch; } } - iexps->tdata()[0] = new CommaExp(loc, new DeclarationExp(e2->loc, v), iexps->tdata()[0]); + (*iexps)[0] = new CommaExp(loc, new DeclarationExp(e2->loc, v), (*iexps)[0]); e2 = new TupleExp(e2->loc, iexps); e2 = e2->semantic(sc); goto Ltupleassign; @@ -10474,16 +10651,6 @@ Ltupleassign: sd->cpctor) { /* We have a copy constructor for this */ - // Scan past commma's - Expression *ec = NULL; - while (e2->op == TOKcomma) - { CommaExp *ecomma = (CommaExp *)e2; - e2 = ecomma->e2; - if (ec) - ec = new CommaExp(ecomma->loc, ec, ecomma->e1); - else - ec = ecomma->e1; - } if (e2->op == TOKquestion) { /* Write as: * a ? e1 = b : e1 = c; @@ -10494,15 +10661,9 @@ Ltupleassign: AssignExp *ea2 = new AssignExp(econd->e1->loc, e1, econd->e2); ea2->op = op; Expression *e = new CondExp(loc, econd->econd, ea1, ea2); - if (ec) - e = new CommaExp(loc, ec, e); return e->semantic(sc); } - else if (e2->op == TOKvar || - e2->op == TOKdotvar || - e2->op == TOKstar || - e2->op == TOKthis || - e2->op == TOKindex) + else if (e2->isLvalue()) { /* Write as: * e1.cpctor(e2); */ @@ -10511,8 +10672,6 @@ Ltupleassign: Expression *e = new DotVarExp(loc, e1, sd->cpctor, 0); e = new CallExp(loc, e, e2); - if (ec) - e = new CommaExp(loc, ec, e); return e->semantic(sc); } else if (e2->op == TOKcall) @@ -10537,6 +10696,21 @@ Ltupleassign: if (t1->ty == Tsarray && !refinit) { + Type *t2 = e2->type->toBasetype(); + + if (t2->ty == Tsarray && !t2->implicitConvTo(t1->nextOf())) + { // static array assignment should check their lengths + TypeSArray *tsa1 = (TypeSArray *)t1; + TypeSArray *tsa2 = (TypeSArray *)t2; + uinteger_t dim1 = tsa1->dim->toInteger(); + uinteger_t dim2 = tsa2->dim->toInteger(); + if (dim1 != dim2) + { + error("mismatched array lengths, %d and %d", (int)dim1, (int)dim2); + return new ErrorExp(); + } + } + if (e1->op == TOKindex && ((IndexExp *)e1)->e1->type->toBasetype()->ty == Taarray) { @@ -10548,7 +10722,6 @@ Ltupleassign: } else { - Type *t2 = e2->type->toBasetype(); // Convert e2 to e2[], unless e2-> e1[0] if (t2->ty == Tsarray && !t2->implicitConvTo(t1->nextOf())) { @@ -10567,6 +10740,11 @@ Ltupleassign: if (!e2->rvalue()) return new ErrorExp(); + if (e2->op == TOKarrayliteral) + { + e2 = callCpCtor(loc, sc, e2, 1); + } + if (e1->op == TOKarraylength) { // e1 is not an lvalue, but we let code generator handle it @@ -10741,7 +10919,9 @@ Expression *CatAssignExp::semantic(Scope *sc) (tb2->ty == Tarray || tb2->ty == Tsarray) && (e2->implicitConvTo(e1->type) #if DMDV2 - || tb2->nextOf()->implicitConvTo(tb1next) + || (tb2->nextOf()->implicitConvTo(tb1next) && + (tb2->nextOf()->size(0) == tb1next->size(0) || + tb1next->ty == Tchar || tb1next->ty == Twchar || tb1next->ty == Tdchar)) #endif ) ) @@ -11476,7 +11656,7 @@ Expression *PowExp::semantic(Scope *sc) { importMathChecked = 1; for (size_t i = 0; i < Module::amodules.dim; i++) - { Module *mi = Module::amodules.tdata()[i]; + { Module *mi = Module::amodules[i]; //printf("\t[%d] %s\n", i, mi->toChars()); if (mi->ident == Id::math && mi->parent->ident == Id::std && @@ -12315,12 +12495,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/dmd2/expression.h b/dmd2/expression.h index 8dea5625..1054d696 100644 --- a/dmd2/expression.h +++ b/dmd2/expression.h @@ -18,6 +18,7 @@ #include "intrange.h" struct Type; +struct TypeVector; struct Scope; struct TupleDeclaration; struct VarDeclaration; @@ -183,6 +184,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(); @@ -432,7 +438,6 @@ struct StringExp : Expression StringExp(Loc loc, void *s, size_t len, unsigned char postfix); //Expression *syntaxCopy(); int equals(Object *o); - char *toChars(); Expression *semantic(Scope *sc); Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); size_t length(); @@ -793,7 +798,6 @@ struct FuncExp : Expression FuncLiteralDeclaration *fd; TemplateDeclaration *td; enum TOK tok; - Type *treq; FuncExp(Loc loc, FuncLiteralDeclaration *fd, TemplateDeclaration *td = NULL); Expression *syntaxCopy(); @@ -947,10 +951,11 @@ 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 *arrayOp(Scope *sc); + Expression *interpretFourPointerRelation(InterState *istate, CtfeGoal goal); + virtual Expression *arrayOp(Scope *sc); Expression *doInline(InlineDoState *ids); Expression *inlineScan(InlineScanState *iss); @@ -971,6 +976,7 @@ struct BinAssignExp : BinExp } Expression *semantic(Scope *sc); + Expression *arrayOp(Scope *sc); Expression *op_overload(Scope *sc); @@ -1330,7 +1336,7 @@ struct CastExp : UnaExp struct VectorExp : UnaExp { - Type *to; + TypeVector *to; // the target vector type before semantic() unsigned dim; // number of elements in the vector VectorExp(Loc loc, Expression *e, Type *t); @@ -1339,6 +1345,7 @@ struct VectorExp : UnaExp void toCBuffer(OutBuffer *buf, HdrGenState *hgs); #if IN_DMD elem *toElem(IRState *irs); + dt_t **toDt(dt_t **pdt); #endif #if IN_LLVM DValue* toElem(IRState* irs); @@ -2154,5 +2161,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/dmd2/func.c b/dmd2/func.c index 852c16bb..8a63431e 100644 --- a/dmd2/func.c +++ b/dmd2/func.c @@ -51,13 +51,15 @@ FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, StorageCla outId = NULL; vresult = NULL; returnLabel = NULL; + scout = NULL; fensure = NULL; fbody = NULL; localsymtab = NULL; vthis = NULL; v_arguments = NULL; -#if IN_GCC +#ifdef IN_GCC v_argptr = NULL; + v_arguments_var = NULL; #endif v_argsave = NULL; parameters = NULL; @@ -223,11 +225,9 @@ void FuncDeclaration::semantic(Scope *sc) if (isCtorDeclaration()) sc->flags |= SCOPEctor; - type = type->semantic(loc, sc); - sc = sc->pop(); - /* Apply const, immutable and shared storage class - * to the function type + /* Apply const, immutable, wild and shared storage class + * to the function type. Do this before type semantic. */ StorageClass stc = storage_class; if (type->isImmutable()) @@ -250,35 +250,28 @@ void FuncDeclaration::semantic(Scope *sc) case STCimmutable | STCshared | STCwild: // Don't use toInvariant(), as that will do a merge() type = type->makeInvariant(); - goto Lmerge; + break; case STCconst: case STCconst | STCwild: type = type->makeConst(); - goto Lmerge; + break; case STCshared | STCconst: case STCshared | STCconst | STCwild: type = type->makeSharedConst(); - goto Lmerge; + break; case STCshared: type = type->makeShared(); - goto Lmerge; + break; case STCwild: type = type->makeWild(); - goto Lmerge; + break; case STCshared | STCwild: type = type->makeSharedWild(); - goto Lmerge; - - Lmerge: - if (!(type->ty == Tfunction && !type->nextOf())) - /* Can't do merge if return type is not known yet - */ - type->deco = type->merge()->deco; break; case 0: @@ -287,7 +280,11 @@ void FuncDeclaration::semantic(Scope *sc) default: assert(0); } + + type = type->semantic(loc, sc); + sc = sc->pop(); } + storage_class &= ~STCref; if (type->ty != Tfunction) { @@ -401,18 +398,6 @@ void FuncDeclaration::semantic(Scope *sc) if (!fbody && (fensure || frequire) && !(id && isVirtual())) error("in and out contracts require function body"); - /* Template member functions aren't virtual: - * interface TestInterface { void tpl(T)(); } - * and so won't work in interfaces - */ - if ((pd = toParent()) != NULL && - pd->isTemplateInstance() && - (pd = toParent2()) != NULL && - (id = pd->isInterfaceDeclaration()) != NULL) - { - error("template member functions are not allowed in interface %s", id->toChars()); - } - cd = parent->isClassDeclaration(); if (cd) { int vi; @@ -550,9 +535,6 @@ void FuncDeclaration::semantic(Scope *sc) break; else if (!this->parent->isClassDeclaration() // if both are mixins then error -#if !BREAKABI - && !isDtorDeclaration() -#endif #if DMDV2 && !isPostBlitDeclaration() #endif @@ -610,7 +592,7 @@ void FuncDeclaration::semantic(Scope *sc) return; default: - { FuncDeclaration *fdv = (FuncDeclaration *)b->base->vtbl.tdata()[vi]; + { FuncDeclaration *fdv = (FuncDeclaration *)b->base->vtbl[vi]; Type *ti = NULL; /* Remember which functions this overrides @@ -920,7 +902,7 @@ void FuncDeclaration::semantic3(Scope *sc) { for (int i = 0; i < fthrows->dim; i++) { - Type *t = fthrows->tdata()[i]; + Type *t = (*fthrows)[i]; t = t->semantic(loc, sc); if (!t->isClassHandle()) @@ -929,11 +911,17 @@ void FuncDeclaration::semantic3(Scope *sc) } #endif + 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++) { - FuncDeclaration *fdv = foverrides.tdata()[i]; + FuncDeclaration *fdv = foverrides[i]; if (fdv->fbody && !fdv->frequire) { @@ -971,7 +959,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; #if !IN_LLVM sc2->tf = NULL; @@ -992,9 +980,6 @@ void FuncDeclaration::semantic3(Scope *sc) } else assert(!isNested() || sc->intypeof); // can't be both member and nested -#if IN_GCC - ad->methods.push(this); -#endif } vthis = declareThis(sc2, ad); @@ -1028,7 +1013,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; v_arguments->semantic(sc2); @@ -1041,18 +1025,10 @@ 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 -#if IN_GCC +#ifdef IN_GCC t = d_gcc_builtin_va_list_d_type; #else t = Type::tvoid->pointerTo(); @@ -1094,7 +1070,7 @@ void FuncDeclaration::semantic3(Scope *sc) if (f->parameters) { for (size_t i = 0; i < f->parameters->dim; i++) - { Parameter *arg = f->parameters->tdata()[i]; + { Parameter *arg = (*f->parameters)[i]; //printf("[%d] arg->type->ty = %d %s\n", i, arg->type->ty, arg->type->toChars()); if (arg->type->ty == Ttuple) @@ -1158,7 +1134,7 @@ void FuncDeclaration::semantic3(Scope *sc) if (f->parameters) { for (size_t i = 0; i < f->parameters->dim; i++) - { Parameter *arg = f->parameters->tdata()[i]; + { Parameter *arg = (*f->parameters)[i]; if (!arg->ident) continue; // never used, so ignore @@ -1173,7 +1149,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->tdata()[j] = e; + (*exps)[j] = e; } assert(arg->ident); TupleDeclaration *v = new TupleDeclaration(loc, arg->ident, exps); @@ -1187,151 +1163,120 @@ 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 +#if IN_LLVM + // We actually need a valid 'var' for codegen. + ThisExp* tv = new ThisExp(0); + tv->var = vthis; + Expression *v = tv; +#else + Expression *v = new ThisExp(0); +#endif + 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 +#if IN_LLVM + // We actually need a valid 'var' for codegen. + ThisExp* tv = new ThisExp(0); + tv->var = vthis; + Expression *v = tv; +#else + Expression *v = new ThisExp(0); +#endif + 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()) // if return type is inferred - { /* This case: - * auto fp = function() out { } body { }; - * Can fix by doing semantic() onf 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 - Loc loc = this->loc; - - if (fensure) - loc = fensure->loc; - - 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 (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 - ThisExp *tv = new ThisExp(0); - tv->type = vthis->type; - tv->var = vthis; - Expression* v = tv; - -#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) - { AggregateDeclaration *ad = isAggregateMember(); + AggregateDeclaration *ad = isAggregateMember(); /* If this is a class constructor */ @@ -1375,7 +1320,7 @@ void FuncDeclaration::semantic3(Scope *sc) else { for (size_t i = 0; i < pd->members->dim; i++) - { Dsymbol *s = pd->members->tdata()[i]; + { Dsymbol *s = (*pd->members)[i]; s->checkCtorConstInit(); } @@ -1460,15 +1405,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; @@ -1497,6 +1434,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; } { @@ -1506,7 +1503,7 @@ void FuncDeclaration::semantic3(Scope *sc) if (parameters) { for (size_t i = 0; i < parameters->dim; i++) { - VarDeclaration *v = parameters->tdata()[i]; + VarDeclaration *v = (*parameters)[i]; if (v->storage_class & STCout) { assert(v->init); @@ -1548,7 +1545,7 @@ void FuncDeclaration::semantic3(Scope *sc) if (parameters && parameters->dim) { int lastNonref = parameters->dim -1; - p = parameters->tdata()[lastNonref]; + p = (*parameters)[lastNonref]; /* The trouble with out and ref parameters is that taking * the address of it doesn't work, because later processing * adds in an extra level of indirection. So we skip over them. @@ -1562,7 +1559,7 @@ void FuncDeclaration::semantic3(Scope *sc) p = v_arguments; break; } - p = parameters->tdata()[lastNonref]; + p = (*parameters)[lastNonref]; } } else @@ -1586,6 +1583,10 @@ void FuncDeclaration::semantic3(Scope *sc) if (_arguments) { +#ifdef IN_GCC + v_arguments_var = _arguments; + v_arguments_var->init = new VoidInitializer(loc); +#endif /* Advance to elements[] member of TypeInfo_Tuple with: * _arguments = v_arguments.elements; */ @@ -1601,74 +1602,32 @@ 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 - ThisExp* tv = new ThisExp(0); - tv->type = vthis->type; - tv->var = vthis; - Expression *v = tv; - -#if STRUCTTHISREF - if (ad->isStructDeclaration()) - v = v->addressOf(sc); -#endif - Expression *se = new StringExp(0, (char *)"null this"); - se = se->semantic(sc); -#if !IN_LLVM - se->type = Type::tchar->arrayOf(); -#endif - e = new AssertExp(loc, v, 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) { #if IN_LLVM Expression *e = 0; @@ -1682,7 +1641,6 @@ void FuncDeclaration::semantic3(Scope *sc) } #else // Create: return vresult; - assert(vresult); Expression *e = new VarExp(0, vresult); #endif if (tintro) @@ -1693,6 +1651,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 @@ -1701,17 +1664,19 @@ void FuncDeclaration::semantic3(Scope *sc) if (parameters) { for (size_t i = 0; i < parameters->dim; i++) { - VarDeclaration *v = parameters->tdata()[i]; + VarDeclaration *v = (*parameters)[i]; - if (v->storage_class & (STCref | STCout)) + if (v->storage_class & (STCref | STCout | STClazy)) continue; +#if !SARRAYVALUE /* Don't do this for static arrays, since static * arrays are called by reference. Remove this * when we change them to call by value. */ if (v->type->toBasetype()->ty == Tsarray) continue; +#endif if (v->noscope) continue; @@ -1948,6 +1913,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. @@ -1992,7 +1999,7 @@ Statement *FuncDeclaration::mergeFrequire(Statement *sf, Expressions *params) */ for (int i = 0; i < foverrides.dim; i++) { - FuncDeclaration *fdv = foverrides.tdata()[i]; + FuncDeclaration *fdv = foverrides[i]; /* The semantic pass on the contracts of the overridden functions must * be completed before code generation occurs (bug 3602). @@ -2050,7 +2057,7 @@ Statement *FuncDeclaration::mergeFensure(Statement *sf, Expressions *params) */ for (int i = 0; i < foverrides.dim; i++) { - FuncDeclaration *fdv = foverrides.tdata()[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). @@ -2119,14 +2126,28 @@ int FuncDeclaration::findVtblIndex(Dsymbols *vtbl, int dim) FuncDeclaration *mismatch = NULL; StorageClass mismatchstc = 0; int mismatchvi = -1; + int exactvi = -1; int bestvi = -1; for (int vi = 0; vi < dim; vi++) { - FuncDeclaration *fdv = vtbl->tdata()[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; + } StorageClass stc = 0; int cov = type->covariant(fdv->type, &stc); @@ -2488,7 +2509,7 @@ if (arguments) for (i = 0; i < arguments->dim; i++) { Expression *arg; - arg = arguments->tdata()[i]; + arg = (*arguments)[i]; assert(arg->type); printf("\t%s: ", arg->toChars()); arg->type->print(); @@ -2531,7 +2552,7 @@ if (arguments) OutBuffer buf2; tf->modToBuffer(&buf2); - //printf("tf = %s, args = %s\n", tf->deco, arguments->tdata()[0]->type->deco); + //printf("tf = %s, args = %s\n", tf->deco, (*arguments)[0]->type->deco); error(loc, "%s%s is not callable using argument types %s", Parameter::argsTypesToChars(tf->parameters, tf->varargs), buf2.toChars(), @@ -2617,7 +2638,7 @@ MATCH FuncDeclaration::leastAsSpecialized(FuncDeclaration *g) } else e = p->type->defaultInitLiteral(0); - args.tdata()[u] = e; + args[u] = e; } MATCH m = (MATCH) tg->callMatch(NULL, &args, 1); @@ -2758,14 +2779,25 @@ int FuncDeclaration::getLevel(Loc loc, Scope *sc, FuncDeclaration *fd) //printf("\ts = %s, '%s'\n", s->kind(), s->toChars()); FuncDeclaration *thisfd = s->isFuncDeclaration(); if (thisfd) - { if (!thisfd->isNested() && !thisfd->vthis) + { if (!thisfd->isNested() && !thisfd->vthis && !sc->intypeof) goto Lerr; } else { AggregateDeclaration *thiscd = s->isAggregateDeclaration(); if (thiscd) - { if (!thiscd->isNested()) + { + /* AggregateDeclaration::isNested returns true only when + * it has a hidden pointer. + * But, calling the function belongs unrelated lexical scope + * is still allowed inside typeof. + * + * struct Map(alias fun) { + * typeof({ return fun(); }) RetType; + * // No member function makes Map struct 'not nested'. + * } + */ + if (!thiscd->isNested() && !sc->intypeof) goto Lerr; } else @@ -3042,6 +3074,7 @@ int FuncDeclaration::isNested() FuncDeclaration *f = toAliasFunc(); //printf("\ttoParent2() = '%s'\n", f->toParent2()->toChars()); return ((f->storage_class & STCstatic) == 0) && + (f->linkage == LINKd) && (f->toParent2()->isFuncDeclaration() != NULL); } @@ -3183,12 +3216,12 @@ int FuncDeclaration::needsClosure() //printf("FuncDeclaration::needsClosure() %s\n", toChars()); for (int i = 0; i < closureVars.dim; i++) - { VarDeclaration *v = closureVars.tdata()[i]; + { VarDeclaration *v = closureVars[i]; assert(v->isVarDeclaration()); //printf("\tv = %s\n", v->toChars()); for (int j = 0; j < v->nestedrefs.dim; j++) - { FuncDeclaration *f = v->nestedrefs.tdata()[j]; + { FuncDeclaration *f = v->nestedrefs[j]; assert(f != this); //printf("\t\tf = %s, %d, %p, %d\n", f->toChars(), f->isVirtual(), f->isThis(), f->tookAddressOf); @@ -3259,7 +3292,7 @@ int FuncDeclaration::hasNestedFrameRefs() { for (size_t i = 0; i < foverrides.dim; i++) { - FuncDeclaration *fdv = foverrides.tdata()[i]; + FuncDeclaration *fdv = foverrides[i]; if (fdv->hasNestedFrameRefs()) return 1; } @@ -3347,6 +3380,7 @@ FuncLiteralDeclaration::FuncLiteralDeclaration(Loc loc, Loc endloc, Type *type, this->ident = Lexer::uniqueId(id); this->tok = tok; this->fes = fes; + this->treq = NULL; //printf("FuncLiteralDeclaration() id = '%s', type = '%s'\n", this->ident->toChars(), type->toChars()); } @@ -3360,6 +3394,7 @@ Dsymbol *FuncLiteralDeclaration::syntaxCopy(Dsymbol *s) else { f = new FuncLiteralDeclaration(loc, endloc, type->syntaxCopy(), tok, fes); f->ident = ident; // keep old identifier + f->treq = treq; // don't need to copy } FuncDeclaration::syntaxCopy(f); return f; @@ -3674,14 +3709,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/dmd2/gpl.txt b/dmd2/gpl.txt index cc468912..43cd72c3 100644 --- a/dmd2/gpl.txt +++ b/dmd2/gpl.txt @@ -1,248 +1,248 @@ - GNU GENERAL PUBLIC LICENSE - Version 1, February 1989 - - Copyright (C) 1989 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The license agreements of most software companies try to keep users -at the mercy of those companies. By contrast, our General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. The -General Public License applies to the Free Software Foundation's -software and to any other program whose authors commit to using it. -You can use it for your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Specifically, the General Public License is designed to make -sure that you have the freedom to give away or sell copies of free -software, that you receive source code or can get it if you want it, -that you can change the software or use pieces of it in new free -programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of a such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must tell them their rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any program or other work which -contains a notice placed by the copyright holder saying it may be -distributed under the terms of this General Public License. The -"Program", below, refers to any such program or work, and a "work based -on the Program" means either the Program or any work containing the -Program or a portion of it, either verbatim or with modifications. Each -licensee is addressed as "you". - - 1. You may copy and distribute verbatim copies of the Program's source -code as you receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice and -disclaimer of warranty; keep intact all the notices that refer to this -General Public License and to the absence of any warranty; and give any -other recipients of the Program a copy of this General Public License -along with the Program. You may charge a fee for the physical act of -transferring a copy. - - 2. You may modify your copy or copies of the Program or any portion of -it, and copy and distribute such modifications under the terms of Paragraph -1 above, provided that you also do the following: - - a) cause the modified files to carry prominent notices stating that - you changed the files and the date of any change; and - - b) cause the whole of any work that you distribute or publish, that - in whole or in part contains the Program or any part thereof, either - with or without modifications, to be licensed at no charge to all - third parties under the terms of this General Public License (except - that you may choose to grant warranty protection to some or all - third parties, at your option). - - c) If the modified program normally reads commands interactively when - run, you must cause it, when started running for such interactive use - in the simplest and most usual way, to print or display an - announcement including an appropriate copyright notice and a notice - that there is no warranty (or else, saying that you provide a - warranty) and that users may redistribute the program under these - conditions, and telling the user how to view a copy of this General - Public License. - - d) You may charge a fee for the physical act of transferring a - copy, and you may at your option offer warranty protection in - exchange for a fee. - -Mere aggregation of another independent work with the Program (or its -derivative) on a volume of a storage or distribution medium does not bring -the other work under the scope of these terms. - - 3. You may copy and distribute the Program (or a portion or derivative of -it, under Paragraph 2) in object code or executable form under the terms of -Paragraphs 1 and 2 above provided that you also do one of the following: - - a) accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of - Paragraphs 1 and 2 above; or, - - b) accompany it with a written offer, valid for at least three - years, to give any third party free (except for a nominal charge - for the cost of distribution) a complete machine-readable copy of the - corresponding source code, to be distributed under the terms of - Paragraphs 1 and 2 above; or, - - c) accompany it with the information you received as to where the - corresponding source code may be obtained. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form alone.) - -Source code for a work means the preferred form of the work for making -modifications to it. For an executable file, complete source code means -all the source code for all modules it contains; but, as a special -exception, it need not include source code for modules which are standard -libraries that accompany the operating system on which the executable -file runs, or for standard header files or definitions files that -accompany that operating system. - - 4. You may not copy, modify, sublicense, distribute or transfer the -Program except as expressly provided under this General Public License. -Any attempt otherwise to copy, modify, sublicense, distribute or transfer -the Program is void, and will automatically terminate your rights to use -the Program under this License. However, parties who have received -copies, or rights to use copies, from you under this General Public -License will not have their licenses terminated so long as such parties -remain in full compliance. - - 5. By copying, distributing or modifying the Program (or any work based -on the Program) you indicate your acceptance of this license to do so, -and all its terms and conditions. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the original -licensor to copy, distribute or modify the Program subject to these -terms and conditions. You may not impose any further restrictions on the -recipients' exercise of the rights granted herein. - - 7. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of the license which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -the license, you may choose any version ever published by the Free Software -Foundation. - - 8. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - Appendix: How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to humanity, the best way to achieve this is to make it -free software which everyone can redistribute and change under these -terms. - - To do so, attach the following notices to the program. It is safest to -attach them to the start of each source file to most effectively convey -the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) 19yy - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 1, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) 19xx name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the -appropriate parts of the General Public License. Of course, the -commands you use may be called something other than `show w' and `show -c'; they could even be mouse-clicks or menu items--whatever suits your -program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - program `Gnomovision' (a program to direct compilers to make passes - at assemblers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -That's all there is to it! + GNU GENERAL PUBLIC LICENSE + Version 1, February 1989 + + Copyright (C) 1989 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The license agreements of most software companies try to keep users +at the mercy of those companies. By contrast, our General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. The +General Public License applies to the Free Software Foundation's +software and to any other program whose authors commit to using it. +You can use it for your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Specifically, the General Public License is designed to make +sure that you have the freedom to give away or sell copies of free +software, that you receive source code or can get it if you want it, +that you can change the software or use pieces of it in new free +programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of a such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must tell them their rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any program or other work which +contains a notice placed by the copyright holder saying it may be +distributed under the terms of this General Public License. The +"Program", below, refers to any such program or work, and a "work based +on the Program" means either the Program or any work containing the +Program or a portion of it, either verbatim or with modifications. Each +licensee is addressed as "you". + + 1. You may copy and distribute verbatim copies of the Program's source +code as you receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice and +disclaimer of warranty; keep intact all the notices that refer to this +General Public License and to the absence of any warranty; and give any +other recipients of the Program a copy of this General Public License +along with the Program. You may charge a fee for the physical act of +transferring a copy. + + 2. You may modify your copy or copies of the Program or any portion of +it, and copy and distribute such modifications under the terms of Paragraph +1 above, provided that you also do the following: + + a) cause the modified files to carry prominent notices stating that + you changed the files and the date of any change; and + + b) cause the whole of any work that you distribute or publish, that + in whole or in part contains the Program or any part thereof, either + with or without modifications, to be licensed at no charge to all + third parties under the terms of this General Public License (except + that you may choose to grant warranty protection to some or all + third parties, at your option). + + c) If the modified program normally reads commands interactively when + run, you must cause it, when started running for such interactive use + in the simplest and most usual way, to print or display an + announcement including an appropriate copyright notice and a notice + that there is no warranty (or else, saying that you provide a + warranty) and that users may redistribute the program under these + conditions, and telling the user how to view a copy of this General + Public License. + + d) You may charge a fee for the physical act of transferring a + copy, and you may at your option offer warranty protection in + exchange for a fee. + +Mere aggregation of another independent work with the Program (or its +derivative) on a volume of a storage or distribution medium does not bring +the other work under the scope of these terms. + + 3. You may copy and distribute the Program (or a portion or derivative of +it, under Paragraph 2) in object code or executable form under the terms of +Paragraphs 1 and 2 above provided that you also do one of the following: + + a) accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of + Paragraphs 1 and 2 above; or, + + b) accompany it with a written offer, valid for at least three + years, to give any third party free (except for a nominal charge + for the cost of distribution) a complete machine-readable copy of the + corresponding source code, to be distributed under the terms of + Paragraphs 1 and 2 above; or, + + c) accompany it with the information you received as to where the + corresponding source code may be obtained. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form alone.) + +Source code for a work means the preferred form of the work for making +modifications to it. For an executable file, complete source code means +all the source code for all modules it contains; but, as a special +exception, it need not include source code for modules which are standard +libraries that accompany the operating system on which the executable +file runs, or for standard header files or definitions files that +accompany that operating system. + + 4. You may not copy, modify, sublicense, distribute or transfer the +Program except as expressly provided under this General Public License. +Any attempt otherwise to copy, modify, sublicense, distribute or transfer +the Program is void, and will automatically terminate your rights to use +the Program under this License. However, parties who have received +copies, or rights to use copies, from you under this General Public +License will not have their licenses terminated so long as such parties +remain in full compliance. + + 5. By copying, distributing or modifying the Program (or any work based +on the Program) you indicate your acceptance of this license to do so, +and all its terms and conditions. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the original +licensor to copy, distribute or modify the Program subject to these +terms and conditions. You may not impose any further restrictions on the +recipients' exercise of the rights granted herein. + + 7. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of the license which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +the license, you may choose any version ever published by the Free Software +Foundation. + + 8. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to humanity, the best way to achieve this is to make it +free software which everyone can redistribute and change under these +terms. + + To do so, attach the following notices to the program. It is safest to +attach them to the start of each source file to most effectively convey +the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 1, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19xx name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the +appropriate parts of the General Public License. Of course, the +commands you use may be called something other than `show w' and `show +c'; they could even be mouse-clicks or menu items--whatever suits your +program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + program `Gnomovision' (a program to direct compilers to make passes + at assemblers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/dmd2/hdrgen.c b/dmd2/hdrgen.c index 78dd4001..87b8368f 100644 --- a/dmd2/hdrgen.c +++ b/dmd2/hdrgen.c @@ -84,7 +84,7 @@ void Module::toCBuffer(OutBuffer *buf, HdrGenState *hgs) } for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = members->tdata()[i]; + { Dsymbol *s = (*members)[i]; s->toHBuffer(buf, hgs); } diff --git a/dmd2/hdrgen.h b/dmd2/hdrgen.h index 79cfb732..c60787ae 100644 --- a/dmd2/hdrgen.h +++ b/dmd2/hdrgen.h @@ -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/dmd2/idgen.c b/dmd2/idgen.c index 41f52ab7..457220bd 100644 --- a/dmd2/idgen.c +++ b/dmd2/idgen.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 @@ -66,6 +66,7 @@ Msgtable msgtable[] = { "outer" }, { "Exception" }, { "AssociativeArray" }, + { "RTInfo" }, { "Throwable" }, { "Error" }, { "withSym", "__withSym" }, @@ -356,6 +357,7 @@ Msgtable msgtable[] = { "derivedMembers" }, { "isSame" }, { "compiles" }, + { "parameters" }, }; diff --git a/dmd2/import.c b/dmd2/import.c index f4582c23..07670f4f 100644 --- a/dmd2/import.c +++ b/dmd2/import.c @@ -45,7 +45,7 @@ Import::Import(Loc loc, Identifiers *packages, Identifier *id, Identifier *alias this->ident = aliasId; // import [std].stdio; else if (packages && packages->dim) - this->ident = packages->tdata()[0]; + this->ident = (*packages)[0]; // import [foo]; else this->ident = id; @@ -112,8 +112,18 @@ void Import::load(Scope *sc) if (s->isModule()) mod = (Module *)s; else - ::error(loc, "can only import from a module, not from package %s.%s", - pkg->toPrettyChars(), id->toChars()); + { + 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 } @@ -356,8 +366,8 @@ int Import::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) */ for (size_t i = 0; i < names.dim; i++) { - Identifier *name = names.tdata()[i]; - Identifier *alias = aliases.tdata()[i]; + Identifier *name = names[i]; + Identifier *alias = aliases[i]; if (!alias) alias = name; @@ -413,12 +423,30 @@ void Import::toCBuffer(OutBuffer *buf, HdrGenState *hgs) if (packages && packages->dim) { for (size_t i = 0; i < packages->dim; i++) - { Identifier *pid = packages->tdata()[i]; + { Identifier *pid = (*packages)[i]; buf->printf("%s.", pid->toChars()); } } - buf->printf("%s;", id->toChars()); + buf->printf("%s", id->toChars()); + if (names.dim) + { + buf->writestring(" : "); + for (size_t i = 0; i < names.dim; i++) + { + Identifier *name = names[i]; + Identifier *alias = aliases[i]; + + if (alias) + buf->printf("%s = %s", alias->toChars(), name->toChars()); + else + buf->printf("%s", name->toChars()); + + if (i < names.dim - 1) + buf->writestring(", "); + } + } + buf->printf(";"); buf->writenl(); } diff --git a/dmd2/inifile.c b/dmd2/inifile.c index 1bed9fe7..36b2dd41 100644 --- a/dmd2/inifile.c +++ b/dmd2/inifile.c @@ -1,6 +1,6 @@ /* * Some portions copyright (c) 1994-1995 by Symantec - * Copyright (c) 1999-2011 by Digital Mars + * Copyright (c) 1999-2012 by Digital Mars * All Rights Reserved * http://www.digitalmars.com * Written by Walter Bright @@ -31,6 +31,10 @@ #include #endif +#if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ +#include "gnuc.h" +#endif + #include "root.h" #include "rmem.h" diff --git a/dmd2/init.c b/dmd2/init.c index 5de6b114..23758bda 100644 --- a/dmd2/init.c +++ b/dmd2/init.c @@ -35,7 +35,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; } @@ -88,7 +88,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; @@ -145,7 +145,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; @@ -227,7 +227,7 @@ Initializer *StructInitializer::semantic(Scope *sc, Type *t, int needInterpret) } if (s && (v = s->isVarDeclaration()) != NULL) { - val = val->semantic(sc, v->type, needInterpret); + val = val->semantic(sc, v->type->addMod(t->mod), needInterpret); value[i] = val; vars[i] = v; } @@ -353,8 +353,12 @@ Expression *StructInitializer::toExpression() else { if (!(*elements)[i]) - // Default initialize - (*elements)[i] = vd->type->defaultInit(); + { // Default initialize + if (vd->init) + (*elements)[i] = vd->init->toExpression(); + else + (*elements)[i] = vd->type->defaultInit(); + } } offset = vd->offset + vd->type->size(); i++; @@ -464,7 +468,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; @@ -482,6 +486,10 @@ Initializer *ArrayInitializer::semantic(Scope *sc, Type *t, int needInterpret) case Tarray: break; + case Tvector: + t = ((TypeVector *)t)->basetype; + break; + default: error(loc, "cannot use array to initialize %s", type->toChars()); goto Lerr; @@ -493,14 +501,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"); @@ -746,6 +779,7 @@ ExpInitializer::ExpInitializer(Loc loc, Expression *exp) : Initializer(loc) { this->exp = exp; + this->expandTuples = 0; } Initializer *ExpInitializer::syntaxCopy() @@ -757,6 +791,9 @@ bool arrayHasNonConstPointers(Expressions *elems); bool hasNonConstPointers(Expression *e) { + if (e->type->ty == Terror) + return false; + if (e->op == TOKnull) return false; if (e->op == TOKstructliteral) @@ -817,15 +854,19 @@ bool arrayHasNonConstPointers(Expressions *elems) -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); exp = resolveProperties(sc, exp); - 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 @@ -841,6 +882,11 @@ Initializer *ExpInitializer::semantic(Scope *sc, Type *t, int needInterpret) 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"; @@ -870,8 +916,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/dmd2/init.h b/dmd2/init.h index d038dd9e..260f35c8 100644 --- a/dmd2/init.h +++ b/dmd2/init.h @@ -34,6 +34,7 @@ namespace llvm { } #endif +enum NeedInterpret { INITnointerpret, INITinterpret }; struct Initializer : Object { @@ -41,8 +42,8 @@ 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); + // needInterpret is INITinterpret if must be a manifest constant, 0 if not. + 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 +67,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 +89,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 +114,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); int isAssociativeArray(); Type *inferType(Scope *sc); Expression *toExpression(); @@ -131,10 +132,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/dmd2/inline.c b/dmd2/inline.c index 6b3f589f..8bf6fe8c 100644 --- a/dmd2/inline.c +++ b/dmd2/inline.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 @@ -14,6 +14,7 @@ #include #include #include +#include // memset() #include "id.h" #include "init.h" @@ -618,11 +619,11 @@ Expressions *arrayExpressiondoInline(Expressions *a, InlineDoState *ids) newa->setDim(a->dim); for (size_t i = 0; i < a->dim; i++) - { Expression *e = a->tdata()[i]; + { Expression *e = (*a)[i]; if (e) e = e->doInline(ids); - newa->tdata()[i] = e; + (*newa)[i] = e; } } return newa; @@ -639,11 +640,11 @@ Expression *SymOffExp::doInline(InlineDoState *ids) //printf("SymOffExp::doInline(%s)\n", toChars()); for (size_t i = 0; i < ids->from.dim; i++) { - if (var == ids->from.tdata()[i]) + if (var == ids->from[i]) { SymOffExp *se = (SymOffExp *)copy(); - se->var = (Declaration *)ids->to.tdata()[i]; + se->var = (Declaration *)ids->to[i]; return se; } } @@ -655,11 +656,11 @@ Expression *VarExp::doInline(InlineDoState *ids) //printf("VarExp::doInline(%s)\n", toChars()); for (size_t i = 0; i < ids->from.dim; i++) { - if (var == ids->from.tdata()[i]) + if (var == ids->from[i]) { VarExp *ve = (VarExp *)copy(); - ve->var = (Declaration *)ids->to.tdata()[i]; + ve->var = (Declaration *)ids->to[i]; return ve; } } @@ -709,7 +710,7 @@ Expression *DeclarationExp::doInline(InlineDoState *ids) if (td) { for (size_t i = 0; i < td->objects->dim; i++) - { DsymbolExp *se = td->objects->tdata()[i]; + { DsymbolExp *se = (*td->objects)[i]; assert(se->op == TOKdsymbol); se->s; } @@ -1098,8 +1099,8 @@ Statement *SwitchStatement::inlineScan(InlineScanState *iss) for (size_t i = 0; i < cases->dim; i++) { CaseStatement *s; - s = cases->tdata()[i]; - cases->tdata()[i] = (CaseStatement *)s->inlineScan(iss); + s = (*cases)[i]; + (*cases)[i] = (CaseStatement *)s->inlineScan(iss); } } return this; @@ -1130,6 +1131,65 @@ Statement *ReturnStatement::inlineScan(InlineScanState *iss) if (exp) { exp = exp->inlineScan(iss); + + FuncDeclaration *func = iss->fd; + TypeFunction *tf = (TypeFunction *)(func->type); + + /* Postblit call on return statement is processed in glue layer + * (Because NRVO may eliminate the copy), but inlining may remove + * ReturnStatement itself. To keep semantics we should insert + * temporary variable for postblit call. + * This is mostly the same as ReturnStatement::toIR. + */ + enum RET retmethod = tf->retStyle(); + if (retmethod == RETstack) + { + if (func->nrvo_can && func->nrvo_var) + ; + else + { + Type *tb = exp->type->toBasetype(); + if (exp->isLvalue() && tb->ty == Tstruct) + { StructDeclaration *sd = ((TypeStruct *)tb)->sym; + if (sd->postblit) + { FuncDeclaration *fd = sd->postblit; + if (fd->storage_class & STCdisable) + { + fd->toParent()->error(loc, "is not copyable because it is annotated with @disable"); + } + + /* Rewirte exp as: + * (__inlinectmp = exp), __inlinectmp.__postblit(), __inlinectmp + * And, __inlinectmp is marked as rvalue (See STCtemp comment) + */ + ExpInitializer *ei = new ExpInitializer(loc, exp); + + Identifier* tmp = Identifier::generateId("__inlinectmp"); + VarDeclaration *v = new VarDeclaration(loc, exp->type, tmp, ei); + v->storage_class = STCtemp; + v->linkage = LINKd; + v->parent = func; + + VarExp *ve = new VarExp(loc, v); + ve->type = exp->type; + + ei->exp = new ConstructExp(loc, ve, exp); + ei->exp->type = exp->type; + + DeclarationExp *de = new DeclarationExp(0, v); + de->type = Type::tvoid; + + Expression *e = new DotVarExp(ve->loc, ve, sd->postblit, 0); + e->type = sd->postblit->type; + e = new CallExp(ve->loc, e); + e->type = Type::tvoid; + + exp = Expression::combine(de, e); + exp = Expression::combine(exp, ve); + } + } + } + } } return this; } @@ -1162,7 +1222,7 @@ Statement *TryCatchStatement::inlineScan(InlineScanState *iss) if (catches) { for (size_t i = 0; i < catches->dim; i++) - { Catch *c = catches->tdata()[i]; + { Catch *c = (*catches)[i]; if (c->handler) c->handler = c->handler->inlineScan(iss); @@ -1212,12 +1272,12 @@ void arrayInlineScan(InlineScanState *iss, Expressions *arguments) if (arguments) { for (size_t i = 0; i < arguments->dim; i++) - { Expression *e = arguments->tdata()[i]; + { Expression *e = (*arguments)[i]; if (e) { e = e->inlineScan(iss); - arguments->tdata()[i] = e; + (*arguments)[i] = e; } } } @@ -1237,7 +1297,7 @@ void scanVar(Dsymbol *s, InlineScanState *iss) if (td) { for (size_t i = 0; i < td->objects->dim; i++) - { DsymbolExp *se = (DsymbolExp *)td->objects->tdata()[i]; + { DsymbolExp *se = (DsymbolExp *)(*td->objects)[i]; assert(se->op == TOKdsymbol); scanVar(se->s, iss); } @@ -1546,7 +1606,7 @@ int FuncDeclaration::canInline(int hasthis, int hdrscan, int statementsToo) { for (size_t i = 0; i < parameters->dim; i++) { - VarDeclaration *v = parameters->tdata()[i]; + VarDeclaration *v = (*parameters)[i]; if (v->type->toBasetype()->ty == Tsarray) goto Lno; } @@ -1701,9 +1761,9 @@ Expression *FuncDeclaration::expandInline(InlineScanState *iss, Expression *ethi for (size_t i = 0; i < arguments->dim; i++) { - VarDeclaration *vfrom = parameters->tdata()[i]; + VarDeclaration *vfrom = (*parameters)[i]; VarDeclaration *vto; - Expression *arg = arguments->tdata()[i]; + Expression *arg = (*arguments)[i]; ExpInitializer *ei; VarExp *ve; @@ -1778,7 +1838,7 @@ Expression *FuncDeclaration::expandInline(InlineScanState *iss, Expression *ethi Identifier* tmp = Identifier::generateId("__inlineretval"); VarDeclaration* vd = new VarDeclaration(loc, tf->next, tmp, ei); - vd->storage_class = tf->isref ? STCref : 0; + vd->storage_class = (tf->isref ? STCref : 0) | STCtemp; vd->linkage = tf->linkage; vd->parent = iss->fd; diff --git a/dmd2/interpret.c b/dmd2/interpret.c index 425a836d..b213d624 100644 --- a/dmd2/interpret.c +++ b/dmd2/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: @@ -582,7 +596,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)) @@ -635,13 +649,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 @@ -807,7 +821,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) { @@ -834,7 +848,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) @@ -954,19 +968,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; @@ -1219,38 +1220,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) @@ -1303,79 +1280,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; } @@ -1433,7 +1384,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; @@ -1973,11 +1924,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) @@ -1985,7 +1937,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(); @@ -2076,10 +2028,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; @@ -2261,7 +2213,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); @@ -2289,10 +2241,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) @@ -2315,7 +2267,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 @@ -2336,10 +2288,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; } } } @@ -2481,7 +2433,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; @@ -2501,10 +2453,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; } } } @@ -2536,7 +2488,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; @@ -2576,7 +2528,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()); @@ -2591,7 +2543,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; @@ -2652,7 +2604,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); @@ -2930,20 +2882,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; @@ -2961,16 +2917,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 { @@ -2983,30 +2950,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; @@ -3023,14 +3197,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)) @@ -3064,7 +3244,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; @@ -3079,9 +3259,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 */ @@ -3097,9 +3277,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; } @@ -3299,7 +3479,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 @@ -3591,7 +3771,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 ) @@ -3831,18 +4012,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; @@ -4046,7 +4227,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) @@ -4684,12 +4865,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; @@ -4708,17 +5061,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 @@ -4737,7 +5087,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; @@ -4997,7 +5353,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; @@ -5233,7 +5589,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]", @@ -5402,7 +5758,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]", @@ -5561,7 +5917,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; @@ -5759,9 +6117,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; } @@ -5920,7 +6285,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) @@ -6206,8 +6573,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)) @@ -6438,7 +6805,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; @@ -6461,7 +6828,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)) @@ -6502,11 +6869,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) @@ -6579,7 +6946,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; @@ -6607,11 +6974,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/dmd2/json.c b/dmd2/json.c index d3efacf5..26daa65e 100644 --- a/dmd2/json.c +++ b/dmd2/json.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars +// Copyright (c) 1999-2012 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -53,7 +53,7 @@ void json_generate(Modules *modules) buf.writestring("[\n"); for (size_t i = 0; i < modules->dim; i++) - { Module *m = modules->tdata()[i]; + { Module *m = (*modules)[i]; if (global.params.verbose) printf("json gen %s\n", m->toChars()); m->toJsonBuffer(&buf); @@ -66,7 +66,7 @@ void json_generate(Modules *modules) char *arg = global.params.xfilename; if (!arg || !*arg) { // Generate lib file name from first obj name - char *n = global.params.objfiles->tdata()[0]; + char *n = (*global.params.objfiles)[0]; n = FileName::name(n); FileName *fn = FileName::forceExt(n, global.json_ext); @@ -195,7 +195,7 @@ void Module::toJsonBuffer(OutBuffer *buf) size_t offset = buf->offset; for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = members->tdata()[i]; + { Dsymbol *s = (*members)[i]; if (offset != buf->offset) { buf->writestring(",\n"); offset = buf->offset; @@ -219,7 +219,7 @@ void AttribDeclaration::toJsonBuffer(OutBuffer *buf) { size_t offset = buf->offset; for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = d->tdata()[i]; + { Dsymbol *s = (*d)[i]; //printf("AttribDeclaration::toJsonBuffer %s\n", s->toChars()); if (offset != buf->offset) { buf->writestring(",\n"); @@ -332,7 +332,7 @@ void AggregateDeclaration::toJsonBuffer(OutBuffer *buf) buf->writestring(" : [\n"); size_t offset = buf->offset; for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = members->tdata()[i]; + { Dsymbol *s = (*members)[i]; if (offset != buf->offset) { buf->writestring(",\n"); offset = buf->offset; @@ -369,7 +369,7 @@ void TemplateDeclaration::toJsonBuffer(OutBuffer *buf) buf->writestring(" : [\n"); size_t offset = buf->offset; for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = members->tdata()[i]; + { Dsymbol *s = (*members)[i]; if (offset != buf->offset) { buf->writestring(",\n"); offset = buf->offset; @@ -391,7 +391,7 @@ void EnumDeclaration::toJsonBuffer(OutBuffer *buf) { for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = members->tdata()[i]; + Dsymbol *s = (*members)[i]; s->toJsonBuffer(buf); buf->writestring(",\n"); } @@ -423,7 +423,7 @@ void EnumDeclaration::toJsonBuffer(OutBuffer *buf) buf->writestring(" : [\n"); size_t offset = buf->offset; for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = members->tdata()[i]; + { Dsymbol *s = (*members)[i]; if (offset != buf->offset) { buf->writestring(",\n"); offset = buf->offset; diff --git a/dmd2/lexer.c b/dmd2/lexer.c index ed3dfae0..741cc859 100644 --- a/dmd2/lexer.c +++ b/dmd2/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 @@ -108,14 +108,22 @@ const char *Token::toChars() switch (value) { case TOKint32v: +#if defined(IN_GCC) || defined(IN_LLVM) sprintf(buffer,"%d",(d_int32)int64value); +#else + sprintf(buffer,"%d",int32value); +#endif break; case TOKuns32v: case TOKcharv: case TOKwcharv: case TOKdcharv: +#ifdef defined(IN_GCC) || defined(IN_LLVM) sprintf(buffer,"%uU",(d_uns32)uns64value); +#else + sprintf(buffer,"%uU",uns32value); +#endif break; case TOKint64v: @@ -126,7 +134,7 @@ const char *Token::toChars() sprintf(buffer,"%lluUL",(uintmax_t)uns64value); break; -#if IN_GCC +#ifdef IN_GCC case TOKfloat32v: case TOKfloat64v: case TOKfloat80v: @@ -171,9 +179,6 @@ const char *Token::toChars() #endif case TOKstring: -#if CSTRINGS - p = string; -#else { OutBuffer buf; buf.writeByte('"'); @@ -208,7 +213,6 @@ const char *Token::toChars() buf.writeByte(0); p = (char *)buf.extractData(); } -#endif break; case TOKidentifier: @@ -305,7 +309,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); } @@ -313,34 +317,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; @@ -524,30 +504,6 @@ void Lexer::scan(Token *t) t->value = number(t); return; -#if CSTRINGS - case '\'': - t->value = charConstant(t, 0); - return; - - case '"': - t->value = stringConstant(t,0); - return; - - case 'l': - case 'L': - if (p[1] == '\'') - { - p++; - t->value = charConstant(t, 1); - return; - } - else if (p[1] == '"') - { - p++; - t->value = stringConstant(t, 1); - return; - } -#else case '\'': t->value = charConstant(t,0); return; @@ -627,12 +583,9 @@ void Lexer::scan(Token *t) } #endif - case 'l': - case 'L': -#endif case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': - case 'k': case 'm': case 'n': case 'o': + case 'k': case 'l': case 'm': case 'n': case 'o': #if DMDV2 case 'p': /*case 'q': case 'r':*/ case 's': case 't': #else @@ -642,7 +595,7 @@ void Lexer::scan(Token *t) case 'z': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': - case 'K': case 'M': case 'N': case 'O': + case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': @@ -669,7 +622,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; @@ -1228,10 +1181,10 @@ void Lexer::scan(Token *t) case '#': { p++; - Token *n = peek(t); - if (n->value == TOKidentifier && n->ident == Id::line) + Token n; + scan(&n); + if (n.value == TOKidentifier && n.ident == Id::line) { - nextToken(); poundLine(); continue; } @@ -1931,45 +1884,6 @@ void Lexer::stringPostfix(Token *t) } } -/*************************************** - * Read \u or \U unicode sequence - * Input: - * u 'u' or 'U' - */ - -#if 0 -unsigned Lexer::wchar(unsigned u) -{ - unsigned value; - unsigned n; - unsigned char c; - unsigned nchars; - - nchars = (u == 'U') ? 8 : 4; - value = 0; - for (n = 0; 1; n++) - { - ++p; - if (n == nchars) - break; - c = *p; - if (!ishex(c)) - { error("\\%c sequence must be followed by %d hex characters", u, nchars); - break; - } - if (isdigit(c)) - c -= '0'; - else if (islower(c)) - c -= 'a' - 10; - else - c -= 'A' - 10; - value <<= 4; - value |= c; - } - return value; -} -#endif - /************************************** * Read in a number. * If it's an integer, store it in tok.TKutok.Vlong. @@ -1996,14 +1910,12 @@ TOK Lexer::number(Token *t) }; enum FLAGS flags = FLAGS_decimal; - int base; unsigned c; unsigned char *start; TOK result; //printf("Lexer::number()\n"); state = STATE_initial; - base = 0; stringbuffer.reset(); start = p; while (1) @@ -2022,11 +1934,6 @@ TOK Lexer::number(Token *t) flags = (FLAGS) (flags & ~FLAGS_decimal); switch (c) { -#if ZEROH - case 'H': // 0h - case 'h': - goto hexh; -#endif case 'X': case 'x': state = STATE_hex0; @@ -2035,15 +1942,14 @@ TOK Lexer::number(Token *t) case '.': if (p[1] == '.') // .. is a separate token goto done; +#if DMDV2 + if (isalpha(p[1]) || p[1] == '_') + goto done; +#endif case 'i': case 'f': case 'F': goto real; -#if ZEROH - case 'E': - case 'e': - goto case_hex; -#endif case 'B': case 'b': state = STATE_binary0; @@ -2054,14 +1960,6 @@ TOK Lexer::number(Token *t) state = STATE_octal; break; -#if ZEROH - case '8': case '9': case 'A': - case 'C': case 'D': case 'F': - case 'a': case 'c': case 'd': case 'f': - case_hex: - state = STATE_hexh; - break; -#endif case '_': state = STATE_octal; p++; @@ -2080,12 +1978,6 @@ TOK Lexer::number(Token *t) case STATE_decimal: // reading decimal number if (!isdigit(c)) { -#if ZEROH - if (ishex(c) - || c == 'H' || c == 'h' - ) - goto hexh; -#endif if (c == '_') // ignore embedded _ { p++; continue; @@ -2130,41 +2022,10 @@ TOK Lexer::number(Token *t) state = STATE_hex; break; -#if ZEROH - hexh: - state = STATE_hexh; - case STATE_hexh: // parse numbers like 0FFh - if (!ishex(c)) - { - if (c == 'H' || c == 'h') - { - p++; - base = 16; - goto done; - } - else - { - // Check for something like 1E3 or 0E24 - if (memchr((char *)stringbuffer.data, 'E', stringbuffer.offset) || - memchr((char *)stringbuffer.data, 'e', stringbuffer.offset)) - goto real; - error("Hex digit expected, not '%c'", c); - goto done; - } - } - break; -#endif - case STATE_octal: // reading octal number case STATE_octale: // reading octal number with non-octal digits if (!isoctal(c)) { -#if ZEROH - if (ishex(c) - || c == 'H' || c == 'h' - ) - goto hexh; -#endif if (c == '_') // ignore embedded _ { p++; continue; @@ -2186,12 +2047,6 @@ TOK Lexer::number(Token *t) case STATE_binary: // reading binary number if (c != '0' && c != '1') { -#if ZEROH - if (ishex(c) - || c == 'H' || c == 'h' - ) - goto hexh; -#endif if (c == '_') // ignore embedded _ { p++; continue; @@ -2232,7 +2087,7 @@ done: // Convert string to integer #if __DMC__ errno = 0; - n = strtoull((char *)stringbuffer.data,NULL,base); + n = strtoull((char *)stringbuffer.data,NULL,0); if (errno == ERANGE) error("integer overflow"); #else @@ -2636,8 +2491,9 @@ void Lexer::poundLine() { p += 8; filespec = mem.strdup(loc.filename ? loc.filename : mod->ident->toChars()); + continue; } - continue; + goto Lerr; case '"': if (filespec) @@ -2920,7 +2776,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; @@ -3067,6 +2923,7 @@ static Keyword keywords[] = // Added after 1.0 { "__argTypes", TOKargTypes }, + { "__parameters", TOKparameters }, { "ref", TOKref }, { "macro", TOKmacro }, #if DMDV2 @@ -3111,7 +2968,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; diff --git a/dmd2/lexer.h b/dmd2/lexer.h index 848d7123..293c9538 100644 --- a/dmd2/lexer.h +++ b/dmd2/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 @@ -156,6 +156,7 @@ enum TOK TOKref, TOKmacro, #if DMDV2 + TOKparameters, TOKtraits, TOKoverloadset, TOKpure, @@ -311,7 +312,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 poundLine(); unsigned decodeUTF(); void getDocComment(Token *t, unsigned lineComment); diff --git a/dmd2/lib.h b/dmd2/lib.h index 3a67ed30..d63e1ace 100644 --- a/dmd2/lib.h +++ b/dmd2/lib.h @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2008 by Digital Mars +// Copyright (c) 1999-2012 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -15,53 +15,15 @@ #pragma once #endif /* __DMC__ */ -struct ObjModule; - -struct ObjSymbol +class Library { - char *name; - ObjModule *om; -}; + public: + static Library *factory(); -#include "arraytypes.h" - -typedef ArrayBase ObjModules; -typedef ArrayBase ObjSymbols; - -struct Library -{ - File *libfile; - ObjModules objmodules; // ObjModule[] - ObjSymbols objsymbols; // ObjSymbol[] - - StringTable tab; - - Library(); - void setFilename(char *dir, char *filename); - void addObject(const char *module_name, void *buf, size_t buflen); - void addLibrary(void *buf, size_t buflen); - void write(); - - private: - void addSymbol(ObjModule *om, char *name, int pickAny = 0); - void scanObjModule(ObjModule *om); - unsigned short numDictPages(unsigned padding); - int FillDict(unsigned char *bucketsP, unsigned short uNumPages); - void WriteLibToBuffer(OutBuffer *libbuf); - - void error(const char *format, ...) - { - Loc loc; - if (libfile) - { - loc.filename = libfile->name->toChars(); - loc.linnum = 0; - } - va_list ap; - va_start(ap, format); - ::verror(loc, format, ap); - va_end(ap); - } + virtual void setFilename(char *dir, char *filename) = 0; + virtual void addObject(const char *module_name, void *buf, size_t buflen) = 0; + virtual void addLibrary(void *buf, size_t buflen) = 0; + virtual void write() = 0; }; #endif /* DMD_LIB_H */ diff --git a/dmd2/mangle.c b/dmd2/mangle.c index fc97aa51..75c75b53 100644 --- a/dmd2/mangle.c +++ b/dmd2/mangle.c @@ -266,7 +266,7 @@ char *TemplateMixin::mangle() p += 2; buf.writestring(p); } - buf.printf("%zu%s", strlen(id), id); + buf.printf("%llu%s", (ulonglong)strlen(id), id); id = buf.toChars(); buf.data = NULL; //printf("TemplateMixin::mangle() %s = %s\n", toChars(), id); diff --git a/dmd2/mars.c b/dmd2/mars.c index d04b7024..607c2964 100644 --- a/dmd2/mars.c +++ b/dmd2/mars.c @@ -1,1634 +1,1640 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// https://github.com/D-Programming-Language/dmd/blob/master/src/mars.c -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include -#include -#include -#include -#include - -#if POSIX -#include -#endif - -#include "rmem.h" -#include "root.h" -#if !IN_LLVM -#include "async.h" -#endif - -#include "mars.h" -#include "module.h" -#include "mtype.h" -#include "id.h" -#include "cond.h" -#include "expression.h" -#include "lexer.h" -#if !IN_LLVM -#include "lib.h" -#include "json.h" -#endif - -#if WINDOWS_SEH -#include -long __cdecl __ehfilter(LPEXCEPTION_POINTERS ep); -#endif - -#if !IN_LLVM -int response_expand(int *pargc, char ***pargv); -void browse(const char *url); -void getenv_setargv(const char *envvar, int *pargc, char** *pargv); - -void obj_start(char *srcfile); -void obj_end(Library *library, File *objfile); -#endif - -void printCtfePerformanceStats(); - -Global global; - -Global::Global() -{ - mars_ext = "d"; - sym_ext = "d"; - hdr_ext = "di"; - doc_ext = "html"; - ddoc_ext = "ddoc"; - json_ext = "json"; - map_ext = "map"; - -#if IN_LLVM - ll_ext = "ll"; - bc_ext = "bc"; - s_ext = "s"; - obj_ext = "o"; - obj_ext_alt = "obj"; -#else -#if TARGET_WINDOS - obj_ext = "obj"; -#elif TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS - obj_ext = "o"; -#elif TARGET_NET -#else -#error "fix this" -#endif - -#if TARGET_WINDOS - lib_ext = "lib"; -#elif TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS - lib_ext = "a"; -#elif TARGET_NET -#else -#error "fix this" -#endif -#endif - - copyright = "Copyright (c) 1999-2012 by Digital Mars"; - written = "written by Walter Bright" -#if TARGET_NET - "\nMSIL back-end (alpha release) by Cristian L. Vlasceanu and associates."; -#endif - ; - version = "v2.059"; -#if IN_LLVM - ldc_version = "LDC trunk"; - llvm_version = "LLVM "LDC_LLVM_VERSION_STRING; -#endif - global.structalign = 8; - - // This should only be used as a global, so the other fields are - // automatically initialized to zero when the program is loaded. - // In particular, DO NOT zero-initialize .params here (like DMD - // does) because command-line options initialize some of those - // fields to non-zero defaults, and do so from constructors that - // may run before this one. -} - -unsigned Global::startGagging() -{ - ++gag; - return gaggedErrors; -} - -bool Global::endGagging(unsigned oldGagged) -{ - bool anyErrs = (gaggedErrors != oldGagged); - --gag; - // Restore the original state of gagged errors; set total errors - // to be original errors + new ungagged errors. - errors -= (gaggedErrors - oldGagged); - gaggedErrors = oldGagged; - return anyErrs; -} - -bool Global::isSpeculativeGagging() -{ - return gag && gag == speculativeGag; -} - - -char *Loc::toChars() -{ - OutBuffer buf; - - if (filename) - { - buf.printf("%s", filename); - } - - if (linnum) - buf.printf("(%d)", linnum); - buf.writeByte(0); - return (char *)buf.extractData(); -} - -Loc::Loc(Module *mod, unsigned linnum) -{ - this->linnum = linnum; - this->filename = mod ? mod->srcfile->toChars() : NULL; -} - -bool Loc::equals(const Loc& loc) -{ - return linnum == loc.linnum && FileName::equals(filename, loc.filename); -} - -/************************************** - * Print error message - */ - -void error(Loc loc, const char *format, ...) -{ - va_list ap; - va_start(ap, format); - verror(loc, format, ap); - va_end( ap ); -} - -void warning(Loc loc, const char *format, ...) -{ - va_list ap; - va_start(ap, format); - vwarning(loc, format, ap); - va_end( ap ); -} - -/************************************** - * Print supplementary message about the last error - * Used for backtraces, etc - */ -void errorSupplemental(Loc loc, const char *format, ...) -{ - va_list ap; - va_start(ap, format); - verrorSupplemental(loc, format, ap); - va_end( ap ); -} - -void verror(Loc loc, const char *format, va_list ap) -{ - if (!global.gag) - { - char *p = loc.toChars(); - - if (*p) - fprintf(stdmsg, "%s: ", p); - mem.free(p); - - fprintf(stdmsg, "Error: "); - // MS doesn't recognize %zu format - OutBuffer tmp; - tmp.vprintf(format, ap); -#if _MSC_VER - fprintf(stdmsg, "%s", tmp.toChars()); -#else - vfprintf(stdmsg, format, ap); -#endif - fprintf(stdmsg, "\n"); - fflush(stdmsg); -//halt(); - } - else - { - global.gaggedErrors++; - } - global.errors++; -} - -// Doesn't increase error count, doesn't print "Error:". -void verrorSupplemental(Loc loc, const char *format, va_list ap) -{ - if (!global.gag) - { - fprintf(stdmsg, "%s: ", loc.toChars()); -#if _MSC_VER - // MS doesn't recognize %zu format - OutBuffer tmp; - tmp.vprintf(format, ap); - fprintf(stdmsg, "%s", tmp.toChars()); -#else - vfprintf(stdmsg, format, ap); -#endif - fprintf(stdmsg, "\n"); - fflush(stdmsg); - } -} - -void vwarning(Loc loc, const char *format, va_list ap) -{ - if (global.params.warnings && !global.gag) - { - char *p = loc.toChars(); - - if (*p) - fprintf(stdmsg, "%s: ", p); - mem.free(p); - - fprintf(stdmsg, "Warning: "); -#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); -//halt(); - if (global.params.warnings == 1) - global.warnings++; // warnings don't count if gagged - } -} - -/*************************************** - * Call this after printing out fatal error messages to clean up and exit - * the compiler. - */ - -void fatal() -{ -#if 0 - halt(); -#endif - exit(EXIT_FAILURE); -} - -/************************************** - * Try to stop forgetting to remove the breakpoints from - * release builds. - */ -void halt() -{ -#ifdef DEBUG - *(volatile char*)0=0; -#endif -} - -#if !IN_LLVM - -extern void backend_init(); -extern void backend_term(); - -void usage() -{ -#if TARGET_LINUX - const char fpic[] ="\ - -fPIC generate position independent code\n\ -"; -#else - const char fpic[] = ""; -#endif - printf("DMD%s D Compiler %s\n%s %s\n", - sizeof(size_t) == 4 ? "32" : "64", - global.version, global.copyright, global.written); - printf("\ -Documentation: http://www.dlang.org/index.html\n\ -Usage:\n\ - dmd files.d ... { -switch }\n\ -\n\ - files.d D source files\n\ - @cmdfile read arguments from cmdfile\n\ - -c do not link\n\ - -cov do code coverage analysis\n\ - -D generate documentation\n\ - -Dddocdir write documentation file to docdir directory\n\ - -Dffilename write documentation file to filename\n\ - -d allow deprecated features\n\ - -debug compile in debug code\n\ - -debug=level compile in debug code <= level\n\ - -debug=ident compile in debug code identified by ident\n\ - -debuglib=name set symbolic debug library to name\n\ - -defaultlib=name set default library to name\n\ - -deps=filename write module dependencies to filename\n%s" -" -g add symbolic debug info\n\ - -gc add symbolic debug info, pretend to be C\n\ - -gs always emit stack frame\n\ - -H generate 'header' file\n\ - -Hddirectory write 'header' file to directory\n\ - -Hffilename write 'header' file to filename\n\ - --help print help\n\ - -Ipath where to look for imports\n\ - -ignore ignore unsupported pragmas\n\ - -inline do function inlining\n\ - -Jpath where to look for string imports\n\ - -Llinkerflag pass linkerflag to link\n\ - -lib generate library rather than object files\n" -#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS -" -m32 generate 32 bit code\n\ - -m64 generate 64 bit code\n" -#endif -" -man open web browser on manual page\n\ - -map generate linker .map file\n\ - -noboundscheck turns off array bounds checking for all functions\n\ - -nofloat do not emit reference to floating point\n\ - -O optimize\n\ - -o- do not write object file\n\ - -odobjdir write object & library files to directory objdir\n\ - -offilename name output file to filename\n\ - -op do not strip paths from source file\n\ - -profile profile runtime performance of generated code\n\ - -property enforce property syntax\n\ - -quiet suppress unnecessary messages\n\ - -release compile release version\n\ - -run srcfile args... run resulting program, passing args\n" -#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS -" -shared generate shared library\n" -#endif -" -unittest compile in unit tests\n\ - -v verbose\n\ - -version=level compile in version code >= level\n\ - -version=ident compile in version code identified by ident\n\ - -vtls list all variables going into thread local storage\n\ - -w enable warnings\n\ - -wi enable informational warnings\n\ - -X generate JSON file\n\ - -Xffilename write JSON file to filename\n\ -", fpic); -} - -extern signed char tyalignsize[]; - -#if _WIN32 && __DMC__ -extern "C" -{ - extern int _xi_a; - extern int _end; -} -#endif - -int tryMain(int argc, char *argv[]) -{ - mem.init(); // initialize storage allocator - mem.setStackBottom(&argv); -#if _WIN32 && __DMC__ - mem.addroots((char *)&_xi_a, (char *)&_end); -#endif - - Strings files; - Strings libmodules; - char *p; - Module *m; - int status = EXIT_SUCCESS; - int argcstart = argc; - int setdebuglib = 0; - char noboundscheck = 0; - const char *inifilename = NULL; - -#ifdef DEBUG - printf("DMD %s DEBUG\n", global.version); -#endif - - unittests(); - - // Check for malformed input - if (argc < 1 || !argv) - { - Largs: - error(0, "missing or null command line arguments"); - fatal(); - } - for (size_t i = 0; i < argc; i++) - { - if (!argv[i]) - goto Largs; - } - - if (response_expand(&argc,&argv)) // expand response files - error(0, "can't open response file"); - - files.reserve(argc - 1); - - // Set default values - global.params.argv0 = argv[0]; - global.params.link = 1; - global.params.useAssert = 1; - global.params.useInvariants = 1; - global.params.useIn = 1; - global.params.useOut = 1; - global.params.useArrayBounds = 2; // default to all functions - global.params.useSwitchError = 1; - global.params.useInline = 0; - global.params.obj = 1; - global.params.Dversion = 2; - global.params.quiet = 1; - - global.params.linkswitches = new Strings(); - global.params.libfiles = new Strings(); - global.params.objfiles = new Strings(); - global.params.ddocfiles = new Strings(); - - // Default to -m32 for 32 bit dmd, -m64 for 64 bit dmd - global.params.is64bit = (sizeof(size_t) == 8); - -#if TARGET_WINDOS - global.params.is64bit = 0; - global.params.defaultlibname = "phobos"; -#elif TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS - global.params.defaultlibname = "phobos2"; -#elif TARGET_NET -#else -#error "fix this" -#endif - - // Predefine version identifiers - VersionCondition::addPredefinedGlobalIdent("DigitalMars"); - -#if TARGET_WINDOS - VersionCondition::addPredefinedGlobalIdent("Windows"); - global.params.isWindows = 1; -#if TARGET_NET - // TARGET_NET macro is NOT mutually-exclusive with TARGET_WINDOS - VersionCondition::addPredefinedGlobalIdent("D_NET"); -#endif -#elif TARGET_LINUX - VersionCondition::addPredefinedGlobalIdent("Posix"); - VersionCondition::addPredefinedGlobalIdent("linux"); - global.params.isLinux = 1; -#elif TARGET_OSX - VersionCondition::addPredefinedGlobalIdent("Posix"); - VersionCondition::addPredefinedGlobalIdent("OSX"); - global.params.isOSX = 1; - - // For legacy compatibility - VersionCondition::addPredefinedGlobalIdent("darwin"); -#elif TARGET_FREEBSD - VersionCondition::addPredefinedGlobalIdent("Posix"); - VersionCondition::addPredefinedGlobalIdent("FreeBSD"); - global.params.isFreeBSD = 1; -#elif TARGET_OPENBSD - VersionCondition::addPredefinedGlobalIdent("Posix"); - VersionCondition::addPredefinedGlobalIdent("OpenBSD"); - global.params.isFreeBSD = 1; -#elif TARGET_SOLARIS - VersionCondition::addPredefinedGlobalIdent("Posix"); - VersionCondition::addPredefinedGlobalIdent("Solaris"); - global.params.isSolaris = 1; -#else -#error "fix this" -#endif - - VersionCondition::addPredefinedGlobalIdent("LittleEndian"); - //VersionCondition::addPredefinedGlobalIdent("D_Bits"); -#if DMDV2 - VersionCondition::addPredefinedGlobalIdent("D_Version2"); -#endif - VersionCondition::addPredefinedGlobalIdent("all"); - -#if _WIN32 - inifilename = inifile(argv[0], "sc.ini"); -#elif linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4 - inifilename = inifile(argv[0], "dmd.conf"); -#else -#error "fix this" -#endif - getenv_setargv("DFLAGS", &argc, &argv); - -#if 0 - for (size_t i = 0; i < argc; i++) - { - printf("argv[%d] = '%s'\n", i, argv[i]); - } -#endif - - for (size_t i = 1; i < argc; i++) - { - p = argv[i]; - if (*p == '-') - { - if (strcmp(p + 1, "d") == 0) - global.params.useDeprecated = 1; - else if (strcmp(p + 1, "c") == 0) - global.params.link = 0; - else if (strcmp(p + 1, "cov") == 0) - global.params.cov = 1; -#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS - else if (strcmp(p + 1, "shared") == 0 -#if TARGET_OSX - // backwards compatibility with old switch - || strcmp(p + 1, "dylib") == 0 -#endif - ) - global.params.dll = 1; - else if (strcmp(p + 1, "fPIC") == 0) - global.params.pic = 1; -#endif - else if (strcmp(p + 1, "map") == 0) - global.params.map = 1; - else if (strcmp(p + 1, "multiobj") == 0) - global.params.multiobj = 1; - else if (strcmp(p + 1, "g") == 0) - global.params.symdebug = 1; - else if (strcmp(p + 1, "gc") == 0) - global.params.symdebug = 2; - else if (strcmp(p + 1, "gs") == 0) - global.params.alwaysframe = 1; - else if (strcmp(p + 1, "gt") == 0) - { error(0, "use -profile instead of -gt\n"); - global.params.trace = 1; - } - else if (strcmp(p + 1, "m32") == 0) - global.params.is64bit = 0; - else if (strcmp(p + 1, "m64") == 0) - global.params.is64bit = 1; - else if (strcmp(p + 1, "profile") == 0) - global.params.trace = 1; - else if (strcmp(p + 1, "v") == 0) - global.params.verbose = 1; -#if DMDV2 - else if (strcmp(p + 1, "vtls") == 0) - global.params.vtls = 1; -#endif - else if (strcmp(p + 1, "v1") == 0) - { -#if DMDV1 - global.params.Dversion = 1; -#else - error(0, "use DMD 1.0 series compilers for -v1 switch"); - break; -#endif - } - else if (strcmp(p + 1, "w") == 0) - global.params.warnings = 1; - else if (strcmp(p + 1, "wi") == 0) - global.params.warnings = 2; - else if (strcmp(p + 1, "O") == 0) - global.params.optimize = 1; - else if (p[1] == 'o') - { - switch (p[2]) - { - case '-': - global.params.obj = 0; - break; - - case 'd': - if (!p[3]) - goto Lnoarg; - global.params.objdir = p + 3; - break; - - case 'f': - if (!p[3]) - goto Lnoarg; - global.params.objname = p + 3; - break; - - case 'p': - if (p[3]) - goto Lerror; - global.params.preservePaths = 1; - break; - - case 0: - error(0, "-o no longer supported, use -of or -od"); - break; - - default: - goto Lerror; - } - } - else if (p[1] == 'D') - { global.params.doDocComments = 1; - switch (p[2]) - { - case 'd': - if (!p[3]) - goto Lnoarg; - global.params.docdir = p + 3; - break; - case 'f': - if (!p[3]) - goto Lnoarg; - global.params.docname = p + 3; - break; - - case 0: - break; - - default: - goto Lerror; - } - } - else if (p[1] == 'H') - { global.params.doHdrGeneration = 1; - switch (p[2]) - { - case 'd': - if (!p[3]) - goto Lnoarg; - global.params.hdrdir = p + 3; - break; - - case 'f': - if (!p[3]) - goto Lnoarg; - global.params.hdrname = p + 3; - break; - - case 0: - break; - - default: - goto Lerror; - } - } - else if (p[1] == 'X') - { global.params.doXGeneration = 1; - switch (p[2]) - { - case 'f': - if (!p[3]) - goto Lnoarg; - global.params.xfilename = p + 3; - break; - - case 0: - break; - - default: - goto Lerror; - } - } - else if (strcmp(p + 1, "ignore") == 0) - global.params.ignoreUnsupportedPragmas = 1; - else if (strcmp(p + 1, "property") == 0) - global.params.enforcePropertySyntax = 1; - else if (strcmp(p + 1, "inline") == 0) - global.params.useInline = 1; - else if (strcmp(p + 1, "lib") == 0) - global.params.lib = 1; - else if (strcmp(p + 1, "nofloat") == 0) - global.params.nofloat = 1; - else if (strcmp(p + 1, "quiet") == 0) - global.params.quiet = 1; - else if (strcmp(p + 1, "release") == 0) - global.params.release = 1; -#if DMDV2 - else if (strcmp(p + 1, "noboundscheck") == 0) - noboundscheck = 1; -#endif - else if (strcmp(p + 1, "unittest") == 0) - global.params.useUnitTests = 1; - else if (p[1] == 'I') - { - if (!global.params.imppath) - global.params.imppath = new Strings(); - global.params.imppath->push(p + 2); - } - else if (p[1] == 'J') - { - if (!global.params.fileImppath) - global.params.fileImppath = new Strings(); - global.params.fileImppath->push(p + 2); - } - else if (memcmp(p + 1, "debug", 5) == 0 && p[6] != 'l') - { - // Parse: - // -debug - // -debug=number - // -debug=identifier - if (p[6] == '=') - { - if (isdigit((unsigned char)p[7])) - { long level; - - errno = 0; - level = strtol(p + 7, &p, 10); - if (*p || errno || level > INT_MAX) - goto Lerror; - DebugCondition::setGlobalLevel((int)level); - } - else if (Lexer::isValidIdentifier(p + 7)) - DebugCondition::addGlobalIdent(p + 7); - else - goto Lerror; - } - else if (p[6]) - goto Lerror; - else - global.params.debuglevel = 1; - } - else if (memcmp(p + 1, "version", 5) == 0) - { - // Parse: - // -version=number - // -version=identifier - if (p[8] == '=') - { - if (isdigit((unsigned char)p[9])) - { long level; - - errno = 0; - level = strtol(p + 9, &p, 10); - if (*p || errno || level > INT_MAX) - goto Lerror; - VersionCondition::setGlobalLevel((int)level); - } - else if (Lexer::isValidIdentifier(p + 9)) - VersionCondition::addGlobalIdent(p + 9); - else - goto Lerror; - } - else - goto Lerror; - } - else if (strcmp(p + 1, "-b") == 0) - global.params.debugb = 1; - else if (strcmp(p + 1, "-c") == 0) - global.params.debugc = 1; - else if (strcmp(p + 1, "-f") == 0) - global.params.debugf = 1; - else if (strcmp(p + 1, "-help") == 0) - { usage(); - exit(EXIT_SUCCESS); - } - else if (strcmp(p + 1, "-r") == 0) - global.params.debugr = 1; - else if (strcmp(p + 1, "-x") == 0) - global.params.debugx = 1; - else if (strcmp(p + 1, "-y") == 0) - global.params.debugy = 1; - else if (p[1] == 'L') - { - global.params.linkswitches->push(p + 2); - } - else if (memcmp(p + 1, "defaultlib=", 11) == 0) - { - global.params.defaultlibname = p + 1 + 11; - } - else if (memcmp(p + 1, "debuglib=", 9) == 0) - { - setdebuglib = 1; - global.params.debuglibname = p + 1 + 9; - } - else if (memcmp(p + 1, "deps=", 5) == 0) - { - global.params.moduleDepsFile = p + 1 + 5; - if (!global.params.moduleDepsFile[0]) - goto Lnoarg; - global.params.moduleDeps = new OutBuffer; - } - else if (memcmp(p + 1, "man", 3) == 0) - { -#if _WIN32 -#if DMDV1 - browse("http://www.digitalmars.com/d/1.0/dmd-windows.html"); -#else - browse("http://www.dlang.org/dmd-windows.html"); -#endif -#endif -#if linux -#if DMDV1 - browse("http://www.digitalmars.com/d/1.0/dmd-linux.html"); -#else - browse("http://www.dlang.org/dmd-linux.html"); -#endif -#endif -#if __APPLE__ -#if DMDV1 - browse("http://www.digitalmars.com/d/1.0/dmd-osx.html"); -#else - browse("http://www.dlang.org/dmd-osx.html"); -#endif -#endif -#if __FreeBSD__ -#if DMDV1 - browse("http://www.digitalmars.com/d/1.0/dmd-freebsd.html"); -#else - browse("http://www.dlang.org/dmd-freebsd.html"); -#endif -#endif -#if __OpenBSD__ -#if DMDV1 - browse("http://www.digitalmars.com/d/1.0/dmd-openbsd.html"); -#else - browse("http://www.dlang.org/dmd-openbsd.html"); -#endif -#endif - exit(EXIT_SUCCESS); - } - else if (strcmp(p + 1, "run") == 0) - { global.params.run = 1; - global.params.runargs_length = ((i >= argcstart) ? argc : argcstart) - i - 1; - if (global.params.runargs_length) - { - files.push(argv[i + 1]); - global.params.runargs = &argv[i + 2]; - i += global.params.runargs_length; - global.params.runargs_length--; - } - else - { global.params.run = 0; - goto Lnoarg; - } - } - else - { - Lerror: - error(0, "unrecognized switch '%s'", argv[i]); - continue; - - Lnoarg: - error(0, "argument expected for switch '%s'", argv[i]); - continue; - } - } - else - { -#if TARGET_WINDOS - char *ext = FileName::ext(p); - if (ext && FileName::compare(ext, "exe") == 0) - { - global.params.objname = p; - continue; - } -#endif - files.push(p); - } - } - if (global.errors) - { - fatal(); - } - if (files.dim == 0) - { usage(); - return EXIT_FAILURE; - } - - if (!setdebuglib) - global.params.debuglibname = global.params.defaultlibname; - -#if TARGET_OSX - global.params.pic = 1; -#endif - -#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS - if (global.params.lib && global.params.dll) - error(0, "cannot mix -lib and -shared\n"); -#endif - - if (global.params.release) - { global.params.useInvariants = 0; - global.params.useIn = 0; - global.params.useOut = 0; - global.params.useAssert = 0; - global.params.useArrayBounds = 1; - global.params.useSwitchError = 0; - } - if (noboundscheck) - global.params.useArrayBounds = 0; - - if (global.params.run) - global.params.quiet = 1; - - if (global.params.useUnitTests) - global.params.useAssert = 1; - - if (!global.params.obj || global.params.lib) - global.params.link = 0; - - if (global.params.link) - { - global.params.exefile = global.params.objname; - global.params.oneobj = 1; - if (global.params.objname) - { - /* Use this to name the one object file with the same - * name as the exe file. - */ - global.params.objname = FileName::forceExt(global.params.objname, global.obj_ext)->toChars(); - - /* If output directory is given, use that path rather than - * the exe file path. - */ - if (global.params.objdir) - { char *name = FileName::name(global.params.objname); - global.params.objname = FileName::combine(global.params.objdir, name); - } - } - } - else if (global.params.lib) - { - global.params.libname = global.params.objname; - global.params.objname = NULL; - - // Haven't investigated handling these options with multiobj - if (!global.params.cov && !global.params.trace -#if 0 && TARGET_WINDOS - /* multiobj causes class/struct debug info to be attached to init-data, - * but this will not be linked into the executable, so this info is lost. - * Bugzilla 4014 - */ - && !global.params.symdebug -#endif - ) - global.params.multiobj = 1; - } - else if (global.params.run) - { - error(0, "flags conflict with -run"); - fatal(); - } - else - { - if (global.params.objname && files.dim > 1) - { - global.params.oneobj = 1; - //error("multiple source files, but only one .obj name"); - //fatal(); - } - } - if (global.params.is64bit) - { - VersionCondition::addPredefinedGlobalIdent("D_InlineAsm_X86_64"); - VersionCondition::addPredefinedGlobalIdent("X86_64"); - VersionCondition::addPredefinedGlobalIdent("D_LP64"); - VersionCondition::addPredefinedGlobalIdent("D_SIMD"); -#if TARGET_WINDOS - VersionCondition::addPredefinedGlobalIdent("Win64"); -#endif - } - else - { - VersionCondition::addPredefinedGlobalIdent("D_InlineAsm"); - VersionCondition::addPredefinedGlobalIdent("D_InlineAsm_X86"); - VersionCondition::addPredefinedGlobalIdent("X86"); -#if TARGET_OSX - VersionCondition::addPredefinedGlobalIdent("D_SIMD"); -#endif -#if TARGET_WINDOS - VersionCondition::addPredefinedGlobalIdent("Win32"); -#endif - } - if (global.params.doDocComments) - VersionCondition::addPredefinedGlobalIdent("D_Ddoc"); - if (global.params.cov) - VersionCondition::addPredefinedGlobalIdent("D_Coverage"); - if (global.params.pic) - VersionCondition::addPredefinedGlobalIdent("D_PIC"); -#if DMDV2 - if (global.params.useUnitTests) - VersionCondition::addPredefinedGlobalIdent("unittest"); -#endif - - // Initialization - Type::init(); - Id::initialize(); - Module::init(); - initPrecedence(); - - if (global.params.verbose) - { printf("binary %s\n", argv[0]); - printf("version %s\n", global.version); - printf("config %s\n", inifilename ? inifilename : "(none)"); - } - - //printf("%d source files\n",files.dim); - - // Build import search path - if (global.params.imppath) - { - for (size_t i = 0; i < global.params.imppath->dim; i++) - { - char *path = (*global.params.imppath)[i]; - Strings *a = FileName::splitPath(path); - - if (a) - { - if (!global.path) - global.path = new Strings(); - global.path->append(a); - } - } - } - - // Build string import search path - if (global.params.fileImppath) - { - for (size_t i = 0; i < global.params.fileImppath->dim; i++) - { - char *path = global.params.fileImppath->tdata()[i]; - Strings *a = FileName::splitPath(path); - - if (a) - { - if (!global.filePath) - global.filePath = new Strings(); - global.filePath->append(a); - } - } - } - - // Create Modules - Modules modules; - modules.reserve(files.dim); - int firstmodule = 1; - for (size_t i = 0; i < files.dim; i++) - { - char *ext; - char *name; - - p = files.tdata()[i]; - -#if _WIN32 - // Convert / to \ so linker will work - for (size_t j = 0; p[j]; j++) - { - if (p[j] == '/') - p[j] = '\\'; - } -#endif - - p = FileName::name(p); // strip path - ext = FileName::ext(p); - if (ext) - { /* Deduce what to do with a file based on its extension - */ - if (FileName::equals(ext, global.obj_ext)) - { - global.params.objfiles->push(files.tdata()[i]); - libmodules.push(files.tdata()[i]); - continue; - } - - if (FileName::equals(ext, global.lib_ext)) - { - global.params.libfiles->push(files.tdata()[i]); - libmodules.push(files.tdata()[i]); - continue; - } - - if (strcmp(ext, global.ddoc_ext) == 0) - { - global.params.ddocfiles->push(files.tdata()[i]); - continue; - } - - if (FileName::equals(ext, global.json_ext)) - { - global.params.doXGeneration = 1; - global.params.xfilename = files.tdata()[i]; - continue; - } - - if (FileName::equals(ext, global.map_ext)) - { - global.params.mapfile = files.tdata()[i]; - continue; - } - -#if TARGET_WINDOS - if (FileName::equals(ext, "res")) - { - global.params.resfile = files.tdata()[i]; - continue; - } - - if (FileName::equals(ext, "def")) - { - global.params.deffile = files.tdata()[i]; - continue; - } - - if (FileName::equals(ext, "exe")) - { - assert(0); // should have already been handled - } -#endif - - /* Examine extension to see if it is a valid - * D source file extension - */ - if (FileName::equals(ext, global.mars_ext) || - FileName::equals(ext, global.hdr_ext) || - FileName::equals(ext, "dd") || - FileName::equals(ext, "htm") || - FileName::equals(ext, "html") || - FileName::equals(ext, "xhtml")) - { - ext--; // skip onto '.' - assert(*ext == '.'); - name = (char *)mem.malloc((ext - p) + 1); - memcpy(name, p, ext - p); - name[ext - p] = 0; // strip extension - - if (name[0] == 0 || - strcmp(name, "..") == 0 || - strcmp(name, ".") == 0) - { - Linvalid: - error(0, "invalid file name '%s'", files.tdata()[i]); - fatal(); - } - } - else - { error(0, "unrecognized file extension %s\n", ext); - fatal(); - } - } - else - { name = p; - if (!*name) - goto Linvalid; - } - - /* At this point, name is the D source file name stripped of - * its path and extension. - */ - - Identifier *id = Lexer::idPool(name); - m = new Module(files[i], id, global.params.doDocComments, global.params.doHdrGeneration); - modules.push(m); - - if (firstmodule) - { global.params.objfiles->push(m->objfile->name->str); - firstmodule = 0; - } - } - - // Read files -#define ASYNCREAD 1 -#if ASYNCREAD - // Multi threaded - AsyncRead *aw = AsyncRead::create(modules.dim); - for (size_t i = 0; i < modules.dim; i++) - { - m = modules[i]; - aw->addFile(m->srcfile); - } - aw->start(); -#else - // Single threaded - for (size_t i = 0; i < modules.dim; i++) - { - m = modules[i]; - m->read(0); - } -#endif - - // Parse files - bool anydocfiles = false; - size_t filecount = modules.dim; - for (size_t filei = 0, modi = 0; filei < filecount; filei++, modi++) - { - m = modules[modi]; - if (global.params.verbose) - printf("parse %s\n", m->toChars()); - if (!Module::rootModule) - Module::rootModule = m; - m->importedFrom = m; - if (!global.params.oneobj || modi == 0 || m->isDocFile) - m->deleteObjFile(); -#if ASYNCREAD - if (aw->read(filei)) - { - error(0, "cannot read file %s", m->srcfile->name->toChars()); - fatal(); - } -#endif - m->parse(); - if (m->isDocFile) - { - anydocfiles = true; - m->gendocfile(); - - // Remove m from list of modules - modules.remove(modi); - modi--; - - // Remove m's object file from list of object files - for (size_t j = 0; j < global.params.objfiles->dim; j++) - { - if (m->objfile->name->str == global.params.objfiles->tdata()[j]) - { - global.params.objfiles->remove(j); - break; - } - } - - if (global.params.objfiles->dim == 0) - global.params.link = 0; - } - } -#if ASYNCREAD - AsyncRead::dispose(aw); -#endif - - if (anydocfiles && modules.dim && - (global.params.oneobj || global.params.objname)) - { - error(0, "conflicting Ddoc and obj generation options"); - fatal(); - } - if (global.errors) - fatal(); - if (global.params.doHdrGeneration) - { - /* Generate 'header' import files. - * Since 'header' import files must be independent of command - * line switches and what else is imported, they are generated - * before any semantic analysis. - */ - for (size_t i = 0; i < modules.dim; i++) - { - m = modules[i]; - if (global.params.verbose) - printf("import %s\n", m->toChars()); - m->genhdrfile(); - } - } - if (global.errors) - fatal(); - - // load all unconditional imports for better symbol resolving - for (size_t i = 0; i < modules.dim; i++) - { - m = modules[i]; - if (global.params.verbose) - printf("importall %s\n", m->toChars()); - m->importAll(0); - } - if (global.errors) - fatal(); - - backend_init(); - - // Do semantic analysis - for (size_t i = 0; i < modules.dim; i++) - { - m = modules[i]; - if (global.params.verbose) - printf("semantic %s\n", m->toChars()); - m->semantic(); - } - if (global.errors) - fatal(); - - Module::dprogress = 1; - Module::runDeferredSemantic(); - - // Do pass 2 semantic analysis - for (size_t i = 0; i < modules.dim; i++) - { - m = modules[i]; - if (global.params.verbose) - printf("semantic2 %s\n", m->toChars()); - m->semantic2(); - } - if (global.errors) - fatal(); - - // Do pass 3 semantic analysis - for (size_t i = 0; i < modules.dim; i++) - { - m = modules[i]; - if (global.params.verbose) - printf("semantic3 %s\n", m->toChars()); - m->semantic3(); - } - if (global.errors) - fatal(); - - if (global.params.moduleDeps != NULL) - { - assert(global.params.moduleDepsFile != NULL); - - File deps(global.params.moduleDepsFile); - OutBuffer* ob = global.params.moduleDeps; - deps.setbuffer((void*)ob->data, ob->offset); - deps.writev(); - } - - - // Scan for functions to inline - if (global.params.useInline) - { - /* The problem with useArrayBounds and useAssert is that the - * module being linked to may not have generated them, so if - * we inline functions from those modules, the symbols for them will - * not be found at link time. - */ - if (!global.params.useArrayBounds && !global.params.useAssert) - { - // Do pass 3 semantic analysis on all imported modules, - // since otherwise functions in them cannot be inlined - for (size_t i = 0; i < Module::amodules.dim; i++) - { - m = Module::amodules[i]; - if (global.params.verbose) - printf("semantic3 %s\n", m->toChars()); - m->semantic3(); - } - if (global.errors) - fatal(); - } - - for (size_t i = 0; i < modules.dim; i++) - { - m = modules[i]; - if (global.params.verbose) - printf("inline scan %s\n", m->toChars()); - m->inlineScan(); - } - } - - // Do not attempt to generate output files if errors or warnings occurred - if (global.errors || global.warnings) - fatal(); - - printCtfePerformanceStats(); - - Library *library = NULL; - if (global.params.lib) - { - library = new Library(); - library->setFilename(global.params.objdir, global.params.libname); - - // Add input object and input library files to output library - for (size_t i = 0; i < libmodules.dim; i++) - { - char *p = libmodules[i]; - library->addObject(p, NULL, 0); - } - } - - // Generate output files - - if (global.params.doXGeneration) - json_generate(&modules); - - if (global.params.oneobj) - { - for (size_t i = 0; i < modules.dim; i++) - { - m = modules[i]; - if (global.params.verbose) - printf("code %s\n", m->toChars()); - if (i == 0) - obj_start(m->srcfile->toChars()); - m->genobjfile(0); - if (!global.errors && global.params.doDocComments) - m->gendocfile(); - } - if (!global.errors && modules.dim) - { - obj_end(library, modules.tdata()[0]->objfile); - } - } - else - { - for (size_t i = 0; i < modules.dim; i++) - { - m = modules[i]; - if (global.params.verbose) - printf("code %s\n", m->toChars()); - if (global.params.obj) - { obj_start(m->srcfile->toChars()); - m->genobjfile(global.params.multiobj); - obj_end(library, m->objfile); - obj_write_deferred(library); - } - if (global.errors) - { - if (!global.params.lib) - m->deleteObjFile(); - } - else - { - if (global.params.doDocComments) - m->gendocfile(); - } - } - } - - if (global.params.lib && !global.errors) - library->write(); - - backend_term(); - if (global.errors) - fatal(); - - if (!global.params.objfiles->dim) - { - if (global.params.link) - error(0, "no object files to link"); - } - else - { - if (global.params.link) - status = runLINK(); - - if (global.params.run) - { - if (!status) - { - status = runProgram(); - - /* Delete .obj files and .exe file - */ - for (size_t i = 0; i < modules.dim; i++) - { - Module *m = modules[i]; - m->deleteObjFile(); - if (global.params.oneobj) - break; - } - deleteExeFile(); - } - } - } - - return status; -} - -int main(int argc, char *argv[]) -{ - int status = -1; -#if WINDOWS_SEH - __try - { -#endif - status = tryMain(argc, argv); -#if WINDOWS_SEH - } - __except (__ehfilter(GetExceptionInformation())) - { - printf("Stack overflow\n"); - fatal(); - } -#endif - return status; -} - -#endif // !IN_LLVM - -/*********************************** - * Parse and append contents of environment variable envvar - * to argc and argv[]. - * The string is separated into arguments, processing \ and ". - */ - -void getenv_setargv(const char *envvar, int *pargc, char** *pargv) -{ - char *p; - - int instring; - int slash; - char c; - - char *env = getenv(envvar); - if (!env) - return; - - env = mem.strdup(env); // create our own writable copy - - int argc = *pargc; - Strings *argv = new Strings(); - argv->setDim(argc); - - int argc_left = 0; - for (int i = 0; i < argc; i++) { - if (!strcmp((*pargv)[i], "-run") || !strcmp((*pargv)[i], "--run")) { - // HACK: set flag to indicate we saw '-run' here - global.params.run = true; - // Don't eat -run yet so the program arguments don't get changed - argc_left = argc - i; - argc = i; - *pargv = &(*pargv)[i]; - argv->setDim(i); - break; - } else { - } - } - // HACK to stop required values from command line being drawn from DFLAGS - argv->push((char*)""); - argc++; - - size_t j = 1; // leave argv[0] alone - while (1) - { - int wildcard = 1; // do wildcard expansion - switch (*env) - { - case ' ': - case '\t': - env++; - break; - - case 0: - goto Ldone; - - case '"': - wildcard = 0; - default: - argv->push(env); // append - //argv->insert(j, env); // insert at position j - j++; - argc++; - p = env; - slash = 0; - instring = 0; - c = 0; - - while (1) - { - c = *env++; - switch (c) - { - case '"': - p -= (slash >> 1); - if (slash & 1) - { p--; - goto Laddc; - } - instring ^= 1; - slash = 0; - continue; - - case ' ': - case '\t': - if (instring) - goto Laddc; - *p = 0; - //if (wildcard) - //wildcardexpand(); // not implemented - break; - - case '\\': - slash++; - *p++ = c; - continue; - - case 0: - *p = 0; - //if (wildcard) - //wildcardexpand(); // not implemented - goto Ldone; - - default: - Laddc: - slash = 0; - *p++ = c; - continue; - } - break; - } - } - } - -Ldone: - assert(argc == argv->dim); - argv->reserve(argc_left); - for (int i = 0; i < argc_left; i++) - argv->data[argc++] = (void *)(*pargv)[i]; - - *pargc = argc; - *pargv = argv->tdata(); -} - -#if WINDOWS_SEH - -long __cdecl __ehfilter(LPEXCEPTION_POINTERS ep) -{ - //printf("%x\n", ep->ExceptionRecord->ExceptionCode); - if (ep->ExceptionRecord->ExceptionCode == STATUS_STACK_OVERFLOW) - { -#if 1 //ndef DEBUG - return EXCEPTION_EXECUTE_HANDLER; -#endif - } - return EXCEPTION_CONTINUE_SEARCH; -} - -#endif + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2012 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// https://github.com/D-Programming-Language/dmd/blob/master/src/mars.c +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#include +#include +#include +#include +#include +#include +#include + +#if POSIX +#include +#endif + +#include "rmem.h" +#include "root.h" +#if !IN_LLVM +#include "async.h" +#endif + +#include "mars.h" +#include "module.h" +#include "mtype.h" +#include "id.h" +#include "cond.h" +#include "expression.h" +#include "lexer.h" +#if !IN_LLVM +#include "lib.h" +#include "json.h" +#endif + +#if WINDOWS_SEH +#include +long __cdecl __ehfilter(LPEXCEPTION_POINTERS ep); +#endif + +#if !IN_LLVM +int response_expand(int *pargc, char ***pargv); +void browse(const char *url); +void getenv_setargv(const char *envvar, int *pargc, char** *pargv); + +void obj_start(char *srcfile); +void obj_end(Library *library, File *objfile); +#endif + +void printCtfePerformanceStats(); + +Global global; + +Global::Global() +{ + mars_ext = "d"; + sym_ext = "d"; + hdr_ext = "di"; + doc_ext = "html"; + ddoc_ext = "ddoc"; + json_ext = "json"; + map_ext = "map"; + +#if IN_LLVM + ll_ext = "ll"; + bc_ext = "bc"; + s_ext = "s"; + obj_ext = "o"; + obj_ext_alt = "obj"; +#else +#if TARGET_WINDOS + obj_ext = "obj"; +#elif TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS + obj_ext = "o"; +#elif TARGET_NET +#else +#error "fix this" +#endif + +#if TARGET_WINDOS + lib_ext = "lib"; +#elif TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS + lib_ext = "a"; +#elif TARGET_NET +#else +#error "fix this" +#endif +#endif + + copyright = "Copyright (c) 1999-2012 by Digital Mars"; + written = "written by Walter Bright" +#if TARGET_NET + "\nMSIL back-end (alpha release) by Cristian L. Vlasceanu and associates."; +#endif + ; + version = "v2.060"; +#if IN_LLVM + ldc_version = "LDC trunk"; + llvm_version = "LLVM "LDC_LLVM_VERSION_STRING; +#endif + 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. + // In particular, DO NOT zero-initialize .params here (like DMD + // does) because command-line options initialize some of those + // fields to non-zero defaults, and do so from constructors that + // may run before this one. +} + +unsigned Global::startGagging() +{ + ++gag; + return gaggedErrors; +} + +bool Global::endGagging(unsigned oldGagged) +{ + bool anyErrs = (gaggedErrors != oldGagged); + --gag; + // Restore the original state of gagged errors; set total errors + // to be original errors + new ungagged errors. + errors -= (gaggedErrors - oldGagged); + gaggedErrors = oldGagged; + return anyErrs; +} + +bool Global::isSpeculativeGagging() +{ + return gag && gag == speculativeGag; +} + + +char *Loc::toChars() +{ + OutBuffer buf; + + if (filename) + { + buf.printf("%s", filename); + } + + if (linnum) + buf.printf("(%d)", linnum); + buf.writeByte(0); + return (char *)buf.extractData(); +} + +Loc::Loc(Module *mod, unsigned linnum) +{ + this->linnum = linnum; + this->filename = mod ? mod->srcfile->toChars() : NULL; +} + +bool Loc::equals(const Loc& loc) +{ + return linnum == loc.linnum && FileName::equals(filename, loc.filename); +} + +/************************************** + * Print error message + */ + +void error(Loc loc, const char *format, ...) +{ + va_list ap; + va_start(ap, format); + verror(loc, format, ap); + va_end( ap ); +} + +void warning(Loc loc, const char *format, ...) +{ + va_list ap; + va_start(ap, format); + vwarning(loc, format, ap); + va_end( ap ); +} + +/************************************** + * Print supplementary message about the last error + * Used for backtraces, etc + */ +void errorSupplemental(Loc loc, const char *format, ...) +{ + va_list ap; + va_start(ap, format); + verrorSupplemental(loc, format, ap); + va_end( ap ); +} + +void verror(Loc loc, const char *format, va_list ap, const char *p1, const char *p2) +{ + if (!global.gag) + { + char *p = loc.toChars(); + + if (*p) + fprintf(stdmsg, "%s: ", p); + 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 + { + global.gaggedErrors++; + } + global.errors++; +} + +// Doesn't increase error count, doesn't print "Error:". +void verrorSupplemental(Loc loc, const char *format, va_list ap) +{ + if (!global.gag) + { + fprintf(stdmsg, "%s: ", loc.toChars()); +#if _MSC_VER + // MS doesn't recognize %zu format + OutBuffer tmp; + tmp.vprintf(format, ap); + fprintf(stdmsg, "%s", tmp.toChars()); +#else + vfprintf(stdmsg, format, ap); +#endif + fprintf(stdmsg, "\n"); + fflush(stdmsg); + } +} + +void vwarning(Loc loc, const char *format, va_list ap) +{ + if (global.params.warnings && !global.gag) + { + char *p = loc.toChars(); + + if (*p) + fprintf(stdmsg, "%s: ", p); + mem.free(p); + + fprintf(stdmsg, "Warning: "); +#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); +//halt(); + if (global.params.warnings == 1) + global.warnings++; // warnings don't count if gagged + } +} + +/*************************************** + * Call this after printing out fatal error messages to clean up and exit + * the compiler. + */ + +void fatal() +{ +#if 0 + halt(); +#endif + exit(EXIT_FAILURE); +} + +/************************************** + * Try to stop forgetting to remove the breakpoints from + * release builds. + */ +void halt() +{ +#ifdef DEBUG + *(volatile char*)0=0; +#endif +} + +#if !IN_LLVM + +extern void backend_init(); +extern void backend_term(); + +void usage() +{ +#if TARGET_LINUX + const char fpic[] ="\ + -fPIC generate position independent code\n\ +"; +#else + const char fpic[] = ""; +#endif + printf("DMD%s D Compiler %s\n%s %s\n", + sizeof(size_t) == 4 ? "32" : "64", + global.version, global.copyright, global.written); + printf("\ +Documentation: http://www.dlang.org/index.html\n\ +Usage:\n\ + dmd files.d ... { -switch }\n\ +\n\ + files.d D source files\n\ + @cmdfile read arguments from cmdfile\n\ + -c do not link\n\ + -cov do code coverage analysis\n\ + -D generate documentation\n\ + -Dddocdir write documentation file to docdir directory\n\ + -Dffilename write documentation file to filename\n\ + -d allow deprecated features\n\ + -debug compile in debug code\n\ + -debug=level compile in debug code <= level\n\ + -debug=ident compile in debug code identified by ident\n\ + -debuglib=name set symbolic debug library to name\n\ + -defaultlib=name set default library to name\n\ + -deps=filename write module dependencies to filename\n%s" +" -g add symbolic debug info\n\ + -gc add symbolic debug info, pretend to be C\n\ + -gs always emit stack frame\n\ + -H generate 'header' file\n\ + -Hddirectory write 'header' file to directory\n\ + -Hffilename write 'header' file to filename\n\ + --help print help\n\ + -Ipath where to look for imports\n\ + -ignore ignore unsupported pragmas\n\ + -inline do function inlining\n\ + -Jpath where to look for string imports\n\ + -Llinkerflag pass linkerflag to link\n\ + -lib generate library rather than object files\n" +#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS +" -m32 generate 32 bit code\n\ + -m64 generate 64 bit code\n" +#endif +" -man open web browser on manual page\n\ + -map generate linker .map file\n\ + -noboundscheck turns off array bounds checking for all functions\n\ + -nofloat do not emit reference to floating point\n\ + -O optimize\n\ + -o- do not write object file\n\ + -odobjdir write object & library files to directory objdir\n\ + -offilename name output file to filename\n\ + -op do not strip paths from source file\n\ + -profile profile runtime performance of generated code\n\ + -property enforce property syntax\n\ + -quiet suppress unnecessary messages\n\ + -release compile release version\n\ + -run srcfile args... run resulting program, passing args\n" +#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS +" -shared generate shared library\n" +#endif +" -unittest compile in unit tests\n\ + -v verbose\n\ + -version=level compile in version code >= level\n\ + -version=ident compile in version code identified by ident\n\ + -vtls list all variables going into thread local storage\n\ + -w warnings as errors (compilation will halt)\n\ + -wi warnings as messages (compilation will continue)\n\ + -X generate JSON file\n\ + -Xffilename write JSON file to filename\n\ +", fpic); +} + +extern signed char tyalignsize[]; + +#if _WIN32 && __DMC__ +extern "C" +{ + extern int _xi_a; + extern int _end; +} +#endif + +int tryMain(int argc, char *argv[]) +{ + mem.init(); // initialize storage allocator + mem.setStackBottom(&argv); +#if _WIN32 && __DMC__ + mem.addroots((char *)&_xi_a, (char *)&_end); +#endif + + Strings files; + Strings libmodules; + char *p; + Module *m; + int status = EXIT_SUCCESS; + int argcstart = argc; + int setdebuglib = 0; + char noboundscheck = 0; + const char *inifilename = NULL; + +#ifdef DEBUG + printf("DMD %s DEBUG\n", global.version); +#endif + + unittests(); + + // Check for malformed input + if (argc < 1 || !argv) + { + Largs: + error(0, "missing or null command line arguments"); + fatal(); + } + for (size_t i = 0; i < argc; i++) + { + if (!argv[i]) + goto Largs; + } + + if (response_expand(&argc,&argv)) // expand response files + error(0, "can't open response file"); + + files.reserve(argc - 1); + + // Set default values + global.params.argv0 = argv[0]; + global.params.link = 1; + global.params.useAssert = 1; + global.params.useInvariants = 1; + global.params.useIn = 1; + global.params.useOut = 1; + global.params.useArrayBounds = 2; // default to all functions + global.params.useSwitchError = 1; + global.params.useInline = 0; + global.params.obj = 1; + global.params.Dversion = 2; + global.params.quiet = 1; + + global.params.linkswitches = new Strings(); + global.params.libfiles = new Strings(); + global.params.objfiles = new Strings(); + global.params.ddocfiles = new Strings(); + + // Default to -m32 for 32 bit dmd, -m64 for 64 bit dmd + global.params.is64bit = (sizeof(size_t) == 8); + +#if TARGET_WINDOS + global.params.is64bit = 0; + global.params.defaultlibname = "phobos"; +#elif TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS + global.params.defaultlibname = "phobos2"; +#elif TARGET_NET +#else +#error "fix this" +#endif + + // Predefine version identifiers + VersionCondition::addPredefinedGlobalIdent("DigitalMars"); + +#if TARGET_WINDOS + VersionCondition::addPredefinedGlobalIdent("Windows"); + global.params.isWindows = 1; +#if TARGET_NET + // TARGET_NET macro is NOT mutually-exclusive with TARGET_WINDOS + VersionCondition::addPredefinedGlobalIdent("D_NET"); +#endif +#elif TARGET_LINUX + VersionCondition::addPredefinedGlobalIdent("Posix"); + VersionCondition::addPredefinedGlobalIdent("linux"); + global.params.isLinux = 1; +#elif TARGET_OSX + VersionCondition::addPredefinedGlobalIdent("Posix"); + VersionCondition::addPredefinedGlobalIdent("OSX"); + global.params.isOSX = 1; + + // For legacy compatibility + VersionCondition::addPredefinedGlobalIdent("darwin"); +#elif TARGET_FREEBSD + VersionCondition::addPredefinedGlobalIdent("Posix"); + VersionCondition::addPredefinedGlobalIdent("FreeBSD"); + global.params.isFreeBSD = 1; +#elif TARGET_OPENBSD + VersionCondition::addPredefinedGlobalIdent("Posix"); + VersionCondition::addPredefinedGlobalIdent("OpenBSD"); + global.params.isFreeBSD = 1; +#elif TARGET_SOLARIS + VersionCondition::addPredefinedGlobalIdent("Posix"); + VersionCondition::addPredefinedGlobalIdent("Solaris"); + global.params.isSolaris = 1; +#else +#error "fix this" +#endif + + VersionCondition::addPredefinedGlobalIdent("LittleEndian"); + //VersionCondition::addPredefinedGlobalIdent("D_Bits"); +#if DMDV2 + VersionCondition::addPredefinedGlobalIdent("D_Version2"); +#endif + VersionCondition::addPredefinedGlobalIdent("all"); + +#if _WIN32 + inifilename = inifile(argv[0], "sc.ini"); +#elif linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4 + inifilename = inifile(argv[0], "dmd.conf"); +#else +#error "fix this" +#endif + getenv_setargv("DFLAGS", &argc, &argv); + +#if 0 + for (size_t i = 0; i < argc; i++) + { + printf("argv[%d] = '%s'\n", i, argv[i]); + } +#endif + + for (size_t i = 1; i < argc; i++) + { + p = argv[i]; + if (*p == '-') + { + if (strcmp(p + 1, "d") == 0) + global.params.useDeprecated = 1; + else if (strcmp(p + 1, "c") == 0) + global.params.link = 0; + else if (strcmp(p + 1, "cov") == 0) + global.params.cov = 1; +#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS + else if (strcmp(p + 1, "shared") == 0 +#if TARGET_OSX + // backwards compatibility with old switch + || strcmp(p + 1, "dylib") == 0 +#endif + ) + global.params.dll = 1; + else if (strcmp(p + 1, "fPIC") == 0) + global.params.pic = 1; +#endif + else if (strcmp(p + 1, "map") == 0) + global.params.map = 1; + else if (strcmp(p + 1, "multiobj") == 0) + global.params.multiobj = 1; + else if (strcmp(p + 1, "g") == 0) + global.params.symdebug = 1; + else if (strcmp(p + 1, "gc") == 0) + global.params.symdebug = 2; + else if (strcmp(p + 1, "gs") == 0) + global.params.alwaysframe = 1; + else if (strcmp(p + 1, "gt") == 0) + { error(0, "use -profile instead of -gt\n"); + global.params.trace = 1; + } + else if (strcmp(p + 1, "m32") == 0) + global.params.is64bit = 0; + else if (strcmp(p + 1, "m64") == 0) + global.params.is64bit = 1; + else if (strcmp(p + 1, "profile") == 0) + global.params.trace = 1; + else if (strcmp(p + 1, "v") == 0) + global.params.verbose = 1; +#if DMDV2 + else if (strcmp(p + 1, "vtls") == 0) + global.params.vtls = 1; +#endif + else if (strcmp(p + 1, "v1") == 0) + { +#if DMDV1 + global.params.Dversion = 1; +#else + error(0, "use DMD 1.0 series compilers for -v1 switch"); + break; +#endif + } + else if (strcmp(p + 1, "w") == 0) + global.params.warnings = 1; + else if (strcmp(p + 1, "wi") == 0) + global.params.warnings = 2; + else if (strcmp(p + 1, "O") == 0) + global.params.optimize = 1; + else if (p[1] == 'o') + { + switch (p[2]) + { + case '-': + global.params.obj = 0; + break; + + case 'd': + if (!p[3]) + goto Lnoarg; + global.params.objdir = p + 3; + break; + + case 'f': + if (!p[3]) + goto Lnoarg; + global.params.objname = p + 3; + break; + + case 'p': + if (p[3]) + goto Lerror; + global.params.preservePaths = 1; + break; + + case 0: + error(0, "-o no longer supported, use -of or -od"); + break; + + default: + goto Lerror; + } + } + else if (p[1] == 'D') + { global.params.doDocComments = 1; + switch (p[2]) + { + case 'd': + if (!p[3]) + goto Lnoarg; + global.params.docdir = p + 3; + break; + case 'f': + if (!p[3]) + goto Lnoarg; + global.params.docname = p + 3; + break; + + case 0: + break; + + default: + goto Lerror; + } + } + else if (p[1] == 'H') + { global.params.doHdrGeneration = 1; + switch (p[2]) + { + case 'd': + if (!p[3]) + goto Lnoarg; + global.params.hdrdir = p + 3; + break; + + case 'f': + if (!p[3]) + goto Lnoarg; + global.params.hdrname = p + 3; + break; + + case 0: + break; + + default: + goto Lerror; + } + } + else if (p[1] == 'X') + { global.params.doXGeneration = 1; + switch (p[2]) + { + case 'f': + if (!p[3]) + goto Lnoarg; + global.params.xfilename = p + 3; + break; + + case 0: + break; + + default: + goto Lerror; + } + } + else if (strcmp(p + 1, "ignore") == 0) + global.params.ignoreUnsupportedPragmas = 1; + else if (strcmp(p + 1, "property") == 0) + global.params.enforcePropertySyntax = 1; + else if (strcmp(p + 1, "inline") == 0) + global.params.useInline = 1; + else if (strcmp(p + 1, "lib") == 0) + global.params.lib = 1; + else if (strcmp(p + 1, "nofloat") == 0) + global.params.nofloat = 1; + else if (strcmp(p + 1, "quiet") == 0) + global.params.quiet = 1; + else if (strcmp(p + 1, "release") == 0) + global.params.release = 1; +#if DMDV2 + else if (strcmp(p + 1, "noboundscheck") == 0) + noboundscheck = 1; +#endif + else if (strcmp(p + 1, "unittest") == 0) + global.params.useUnitTests = 1; + else if (p[1] == 'I') + { + if (!global.params.imppath) + global.params.imppath = new Strings(); + global.params.imppath->push(p + 2); + } + else if (p[1] == 'J') + { + if (!global.params.fileImppath) + global.params.fileImppath = new Strings(); + global.params.fileImppath->push(p + 2); + } + else if (memcmp(p + 1, "debug", 5) == 0 && p[6] != 'l') + { + // Parse: + // -debug + // -debug=number + // -debug=identifier + if (p[6] == '=') + { + if (isdigit((unsigned char)p[7])) + { long level; + + errno = 0; + level = strtol(p + 7, &p, 10); + if (*p || errno || level > INT_MAX) + goto Lerror; + DebugCondition::setGlobalLevel((int)level); + } + else if (Lexer::isValidIdentifier(p + 7)) + DebugCondition::addGlobalIdent(p + 7); + else + goto Lerror; + } + else if (p[6]) + goto Lerror; + else + global.params.debuglevel = 1; + } + else if (memcmp(p + 1, "version", 5) == 0) + { + // Parse: + // -version=number + // -version=identifier + if (p[8] == '=') + { + if (isdigit((unsigned char)p[9])) + { long level; + + errno = 0; + level = strtol(p + 9, &p, 10); + if (*p || errno || level > INT_MAX) + goto Lerror; + VersionCondition::setGlobalLevel((int)level); + } + else if (Lexer::isValidIdentifier(p + 9)) + VersionCondition::addGlobalIdent(p + 9); + else + goto Lerror; + } + else + goto Lerror; + } + else if (strcmp(p + 1, "-b") == 0) + global.params.debugb = 1; + else if (strcmp(p + 1, "-c") == 0) + global.params.debugc = 1; + else if (strcmp(p + 1, "-f") == 0) + global.params.debugf = 1; + else if (strcmp(p + 1, "-help") == 0) + { usage(); + exit(EXIT_SUCCESS); + } + else if (strcmp(p + 1, "-r") == 0) + global.params.debugr = 1; + else if (strcmp(p + 1, "-x") == 0) + global.params.debugx = 1; + else if (strcmp(p + 1, "-y") == 0) + global.params.debugy = 1; + else if (p[1] == 'L') + { + global.params.linkswitches->push(p + 2); + } + else if (memcmp(p + 1, "defaultlib=", 11) == 0) + { + global.params.defaultlibname = p + 1 + 11; + } + else if (memcmp(p + 1, "debuglib=", 9) == 0) + { + setdebuglib = 1; + global.params.debuglibname = p + 1 + 9; + } + else if (memcmp(p + 1, "deps=", 5) == 0) + { + global.params.moduleDepsFile = p + 1 + 5; + if (!global.params.moduleDepsFile[0]) + goto Lnoarg; + global.params.moduleDeps = new OutBuffer; + } + else if (memcmp(p + 1, "man", 3) == 0) + { +#if _WIN32 +#if DMDV1 + browse("http://www.digitalmars.com/d/1.0/dmd-windows.html"); +#else + browse("http://www.dlang.org/dmd-windows.html"); +#endif +#endif +#if linux +#if DMDV1 + browse("http://www.digitalmars.com/d/1.0/dmd-linux.html"); +#else + browse("http://www.dlang.org/dmd-linux.html"); +#endif +#endif +#if __APPLE__ +#if DMDV1 + browse("http://www.digitalmars.com/d/1.0/dmd-osx.html"); +#else + browse("http://www.dlang.org/dmd-osx.html"); +#endif +#endif +#if __FreeBSD__ +#if DMDV1 + browse("http://www.digitalmars.com/d/1.0/dmd-freebsd.html"); +#else + browse("http://www.dlang.org/dmd-freebsd.html"); +#endif +#endif +#if __OpenBSD__ +#if DMDV1 + browse("http://www.digitalmars.com/d/1.0/dmd-openbsd.html"); +#else + browse("http://www.dlang.org/dmd-openbsd.html"); +#endif +#endif + exit(EXIT_SUCCESS); + } + else if (strcmp(p + 1, "run") == 0) + { global.params.run = 1; + global.params.runargs_length = ((i >= argcstart) ? argc : argcstart) - i - 1; + if (global.params.runargs_length) + { + files.push(argv[i + 1]); + global.params.runargs = &argv[i + 2]; + i += global.params.runargs_length; + global.params.runargs_length--; + } + else + { global.params.run = 0; + goto Lnoarg; + } + } + else + { + Lerror: + error(0, "unrecognized switch '%s'", argv[i]); + continue; + + Lnoarg: + error(0, "argument expected for switch '%s'", argv[i]); + continue; + } + } + else + { +#if TARGET_WINDOS + char *ext = FileName::ext(p); + if (ext && FileName::compare(ext, "exe") == 0) + { + global.params.objname = p; + continue; + } +#endif + files.push(p); + } + } + if (global.errors) + { + fatal(); + } + if (files.dim == 0) + { usage(); + return EXIT_FAILURE; + } + + if (!setdebuglib) + global.params.debuglibname = global.params.defaultlibname; + +#if TARGET_OSX + global.params.pic = 1; +#endif + +#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS + if (global.params.lib && global.params.dll) + error(0, "cannot mix -lib and -shared\n"); +#endif + + if (global.params.release) + { global.params.useInvariants = 0; + global.params.useIn = 0; + global.params.useOut = 0; + global.params.useAssert = 0; + global.params.useArrayBounds = 1; + global.params.useSwitchError = 0; + } + if (noboundscheck) + global.params.useArrayBounds = 0; + + if (global.params.run) + global.params.quiet = 1; + + if (global.params.useUnitTests) + global.params.useAssert = 1; + + if (!global.params.obj || global.params.lib) + global.params.link = 0; + + if (global.params.link) + { + global.params.exefile = global.params.objname; + global.params.oneobj = 1; + if (global.params.objname) + { + /* Use this to name the one object file with the same + * name as the exe file. + */ + global.params.objname = FileName::forceExt(global.params.objname, global.obj_ext)->toChars(); + + /* If output directory is given, use that path rather than + * the exe file path. + */ + if (global.params.objdir) + { char *name = FileName::name(global.params.objname); + global.params.objname = FileName::combine(global.params.objdir, name); + } + } + } + else if (global.params.lib) + { + global.params.libname = global.params.objname; + global.params.objname = NULL; + + // Haven't investigated handling these options with multiobj + if (!global.params.cov && !global.params.trace +#if 0 && TARGET_WINDOS + /* multiobj causes class/struct debug info to be attached to init-data, + * but this will not be linked into the executable, so this info is lost. + * Bugzilla 4014 + */ + && !global.params.symdebug +#endif + ) + global.params.multiobj = 1; + } + else if (global.params.run) + { + error(0, "flags conflict with -run"); + fatal(); + } + else + { + if (global.params.objname && files.dim > 1) + { + global.params.oneobj = 1; + //error("multiple source files, but only one .obj name"); + //fatal(); + } + } + if (global.params.is64bit) + { + VersionCondition::addPredefinedGlobalIdent("D_InlineAsm_X86_64"); + VersionCondition::addPredefinedGlobalIdent("X86_64"); + VersionCondition::addPredefinedGlobalIdent("D_LP64"); + VersionCondition::addPredefinedGlobalIdent("D_SIMD"); +#if TARGET_WINDOS + VersionCondition::addPredefinedGlobalIdent("Win64"); +#endif + } + else + { + VersionCondition::addPredefinedGlobalIdent("D_InlineAsm"); + VersionCondition::addPredefinedGlobalIdent("D_InlineAsm_X86"); + VersionCondition::addPredefinedGlobalIdent("X86"); +#if TARGET_OSX + VersionCondition::addPredefinedGlobalIdent("D_SIMD"); +#endif +#if TARGET_WINDOS + VersionCondition::addPredefinedGlobalIdent("Win32"); +#endif + } + if (global.params.doDocComments) + VersionCondition::addPredefinedGlobalIdent("D_Ddoc"); + if (global.params.cov) + VersionCondition::addPredefinedGlobalIdent("D_Coverage"); + if (global.params.pic) + VersionCondition::addPredefinedGlobalIdent("D_PIC"); +#if DMDV2 + if (global.params.useUnitTests) + VersionCondition::addPredefinedGlobalIdent("unittest"); +#endif + + // Initialization + Type::init(); + Id::initialize(); + Module::init(); + initPrecedence(); + + if (global.params.verbose) + { printf("binary %s\n", argv[0]); + printf("version %s\n", global.version); + printf("config %s\n", inifilename ? inifilename : "(none)"); + } + + //printf("%d source files\n",files.dim); + + // Build import search path + if (global.params.imppath) + { + for (size_t i = 0; i < global.params.imppath->dim; i++) + { + char *path = (*global.params.imppath)[i]; + Strings *a = FileName::splitPath(path); + + if (a) + { + if (!global.path) + global.path = new Strings(); + global.path->append(a); + } + } + } + + // Build string import search path + if (global.params.fileImppath) + { + for (size_t i = 0; i < global.params.fileImppath->dim; i++) + { + char *path = (*global.params.fileImppath)[i]; + Strings *a = FileName::splitPath(path); + + if (a) + { + if (!global.filePath) + global.filePath = new Strings(); + global.filePath->append(a); + } + } + } + + // Create Modules + Modules modules; + modules.reserve(files.dim); + int firstmodule = 1; + for (size_t i = 0; i < files.dim; i++) + { + char *ext; + char *name; + + p = files[i]; + +#if _WIN32 + // Convert / to \ so linker will work + for (size_t j = 0; p[j]; j++) + { + if (p[j] == '/') + p[j] = '\\'; + } +#endif + + p = FileName::name(p); // strip path + ext = FileName::ext(p); + if (ext) + { /* Deduce what to do with a file based on its extension + */ + if (FileName::equals(ext, global.obj_ext)) + { + global.params.objfiles->push(files[i]); + libmodules.push(files[i]); + continue; + } + + if (FileName::equals(ext, global.lib_ext)) + { + global.params.libfiles->push(files[i]); + libmodules.push(files[i]); + continue; + } + + if (strcmp(ext, global.ddoc_ext) == 0) + { + global.params.ddocfiles->push(files[i]); + continue; + } + + if (FileName::equals(ext, global.json_ext)) + { + global.params.doXGeneration = 1; + global.params.xfilename = files[i]; + continue; + } + + if (FileName::equals(ext, global.map_ext)) + { + global.params.mapfile = files[i]; + continue; + } + +#if TARGET_WINDOS + if (FileName::equals(ext, "res")) + { + global.params.resfile = files[i]; + continue; + } + + if (FileName::equals(ext, "def")) + { + global.params.deffile = files[i]; + continue; + } + + if (FileName::equals(ext, "exe")) + { + assert(0); // should have already been handled + } +#endif + + /* Examine extension to see if it is a valid + * D source file extension + */ + if (FileName::equals(ext, global.mars_ext) || + FileName::equals(ext, global.hdr_ext) || + FileName::equals(ext, "dd")) + { + ext--; // skip onto '.' + assert(*ext == '.'); + name = (char *)mem.malloc((ext - p) + 1); + memcpy(name, p, ext - p); + name[ext - p] = 0; // strip extension + + if (name[0] == 0 || + strcmp(name, "..") == 0 || + strcmp(name, ".") == 0) + { + Linvalid: + error(0, "invalid file name '%s'", files[i]); + fatal(); + } + } + else + { error(0, "unrecognized file extension %s\n", ext); + fatal(); + } + } + else + { name = p; + if (!*name) + goto Linvalid; + } + + /* At this point, name is the D source file name stripped of + * its path and extension. + */ + + Identifier *id = Lexer::idPool(name); + m = new Module(files[i], id, global.params.doDocComments, global.params.doHdrGeneration); + modules.push(m); + + if (firstmodule) + { global.params.objfiles->push(m->objfile->name->str); + firstmodule = 0; + } + } + + // Read files +#define ASYNCREAD 1 +#if ASYNCREAD + // Multi threaded + AsyncRead *aw = AsyncRead::create(modules.dim); + for (size_t i = 0; i < modules.dim; i++) + { + m = modules[i]; + aw->addFile(m->srcfile); + } + aw->start(); +#else + // Single threaded + for (size_t i = 0; i < modules.dim; i++) + { + m = modules[i]; + m->read(0); + } +#endif + + // Parse files + bool anydocfiles = false; + size_t filecount = modules.dim; + for (size_t filei = 0, modi = 0; filei < filecount; filei++, modi++) + { + m = modules[modi]; + if (global.params.verbose) + printf("parse %s\n", m->toChars()); + if (!Module::rootModule) + Module::rootModule = m; + m->importedFrom = m; + if (!global.params.oneobj || modi == 0 || m->isDocFile) + m->deleteObjFile(); +#if ASYNCREAD + if (aw->read(filei)) + { + error(0, "cannot read file %s", m->srcfile->name->toChars()); + fatal(); + } +#endif + m->parse(); + if (m->isDocFile) + { + anydocfiles = true; + m->gendocfile(); + + // Remove m from list of modules + modules.remove(modi); + modi--; + + // Remove m's object file from list of object files + for (size_t j = 0; j < global.params.objfiles->dim; j++) + { + if (m->objfile->name->str == (*global.params.objfiles)[j]) + { + global.params.objfiles->remove(j); + break; + } + } + + if (global.params.objfiles->dim == 0) + global.params.link = 0; + } + } +#if ASYNCREAD + AsyncRead::dispose(aw); +#endif + + if (anydocfiles && modules.dim && + (global.params.oneobj || global.params.objname)) + { + error(0, "conflicting Ddoc and obj generation options"); + fatal(); + } + if (global.errors) + fatal(); + if (global.params.doHdrGeneration) + { + /* Generate 'header' import files. + * Since 'header' import files must be independent of command + * line switches and what else is imported, they are generated + * before any semantic analysis. + */ + for (size_t i = 0; i < modules.dim; i++) + { + m = modules[i]; + if (global.params.verbose) + printf("import %s\n", m->toChars()); + m->genhdrfile(); + } + } + if (global.errors) + fatal(); + + // load all unconditional imports for better symbol resolving + for (size_t i = 0; i < modules.dim; i++) + { + m = modules[i]; + if (global.params.verbose) + printf("importall %s\n", m->toChars()); + m->importAll(0); + } + if (global.errors) + fatal(); + + backend_init(); + + // Do semantic analysis + for (size_t i = 0; i < modules.dim; i++) + { + m = modules[i]; + if (global.params.verbose) + printf("semantic %s\n", m->toChars()); + m->semantic(); + } + if (global.errors) + fatal(); + + Module::dprogress = 1; + Module::runDeferredSemantic(); + + // Do pass 2 semantic analysis + for (size_t i = 0; i < modules.dim; i++) + { + m = modules[i]; + if (global.params.verbose) + printf("semantic2 %s\n", m->toChars()); + m->semantic2(); + } + if (global.errors) + fatal(); + + // Do pass 3 semantic analysis + for (size_t i = 0; i < modules.dim; i++) + { + m = modules[i]; + if (global.params.verbose) + printf("semantic3 %s\n", m->toChars()); + m->semantic3(); + } + if (global.errors) + fatal(); + + if (global.params.useInline) + { + /* The problem with useArrayBounds and useAssert is that the + * module being linked to may not have generated them, so if + * we inline functions from those modules, the symbols for them will + * not be found at link time. + * We must do this BEFORE generating the .deps file! + */ + if (!global.params.useArrayBounds && !global.params.useAssert) + { + // Do pass 3 semantic analysis on all imported modules, + // since otherwise functions in them cannot be inlined + for (size_t i = 0; i < Module::amodules.dim; i++) + { + m = Module::amodules[i]; + if (global.params.verbose) + printf("semantic3 %s\n", m->toChars()); + m->semantic3(); + } + if (global.errors) + fatal(); + } + } + + if (global.params.moduleDeps != NULL) + { + assert(global.params.moduleDepsFile != NULL); + + File deps(global.params.moduleDepsFile); + OutBuffer* ob = global.params.moduleDeps; + deps.setbuffer((void*)ob->data, ob->offset); + deps.writev(); + } + + // Scan for functions to inline + if (global.params.useInline) + { + for (size_t i = 0; i < modules.dim; i++) + { + m = modules[i]; + if (global.params.verbose) + printf("inline scan %s\n", m->toChars()); + m->inlineScan(); + } + } + + // Do not attempt to generate output files if errors or warnings occurred + if (global.errors || global.warnings) + fatal(); + + printCtfePerformanceStats(); + + Library *library = NULL; + if (global.params.lib) + { + library = Library::factory(); + library->setFilename(global.params.objdir, global.params.libname); + + // Add input object and input library files to output library + for (size_t i = 0; i < libmodules.dim; i++) + { + char *p = libmodules[i]; + library->addObject(p, NULL, 0); + } + } + + // Generate output files + + if (global.params.doXGeneration) + json_generate(&modules); + + if (global.params.oneobj) + { + for (size_t i = 0; i < modules.dim; i++) + { + m = modules[i]; + if (global.params.verbose) + printf("code %s\n", m->toChars()); + if (i == 0) + obj_start(m->srcfile->toChars()); + m->genobjfile(0); + if (!global.errors && global.params.doDocComments) + m->gendocfile(); + } + if (!global.errors && modules.dim) + { + obj_end(library, modules[0]->objfile); + } + } + else + { + for (size_t i = 0; i < modules.dim; i++) + { + m = modules[i]; + if (global.params.verbose) + printf("code %s\n", m->toChars()); + if (global.params.obj) + { obj_start(m->srcfile->toChars()); + m->genobjfile(global.params.multiobj); + obj_end(library, m->objfile); + obj_write_deferred(library); + } + if (global.errors) + { + if (!global.params.lib) + m->deleteObjFile(); + } + else + { + if (global.params.doDocComments) + m->gendocfile(); + } + } + } + + if (global.params.lib && !global.errors) + library->write(); + + backend_term(); + if (global.errors) + fatal(); + + if (!global.params.objfiles->dim) + { + if (global.params.link) + error(0, "no object files to link"); + } + else + { + if (global.params.link) + status = runLINK(); + + if (global.params.run) + { + if (!status) + { + status = runProgram(); + + /* Delete .obj files and .exe file + */ + for (size_t i = 0; i < modules.dim; i++) + { + Module *m = modules[i]; + m->deleteObjFile(); + if (global.params.oneobj) + break; + } + deleteExeFile(); + } + } + } + + return status; +} + +int main(int argc, char *argv[]) +{ + int status = -1; +#if WINDOWS_SEH + __try + { +#endif + status = tryMain(argc, argv); +#if WINDOWS_SEH + } + __except (__ehfilter(GetExceptionInformation())) + { + printf("Stack overflow\n"); + fatal(); + } +#endif + return status; +} + +#endif // !IN_LLVM + +/*********************************** + * Parse and append contents of environment variable envvar + * to argc and argv[]. + * The string is separated into arguments, processing \ and ". + */ + +void getenv_setargv(const char *envvar, int *pargc, char** *pargv) +{ + char *p; + + int instring; + int slash; + char c; + + char *env = getenv(envvar); + if (!env) + return; + + env = mem.strdup(env); // create our own writable copy + + int argc = *pargc; + Strings *argv = new Strings(); + argv->setDim(argc); + + int argc_left = 0; + for (int i = 0; i < argc; i++) { + if (!strcmp((*pargv)[i], "-run") || !strcmp((*pargv)[i], "--run")) { + // HACK: set flag to indicate we saw '-run' here + global.params.run = true; + // Don't eat -run yet so the program arguments don't get changed + argc_left = argc - i; + argc = i; + *pargv = &(*pargv)[i]; + argv->setDim(i); + break; + } else { + } + } + // HACK to stop required values from command line being drawn from DFLAGS + argv->push((char*)""); + argc++; + + size_t j = 1; // leave argv[0] alone + while (1) + { + int wildcard = 1; // do wildcard expansion + switch (*env) + { + case ' ': + case '\t': + env++; + break; + + case 0: + goto Ldone; + + case '"': + wildcard = 0; + default: + argv->push(env); // append + //argv->insert(j, env); // insert at position j + j++; + argc++; + p = env; + slash = 0; + instring = 0; + c = 0; + + while (1) + { + c = *env++; + switch (c) + { + case '"': + p -= (slash >> 1); + if (slash & 1) + { p--; + goto Laddc; + } + instring ^= 1; + slash = 0; + continue; + + case ' ': + case '\t': + if (instring) + goto Laddc; + *p = 0; + //if (wildcard) + //wildcardexpand(); // not implemented + break; + + case '\\': + slash++; + *p++ = c; + continue; + + case 0: + *p = 0; + //if (wildcard) + //wildcardexpand(); // not implemented + goto Ldone; + + default: + Laddc: + slash = 0; + *p++ = c; + continue; + } + break; + } + } + } + +Ldone: + assert(argc == argv->dim); + argv->reserve(argc_left); + for (int i = 0; i < argc_left; i++) + argv->data[argc++] = (void *)(*pargv)[i]; + + *pargc = argc; + *pargv = argv->tdata(); +} + +#if WINDOWS_SEH + +long __cdecl __ehfilter(LPEXCEPTION_POINTERS ep) +{ + //printf("%x\n", ep->ExceptionRecord->ExceptionCode); + if (ep->ExceptionRecord->ExceptionCode == STATUS_STACK_OVERFLOW) + { +#if 1 //ndef DEBUG + return EXCEPTION_EXECUTE_HANDLER; +#endif + } + return EXCEPTION_CONTINUE_SEARCH; +} + +#endif diff --git a/dmd2/mars.h b/dmd2/mars.h index 9d56203e..ccc27469 100644 --- a/dmd2/mars.h +++ b/dmd2/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 @@ -97,11 +97,13 @@ void unittests(); #define DMDV1 0 #define DMDV2 1 // 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 #define MODULEINFO_IS_STRUCT DMDV2 // if ModuleInfo is a struct rather than a class +#define BUG6652 1 // Making foreach range statement parameter non-ref in default + // 1: Modifying iteratee in body is warned with -w switch + // 2: Modifying iteratee in body is error without -d switch // Set if C++ mangling is done by the front end #define CPP_MANGLE (DMDV2 && (TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS)) @@ -279,6 +281,10 @@ 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; @@ -301,7 +307,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; #if IN_LLVM char *ldc_version; @@ -473,7 +481,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, 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); void fatal(); @@ -493,7 +501,7 @@ void util_progress(); #endif /*** Where to send error messages ***/ -#if IN_GCC || IN_LLVM +#if defined(IN_GCC) || IN_LLVM #define stdmsg stderr #else #define stdmsg stderr diff --git a/dmd2/module.c b/dmd2/module.c index 1a98b4f0..135b8571 100644 --- a/dmd2/module.c +++ b/dmd2/module.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 @@ -20,7 +20,7 @@ #include #endif -#if IN_GCC +#ifdef IN_GCC #include "gdc_alloca.h" #endif @@ -37,7 +37,10 @@ #include "hdrgen.h" #include "lexer.h" -#include "html.h" +// stricmp +#if __GNUC__ && !_WIN32 +#include "gnuc.h" +#endif #ifdef IN_GCC #include "d-dmd-gcc.h" @@ -88,7 +91,6 @@ Module::Module(char *filename, Identifier *ident, int doDocComment, int doHdrGen errors = 0; numlines = 0; members = NULL; - isHtml = 0; isDocFile = 0; needmoduleinfo = 0; #ifdef IN_GCC @@ -146,17 +148,8 @@ Module::Module(char *filename, Identifier *ident, int doDocComment, int doHdrGen !srcfilename->equalsExt(global.hdr_ext) && !srcfilename->equalsExt("dd")) { - if (srcfilename->equalsExt("html") || - srcfilename->equalsExt("htm") || - srcfilename->equalsExt("xhtml")) - { if (!global.params.useDeprecated) - error("html source files is deprecated %s", srcfilename->toChars()); - isHtml = 1; - } - else - { error("source file name '%s' must have .%s extension", srcfilename->toChars(), global.mars_ext); - fatal(); - } + error("source file name '%s' must have .%s extension", srcfilename->toChars(), global.mars_ext); + fatal(); } #if !IN_LLVM char *argobj; @@ -438,7 +431,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 @@ -499,7 +492,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()); } } @@ -530,7 +523,7 @@ bool Module::read(Loc loc) { for (size_t i = 0; i < global.path->dim; i++) { - char *p = global.path->tdata()[i]; + char *p = (*global.path)[i]; fprintf(stdmsg, "import path[%llu] = %s\n", (ulonglong)i, p); } } @@ -579,24 +572,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) { @@ -609,7 +595,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) @@ -760,7 +747,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); } @@ -779,19 +766,6 @@ void Module::parse() #endif return; } - if (isHtml) - { - OutBuffer *dbuf = new OutBuffer(); - Html h(srcname, buf, buflen); - h.extractCode(dbuf); - buf = dbuf->data; - buflen = dbuf->offset; -#ifdef IN_GCC - // dump extracted source - if (dump_source) - d_gcc_dump_source(srcname, "d.utf-8", buf, buflen); -#endif - } #if IN_LLVM Parser p(this, buf, buflen, gen_docs); #else @@ -890,7 +864,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); } } @@ -903,13 +877,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); } @@ -964,7 +938,7 @@ void Module::semantic(Scope* unused_sc) // 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); @@ -972,7 +946,7 @@ void Module::semantic(Scope* unused_sc) // 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); @@ -993,7 +967,7 @@ void Module::semantic2(Scope* unused_sc) { 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"); } @@ -1017,7 +991,7 @@ void Module::semantic2(Scope* unused_sc) for (size_t i = 0; i < members->dim; i++) { Dsymbol *s; - s = members->tdata()[i]; + s = (*members)[i]; s->semantic2(sc); } @@ -1045,7 +1019,7 @@ void Module::semantic3(Scope* unused_sc) 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); } @@ -1068,7 +1042,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()); @@ -1093,7 +1067,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); } @@ -1154,7 +1128,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; } } @@ -1168,7 +1142,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; @@ -1238,7 +1212,6 @@ void Module::runDeferredSemantic() int Module::imports(Module *m) { //printf("%s Module::imports(%s)\n", toChars(), m->toChars()); - int aimports_dim = aimports.dim; #if 0 for (size_t i = 0; i < aimports.dim; i++) { Module *mi = (Module *)aimports.data[i]; @@ -1246,7 +1219,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) @@ -1270,7 +1243,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; } @@ -1278,7 +1251,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; } @@ -1303,7 +1276,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('.'); @@ -1340,7 +1313,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/dmd2/module.h b/dmd2/module.h index dc241543..71730021 100644 --- a/dmd2/module.h +++ b/dmd2/module.h @@ -79,7 +79,6 @@ struct Module : Package unsigned errors; // if any errors in file unsigned numlines; // number of lines in source file - int isHtml; // if it is an HTML file int isDocFile; // if it is a documentation input file, not D source int needmoduleinfo; #ifdef IN_GCC @@ -141,8 +140,6 @@ 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 parse(bool dump_source = false); // syntactic parse #else void parse(); // syntactic parse #endif diff --git a/dmd2/mtype.c b/dmd2/mtype.c index 72cab1f9..defff32e 100644 --- a/dmd2/mtype.c +++ b/dmd2/mtype.c @@ -87,10 +87,10 @@ int REALSIZE = 16; int REALPAD = 6; int REALALIGNSIZE = 16; #elif TARGET_LINUX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS -int REALSIZE = 12; +int REALSIZE = 12; // FIXME: We differ from DMD here, yet target defines are never set?! int REALPAD = 2; int REALALIGNSIZE = 4; -#elif IN_GCC +#elif defined(IN_GCC) int REALSIZE = 0; int REALPAD = 0; int REALALIGNSIZE = 0; @@ -131,6 +131,7 @@ ClassDeclaration *Type::typeinfoshared; ClassDeclaration *Type::typeinfowild; TemplateDeclaration *Type::associativearray; +TemplateDeclaration *Type::rtinfo; Type *Type::tvoidptr; Type *Type::tstring; @@ -1399,7 +1400,7 @@ Type *Type::aliasthisOf() if (spec && global.errors != olderrs) spec->errors = global.errors - olderrs; } - if (!global.errors) + if (!fd->errors) { Type *t = fd->type->nextOf(); t = t->substWildTo(mod == 0 ? MODmutable : mod); @@ -1728,9 +1729,11 @@ Type *Type::merge() { sv->ptrvalue = this; +#if IN_LLVM // we still need deco strings to be unique // or Type::equals fails, which breaks a bunch of stuff, // like covariant member function overloads. + // TODO: Check if and why this is still needed. OutBuffer mangle; toDecoBuffer(&mangle, 0, true); StringValue* sv2 = deco_stringtable.update((char *)mangle.data, mangle.offset); @@ -1742,8 +1745,11 @@ Type *Type::merge() else { sv2->ptrvalue = this; - deco = (char *)sv2->lstring.string; + deco = (char *)sv2->toDchars(); } +#else + deco = (char *)sv->toDchars(); +#endif //printf("new value, deco = '%s' %p\n", t->deco, t->deco); } } @@ -2044,7 +2050,13 @@ Expression *Type::getProperty(Loc loc, Identifier *ident) error(loc, "void does not have an initializer"); if (ty == Tfunction) error(loc, "function does not have an initializer"); - e = defaultInitLiteral(loc); + if (toBasetype()->ty == Tstruct && + ((TypeStruct *)toBasetype())->sym->isNested()) + { + e = defaultInit(loc); + } + else + e = defaultInitLiteral(loc); } else if (ident == Id::mangleof) { const char *s; @@ -2118,7 +2130,13 @@ Expression *Type::dotExp(Scope *sc, Expression *e, Identifier *ident) } else if (ident == Id::init) { - e = defaultInitLiteral(e->loc); + if (toBasetype()->ty == Tstruct && + ((TypeStruct *)toBasetype())->sym->isNested()) + { + e = defaultInit(e->loc); + } + else + e = defaultInitLiteral(e->loc); goto Lreturn; } } @@ -2143,6 +2161,15 @@ Lreturn: return e; } +/************************************ + * Return alignment to use for this type. + */ + +structalign_t Type::alignment() +{ + return STRUCTALIGN_DEFAULT; +} + /*************************************** * Figures out what to do with an undefined member reference * for classes and structs. @@ -2191,10 +2218,9 @@ Expression *Type::noMember(Scope *sc, Expression *e, Identifier *ident) StringExp *se = new StringExp(e->loc, ident->toChars()); Objects *tiargs = new Objects(); tiargs->push(se); - e = new DotTemplateInstanceExp(e->loc, e, Id::opDispatch, tiargs); - ((DotTemplateInstanceExp *)e)->ti->tempdecl = td; - e = e->semantic(sc); - return e; + DotTemplateInstanceExp *dti = new DotTemplateInstanceExp(e->loc, e, Id::opDispatch, tiargs); + dti->ti->tempdecl = td; + return dti->semantic(sc, 1); } /* See if we should forward to the alias this. @@ -2204,19 +2230,14 @@ Expression *Type::noMember(Scope *sc, Expression *e, Identifier *ident) * e.aliasthis.ident */ e = resolveAliasThis(sc, e); - e = new DotIdExp(e->loc, e, ident); - return e->semantic(sc); + DotIdExp *die = new DotIdExp(e->loc, e, ident); + return die->semantic(sc, 1); } } return Type::dotExp(sc, e, ident); } -unsigned Type::memalign(unsigned salign) -{ - return salign; -} - void Type::error(Loc loc, const char *format, ...) { va_list ap; @@ -2859,11 +2880,11 @@ unsigned TypeBasic::alignsize() } #if IN_LLVM -unsigned TypeBasic::memalign(unsigned salign) +unsigned TypeBasic::alignment() { if (global.params.cpu == ARCHx86_64 && (ty == Tfloat80 || ty == Timaginary80)) return 16; - return Type::memalign(salign); + return Type::alignment(); } #endif @@ -3354,7 +3375,7 @@ MATCH TypeBasic::implicitConvTo(Type *to) return MATCHnomatch; TypeBasic *tob; - if (to->ty == Tvector) + if (to->ty == Tvector && to->deco) { TypeVector *tv = (TypeVector *)to; tob = tv->elementType(); @@ -3422,6 +3443,8 @@ TypeBasic *TypeBasic::isTypeBasic() /* The basetype must be one of: * byte[16],ubyte[16],short[8],ushort[8],int[4],uint[4],long[2],ulong[2],float[4],double[2] + * For AVX: + * byte[32],ubyte[32],short[16],ushort[16],int[8],uint[8],long[4],ulong[4],float[8],double[4] */ TypeVector::TypeVector(Loc loc, Type *basetype) : Type(Tvector) @@ -3456,8 +3479,9 @@ Type *TypeVector::semantic(Loc loc, Scope *sc) return this; } - if (t->size(loc) != 16) - { error(loc, "base type of __vector must be a 16 byte static array, not %s", t->toChars()); + d_uns64 sz = t->size(loc); + if (sz != 16 && sz != 32) + { error(loc, "base type of __vector must be a 16 or 32 byte static array, not %s", t->toChars()); return terror; } TypeBasic *tb = t->nextOf()->isTypeBasic(); @@ -3511,12 +3535,12 @@ void TypeVector::toDecoBuffer(OutBuffer *buf, int flag, bool mangle) d_uns64 TypeVector::size(Loc loc) { - return 16; + return basetype->size(); } unsigned TypeVector::alignsize() { - return 16; + return (unsigned)basetype->size(); } Expression *TypeVector::getProperty(Loc loc, Identifier *ident) @@ -3865,7 +3889,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(); @@ -3874,7 +3898,7 @@ void TypeSArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol { error(loc, "tuple index %llu exceeds length %u", d, td->objects->dim); goto Ldefault; } - Object *o = td->objects->tdata()[(size_t)d]; + Object *o = (*td->objects)[(size_t)d]; if (o->dyncast() == DYNCAST_DSYMBOL) { *ps = (Dsymbol *)o; @@ -3900,7 +3924,7 @@ void TypeSArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol */ Objects *objects = new Objects; objects->setDim(1); - objects->tdata()[0] = o; + (*objects)[0] = o; TupleDeclaration *tds = new TupleDeclaration(loc, td->ident, objects); *ps = tds; @@ -3927,14 +3951,14 @@ 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) { error(loc, "tuple index %llu exceeds %u", d, sd->objects->dim); return Type::terror; } - Object *o = sd->objects->tdata()[(size_t)d]; + Object *o = (*sd->objects)[(size_t)d]; if (o->dyncast() != DYNCAST_TYPE) { error(loc, "%s is not a type", toChars()); return Type::terror; @@ -3966,11 +3990,17 @@ Type *TypeSArray::semantic(Loc loc, Scope *sc) */ return this; } - dim = dim->optimize(WANTvalue | WANTinterpret); + dim = dim->ctfeInterpret(); + errors = global.errors; dinteger_t d1 = dim->toInteger(); + if (errors != global.errors) + goto Lerror; dim = dim->implicitCastTo(sc, tsize_t); dim = dim->optimize(WANTvalue); + errors = global.errors; dinteger_t d2 = dim->toInteger(); + if (errors != global.errors) + goto Lerror; if (dim->op == TOKerror) goto Lerror; @@ -4015,7 +4045,7 @@ Type *TypeSArray::semantic(Loc loc, Scope *sc) { error(loc, "tuple index %llu exceeds %u", d, tt->arguments->dim); goto Lerror; } - Parameter *arg = tt->arguments->tdata()[(size_t)d]; + Parameter *arg = (*tt->arguments)[(size_t)d]; return arg->type; } case Tstruct: @@ -4094,17 +4124,17 @@ Expression *TypeSArray::dotExp(Scope *sc, Expression *e, Identifier *ident) return e; } +structalign_t TypeSArray::alignment() +{ + return next->alignment(); +} + int TypeSArray::isString() { TY nty = next->toBasetype()->ty; return nty == Tchar || nty == Twchar || nty == Tdchar; } -unsigned TypeSArray::memalign(unsigned salign) -{ - return next->memalign(salign); -} - MATCH TypeSArray::constConv(Type *to) { if (to->ty == Tsarray) @@ -4210,7 +4240,7 @@ Expression *TypeSArray::defaultInitLiteral(Loc loc) Expressions *elements = new Expressions(); elements->setDim(d); for (size_t i = 0; i < d; i++) - elements->tdata()[i] = elementinit; + (*elements)[i] = elementinit; ArrayLiteralExp *ae = new ArrayLiteralExp(0, elements); ae->type = this; return ae; @@ -4895,6 +4925,15 @@ MATCH TypeAArray::constConv(Type *to) return Type::constConv(to); } +Type *TypeAArray::reliesOnTident(TemplateParameters *tparams) +{ + Type *t = TypeNext::reliesOnTident(tparams); + if (!t) + t = index->reliesOnTident(tparams); + return t; +} + + /***************************** TypePointer *****************************/ TypePointer::TypePointer(Type *t) @@ -4916,7 +4955,7 @@ Type *TypePointer::syntaxCopy() Type *TypePointer::semantic(Loc loc, Scope *sc) { - //printf("TypePointer::semantic()\n"); + //printf("TypePointer::semantic() %s\n", toChars()); if (deco) return this; Type *n = next->semantic(loc, sc); @@ -4933,8 +4972,19 @@ Type *TypePointer::semantic(Loc loc, Scope *sc) } next = n; if (next->ty != Tfunction) - transitive(); + { transitive(); + return merge(); + } +#if 1 return merge(); +#else + deco = merge()->deco; + /* Don't return merge(), because arg identifiers and default args + * can be different + * even though the types match + */ + return this; +#endif } @@ -5302,6 +5352,8 @@ int Type::covariant(Type *t, StorageClass *pstc) } else if (t1n->ty == t2n->ty && t1n->implicitConvTo(t2n)) goto Lcovariant; + else if (t1n->ty == Tnull && t1n->implicitConvTo(t2n)) + goto Lcovariant; } goto Lnotcovariant; @@ -5536,7 +5588,7 @@ void TypeFunction::toCBufferWithAttributes(OutBuffer *buf, Identifier *ident, Hd { buf->writeByte('('); for (size_t i = 0; i < td->origParameters->dim; i++) { - TemplateParameter *tp = td->origParameters->tdata()[i]; + TemplateParameter *tp = (*td->origParameters)[i]; if (i) buf->writestring(", "); tp->toCBuffer(buf, hgs); @@ -5547,18 +5599,13 @@ void TypeFunction::toCBufferWithAttributes(OutBuffer *buf, Identifier *ident, Hd inuse--; } -void TypeFunction::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) +// 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) { - //printf("TypeFunction::toCBuffer2() this = %p, ref = %d\n", this, isref); - if (inuse) - { inuse = 2; // flag error to caller - return; - } - inuse++; if (hgs->ddoc != 1) { const char *p = NULL; - switch (linkage) + switch (t->linkage) { case LINKd: p = NULL; break; case LINKc: p = "C"; break; @@ -5579,14 +5626,27 @@ void TypeFunction::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) buf->writestring(") "); } } - if (next) + if (t->next) { - next->toCBuffer2(buf, hgs, 0); + t->next->toCBuffer2(buf, hgs, 0); buf->writeByte(' '); } - buf->writestring("function"); - Parameter::argsToCBuffer(buf, hgs, parameters, varargs); - attributesToCBuffer(buf, mod); + buf->writestring(kind); + Parameter::argsToCBuffer(buf, hgs, t->parameters, t->varargs); + t->attributesToCBuffer(buf, mod); +} + +void TypeFunction::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) +{ + //printf("TypeFunction::toCBuffer2() this = %p, ref = %d\n", this, isref); + if (inuse) + { inuse = 2; // flag error to caller + return; + } + inuse++; + + functionToCBuffer2(this, buf, hgs, mod, "function"); + inuse--; } @@ -5642,10 +5702,10 @@ Type *TypeFunction::semantic(Loc loc, Scope *sc) if (parameters) { tf->parameters = (Parameters *)parameters->copy(); for (size_t i = 0; i < parameters->dim; i++) - { Parameter *arg = parameters->tdata()[i]; + { Parameter *arg = (*parameters)[i]; Parameter *cpy = (Parameter *)mem.malloc(sizeof(Parameter)); memcpy(cpy, arg, sizeof(Parameter)); - tf->parameters->tdata()[i] = cpy; + (*tf->parameters)[i] = cpy; } } @@ -5767,24 +5827,12 @@ Type *TypeFunction::semantic(Loc loc, Scope *sc) e = resolveProperties(argsc, e); if (e->op == TOKfunction) // see Bugzilla 4820 { FuncExp *fe = (FuncExp *)e; - if (fe->fd) - { if (fe->fd->tok == TOKreserved) - { - if (fe->type->ty == Tpointer) - { - fe->fd->vthis = NULL; - fe->fd->tok = TOKfunction; - } - else - fe->fd->tok = TOKdelegate; - } - // Replace function literal with a function symbol, - // since default arg expression must be copied when used - // and copying the literal itself is wrong. - e = new VarExp(e->loc, fe->fd, 0); - e = new AddrExp(e->loc, e); - e = e->semantic(argsc); - } + // Replace function literal with a function symbol, + // since default arg expression must be copied when used + // and copying the literal itself is wrong. + e = new VarExp(e->loc, fe->fd, 0); + e = new AddrExp(e->loc, e); + e = e->semantic(argsc); } e = e->implicitCastTo(argsc, fparam->type); fparam->defaultArg = e; @@ -5795,8 +5843,13 @@ Type *TypeFunction::semantic(Loc loc, Scope *sc) */ if (t->ty == Ttuple) { + /* TypeFunction::parameter also is used as the storage of + * Parameter objects for FuncDeclaration. So we should copy + * the elements of TypeTuple::arguments to avoid unintended + * sharing of Parameter object among other functions. + */ TypeTuple *tt = (TypeTuple *)t; - if (fparam->storageClass && tt->arguments && tt->arguments->dim) + if (tt->arguments && tt->arguments->dim) { /* Propagate additional storage class from tuple parameters to their * element-parameters. @@ -5807,7 +5860,7 @@ Type *TypeFunction::semantic(Loc loc, Scope *sc) newparams->setDim(tdim); for (size_t j = 0; j < tdim; j++) { Parameter *narg = (*tt->arguments)[j]; - newparams->tdata()[j] = new Parameter(narg->storageClass | fparam->storageClass, + (*newparams)[j] = new Parameter(narg->storageClass | fparam->storageClass, narg->type, narg->ident, narg->defaultArg); } fparam->type = new TypeTuple(newparams); @@ -5828,7 +5881,7 @@ Type *TypeFunction::semantic(Loc loc, Scope *sc) if (fparam->storageClass & STCauto) { if (fargs && i < fargs->dim) - { Expression *farg = fargs->tdata()[i]; + { Expression *farg = (*fargs)[i]; if (farg->isLvalue()) ; // ref parameter else @@ -6008,7 +6061,7 @@ int TypeFunction::callMatch(Expression *ethis, Expressions *args, int flag) if (u >= nparams) break; Parameter *p = Parameter::getNth(parameters, u); - Expression *arg = args->tdata()[u]; + Expression *arg = (*args)[u]; assert(arg); if (!(p->storageClass & STClazy && p->type->ty == Tvoid && arg->type->ty != Tvoid)) @@ -6049,7 +6102,7 @@ int TypeFunction::callMatch(Expression *ethis, Expressions *args, int flag) goto L1; // try typesafe variadics } { - Expression *arg = args->tdata()[u]; + Expression *arg = (*args)[u]; assert(arg); if (arg->op == TOKfunction) @@ -6064,17 +6117,38 @@ int TypeFunction::callMatch(Expression *ethis, Expressions *args, int flag) Type *targ = arg->type; Type *tprm = wildmatch ? p->type->substWildTo(wildmatch) : p->type; + if (p->storageClass & STClazy && tprm->ty == Tvoid && targ->ty != Tvoid) + m = MATCHconvert; + else + { + //printf("%s of type %s implicitConvTo %s\n", arg->toChars(), targ->toChars(), tprm->toChars()); + if (flag) + // for partial ordering, value is an irrelevant mockup, just look at the type + m = targ->implicitConvTo(tprm); + else + m = arg->implicitConvTo(tprm); + //printf("match %d\n", m); + } + // Non-lvalues do not match ref or out parameters if (p->storageClass & STCref) - { if (!arg->isLvalue()) - { if (arg->op == TOKstring && tprm->ty == Tsarray) + { if (m && !arg->isLvalue()) + { + Type *ta = targ->aliasthisOf(); + if (arg->op == TOKstring && tprm->ty == Tsarray) { if (targ->ty != Tsarray) targ = new TypeSArray(targ->nextOf(), new IntegerExp(0, ((StringExp *)arg)->len, Type::tindex)); } + else if (ta && ta->implicitConvTo(tprm)) + { + goto Nomatch; + } else if (arg->op == TOKstructliteral) + { match = MATCHconvert; + } else if (arg->op == TOKcall) { CallExp *ce = (CallExp *)arg; @@ -6090,13 +6164,24 @@ int TypeFunction::callMatch(Expression *ethis, Expressions *args, int flag) goto Nomatch; } - /* Don't allow static arrays to be passed to mutable references - * to static arrays if the argument cannot be modified. - */ Type *targb = targ->toBasetype(); Type *tprmb = tprm->toBasetype(); //printf("%s\n", targb->toChars()); //printf("%s\n", tprmb->toChars()); + + /* find most derived alias this type being matched. + */ + while (1) + { + Type *tat = targb->aliasthisOf(); + if (!tat || !tat->implicitConvTo(tprm)) + break; + targb = tat; + } + + /* Don't allow static arrays to be passed to mutable references + * to static arrays if the argument cannot be modified. + */ if (targb->nextOf() && tprmb->ty == Tsarray && !MODimplicitConv(targb->nextOf()->mod, tprmb->nextOf()->mod)) goto Nomatch; @@ -6106,22 +6191,9 @@ int TypeFunction::callMatch(Expression *ethis, Expressions *args, int flag) goto Nomatch; } else if (p->storageClass & STCout) - { if (!arg->isLvalue()) + { if (m && !arg->isLvalue()) goto Nomatch; } - - if (p->storageClass & STClazy && tprm->ty == Tvoid && targ->ty != Tvoid) - m = MATCHconvert; - else - { - //printf("%s of type %s implicitConvTo %s\n", arg->toChars(), targ->toChars(), tprm->toChars()); - if (flag) - // for partial ordering, value is an irrelevant mockup, just look at the type - m = targ->implicitConvTo(tprm); - else - m = arg->implicitConvTo(tprm); - //printf("match %d\n", m); - } } /* prefer matching the element type rather than the array @@ -6150,7 +6222,7 @@ int TypeFunction::callMatch(Expression *ethis, Expressions *args, int flag) { TypeArray *ta = (TypeArray *)tb; for (; u < nargs; u++) { - Expression *arg = args->tdata()[u]; + Expression *arg = (*args)[u]; assert(arg); #if 1 if (arg->op == TOKfunction) @@ -6338,6 +6410,7 @@ Type *TypeDelegate::syntaxCopy() Type *TypeDelegate::semantic(Loc loc, Scope *sc) { + //printf("TypeDelegate::semantic() %s\n", toChars()); if (deco) // if semantic() already run { //printf("already done\n"); @@ -6348,13 +6421,16 @@ Type *TypeDelegate::semantic(Loc loc, Scope *sc) * be removed from next before the merge. */ +#if 1 + return merge(); +#else /* Don't return merge(), because arg identifiers and default args * can be different * even though the types match */ - //deco = merge()->deco; - //return this; - return merge(); + deco = merge()->deco; + return this; +#endif } d_uns64 TypeDelegate::size(Loc loc) @@ -6390,12 +6466,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); - tf->attributesToCBuffer(buf, mod); + functionToCBuffer2((TypeFunction *)next, buf, hgs, mod, "delegate"); } Expression *TypeDelegate::defaultInit(Loc loc) @@ -6461,7 +6533,7 @@ void TypeQualified::syntaxCopyHelper(TypeQualified *t) idents.setDim(t->idents.dim); for (size_t i = 0; i < idents.dim; i++) { - Identifier *id = t->idents.tdata()[i]; + Identifier *id = t->idents[i]; if (id->dyncast() == DYNCAST_DSYMBOL) { TemplateInstance *ti = (TemplateInstance *)id; @@ -6469,7 +6541,7 @@ void TypeQualified::syntaxCopyHelper(TypeQualified *t) ti = (TemplateInstance *)ti->syntaxCopy(NULL); id = (Identifier *)ti; } - idents.tdata()[i] = id; + idents[i] = id; } } @@ -6482,7 +6554,7 @@ void TypeQualified::addIdent(Identifier *ident) void TypeQualified::toCBuffer2Helper(OutBuffer *buf, HdrGenState *hgs) { for (size_t i = 0; i < idents.dim; i++) - { Identifier *id = idents.tdata()[i]; + { Identifier *id = idents[i]; buf->writeByte('.'); @@ -6534,7 +6606,7 @@ void TypeQualified::resolveHelper(Loc loc, Scope *sc, //printf("\t2: s = '%s' %p, kind = '%s'\n",s->toChars(), s, s->kind()); for (size_t i = 0; i < idents.dim; i++) { - Identifier *id = idents.tdata()[i]; + Identifier *id = idents[i]; Dsymbol *sm = s->searchX(loc, sc, id); //printf("\t3: s = '%s' %p, kind = '%s'\n",s->toChars(), s, s->kind()); //printf("\tgetType = '%s'\n", s->getType()->toChars()); @@ -6544,9 +6616,7 @@ void TypeQualified::resolveHelper(Loc loc, Scope *sc, v = s->isVarDeclaration(); if (v && id == Id::length) { - e = v->getConstInitializer(); - if (!e) - e = new VarExp(loc, v); + e = new VarExp(loc, v); t = e->type; if (!t) goto Lerror; @@ -6557,7 +6627,7 @@ void TypeQualified::resolveHelper(Loc loc, Scope *sc, e = new DsymbolExp(loc, s, 0); do { - id = idents.tdata()[i]; + id = idents[i]; e = new DotIdExp(loc, e, id); } while (++i < idents.dim); e = e->semantic(sc); @@ -6590,7 +6660,7 @@ void TypeQualified::resolveHelper(Loc loc, Scope *sc, L3: for (; i < idents.dim; i++) { - id = idents.tdata()[i]; + id = idents[i]; //printf("e: '%s', id: '%s', type = %s\n", e->toChars(), id->toChars(), e->type->toChars()); e = new DotIdExp(e->loc, e, id); e = e->semantic(sc); @@ -6819,7 +6889,7 @@ Dsymbol *TypeIdentifier::toDsymbol(Scope *sc) { for (size_t i = 0; i < idents.dim; i++) { - Identifier *id = idents.tdata()[i]; + Identifier *id = idents[i]; s = s->searchX(loc, sc, id); if (!s) // failed to find a symbol { //printf("\tdidn't find a symbol\n"); @@ -6872,7 +6942,7 @@ Type *TypeIdentifier::reliesOnTident(TemplateParameters *tparams) if (idents.dim == 0) { for (size_t i = 0; i < tparams->dim; i++) - { TemplateParameter *tp = tparams->tdata()[i]; + { TemplateParameter *tp = (*tparams)[i]; if (tp->ident->equals(ident)) return this; @@ -6889,7 +6959,7 @@ Expression *TypeIdentifier::toExpression() Expression *e = new IdentifierExp(loc, ident); for (size_t i = 0; i < idents.dim; i++) { - Identifier *id = idents.tdata()[i]; + Identifier *id = idents[i]; e = new DotIdExp(loc, e, id); } @@ -7008,6 +7078,33 @@ Dsymbol *TypeInstance::toDsymbol(Scope *sc) return s; } +Type *TypeInstance::reliesOnTident(TemplateParameters *tparams) +{ + if (tparams) + { + for (size_t i = 0; i < tparams->dim; i++) + { + TemplateParameter *tp = (*tparams)[i]; + if (tempinst->name == tp->ident) + return this; + } + if (!tempinst->tiargs) + return NULL; + for (size_t i = 0; i < tempinst->tiargs->dim; i++) + { + Type *t = isType((*tempinst->tiargs)[i]); + t = t ? t->reliesOnTident(tparams) : NULL; + if (t) + return t; + } + return NULL; + } + else + { + return Type::reliesOnTident(tparams); + } +} + /***************************** TypeTypeof *****************************/ @@ -7160,7 +7257,7 @@ Type *TypeTypeof::semantic(Loc loc, Scope *sc) { if (!s) break; - Identifier *id = idents.tdata()[i]; + Identifier *id = idents[i]; s = s->searchX(loc, sc, id); } @@ -7240,7 +7337,7 @@ Type *TypeReturn::semantic(Loc loc, Scope *sc) { if (!s) break; - Identifier *id = idents.tdata()[i]; + Identifier *id = idents[i]; s = s->searchX(loc, sc, id); } if (s) @@ -7607,6 +7704,20 @@ Expression *TypeTypedef::dotExp(Scope *sc, Expression *e, Identifier *ident) return sym->basetype->dotExp(sc, e, ident); } +structalign_t TypeTypedef::alignment() +{ + if (sym->inuse) + { + sym->error("circular definition"); + sym->basetype = Type::terror; + return STRUCTALIGN_DEFAULT; + } + sym->inuse = 1; + structalign_t a = sym->basetype->alignment(); + sym->inuse = 0; + return a; +} + Expression *TypeTypedef::getProperty(Loc loc, Identifier *ident) { #if LOGDOTEXP @@ -7843,13 +7954,9 @@ d_uns64 TypeStruct::size(Loc loc) } unsigned TypeStruct::alignsize() -{ unsigned sz; - +{ sym->size(0); // give error for forward references - sz = sym->alignsize; - if (sz > sym->structalign) - sz = sym->structalign; - return sz; + return sym->alignsize; } Dsymbol *TypeStruct::toDsymbol(Scope *sc) @@ -7908,7 +8015,7 @@ Expression *TypeStruct::dotExp(Scope *sc, Expression *e, Identifier *ident) Expression *ev = e; for (size_t i = 0; i < sym->fields.dim; i++) - { VarDeclaration *v = sym->fields.tdata()[i]; + { VarDeclaration *v = sym->fields[i]; Expression *fe; if (i == 0 && sc->func && sym->fields.dim > 1 && e->hasSideEffect()) @@ -8061,7 +8168,10 @@ L1: e = e->semantic(sc); return e; } - return new VarExp(e->loc, d, 1); + VarExp *ve = new VarExp(e->loc, d, 1); + if (d->isVarDeclaration() && d->needThis()) + ve->type = d->type->addMod(e->type->mod); + return ve; } if (d->isDataseg()) @@ -8098,10 +8208,11 @@ L1: return de->semantic(sc); } -unsigned TypeStruct::memalign(unsigned salign) +structalign_t TypeStruct::alignment() { - sym->size(0); // give error for forward references - return sym->structalign; + if (sym->alignment == 0) + sym->size(0); + return sym->alignment; } Expression *TypeStruct::defaultInit(Loc loc) @@ -8124,13 +8235,13 @@ Expression *TypeStruct::defaultInitLiteral(Loc loc) #if LOGDEFAULTINIT printf("TypeStruct::defaultInitLiteral() '%s'\n", toChars()); #endif - if (sym->isNested()) - return defaultInit(loc); + //if (sym->isNested()) + // return defaultInit(loc); Expressions *structelems = new Expressions(); - structelems->setDim(sym->fields.dim); + structelems->setDim(sym->fields.dim - sym->isnested); for (size_t j = 0; j < structelems->dim; j++) { - VarDeclaration *vd = sym->fields.tdata()[j]; + VarDeclaration *vd = sym->fields[j]; Expression *e; if (vd->init) { if (vd->init->isVoidInitializer()) @@ -8148,7 +8259,7 @@ Expression *TypeStruct::defaultInitLiteral(Loc loc) /* Copy from the initializer symbol for larger symbols, * otherwise the literals expressed as code get excessively large. */ - if (size(loc) > PTRSIZE * 4) + if (size(loc) > PTRSIZE * 4 && !sym->isnested) structinit->sinit = sym->toInitializer(); #endif @@ -8183,7 +8294,7 @@ int TypeStruct::isAssignable() * then one cannot assign this struct. */ for (size_t i = 0; i < sym->fields.dim; i++) - { VarDeclaration *v = sym->fields.tdata()[i]; + { VarDeclaration *v = sym->fields[i]; //printf("%s [%d] v = (%s) %s, v->offset = %d, v->parent = %s", sym->toChars(), i, v->kind(), v->toChars(), v->offset, v->parent->kind()); if (i == 0) ; @@ -8217,7 +8328,7 @@ int TypeStruct::hasPointers() sym->size(0); // give error for forward references for (size_t i = 0; i < s->fields.dim; i++) { - Dsymbol *sm = s->fields.tdata()[i]; + Dsymbol *sm = s->fields[i]; Declaration *d = sm->isDeclaration(); if (d->storage_class & STCref || d->hasPointers()) return TRUE; @@ -8246,14 +8357,15 @@ MATCH TypeStruct::implicitConvTo(Type *to) { m = MATCHexact; // exact match if (mod != to->mod) { + m = MATCHconst; if (MODimplicitConv(mod, to->mod)) - m = MATCHconst; + ; else { /* Check all the fields. If they can all be converted, * allow the conversion. */ for (size_t i = 0; i < sym->fields.dim; i++) - { Dsymbol *s = sym->fields.tdata()[i]; + { Dsymbol *s = sym->fields[i]; VarDeclaration *v = s->isVarDeclaration(); assert(v && v->storage_class & STCfield); @@ -8263,11 +8375,15 @@ MATCH TypeStruct::implicitConvTo(Type *to) // 'to' type Type *tv = v->type->castMod(to->mod); - //printf("\t%s => %s, match = %d\n", v->type->toChars(), tv->toChars(), tvf->implicitConvTo(tv)); - if (tvf->implicitConvTo(tv) < MATCHconst) - return MATCHnomatch; + // field match + MATCH mf = tvf->implicitConvTo(tv); + //printf("\t%s => %s, match = %d\n", v->type->toChars(), tv->toChars(), mf); + + if (mf == MATCHnomatch) + return mf; + if (mf < m) // if field match is worse + m = mf; } - m = MATCHconst; } } } @@ -8408,7 +8524,7 @@ Expression *TypeClass::dotExp(Scope *sc, Expression *e, Identifier *ident) Expression *ev = e; for (size_t i = 0; i < sym->fields.dim; i++) - { VarDeclaration *v = sym->fields.tdata()[i]; + { VarDeclaration *v = sym->fields[i]; // Don't include hidden 'this' pointer if (v->isThisDeclaration()) continue; @@ -8638,14 +8754,12 @@ L1: return de; } -#if 0 // shouldn't this be here? if (s->isImport() || s->isModule() || s->isPackage()) { e = new DsymbolExp(e->loc, s, 0); e = e->semantic(sc); return e; } -#endif OverloadSet *o = s->isOverloadSet(); if (o) @@ -8706,11 +8820,10 @@ L1: e = de->semantic(sc); return e; } - else - { - VarExp *ve = new VarExp(e->loc, d, 1); - return ve; - } + VarExp *ve = new VarExp(e->loc, d, 1); + if (d->isVarDeclaration() && d->needThis()) + ve->type = d->type->addMod(e->type->mod); + return ve; } if (d->isDataseg()) @@ -8772,7 +8885,7 @@ MATCH TypeClass::implicitConvTo(Type *to) { if (cdto->scope) cdto->semantic(NULL); - if (cdto->isBaseOf(sym, NULL)) + if (cdto->isBaseOf(sym, NULL) && MODimplicitConv(mod, to->mod)) { //printf("'to' is base\n"); return MATCHconvert; } @@ -8867,7 +8980,7 @@ TypeTuple::TypeTuple(Parameters *arguments) { for (size_t i = 0; i < arguments->dim; i++) { - Parameter *arg = arguments->tdata()[i]; + Parameter *arg = (*arguments)[i]; assert(arg && arg->type); } } @@ -8887,11 +9000,11 @@ TypeTuple::TypeTuple(Expressions *exps) { arguments->setDim(exps->dim); for (size_t i = 0; i < exps->dim; i++) - { Expression *e = exps->tdata()[i]; + { Expression *e = (*exps)[i]; if (e->type->ty == Ttuple) e->error("cannot form tuple of tuples"); Parameter *arg = new Parameter(STCundefined, e->type, NULL, NULL); - arguments->tdata()[i] = arg; + (*arguments)[i] = arg; } } this->arguments = arguments; @@ -8958,8 +9071,8 @@ int TypeTuple::equals(Object *o) if (arguments->dim == tt->arguments->dim) { for (size_t i = 0; i < tt->arguments->dim; i++) - { Parameter *arg1 = arguments->tdata()[i]; - Parameter *arg2 = tt->arguments->tdata()[i]; + { Parameter *arg1 = (*arguments)[i]; + Parameter *arg2 = (*tt->arguments)[i]; if (!arg1->type->equals(arg2->type)) return 0; @@ -8976,7 +9089,7 @@ Type *TypeTuple::reliesOnTident(TemplateParameters *tparams) { for (size_t i = 0; i < arguments->dim; i++) { - Parameter *arg = arguments->tdata()[i]; + Parameter *arg = (*arguments)[i]; Type *t = arg->type->reliesOnTident(tparams); if (t) return t; @@ -8995,9 +9108,9 @@ Type *TypeTuple::makeConst() t->arguments = new Parameters(); t->arguments->setDim(arguments->dim); for (size_t i = 0; i < arguments->dim; i++) - { Parameter *arg = arguments->tdata()[i]; + { Parameter *arg = (*arguments)[i]; Parameter *narg = new Parameter(arg->storageClass, arg->type->constOf(), arg->ident, arg->defaultArg); - t->arguments->tdata()[i] = (Parameter *)narg; + (*t->arguments)[i] = (Parameter *)narg; } return t; } @@ -9090,11 +9203,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)) @@ -9105,7 +9218,7 @@ Type *TypeSlice::semantic(Loc loc, Scope *sc) Parameters *args = new Parameters; args->reserve(i2 - i1); for (size_t i = i1; i < i2; i++) - { Parameter *arg = tt->arguments->tdata()[i]; + { Parameter *arg = (*tt->arguments)[i]; args->push(arg); } @@ -9134,11 +9247,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(); @@ -9161,7 +9274,7 @@ void TypeSlice::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol objects->setDim(i2 - i1); for (size_t i = 0; i < objects->dim; i++) { - objects->tdata()[i] = td->objects->tdata()[(size_t)i1 + i]; + (*objects)[i] = (*td->objects)[(size_t)i1 + i]; } TupleDeclaration *tds = new TupleDeclaration(loc, td->ident, objects); @@ -9268,10 +9381,10 @@ Parameters *Parameter::arraySyntaxCopy(Parameters *args) a = new Parameters(); a->setDim(args->dim); for (size_t i = 0; i < a->dim; i++) - { Parameter *arg = args->tdata()[i]; + { Parameter *arg = (*args)[i]; arg = arg->syntaxCopy(); - a->tdata()[i] = arg; + (*a)[i] = arg; } } return a; @@ -9281,32 +9394,9 @@ char *Parameter::argsTypesToChars(Parameters *args, int varargs) { OutBuffer *buf = new OutBuffer(); -#if 1 HdrGenState hgs; argsToCBuffer(buf, &hgs, args, varargs); -#else - 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 (i && varargs == 1) - buf->writeByte(','); - buf->writestring("..."); - } - } - buf->writeByte(')'); -#endif return buf->toChars(); } @@ -9532,7 +9622,7 @@ int Parameter::foreach(Parameters *args, Parameter::ForeachDg dg, void *ctx, siz size_t n = pn ? *pn : 0; // take over index int result = 0; for (size_t i = 0; i < args->dim; i++) - { Parameter *arg = args->tdata()[i]; + { Parameter *arg = (*args)[i]; Type *t = arg->type->toBasetype(); if (t->ty == Ttuple) diff --git a/dmd2/mtype.h b/dmd2/mtype.h index 8a2b1a76..a35f9f5c 100644 --- a/dmd2/mtype.h +++ b/dmd2/mtype.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 @@ -48,7 +48,7 @@ struct HdrGenState; struct Parameter; // Back end -#if IN_GCC +#ifdef IN_GCC union tree_node; typedef union tree_node TYPE; typedef TYPE type; #endif @@ -215,6 +215,7 @@ struct Type : Object static ClassDeclaration *typeinfowild; static TemplateDeclaration *associativearray; + static TemplateDeclaration *rtinfo; static Type *basic[TMAX]; static unsigned char mangleChar[TMAX]; @@ -317,8 +318,8 @@ struct Type : Object virtual ClassDeclaration *isClassHandle(); virtual Expression *getProperty(Loc loc, Identifier *ident); virtual Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); + virtual structalign_t alignment(); Expression *noMember(Scope *sc, Expression *e, Identifier *ident); - virtual unsigned memalign(unsigned salign); virtual Expression *defaultInit(Loc loc = 0); virtual Expression *defaultInitLiteral(Loc loc); virtual Expression *voidInitLiteral(VarDeclaration *var); @@ -375,6 +376,7 @@ struct TypeError : Type Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); Expression *defaultInit(Loc loc); Expression *defaultInitLiteral(Loc loc); + TypeTuple *toArgTypes(); }; struct TypeNext : Type @@ -409,7 +411,7 @@ struct TypeBasic : Type d_uns64 size(Loc loc); unsigned alignsize(); #if IN_LLVM - unsigned memalign(unsigned salign); + unsigned alignment(); #endif Expression *getProperty(Loc loc, Identifier *ident); Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); @@ -488,7 +490,7 @@ struct TypeSArray : TypeArray Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); int isString(); int isZeroInit(Loc loc); - unsigned memalign(unsigned salign); + structalign_t alignment(); MATCH constConv(Type *to); MATCH implicitConvTo(Type *to); Expression *defaultInit(Loc loc); @@ -567,6 +569,7 @@ struct TypeAArray : TypeArray int isZeroInit(Loc loc); int checkBoolean(); TypeInfoDeclaration *getTypeInfoDeclaration(); + Type *reliesOnTident(TemplateParameters *tparams); Expression *toExpression(); int hasPointers(); TypeTuple *toArgTypes(); @@ -778,6 +781,7 @@ struct TypeInstance : TypeQualified void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); Type *semantic(Loc loc, Scope *sc); Dsymbol *toDsymbol(Scope *sc); + Type *reliesOnTident(TemplateParameters *tparams = NULL); MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch = NULL); }; @@ -817,7 +821,7 @@ struct TypeStruct : Type void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - unsigned memalign(unsigned salign); + structalign_t alignment(); Expression *defaultInit(Loc loc); Expression *defaultInitLiteral(Loc loc); Expression *voidInitLiteral(VarDeclaration *var); @@ -907,6 +911,7 @@ struct TypeTypedef : Type void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); + structalign_t alignment(); Expression *getProperty(Loc loc, Identifier *ident); int isintegral(); int isfloating(); diff --git a/dmd2/opover.c b/dmd2/opover.c index bcf1828c..de57524a 100644 --- a/dmd2/opover.c +++ b/dmd2/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 @@ -355,9 +356,11 @@ Expression *UnaExp::op_overload(Scope *sc) /* Rewrite op(e1) as: * op(e1.aliasthis) */ - UnaExp *e = (UnaExp *)syntaxCopy(); - e->e1 = new DotIdExp(loc, e->e1, ad->aliasthis->ident); - return e->trySemantic(sc); + Expression *e1 = new DotIdExp(loc, this->e1, ad->aliasthis->ident); + Expression *e = copy(); + ((UnaExp *)e)->e1 = e1; + e = e->trySemantic(sc); + return e; } #endif } @@ -374,7 +377,7 @@ Expression *ArrayExp::op_overload(Scope *sc) if (fd) { for (size_t i = 0; i < arguments->dim; i++) - { Expression *x = arguments->tdata()[i]; + { Expression *x = (*arguments)[i]; // Create scope for '$' variable for this dimension ArrayScopeSymbol *sym = new ArrayScopeSymbol(sc, this); sym->loc = loc; @@ -393,7 +396,7 @@ Expression *ArrayExp::op_overload(Scope *sc) x = new CommaExp(0, av, x); x->semantic(sc); } - arguments->tdata()[i] = x; + (*arguments)[i] = x; sc = sc->pop(); } @@ -412,9 +415,11 @@ Expression *ArrayExp::op_overload(Scope *sc) /* Rewrite op(e1) as: * op(e1.aliasthis) */ - UnaExp *e = (UnaExp *)syntaxCopy(); - e->e1 = new DotIdExp(loc, e->e1, ad->aliasthis->ident); - return e->trySemantic(sc); + Expression *e1 = new DotIdExp(loc, this->e1, ad->aliasthis->ident); + Expression *e = copy(); + ((UnaExp *)e)->e1 = e1; + e = e->trySemantic(sc); + return e; } } return NULL; @@ -457,9 +462,11 @@ Expression *CastExp::op_overload(Scope *sc) /* Rewrite op(e1) as: * op(e1.aliasthis) */ - UnaExp *e = (UnaExp *)syntaxCopy(); - e->e1 = new DotIdExp(loc, e->e1, ad->aliasthis->ident); - return e->trySemantic(sc); + Expression *e1 = new DotIdExp(loc, this->e1, ad->aliasthis->ident); + Expression *e = copy(); + ((UnaExp *)e)->e1 = e1; + e = e->trySemantic(sc); + return e; } } return NULL; @@ -529,9 +536,9 @@ Expression *BinExp::op_overload(Scope *sc) */ args1.setDim(1); - args1.tdata()[0] = e1; + args1[0] = e1; args2.setDim(1); - args2.tdata()[0] = e2; + args2[0] = e2; argsset = 1; Match m; @@ -622,9 +629,9 @@ L1: if (!argsset) { args1.setDim(1); - args1.tdata()[0] = e1; + args1[0] = e1; args2.setDim(1); - args2.tdata()[0] = e2; + args2[0] = e2; } Match m; @@ -715,9 +722,11 @@ L1: /* Rewrite (e1 op e2) as: * (e1.aliasthis op e2) */ - BinExp *e = (BinExp *)syntaxCopy(); - e->e1 = new DotIdExp(loc, e->e1, ad1->aliasthis->ident); - return e->trySemantic(sc); + Expression *e1 = new DotIdExp(loc, this->e1, ad1->aliasthis->ident); + Expression *e = copy(); + ((BinExp *)e)->e1 = e1; + e = e->trySemantic(sc); + return e; } // Try alias this on second operand @@ -730,9 +739,11 @@ L1: /* Rewrite (e1 op e2) as: * (e1 op e2.aliasthis) */ - BinExp *e = (BinExp *)syntaxCopy(); - e->e2 = new DotIdExp(loc, e->e2, ad2->aliasthis->ident); - return e->trySemantic(sc); + Expression *e2 = new DotIdExp(loc, this->e2, ad2->aliasthis->ident); + Expression *e = copy(); + ((BinExp *)e)->e2 = e2; + e = e->trySemantic(sc); + return e; } #endif return NULL; @@ -776,9 +787,9 @@ Expression *BinExp::compare_overload(Scope *sc, Identifier *id) Expressions args2; args1.setDim(1); - args1.tdata()[0] = e1; + args1[0] = e1; args2.setDim(1); - args2.tdata()[0] = e2; + args2[0] = e2; Match m; memset(&m, 0, sizeof(m)); @@ -884,9 +895,11 @@ Expression *BinExp::compare_overload(Scope *sc, Identifier *id) /* Rewrite (e1 op e2) as: * (e1.aliasthis op e2) */ - BinExp *e = (BinExp *)syntaxCopy(); - e->e1 = new DotIdExp(loc, e->e1, ad1->aliasthis->ident); - return e->trySemantic(sc); + Expression *e1 = new DotIdExp(loc, this->e1, ad1->aliasthis->ident); + Expression *e = copy(); + ((BinExp *)e)->e1 = e1; + e = e->trySemantic(sc); + return e; } // Try alias this on second operand @@ -895,9 +908,11 @@ Expression *BinExp::compare_overload(Scope *sc, Identifier *id) /* Rewrite (e1 op e2) as: * (e1 op e2.aliasthis) */ - BinExp *e = (BinExp *)syntaxCopy(); - e->e2 = new DotIdExp(loc, e->e2, ad2->aliasthis->ident); - return e->trySemantic(sc); + Expression *e2 = new DotIdExp(loc, this->e2, ad2->aliasthis->ident); + Expression *e = copy(); + ((BinExp *)e)->e2 = e2; + e = e->trySemantic(sc); + return e; } return NULL; @@ -916,12 +931,20 @@ Expression *EqualExp::op_overload(Scope *sc) if (!(cd1->isCPPinterface() || cd2->isCPPinterface())) { /* Rewrite as: - * .object.opEquals(cast(Object)e1, cast(Object)e2) + * .object.opEquals(e1, e2) + */ + Expression *e1x = e1; + Expression *e2x = e2; + + /* * The explicit cast is necessary for interfaces, * see http://d.puremagic.com/issues/show_bug.cgi?id=4088 */ - Expression *e1x = new CastExp(loc, e1, ClassDeclaration::object->getType()); - Expression *e2x = new CastExp(loc, e2, ClassDeclaration::object->getType()); + Type *to = ClassDeclaration::object->getType(); + if (cd1->isInterfaceDeclaration()) + e1x = new CastExp(loc, e1, t1->isMutable() ? to : to->constOf()); + if (cd2->isInterfaceDeclaration()) + e2x = new CastExp(loc, e2, t2->isMutable() ? to : to->constOf()); Expression *e = new IdentifierExp(loc, Id::empty); e = new DotIdExp(loc, e, Id::object); @@ -968,7 +991,7 @@ Expression *BinAssignExp::op_overload(Scope *sc) Expressions *a = new Expressions(); a->push(e2); for (size_t i = 0; i < ae->arguments->dim; i++) - a->push(ae->arguments->tdata()[i]); + a->push((*ae->arguments)[i]); Objects *targsi = opToArg(sc, op); Expression *e = new DotTemplateInstanceExp(loc, ae->e1, fd->ident, targsi); @@ -1085,7 +1108,7 @@ Expression *BinAssignExp::op_overload(Scope *sc) */ args2.setDim(1); - args2.tdata()[0] = e2; + args2[0] = e2; Match m; memset(&m, 0, sizeof(m)); @@ -1132,9 +1155,11 @@ L1: /* Rewrite (e1 op e2) as: * (e1.aliasthis op e2) */ - BinExp *e = (BinExp *)syntaxCopy(); - e->e1 = new DotIdExp(loc, e->e1, ad1->aliasthis->ident); - return e->trySemantic(sc); + Expression *e1 = new DotIdExp(loc, this->e1, ad1->aliasthis->ident); + Expression *e = copy(); + ((BinExp *)e)->e1 = e1; + e = e->trySemantic(sc); + return e; } // Try alias this on second operand @@ -1144,9 +1169,11 @@ L1: /* Rewrite (e1 op e2) as: * (e1 op e2.aliasthis) */ - BinExp *e = (BinExp *)syntaxCopy(); - e->e2 = new DotIdExp(loc, e->e2, ad2->aliasthis->ident); - return e->trySemantic(sc); + Expression *e2 = new DotIdExp(loc, this->e2, ad2->aliasthis->ident); + Expression *e = copy(); + ((BinExp *)e)->e2 = e2; + e = e->trySemantic(sc); + return e; } #endif return NULL; @@ -1209,7 +1236,7 @@ int ForeachStatement::inferAggregate(Scope *sc, Dsymbol *&sapply) { Identifier *idapply = (op == TOKforeach) ? Id::apply : Id::applyReverse; #if DMDV2 - Identifier *idhead = (op == TOKforeach) ? Id::Ffront : Id::Fback; + Identifier *idfront = (op == TOKforeach) ? Id::Ffront : Id::Fback; int sliced = 0; #endif Type *tab; @@ -1262,7 +1289,7 @@ int ForeachStatement::inferAggregate(Scope *sc, Dsymbol *&sapply) } } - if (Dsymbol *shead = search_function(ad, idhead)) + if (Dsymbol *shead = ad->search(0, idfront, 0)) { // range aggregate break; } @@ -1316,7 +1343,7 @@ int ForeachStatement::inferApplyArgTypes(Scope *sc, Dsymbol *&sapply) if (sapply) // prefer opApply { for (size_t u = 0; u < arguments->dim; u++) - { Parameter *arg = arguments->tdata()[u]; + { Parameter *arg = (*arguments)[u]; if (arg->type) arg->type = arg->type->semantic(loc, sc); } @@ -1350,14 +1377,14 @@ int ForeachStatement::inferApplyArgTypes(Scope *sc, Dsymbol *&sapply) /* Return if no arguments need types. */ for (size_t u = 0; u < arguments->dim; u++) - { Parameter *arg = arguments->tdata()[u]; + { Parameter *arg = (*arguments)[u]; if (!arg->type) break; } AggregateDeclaration *ad; - Parameter *arg = arguments->tdata()[0]; + Parameter *arg = (*arguments)[0]; Type *taggr = aggr->type; assert(taggr); Type *tab = taggr->toBasetype(); @@ -1370,7 +1397,7 @@ int ForeachStatement::inferApplyArgTypes(Scope *sc, Dsymbol *&sapply) { if (!arg->type) arg->type = Type::tsize_t; // key type - arg = arguments->tdata()[1]; + arg = (*arguments)[1]; } if (!arg->type && tab->ty != Ttuple) arg->type = tab->nextOf(); // value type @@ -1383,7 +1410,7 @@ int ForeachStatement::inferApplyArgTypes(Scope *sc, Dsymbol *&sapply) { if (!arg->type) arg->type = taa->index; // key type - arg = arguments->tdata()[1]; + arg = (*arguments)[1]; } if (!arg->type) arg->type = taa->next; // value type @@ -1403,20 +1430,24 @@ int ForeachStatement::inferApplyArgTypes(Scope *sc, Dsymbol *&sapply) { if (!arg->type) { - /* Look for a head() or rear() overload + /* Look for a front() or back() overload */ Identifier *id = (op == TOKforeach) ? Id::Ffront : Id::Fback; - Dsymbol *s = search_function(ad, id); + Dsymbol *s = ad->search(0, id, 0); FuncDeclaration *fd = s ? s->isFuncDeclaration() : NULL; - if (!fd) - { if (s && s->isTemplateDeclaration()) - break; - break; + if (fd) + { + // Resolve inout qualifier of front type + arg->type = fd->type->nextOf(); + if (arg->type) + arg->type = arg->type->substWildTo(tab->mod); } - // Resolve inout qualifier of front type - arg->type = fd->type->nextOf(); - if (arg->type) - arg->type = arg->type->substWildTo(tab->mod); + else if (s && s->isTemplateDeclaration()) + ; + else if (s && s->isDeclaration()) + arg->type = ((Declaration *)s)->type; + else + break; } break; } @@ -1522,7 +1553,7 @@ static int inferApplyArgTypesY(TypeFunction *tf, Parameters *arguments, int flag for (size_t u = 0; u < nparams; u++) { - Parameter *arg = arguments->tdata()[u]; + Parameter *arg = (*arguments)[u]; Parameter *param = Parameter::getNth(tf->parameters, u); if (arg->type) { if (!arg->type->equals(param->type)) @@ -1560,7 +1591,7 @@ void inferApplyArgTypesZ(TemplateDeclaration *tstart, Parameters *arguments) } if (!td->parameters || td->parameters->dim != 1) continue; - TemplateParameter *tp = td->parameters->tdata()[0]; + TemplateParameter *tp = (*td->parameters)[0]; TemplateAliasParameter *tap = tp->isTemplateAliasParameter(); if (!tap || !tap->specType || tap->specType->ty != Tfunction) continue; diff --git a/dmd2/optimize.c b/dmd2/optimize.c index f007751c..16e30130 100644 --- a/dmd2/optimize.c +++ b/dmd2/optimize.c @@ -153,7 +153,6 @@ Expression *fromConstInitializer(int result, Expression *e1) if (e1->op == TOKvar) { VarExp *ve = (VarExp *)e1; VarDeclaration *v = ve->var->isVarDeclaration(); - int fwdref = (v && !v->originalType && v->scope); e = expandVar(result, v); if (e) { @@ -202,10 +201,10 @@ Expression *VarExp::optimize(int result) Expression *TupleExp::optimize(int result) { for (size_t i = 0; i < exps->dim; i++) - { Expression *e = exps->tdata()[i]; + { Expression *e = (*exps)[i]; e = e->optimize(WANTvalue | (result & WANTinterpret)); - exps->tdata()[i] = e; + (*exps)[i] = e; } return this; } @@ -215,10 +214,10 @@ Expression *ArrayLiteralExp::optimize(int result) if (elements) { for (size_t i = 0; i < elements->dim; i++) - { Expression *e = elements->tdata()[i]; + { Expression *e = (*elements)[i]; e = e->optimize(WANTvalue | (result & (WANTinterpret | WANTexpand))); - elements->tdata()[i] = e; + (*elements)[i] = e; } } return this; @@ -228,14 +227,14 @@ Expression *AssocArrayLiteralExp::optimize(int result) { assert(keys->dim == values->dim); for (size_t i = 0; i < keys->dim; i++) - { Expression *e = keys->tdata()[i]; + { Expression *e = (*keys)[i]; e = e->optimize(WANTvalue | (result & (WANTinterpret | WANTexpand))); - keys->tdata()[i] = e; + (*keys)[i] = e; - e = values->tdata()[i]; + e = (*values)[i]; e = e->optimize(WANTvalue | (result & (WANTinterpret | WANTexpand))); - values->tdata()[i] = e; + (*values)[i] = e; } return this; } @@ -245,11 +244,11 @@ Expression *StructLiteralExp::optimize(int result) if (elements) { for (size_t i = 0; i < elements->dim; i++) - { Expression *e = elements->tdata()[i]; + { Expression *e = (*elements)[i]; if (!e) continue; e = e->optimize(WANTvalue | (result & (WANTinterpret | WANTexpand))); - elements->tdata()[i] = e; + (*elements)[i] = e; } } return this; @@ -495,20 +494,20 @@ Expression *NewExp::optimize(int result) if (newargs) { for (size_t i = 0; i < newargs->dim; i++) - { Expression *e = newargs->tdata()[i]; + { Expression *e = (*newargs)[i]; e = e->optimize(WANTvalue); - newargs->tdata()[i] = e; + (*newargs)[i] = e; } } if (arguments) { for (size_t i = 0; i < arguments->dim; i++) - { Expression *e = arguments->tdata()[i]; + { Expression *e = (*arguments)[i]; e = e->optimize(WANTvalue); - arguments->tdata()[i] = e; + (*arguments)[i] = e; } } if (result & WANTinterpret) @@ -527,10 +526,10 @@ Expression *CallExp::optimize(int result) if (arguments) { for (size_t i = 0; i < arguments->dim; i++) - { Expression *e = arguments->tdata()[i]; + { Expression *e = (*arguments)[i]; e = e->optimize(WANTvalue); - arguments->tdata()[i] = e; + (*arguments)[i] = e; } } diff --git a/dmd2/parse.c b/dmd2/parse.c index 6119ec54..8ad48ce7 100644 --- a/dmd2/parse.c +++ b/dmd2/parse.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 // strlen(),memcpy() #include "rmem.h" #include "lexer.h" @@ -454,7 +455,10 @@ Dsymbols *Parser::parseDeclDefs(int once) ((tk = peek(tk)), 1) && skipAttributes(tk, &tk) && (tk->value == TOKlparen || - tk->value == TOKlcurly) + tk->value == TOKlcurly || + tk->value == TOKin || + tk->value == TOKout || + tk->value == TOKbody) ) { a = parseDeclarations(storageClass, comment); @@ -512,7 +516,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; @@ -535,7 +543,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; @@ -1370,7 +1378,8 @@ Parameters *Parser::parseParameters(int *pvarargs, TemplateParameters **tpl) default: Ldefault: { stc = storageClass & (STCin | STCout | STCref | STClazy); - if (stc & (stc - 1)) // if stc is not a power of 2 + if (stc & (stc - 1) && // if stc is not a power of 2 + !(stc == (STCin | STCref))) error("incompatible parameter storage classes"); if ((storageClass & (STCconst | STCout)) == (STCconst | STCout)) error("out cannot be const"); @@ -2860,7 +2869,10 @@ Dsymbols *Parser::parseDeclarations(StorageClass storage_class, unsigned char *c ((tk = peek(tk)), 1) && skipAttributes(tk, &tk) && (tk->value == TOKlparen || - tk->value == TOKlcurly) + tk->value == TOKlcurly || + tk->value == TOKin || + tk->value == TOKout || + tk->value == TOKbody) ) { ts = NULL; @@ -3347,7 +3359,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; @@ -3601,7 +3621,7 @@ Statement *Parser::parseStatement(int flags) as->reserve(a->dim); for (size_t i = 0; i < a->dim; i++) { - Dsymbol *d = a->tdata()[i]; + Dsymbol *d = (*a)[i]; s = new ExpStatement(loc, d); as->push(s); } @@ -3609,7 +3629,7 @@ Statement *Parser::parseStatement(int flags) } else if (a->dim == 1) { - Dsymbol *d = a->tdata()[0]; + Dsymbol *d = (*a)[0]; s = new ExpStatement(loc, d); } else @@ -3841,7 +3861,7 @@ Statement *Parser::parseStatement(int flags) Expression *aggr = parseExpression(); if (token.value == TOKslice && arguments->dim == 1) { - Parameter *a = arguments->tdata()[0]; + Parameter *a = (*arguments)[0]; delete arguments; nextToken(); Expression *upr = parseExpression(); @@ -4087,7 +4107,7 @@ Statement *Parser::parseStatement(int flags) // Keep cases in order by building the case statements backwards for (size_t i = cases.dim; i; i--) { - exp = cases.tdata()[i - 1]; + exp = cases[i - 1]; s = new CaseStatement(loc, exp, s); } } @@ -4242,7 +4262,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; @@ -5406,6 +5426,7 @@ Expression *Parser::parsePrimaryExp() token.value == TOKenum || token.value == TOKinterface || token.value == TOKargTypes || + token.value == TOKparameters || #if DMDV2 token.value == TOKconst && peek(&token)->value == TOKrparen || token.value == TOKinvariant && peek(&token)->value == TOKrparen || diff --git a/dmd2/readme.txt b/dmd2/readme.txt index 5f2f1516..0d72c9be 100644 --- a/dmd2/readme.txt +++ b/dmd2/readme.txt @@ -1,24 +1,26 @@ - - The D Programming Language - Compiler Front End Source - Copyright (c) 1999-2009, by Digital Mars - http://www.digitalmars.com - All Rights Reserved - - -This is the source code to the front end Digital Mars D compiler. -It covers the lexical analysis, parsing, and semantic analysis -of the D Programming Language defined in the documents at -http://www.digitalmars.com/d/ - -These sources are free, they are redistributable and modifiable -under the terms of the GNU General Public License (attached as gpl.txt), -or the Artistic License (attached as artistic.txt). - -The optimizer and code generator sources are -covered under a separate license, backendlicense.txt. - -It does not apply to anything else distributed by Digital Mars, -including D compiler executables. - --Walter Bright + + The D Programming Language + Compiler Front End Source + Copyright (c) 1999-2009, by Digital Mars + http://www.digitalmars.com + All Rights Reserved + + +This is the source code to the front end Digital Mars D compiler. +It covers the lexical analysis, parsing, and semantic analysis +of the D Programming Language defined in the documents at +http://www.digitalmars.com/d/ + +These sources are free, they are redistributable and modifiable +under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version (attached as gpl.txt), +or the Artistic License (attached as artistic.txt). + +The optimizer and code generator sources are +covered under a separate license, backendlicense.txt. + +It does not apply to anything else distributed by Digital Mars, +including D compiler executables. + +-Walter Bright diff --git a/dmd2/root/aav.c b/dmd2/root/aav.c index ca685d42..7a515a13 100644 --- a/dmd2/root/aav.c +++ b/dmd2/root/aav.c @@ -1,3 +1,12 @@ + +// Copyright (c) 2010-2012 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + /** * Implementation of associative arrays. * diff --git a/dmd2/root/aav.h b/dmd2/root/aav.h index 266b5a83..201ca48f 100644 --- a/dmd2/root/aav.h +++ b/dmd2/root/aav.h @@ -1,4 +1,12 @@ +// Copyright (c) 2010-2012 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + typedef void* Value; typedef void* Key; diff --git a/dmd2/root/array.c b/dmd2/root/array.c index f3440445..3ef48322 100644 --- a/dmd2/root/array.c +++ b/dmd2/root/array.c @@ -40,7 +40,6 @@ #include "port.h" #include "root.h" -#include "dchar.h" #include "rmem.h" diff --git a/dmd2/root/async.c b/dmd2/root/async.c index 78f17c68..92767c8e 100644 --- a/dmd2/root/async.c +++ b/dmd2/root/async.c @@ -1,4 +1,12 @@ +// Copyright (c) 2009-2012 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + #define _MT 1 #include diff --git a/dmd2/root/dchar.c b/dmd2/root/dchar.c deleted file mode 100644 index 0b11a8a4..00000000 --- a/dmd2/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/dmd2/root/dchar.h b/dmd2/root/dchar.h deleted file mode 100644 index 6ac7994c..00000000 --- a/dmd2/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/dmd2/root/gnuc.c b/dmd2/root/gnuc.c index 8f33d839..90358da1 100644 --- a/dmd2/root/gnuc.c +++ b/dmd2/root/gnuc.c @@ -1,4 +1,12 @@ +// Copyright (c) 2009-2012 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + // Put functions in here missing from gnu C #include "gnuc.h" diff --git a/dmd2/root/gnuc.h b/dmd2/root/gnuc.h index 00c9851d..6b25fbf2 100644 --- a/dmd2/root/gnuc.h +++ b/dmd2/root/gnuc.h @@ -1,4 +1,12 @@ +// Copyright (c) 2009-2012 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + #ifndef _GNUC_H #define _GNUC_H 1 diff --git a/dmd2/root/lstring.c b/dmd2/root/lstring.c deleted file mode 100644 index a4e41ed5..00000000 --- a/dmd2/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/dmd2/root/lstring.h b/dmd2/root/lstring.h deleted file mode 100644 index 0c545790..00000000 --- a/dmd2/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/dmd2/root/response.c b/dmd2/root/response.c index 31e35686..45f08662 100644 --- a/dmd2/root/response.c +++ b/dmd2/root/response.c @@ -109,6 +109,7 @@ int response_expand(int *pargc, char ***pargv) char *buffer; char *bufend; char *p; + int comment = 0; cp++; p = getenv(cp); @@ -171,15 +172,31 @@ int response_expand(int *pargc, char ***pargv) goto L2; case 0xD: + case '\n': + if (comment) + { + comment = 0; + } case 0: case ' ': case '\t': - case '\n': continue; // scan to start of argument + case '#': + comment = 1; + continue; + case '@': + if (comment) + { + continue; + } recurse = 1; default: /* start of new argument */ + if (comment) + { + continue; + } if (addargp(&n,p)) goto noexpand; instring = 0; diff --git a/dmd2/root/rmem.c b/dmd2/root/rmem.c index 2504ab93..fd202732 100644 --- a/dmd2/root/rmem.c +++ b/dmd2/root/rmem.c @@ -1,6 +1,11 @@ -/* Copyright (c) 2000 Digital Mars */ -/* All Rights Reserved */ +// Copyright (c) 2000-2012 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. #include #include diff --git a/dmd2/root/rmem.h b/dmd2/root/rmem.h index d22145a9..7307d97b 100644 --- a/dmd2/root/rmem.h +++ b/dmd2/root/rmem.h @@ -1,5 +1,11 @@ -// Copyright (C) 2000-2011 by Digital Mars + +// Copyright (c) 2000-2012 by Digital Mars // All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. #ifndef ROOT_MEM_H #define ROOT_MEM_H diff --git a/dmd2/root/root.c b/dmd2/root/root.c index 773a542a..d4697100 100644 --- a/dmd2/root/root.c +++ b/dmd2/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" #if 0 //__SC__ //def DEBUG @@ -142,22 +142,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"); @@ -206,15 +190,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; @@ -1609,30 +1584,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; @@ -1646,18 +1597,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) @@ -1719,13 +1662,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); @@ -1873,46 +1809,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; @@ -1921,16 +1817,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/dmd2/root/root.h b/dmd2/root/root.h index 830ea43b..842222e3 100644 --- a/dmd2/root/root.h +++ b/dmd2/root/root.h @@ -1,5 +1,4 @@ - // Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright @@ -24,7 +23,6 @@ typedef size_t hash_t; #include "longdouble.h" -#include "dchar.h" char *wchar2ascii(wchar_t *); int wcharIsAscii(wchar_t *); @@ -92,7 +90,6 @@ struct Object virtual void print(); virtual char *toChars(); - virtual dchar *toDchars(); virtual void toBuffer(OutBuffer *buf); /** @@ -282,14 +279,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); @@ -300,10 +294,6 @@ struct OutBuffer : Object void align(unsigned size); void vprintf(const char *format, va_list args); void printf(const char *format, ...); -#if M_UNICODE - void vprintf(const unsigned short *format, va_list args); - void printf(const unsigned short *format, ...); -#endif void bracket(char left, char right); unsigned bracket(unsigned i, const char *left, unsigned j, const char *right); void spread(unsigned offset, unsigned nbytes); diff --git a/dmd2/root/speller.c b/dmd2/root/speller.c index 373baf6d..207b49c0 100644 --- a/dmd2/root/speller.c +++ b/dmd2/root/speller.c @@ -1,4 +1,12 @@ +// Copyright (c) 2010-2012 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + #include #include #include diff --git a/dmd2/root/speller.h b/dmd2/root/speller.h index bfffb739..5f4e28f4 100644 --- a/dmd2/root/speller.h +++ b/dmd2/root/speller.h @@ -1,4 +1,12 @@ +// Copyright (c) 2010-2012 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + typedef void *(fp_speller_t)(void *, const char *); extern const char idchars[]; diff --git a/dmd2/root/stringtable.c b/dmd2/root/stringtable.c index f1c0044a..58dcd0b6 100644 --- a/dmd2/root/stringtable.c +++ b/dmd2/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/dmd2/root/stringtable.h b/dmd2/root/stringtable.h index ce714587..170894e6 100644 --- a/dmd2/root/stringtable.h +++ b/dmd2/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/dmd2/scope.c b/dmd2/scope.c index 010cdb1a..28f6b965 100644 --- a/dmd2/scope.c +++ b/dmd2/scope.c @@ -9,6 +9,7 @@ #include #include +#include // strlen() #include "root.h" #include "speller.h" diff --git a/dmd2/scope.h b/dmd2/scope.h index 4fee6539..2e54ab7b 100644 --- a/dmd2/scope.h +++ b/dmd2/scope.h @@ -87,7 +87,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 @@ -102,7 +102,7 @@ struct Scope #define SCOPEstaticassert 8 // inside static assert #define SCOPEdebug 0x10 // inside debug conditional -#if IN_GCC +#ifdef IN_GCC Expressions *attributes; // GCC decl/type attributes #endif diff --git a/dmd2/statement.c b/dmd2/statement.c index 28f44e8a..87a4080c 100644 --- a/dmd2/statement.c +++ b/dmd2/statement.c @@ -28,6 +28,7 @@ #include "parse.h" #include "template.h" #include "attrib.h" +#include "import.h" #if IN_LLVM #if defined(_MSC_VER) @@ -426,7 +427,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(); @@ -1585,6 +1586,10 @@ Statement *ForeachStatement::semantic(Scope *sc) return s; } + Type *argtype = (*arguments)[dim-1]->type; + if (argtype) + argtype = argtype->semantic(loc, sc); + TypeTuple *tuple = (TypeTuple *)tab; Statements *statements = new Statements(); //printf("aggr: op = %d, %s\n", aggr->op, aggr->toChars()); @@ -1599,9 +1604,8 @@ Statement *ForeachStatement::semantic(Scope *sc) ((DotVarExp *)(*te->exps)[0])->e1->isTemp()) { CommaExp *ce = (CommaExp *)((DotVarExp *)(*te->exps)[0])->e1; - - prelude = ce->e1; - ((DotVarExp *)(*te->exps)[0])->e1 = ce->e2; + prelude = ce->e1; + ((DotVarExp *)(*te->exps)[0])->e1 = ce->e2; } } else if (aggr->op == TOKtype) // type tuple @@ -1612,8 +1616,8 @@ Statement *ForeachStatement::semantic(Scope *sc) assert(0); for (size_t j = 0; j < n; j++) { size_t k = (op == TOKforeach) ? j : n - 1 - j; - Expression *e; - Type *t; + Expression *e = NULL; + Type *t = NULL; if (te) e = (*te->exps)[k]; else @@ -1664,14 +1668,20 @@ Statement *ForeachStatement::semantic(Scope *sc) var = new AliasDeclaration(loc, arg->ident, s); if (arg->storageClass & STCref) error("symbol %s cannot be ref", s->toChars()); + if (argtype && argtype->ty != Terror) + error("cannot specify element type for symbol %s", s->toChars()); } else if (e->op == TOKtype) { var = new AliasDeclaration(loc, arg->ident, e->type); + if (argtype && argtype->ty != Terror) + error("cannot specify element type for type %s", e->type->toChars()); } else { arg->type = e->type; + if (argtype && argtype->ty != Terror) + arg->type = argtype; Initializer *ie = new ExpInitializer(0, e); VarDeclaration *v = new VarDeclaration(loc, arg->type, arg->ident, ie); if (arg->storageClass & STCref) @@ -1688,6 +1698,8 @@ Statement *ForeachStatement::semantic(Scope *sc) else { var = new AliasDeclaration(loc, arg->ident, t); + if (argtype && argtype->ty != Terror) + error("cannot specify element type for symbol %s", s->toChars()); } DeclarationExp *de = new DeclarationExp(loc, var); st->push(new ExpStatement(loc, de)); @@ -1757,23 +1769,47 @@ Lagain: Type *argtype = arg->type->semantic(loc, sc); VarDeclaration *var; - var = new VarDeclaration(loc, argtype, arg->ident, NULL); - var->storage_class |= STCforeach; - var->storage_class |= arg->storageClass & (STCin | STCout | STCref | STC_TYPECTOR); - if (var->storage_class & (STCref | STCout)) - var->storage_class |= STCnodtor; if (dim == 2 && i == 0) - { key = var; - //var->storage_class |= STCfinal; + { +#if (BUG6652 == 1 || BUG6652 == 2) + var = new VarDeclaration(loc, arg->type, Lexer::uniqueId("__key"), NULL); + var->storage_class |= arg->storageClass & (STCin | STCout | STC_TYPECTOR); +#else + if (arg->storageClass & STCref) + var = new VarDeclaration(loc, argtype, arg->ident, NULL); + else + var = new VarDeclaration(loc, arg->type, Lexer::uniqueId("__key"), NULL); + var->storage_class |= arg->storageClass & (STCin | STCout | STC_TYPECTOR); +#endif + var->storage_class |= STCforeach; + if (var->storage_class & (STCref | STCout)) + var->storage_class |= STCnodtor; + + key = var; } else { + var = new VarDeclaration(loc, argtype, arg->ident, NULL); + var->storage_class |= STCforeach; + var->storage_class |= arg->storageClass & (STCin | STCout | STCref | STC_TYPECTOR); + if (var->storage_class & (STCref | STCout)) + var->storage_class |= STCnodtor; + value = var; - /* Reference to immutable data should be marked as const - */ - if (var->storage_class & STCref && !tn->isMutable()) + if (var->storage_class & STCref) { - var->storage_class |= STCconst; + /* Reference to immutable data should be marked as const + */ + if (!tn->isMutable()) + var->storage_class |= STCconst; + + Type *t = tab->nextOf(); + if (!t->invariantOf()->equals(argtype->invariantOf()) || + !MODimplicitConv(t->mod, argtype->mod)) + { + error("argument type mismatch, %s to ref %s", + t->toChars(), argtype->toChars()); + } } } #if 0 @@ -1831,6 +1867,30 @@ Lagain: value->init = new ExpInitializer(loc, new IndexExp(loc, new VarExp(loc, tmp), new VarExp(loc, key))); Statement *ds = new ExpStatement(loc, value); + if (dim == 2) + { Parameter *arg = (*arguments)[0]; +#if (BUG6652 == 1 || BUG6652 == 2) + if ((*arguments)[0]->storageClass & STCref) + { + AliasDeclaration *v = new AliasDeclaration(loc, arg->ident, key); + body = new CompoundStatement(loc, new ExpStatement(loc, v), body); + } + else + { + ExpInitializer *ie = new ExpInitializer(loc, new IdentifierExp(loc, key->ident)); + VarDeclaration *v = new VarDeclaration(loc, NULL, arg->ident, ie); + v->storage_class |= STCforeach | STCref | STCbug6652; + body = new CompoundStatement(loc, new ExpStatement(loc, v), body); + } +#else + if (!(arg->storageClass & STCref)) + { + ExpInitializer *ie = new ExpInitializer(loc, new IdentifierExp(loc, key->ident)); + VarDeclaration *v = new VarDeclaration(loc, NULL, arg->ident, ie); + body = new CompoundStatement(loc, new ExpStatement(loc, v), body); + } +#endif + } body = new CompoundStatement(loc, ds, body); s = new ForStatement(loc, forinit, cond, increment, body); @@ -1901,29 +1961,29 @@ Lagain: goto Lapply; { /* Look for range iteration, i.e. the properties - * .empty, .next, .retreat, .head and .rear + * .empty, .popFront, .popBack, .front and .back * foreach (e; aggr) { ... } * translates to: - * for (auto __r = aggr[]; !__r.empty; __r.next) - * { auto e = __r.head; + * for (auto __r = aggr[]; !__r.empty; __r.popFront) + * { auto e = __r.front; * ... * } */ AggregateDeclaration *ad = (tab->ty == Tclass) ? (AggregateDeclaration *)((TypeClass *)tab)->sym : (AggregateDeclaration *)((TypeStruct *)tab)->sym; - Identifier *idhead; - Identifier *idnext; + Identifier *idfront; + Identifier *idpopFront; if (op == TOKforeach) - { idhead = Id::Ffront; - idnext = Id::FpopFront; + { idfront = Id::Ffront; + idpopFront = Id::FpopFront; } else - { idhead = Id::Fback; - idnext = Id::FpopBack; + { idfront = Id::Fback; + idpopFront = Id::FpopBack; } - Dsymbol *shead = search_function(ad, idhead); - if (!shead) + Dsymbol *sfront = ad->search(0, idfront, 0); + if (!sfront) goto Lapply; /* Generate a temporary __r and initialize it with the aggregate. @@ -1939,13 +1999,13 @@ Lagain: // __r.next e = new VarExp(loc, r); - Expression *increment = new CallExp(loc, new DotIdExp(loc, e, idnext)); + Expression *increment = new CallExp(loc, new DotIdExp(loc, e, idpopFront)); /* Declaration statement for e: - * auto e = __r.idhead; + * auto e = __r.idfront; */ e = new VarExp(loc, r); - Expression *einit = new DotIdExp(loc, e, idhead); + Expression *einit = new DotIdExp(loc, e, idfront); Statement *makeargs, *forbody; if (dim == 1) { @@ -1968,7 +2028,7 @@ Lagain: makeargs = new ExpStatement(loc, de); Expression *ve = new VarExp(loc, vd); - ve->type = shead->isDeclaration()->type; + ve->type = sfront->isDeclaration()->type; if (ve->type->toBasetype()->ty == Tfunction) ve->type = ve->type->toBasetype()->nextOf(); if (!ve->type || ve->type->ty == Terror) @@ -2046,18 +2106,6 @@ Lagain: 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; - } - TypeFunction *tfld = NULL; if (sapply) { FuncDeclaration *fdapply = sapply->isFuncDeclaration(); @@ -2533,7 +2581,14 @@ Statement *ForeachRangeStatement::semantic(Scope *sc) */ ExpInitializer *ie = new ExpInitializer(loc, (op == TOKforeach) ? lwr : upr); - key = new VarDeclaration(loc, arg->type, arg->ident, ie); +#if (BUG6652 == 1 || BUG6652 == 2) + key = new VarDeclaration(loc, arg->type, Lexer::uniqueId("__key"), ie); +#else + if (arg->storageClass & STCref) + key = new VarDeclaration(loc, arg->type, arg->ident, ie); + else + key = new VarDeclaration(loc, arg->type, Lexer::uniqueId("__key"), ie); +#endif Identifier *id = Lexer::uniqueId("__limit"); ie = new ExpInitializer(loc, (op == TOKforeach) ? upr : lwr); @@ -2580,6 +2635,28 @@ Statement *ForeachRangeStatement::semantic(Scope *sc) //increment = new AddAssignExp(loc, new VarExp(loc, key), new IntegerExp(1)); increment = new PreExp(TOKpreplusplus, loc, new VarExp(loc, key)); +#if (BUG6652 == 1 || BUG6652 == 2) + if (arg->storageClass & STCref) + { + AliasDeclaration *v = new AliasDeclaration(loc, arg->ident, key); + body = new CompoundStatement(loc, new ExpStatement(loc, v), body); + } + else + { + ExpInitializer *ie = new ExpInitializer(loc, new IdentifierExp(loc, key->ident)); + VarDeclaration *v = new VarDeclaration(loc, NULL, arg->ident, ie); + v->storage_class |= STCforeach | STCref | STCbug6652; + body = new CompoundStatement(loc, new ExpStatement(loc, v), body); + } +#else + if (!(arg->storageClass & STCref)) + { + ExpInitializer *ie = new ExpInitializer(loc, new IdentifierExp(loc, key->ident)); + VarDeclaration *v = new VarDeclaration(loc, NULL, arg->ident, ie); + body = new CompoundStatement(loc, new ExpStatement(loc, v), body); + } +#endif + ForStatement *fs = new ForStatement(loc, forinit, cond, increment, body); s = fs->semantic(sc); return s; @@ -2971,8 +3048,8 @@ Statement *PragmaStatement::semantic(Scope *sc) Expression *e = (*args)[i]; e = e->semantic(sc); - if (e->op != TOKerror) - e = e->optimize(WANTvalue | WANTinterpret); + if (e->op != TOKerror && e->op != TOKtype) + e = e->ctfeInterpret(); if (e->op == TOKerror) { errorSupplemental(loc, "while evaluating pragma(msg, %s)", (*args)[i]->toChars()); goto Lerror; @@ -3002,7 +3079,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) @@ -3033,7 +3110,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()) @@ -3171,6 +3248,10 @@ Statement *SwitchStatement::semantic(Scope *sc) condition = condition->semantic(sc); condition = resolveProperties(sc, condition); + TypeEnum *te = NULL; + // preserve enum type for final switches + if (condition->type->ty == Tenum) + te = (TypeEnum *)condition->type; if (condition->type->isString()) { // If it's not an array, cast it to one @@ -3235,8 +3316,8 @@ Statement *SwitchStatement::semantic(Scope *sc) { // Don't use toBasetype() because that will skip past enums t = ((TypeTypedef *)t)->sym->basetype; } - if (condition->type->ty == Tenum) - { TypeEnum *te = (TypeEnum *)condition->type; + if (te) + { EnumDeclaration *ed = te->toDsymbol(sc)->isEnumDeclaration(); assert(ed); size_t dim = ed->members->dim; @@ -3247,7 +3328,7 @@ Statement *SwitchStatement::semantic(Scope *sc) { for (size_t j = 0; j < cases->dim; j++) { CaseStatement *cs = (*cases)[j]; - if (cs->exp->equals(em->value)) + if (cs->exp->equals(em->value) || cs->exp->toInteger() == em->value->toInteger()) goto L1; } error("enum member %s not represented in final switch", em->toChars()); @@ -3397,7 +3478,7 @@ Statement *CaseStatement::semantic(Scope *sc) } } else - exp = exp->optimize(WANTvalue | WANTinterpret); + exp = exp->ctfeInterpret(); if (exp->op != TOKstring && exp->op != TOKint64 && exp->op != TOKerror) { @@ -3503,12 +3584,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; @@ -3574,12 +3654,12 @@ DefaultStatement::DefaultStatement(Loc loc, Statement *s) : Statement(loc) { this->statement = s; -#if IN_GCC +#ifdef IN_GCC cblock = NULL; -#endif +#elif IN_LLVM bodyBB = NULL; - // LDC enclosingScopeExit = NULL; +#endif } Statement *DefaultStatement::syntaxCopy() @@ -3749,6 +3829,7 @@ ReturnStatement::ReturnStatement(Loc loc, Expression *exp) : Statement(loc) { this->exp = exp; + this->implicit0 = 0; } Statement *ReturnStatement::syntaxCopy() @@ -3766,7 +3847,6 @@ Statement *ReturnStatement::semantic(Scope *sc) FuncDeclaration *fd = sc->parent->isFuncDeclaration(); Scope *scx = sc; - int implicit0 = 0; Expression *eorg = NULL; if (fd->fes) @@ -3810,8 +3890,11 @@ Statement *ReturnStatement::semantic(Scope *sc) { fd->hasReturnExp |= 1; + FuncLiteralDeclaration *fld = fd->isFuncLiteralDeclaration(); if (tret) exp = exp->inferType(tbret); + else if (fld && fld->treq && fld->treq->nextOf()) + exp = exp->inferType(fld->treq->nextOf()); exp = exp->semantic(sc); exp = resolveProperties(sc, exp); if (!((TypeFunction *)fd->type)->isref) @@ -3984,11 +4067,14 @@ 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->storage_class |= STCresult; - v->semantic(scx); - if (!scx->insert(v)) + if (((TypeFunction *)fd->type)->isref) + v->storage_class |= STCref | STCforeach; + v->semantic(sco); + if (!sco->insert(v)) assert(0); v->parent = fd; fd->vresult = v; @@ -4027,7 +4113,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); @@ -4357,9 +4443,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); } @@ -5313,9 +5406,6 @@ LabelDsymbol::LabelDsymbol(Identifier *ident) : Dsymbol(ident) { statement = NULL; -#if IN_GCC - asmLabelNum = 0; -#endif } LabelDsymbol *LabelDsymbol::isLabel() // is this a LabelDsymbol()? @@ -5353,7 +5443,7 @@ int AsmStatement::comeFrom() int AsmStatement::blockExit(bool mustNotThrow) { if (mustNotThrow) - error("asm statements are assumed to throw", toChars()); + error("asm statements are assumed to throw"); // Assume the worst return BEfallthru | BEthrow | BEreturn | BEgoto | BEhalt; } @@ -5410,9 +5500,29 @@ Statement *ImportStatement::syntaxCopy() Statement *ImportStatement::semantic(Scope *sc) { for (size_t i = 0; i < imports->dim; i++) - { Dsymbol *s = (*imports)[i]; + { Import *s = (*imports)[i]->isImport(); + + for (size_t i = 0; i < s->names.dim; i++) + { + Identifier *name = s->names[i]; + Identifier *alias = s->aliases[i]; + + if (!alias) + alias = name; + + TypeIdentifier *tname = new TypeIdentifier(s->loc, name); + AliasDeclaration *ad = new AliasDeclaration(s->loc, alias, tname); + + s->aliasdecls.push(ad); + } + s->semantic(sc); sc->insert(s); + + for (size_t i = 0; i < s->aliasdecls.dim; i++) + { + sc->insert(s->aliasdecls[i]); + } } return this; } diff --git a/dmd2/statement.h b/dmd2/statement.h index 95336e13..105a944b 100644 --- a/dmd2/statement.h +++ b/dmd2/statement.h @@ -79,7 +79,7 @@ struct DValue; typedef DValue elem; #endif -#if IN_GCC +#ifdef IN_GCC union tree_node; typedef union tree_node block; //union tree_node; typedef union tree_node elem; #else @@ -595,7 +595,7 @@ struct CaseRangeStatement : Statement struct DefaultStatement : Statement { Statement *statement; -#if IN_GCC +#ifdef IN_GCC block *cblock; // back end: label for the block #endif @@ -664,6 +664,7 @@ struct SwitchErrorStatement : Statement struct ReturnStatement : Statement { Expression *exp; + int implicit0; ReturnStatement(Loc loc, Expression *exp); Statement *syntaxCopy(); @@ -930,9 +931,6 @@ struct LabelStatement : Statement struct LabelDsymbol : Dsymbol { LabelStatement *statement; -#if IN_GCC - unsigned asmLabelNum; // GCC-specific -#endif LabelDsymbol(Identifier *ident); LabelDsymbol *isLabel(); diff --git a/dmd2/staticassert.c b/dmd2/staticassert.c index 8e3dcefa..6fa9606c 100644 --- a/dmd2/staticassert.c +++ b/dmd2/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 @@ -59,10 +59,14 @@ void StaticAssert::semantic2(Scope *sc) ++sc->ignoreTemplates; Expression *e = exp->semantic(sc); sc = sc->pop(); - 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()); @@ -74,7 +78,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/dmd2/struct.c b/dmd2/struct.c index d38cc3fc..2e476ace 100644 --- a/dmd2/struct.c +++ b/dmd2/struct.c @@ -37,7 +37,6 @@ AggregateDeclaration::AggregateDeclaration(Loc loc, Identifier *id) scope = 0; structsize = 0; // size of struct alignsize = 0; // size of struct for alignment purposes - structalign = 0; // struct member alignment in effect hasUnions = 0; sizeok = SIZEOKnone; // size not determined yet deferred = NULL; @@ -60,6 +59,7 @@ AggregateDeclaration::AggregateDeclaration(Loc loc, Identifier *id) noDefaultCtor = FALSE; #endif dtor = NULL; + getRTInfo = NULL; #if IN_LLVM availableExternally = true; // assume this unless proven otherwise @@ -83,7 +83,7 @@ void AggregateDeclaration::semantic2(Scope *sc) sc = sc->push(this); for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = members->tdata()[i]; + Dsymbol *s = (*members)[i]; s->semantic2(sc); } sc->pop(); @@ -103,10 +103,25 @@ 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(); + + if (!getRTInfo) + { // Evaluate: gcinfo!type + Objects *tiargs = new Objects(); + tiargs->push(type); + TemplateInstance *ti = new TemplateInstance(loc, Type::rtinfo, tiargs); + ti->semantic(sc); + ti->semantic2(sc); + ti->semantic3(sc); + Dsymbol *s = ti->toAlias(); + Expression *e = new DsymbolExp(0, s, 0); + e = e->semantic(ti->tempdecl->scope); + e = e->ctfeInterpret(); + getRTInfo = e; + } } } @@ -117,7 +132,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(); } @@ -127,6 +142,8 @@ void AggregateDeclaration::inlineScan() unsigned AggregateDeclaration::size(Loc loc) { //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) @@ -196,20 +213,33 @@ int AggregateDeclaration::isExport() */ void AggregateDeclaration::alignmember( - unsigned salign, // struct alignment that is in effect - unsigned size, // alignment requirement of field + structalign_t alignment, // struct alignment that is in effect + unsigned size, // alignment requirement of field unsigned *poffset) { - //printf("salign = %d, size = %d, offset = %d\n",salign,size,offset); - if (salign > 1) + //printf("alignment = %d, size = %d, offset = %d\n",alignment,size,offset); + switch (alignment) { - assert(size != 3); - unsigned sa = size; - if (sa == 0 || salign < sa) - sa = salign; - *poffset = (*poffset + sa - 1) & ~(sa - 1); + case 1: + // No alignment + break; + + case STRUCTALIGN_DEFAULT: + { /* Must match what the corresponding C compiler's default + * alignment behavior is. + */ + assert(size != 3); + unsigned sa = (size == 0 || 8 < size) ? 8 : size; + *poffset = (*poffset + sa - 1) & ~(sa - 1); + break; + } + + default: + // Align on alignment boundary, which must be a positive power of 2 + assert(alignment > 0 && !(alignment & (alignment - 1))); + *poffset = (*poffset + alignment - 1) & ~(alignment - 1); + break; } - //printf("result = %d\n",offset); } /**************************************** @@ -221,25 +251,36 @@ 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 alignment, // alignment in effect for this member unsigned *paggsize, // size of aggregate (updated) unsigned *paggalignsize, // size of aggregate for alignment purposes (updated) bool isunion // the aggregate is a union ) { unsigned ofs = *nextoffset; - alignmember(memalign, memalignsize, &ofs); + alignmember(alignment, memalignsize, &ofs); unsigned memoffset = ofs; ofs += memsize; if (ofs > *paggsize) *paggsize = ofs; if (!isunion) *nextoffset = ofs; - if (global.params.is64bit && memalign == 8 && memalignsize == 16) - /* Not sure how to handle this */ - ; - else if (memalign < memalignsize) - memalignsize = memalign; + + if (alignment == STRUCTALIGN_DEFAULT) + { + if (global.params.is64bit && memalignsize == 16) + ; + else if (8 < memalignsize) + memalignsize = 8; + else if (alignment < memalignsize) + memalignsize = alignment; + } + else + { + if (memalignsize < alignment) + memalignsize = alignment; + } + if (*paggalignsize < memalignsize) *paggalignsize = memalignsize; @@ -265,13 +306,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; @@ -290,7 +331,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. */ @@ -300,7 +341,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; @@ -322,7 +363,10 @@ StructDeclaration::StructDeclaration(Loc loc, Identifier *id) postblit = NULL; xeq = NULL; + alignment = 0; #endif + arg1type = NULL; + arg2type = NULL; // For forward references type = new TypeStruct(this); @@ -389,8 +433,8 @@ void StructDeclaration::semantic(Scope *sc) #else handle = type->pointerTo(); #endif - structalign = sc->structalign; protection = sc->protection; + alignment = sc->structalign; storage_class |= sc->stc; if (sc->stc & STCdeprecated) isdeprecated = true; @@ -403,7 +447,7 @@ void StructDeclaration::semantic(Scope *sc) int hasfunctions = 0; 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); if (s->isFuncDeclaration()) @@ -452,6 +496,7 @@ void StructDeclaration::semantic(Scope *sc) sc2->inunion = 1; sc2->protection = PROTpublic; sc2->explicitProtection = 0; + sc2->structalign = STRUCTALIGN_DEFAULT; size_t members_dim = members->dim; @@ -507,7 +552,7 @@ void StructDeclaration::semantic(Scope *sc) fields.setDim(0); structsize = 0; alignsize = 0; - structalign = 0; +// structalign = 0; scope = scx ? scx : new Scope(*sc); scope->setNoFree(); @@ -631,6 +676,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); @@ -667,6 +721,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; @@ -690,11 +745,56 @@ void StructDeclaration::finalizeSize(Scope *sc) // Round struct size up to next alignsize boundary. // This will ensure that arrays of structs will get their internals // aligned properly. - structsize = (structsize + alignsize - 1) & ~(alignsize - 1); + if (alignment == STRUCTALIGN_DEFAULT) + structsize = (structsize + alignsize - 1) & ~(alignsize - 1); + else + structsize = (structsize + alignment - 1) & ~(alignment - 1); 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() +{ + if (isnested || cpctor || postblit || ctor || dtor) + return false; + + /* Recursively check any fields have a constructor. + * We should cache the results of this. + */ + for (size_t i = 0; i < fields.dim; i++) + { + Dsymbol *s = fields[i]; + VarDeclaration *v = s->isVarDeclaration(); + assert(v && v->storage_class & STCfield); + if (v->storage_class & STCref) + continue; + Type *tv = v->type->toBasetype(); + while (tv->ty == Tsarray) + { TypeSArray *ta = (TypeSArray *)tv; + tv = tv->nextOf()->toBasetype(); + } + if (tv->ty == Tstruct) + { TypeStruct *ts = (TypeStruct *)tv; + StructDeclaration *sd = ts->sym; + if (!sd->isPOD()) + return false; + } + } + return true; +} + void StructDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->printf("%s ", kind()); @@ -711,7 +811,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/dmd2/template.c b/dmd2/template.c index 6bf52076..dd2a67fa 100644 --- a/dmd2/template.c +++ b/dmd2/template.c @@ -1,6441 +1,6611 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -// Handle template implementation - -#include -#include - -#include "root.h" -#include "aav.h" -#include "rmem.h" -#include "stringtable.h" -#include "mars.h" -#include "identifier.h" -#include "mtype.h" -#include "template.h" -#include "init.h" -#include "expression.h" -#include "scope.h" -#include "module.h" -#include "aggregate.h" -#include "declaration.h" -#include "dsymbol.h" -#include "hdrgen.h" -#include "id.h" - -#if WINDOWS_SEH -#include -long __cdecl __ehfilter(LPEXCEPTION_POINTERS ep); -#endif - -#define LOG 0 - -/******************************************** - * These functions substitute for dynamic_cast. dynamic_cast does not work - * on earlier versions of gcc. - */ - -Expression *isExpression(Object *o) -{ - //return dynamic_cast(o); - if (!o || o->dyncast() != DYNCAST_EXPRESSION) - return NULL; - return (Expression *)o; -} - -Dsymbol *isDsymbol(Object *o) -{ - //return dynamic_cast(o); - if (!o || o->dyncast() != DYNCAST_DSYMBOL) - return NULL; - return (Dsymbol *)o; -} - -Type *isType(Object *o) -{ - //return dynamic_cast(o); - if (!o || o->dyncast() != DYNCAST_TYPE) - return NULL; - return (Type *)o; -} - -Tuple *isTuple(Object *o) -{ - //return dynamic_cast(o); - if (!o || o->dyncast() != DYNCAST_TUPLE) - return NULL; - return (Tuple *)o; -} - -/************************************** - * Is this Object an error? - */ -int isError(Object *o) -{ - Type *t = isType(o); - if (t) - return (t->ty == Terror); - Expression *e = isExpression(o); - if (e) - return (e->op == TOKerror); - Tuple *v = isTuple(o); - if (v) - return arrayObjectIsError(&v->objects); - return 0; -} - -/************************************** - * Are any of the Objects an error? - */ -int arrayObjectIsError(Objects *args) -{ - for (size_t i = 0; i < args->dim; i++) - { - Object *o = args->tdata()[i]; - if (isError(o)) - return 1; - } - return 0; -} - -/*********************** - * Try to get arg as a type. - */ - -Type *getType(Object *o) -{ - Type *t = isType(o); - if (!t) - { Expression *e = isExpression(o); - if (e) - t = e->type; - } - return t; -} - -Dsymbol *getDsymbol(Object *oarg) -{ - Dsymbol *sa; - Expression *ea = isExpression(oarg); - if (ea) - { // Try to convert Expression to symbol - if (ea->op == TOKvar) - sa = ((VarExp *)ea)->var; - else if (ea->op == TOKfunction) - sa = ((FuncExp *)ea)->fd; - else - sa = NULL; - } - else - { // Try to convert Type to symbol - Type *ta = isType(oarg); - if (ta) - sa = ta->toDsymbol(NULL); - else - sa = isDsymbol(oarg); // if already a symbol - } - return sa; -} - -/****************************** - * If o1 matches o2, return 1. - * Else, return 0. - */ - -int match(Object *o1, Object *o2, TemplateDeclaration *tempdecl, Scope *sc) -{ - Type *t1 = isType(o1); - Type *t2 = isType(o2); - Expression *e1 = isExpression(o1); - Expression *e2 = isExpression(o2); - Dsymbol *s1 = isDsymbol(o1); - Dsymbol *s2 = isDsymbol(o2); - Tuple *u1 = isTuple(o1); - Tuple *u2 = isTuple(o2); - - //printf("\t match t1 %p t2 %p, e1 %p e2 %p, s1 %p s2 %p, u1 %p u2 %p\n", t1,t2,e1,e2,s1,s2,u1,u2); - - /* A proper implementation of the various equals() overrides - * should make it possible to just do o1->equals(o2), but - * we'll do that another day. - */ - - if (s1) - { - VarDeclaration *v1 = s1->isVarDeclaration(); - if (v1 && v1->storage_class & STCmanifest) - { ExpInitializer *ei1 = v1->init->isExpInitializer(); - if (ei1) - e1 = ei1->exp, s1 = NULL; - } - } - if (s2) - { - VarDeclaration *v2 = s2->isVarDeclaration(); - if (v2 && v2->storage_class & STCmanifest) - { ExpInitializer *ei2 = v2->init->isExpInitializer(); - if (ei2) - e2 = ei2->exp, s2 = NULL; - } - } - - if (t1) - { - /* if t1 is an instance of ti, then give error - * about recursive expansions. - */ - Dsymbol *s = t1->toDsymbol(sc); - if (s && s->parent) - { TemplateInstance *ti1 = s->parent->isTemplateInstance(); - if (ti1 && ti1->tempdecl == tempdecl) - { - for (Scope *sc1 = sc; sc1; sc1 = sc1->enclosing) - { - if (sc1->scopesym == ti1) - { - tempdecl->error("recursive template expansion for template argument %s", t1->toChars()); - return 1; // fake a match - } - } - } - } - - //printf("t1 = %s\n", t1->toChars()); - //printf("t2 = %s\n", t2->toChars()); - if (!t2 || !t1->equals(t2)) - goto Lnomatch; - } - else if (e1) - { -#if 0 - if (e1 && e2) - { - printf("match %d\n", e1->equals(e2)); - e1->print(); - e2->print(); - e1->type->print(); - e2->type->print(); - } -#endif - if (!e2) - goto Lnomatch; - if (!e1->equals(e2)) - goto Lnomatch; - } - else if (s1) - { - if (!s2 || !s1->equals(s2) || s1->parent != s2->parent) - goto Lnomatch; - } - else if (u1) - { - if (!u2) - goto Lnomatch; - if (u1->objects.dim != u2->objects.dim) - goto Lnomatch; - for (size_t i = 0; i < u1->objects.dim; i++) - { - if (!match(u1->objects.tdata()[i], - u2->objects.tdata()[i], - tempdecl, sc)) - goto Lnomatch; - } - } - //printf("match\n"); - return 1; // match - -Lnomatch: - //printf("nomatch\n"); - return 0; // nomatch; -} - - -/************************************ - * Match an array of them. - */ -int arrayObjectMatch(Objects *oa1, Objects *oa2, TemplateDeclaration *tempdecl, Scope *sc) -{ - if (oa1 == oa2) - return 1; - if (oa1->dim != oa2->dim) - return 0; - for (size_t j = 0; j < oa1->dim; j++) - { Object *o1 = oa1->tdata()[j]; - Object *o2 = oa2->tdata()[j]; - if (!match(o1, o2, tempdecl, sc)) - { - return 0; - } - } - return 1; -} - -/**************************************** - * This makes a 'pretty' version of the template arguments. - * It's analogous to genIdent() which makes a mangled version. - */ - -void ObjectToCBuffer(OutBuffer *buf, HdrGenState *hgs, Object *oarg) -{ - //printf("ObjectToCBuffer()\n"); - Type *t = isType(oarg); - Expression *e = isExpression(oarg); - Dsymbol *s = isDsymbol(oarg); - Tuple *v = isTuple(oarg); - /* The logic of this should match what genIdent() does. The _dynamic_cast() - * function relies on all the pretty strings to be unique for different classes - * (see Bugzilla 7375). - * Perhaps it would be better to demangle what genIdent() does. - */ - if (t) - { //printf("\tt: %s ty = %d\n", t->toChars(), t->ty); - t->toCBuffer(buf, NULL, hgs); - } - else if (e) - { - if (e->op == TOKvar) - e = e->optimize(WANTvalue); // added to fix Bugzilla 7375 - e->toCBuffer(buf, hgs); - } - else if (s) - { - char *p = s->ident ? s->ident->toChars() : s->toChars(); - buf->writestring(p); - } - else if (v) - { - Objects *args = &v->objects; - for (size_t i = 0; i < args->dim; i++) - { - if (i) - buf->writeByte(','); - Object *o = (*args)[i]; - ObjectToCBuffer(buf, hgs, o); - } - } - else if (!oarg) - { - buf->writestring("NULL"); - } - else - { -#ifdef DEBUG - printf("bad Object = %p\n", oarg); -#endif - assert(0); - } -} - -#if DMDV2 -Object *objectSyntaxCopy(Object *o) -{ - if (!o) - return NULL; - Type *t = isType(o); - if (t) - return t->syntaxCopy(); - Expression *e = isExpression(o); - if (e) - return e->syntaxCopy(); - return o; -} -#endif - - -/* ======================== TemplateDeclaration ============================= */ - -TemplateDeclaration::TemplateDeclaration(Loc loc, Identifier *id, - TemplateParameters *parameters, Expression *constraint, Dsymbols *decldefs, int ismixin) - : ScopeDsymbol(id) -{ -#if LOG - printf("TemplateDeclaration(this = %p, id = '%s')\n", this, id->toChars()); -#endif -#if 0 - if (parameters) - for (int i = 0; i < parameters->dim; i++) - { TemplateParameter *tp = parameters->tdata()[i]; - //printf("\tparameter[%d] = %p\n", i, tp); - TemplateTypeParameter *ttp = tp->isTemplateTypeParameter(); - - if (ttp) - { - printf("\tparameter[%d] = %s : %s\n", i, tp->ident->toChars(), ttp->specType ? ttp->specType->toChars() : ""); - } - } -#endif - this->loc = loc; - this->parameters = parameters; - this->origParameters = parameters; - this->constraint = constraint; - this->members = decldefs; - this->overnext = NULL; - this->overroot = NULL; - this->semanticRun = PASSinit; - this->onemember = NULL; - this->literal = 0; - this->ismixin = ismixin; - this->previous = NULL; - - // Compute in advance for Ddoc's use - if (members) - { - Dsymbol *s; - if (Dsymbol::oneMembers(members, &s, ident) && s) - { - onemember = s; - s->parent = this; - } - } -} - -Dsymbol *TemplateDeclaration::syntaxCopy(Dsymbol *) -{ - //printf("TemplateDeclaration::syntaxCopy()\n"); - TemplateDeclaration *td; - TemplateParameters *p; - - p = NULL; - if (parameters) - { - p = new TemplateParameters(); - p->setDim(parameters->dim); - for (size_t i = 0; i < p->dim; i++) - { TemplateParameter *tp = (*parameters)[i]; - p->tdata()[i] = tp->syntaxCopy(); - } - } - Expression *e = NULL; - if (constraint) - e = constraint->syntaxCopy(); - Dsymbols *d = Dsymbol::arraySyntaxCopy(members); - td = new TemplateDeclaration(loc, ident, p, e, d, ismixin); - -#if IN_LLVM - td->intrinsicName = intrinsicName; -#endif - - return td; -} - -void TemplateDeclaration::semantic(Scope *sc) -{ -#if LOG - printf("TemplateDeclaration::semantic(this = %p, id = '%s')\n", this, ident->toChars()); - printf("sc->stc = %llx\n", sc->stc); - printf("sc->module = %s\n", sc->module->toChars()); -#endif - if (semanticRun) - return; // semantic() already run - semanticRun = PASSsemantic; - - if (sc->module && sc->module->ident == Id::object && ident == Id::AssociativeArray) - { Type::associativearray = this; - } - - if (sc->func) - { -#if DMDV1 - error("cannot declare template at function scope %s", sc->func->toChars()); -#endif - } - - if (/*global.params.useArrayBounds &&*/ sc->module) - { - // Generate this function as it may be used - // when template is instantiated in other modules - // FIXME: LDC - //sc->module->toModuleArray(); - } - - if (/*global.params.useAssert &&*/ sc->module) - { - // Generate this function as it may be used - // when template is instantiated in other modules - // FIXME: LDC - //sc->module->toModuleAssert(); - } - -#if DMDV2 - if (/*global.params.useUnitTests &&*/ sc->module) - { - // Generate this function as it may be used - // when template is instantiated in other modules - // FIXME: LDC - // sc->module->toModuleUnittest(); - } -#endif - - /* Remember Scope for later instantiations, but make - * a copy since attributes can change. - */ - if (!this->scope) - { this->scope = new Scope(*sc); - this->scope->setNoFree(); - } - - // Set up scope for parameters - ScopeDsymbol *paramsym = new ScopeDsymbol(); - paramsym->parent = sc->parent; - Scope *paramscope = sc->push(paramsym); - paramscope->parameterSpecialization = 1; - paramscope->stc = 0; - - if (!parent) - parent = sc->parent; - - if (global.params.doDocComments) - { - origParameters = new TemplateParameters(); - origParameters->setDim(parameters->dim); - for (size_t i = 0; i < parameters->dim; i++) - { - TemplateParameter *tp = (*parameters)[i]; - origParameters->tdata()[i] = tp->syntaxCopy(); - } - } - - for (size_t i = 0; i < parameters->dim; i++) - { - TemplateParameter *tp = parameters->tdata()[i]; - - tp->declareParameter(paramscope); - } - - for (size_t i = 0; i < parameters->dim; i++) - { - TemplateParameter *tp = (*parameters)[i]; - - tp->semantic(paramscope); - if (i + 1 != parameters->dim && tp->isTemplateTupleParameter()) - { error("template tuple parameter must be last one"); - errors = true; - } - } - - paramscope->pop(); - - // Compute again - onemember = NULL; - if (members) - { - Dsymbol *s; - if (Dsymbol::oneMembers(members, &s, ident) && s) - { - onemember = s; - s->parent = this; - } - } - - /* BUG: should check: - * o no virtual functions or non-static data members of classes - */ -} - -const char *TemplateDeclaration::kind() -{ - return (onemember && onemember->isAggregateDeclaration()) - ? onemember->kind() - : (char *)"template"; -} - -/********************************** - * Overload existing TemplateDeclaration 'this' with the new one 's'. - * Return !=0 if successful; i.e. no conflict. - */ - -int TemplateDeclaration::overloadInsert(Dsymbol *s) -{ - TemplateDeclaration **pf; - TemplateDeclaration *f; - -#if LOG - printf("TemplateDeclaration::overloadInsert('%s')\n", s->toChars()); -#endif - f = s->isTemplateDeclaration(); - if (!f) - return FALSE; - TemplateDeclaration *pthis = this; - for (pf = &pthis; *pf; pf = &(*pf)->overnext) - { -#if 0 - // Conflict if TemplateParameter's match - // Will get caught anyway later with TemplateInstance, but - // should check it now. - TemplateDeclaration *f2 = *pf; - - if (f->parameters->dim != f2->parameters->dim) - goto Lcontinue; - - for (size_t i = 0; i < f->parameters->dim; i++) - { TemplateParameter *p1 = f->parameters->tdata()[i]; - TemplateParameter *p2 = f2->parameters->tdata()[i]; - - if (!p1->overloadMatch(p2)) - goto Lcontinue; - } - -#if LOG - printf("\tfalse: conflict\n"); -#endif - return FALSE; - - Lcontinue: - ; -#endif - } - - f->overroot = this; - *pf = f; -#if LOG - printf("\ttrue: no conflict\n"); -#endif - return TRUE; -} - -/**************************** - * Declare all the function parameters as variables - * and add them to the scope - */ -void TemplateDeclaration::makeParamNamesVisibleInConstraint(Scope *paramscope, Expressions *fargs) -{ - /* We do this ONLY if there is only one function in the template. - */ - FuncDeclaration *fd = onemember && onemember->toAlias() ? - onemember->toAlias()->isFuncDeclaration() : NULL; - if (fd) - { - /* - Making parameters is similar to FuncDeclaration::semantic3 - */ - paramscope->parent = fd; - - TypeFunction *tf = (TypeFunction *)fd->type->syntaxCopy(); - - // Shouldn't run semantic on default arguments and return type. - for (int i = 0; iparameters->dim; i++) - tf->parameters->tdata()[i]->defaultArg = NULL; - tf->next = NULL; - - // Resolve parameter types and 'auto ref's. - tf->fargs = fargs; - tf = (TypeFunction *)tf->semantic(loc, paramscope); - - Parameters *fparameters = tf->parameters; - int fvarargs = tf->varargs; - - size_t nfparams = Parameter::dim(fparameters); // Num function parameters - for (size_t i = 0; i < nfparams; i++) - { - Parameter *fparam = Parameter::getNth(fparameters, i); - // Remove addMod same as func.d L1065 of FuncDeclaration::semantic3 - //Type *vtype = fparam->type; - //if (fd->type && fd->isPure()) - // vtype = vtype->addMod(MODconst); - fparam->storageClass &= (STCin | STCout | STCref | STClazy | STCfinal | STC_TYPECTOR | STCnodtor); - fparam->storageClass |= STCparameter; - if (fvarargs == 2 && i + 1 == nfparams) - fparam->storageClass |= STCvariadic; - } - for (size_t i = 0; i < fparameters->dim; i++) - { - Parameter *fparam = fparameters->tdata()[i]; - if (!fparam->ident) - continue; // don't add it, if it has no name - VarDeclaration *v = new VarDeclaration(loc, fparam->type, fparam->ident, NULL); - v->storage_class = fparam->storageClass; - v->semantic(paramscope); - if (!paramscope->insert(v)) - error("parameter %s.%s is already defined", toChars(), v->toChars()); - else - v->parent = this; - } - } -} - -/*************************************** - * Given that ti is an instance of this TemplateDeclaration, - * deduce the types of the parameters to this, and store - * those deduced types in dedtypes[]. - * Input: - * flag 1: don't do semantic() because of dummy types - * 2: don't change types in matchArg() - * Output: - * dedtypes deduced arguments - * Return match level. - */ - -MATCH TemplateDeclaration::matchWithInstance(TemplateInstance *ti, - Objects *dedtypes, Expressions *fargs, int flag) -{ MATCH m; - size_t dedtypes_dim = dedtypes->dim; - -#define LOGM 0 -#if LOGM - printf("\n+TemplateDeclaration::matchWithInstance(this = %s, ti = %s, flag = %d)\n", toChars(), ti->toChars(), flag); -#endif - -#if 0 - printf("dedtypes->dim = %d, parameters->dim = %d\n", dedtypes_dim, parameters->dim); - if (ti->tiargs->dim) - printf("ti->tiargs->dim = %d, [0] = %p\n", - ti->tiargs->dim, - ti->tiargs->tdata()[0]); -#endif - dedtypes->zero(); - - if (errors) - return MATCHnomatch; - - size_t parameters_dim = parameters->dim; - int variadic = isVariadic() != NULL; - - // If more arguments than parameters, no match - if (ti->tiargs->dim > parameters_dim && !variadic) - { -#if LOGM - printf(" no match: more arguments than parameters\n"); -#endif - return MATCHnomatch; - } - - assert(dedtypes_dim == parameters_dim); - assert(dedtypes_dim >= ti->tiargs->dim || variadic); - - // Set up scope for parameters - assert((size_t)scope > 0x10000); - ScopeDsymbol *paramsym = new ScopeDsymbol(); - paramsym->parent = scope->parent; - Scope *paramscope = scope->push(paramsym); - paramscope->stc = 0; - - // Attempt type deduction - m = MATCHexact; - for (size_t i = 0; i < dedtypes_dim; i++) - { MATCH m2; - TemplateParameter *tp = parameters->tdata()[i]; - Declaration *sparam; - - //printf("\targument [%d]\n", i); -#if LOGM - //printf("\targument [%d] is %s\n", i, oarg ? oarg->toChars() : "null"); - TemplateTypeParameter *ttp = tp->isTemplateTypeParameter(); - if (ttp) - printf("\tparameter[%d] is %s : %s\n", i, tp->ident->toChars(), ttp->specType ? ttp->specType->toChars() : ""); -#endif - - m2 = tp->matchArg(paramscope, ti->tiargs, i, parameters, dedtypes, &sparam); - //printf("\tm2 = %d\n", m2); - - if (m2 == MATCHnomatch) - { -#if 0 - printf("\tmatchArg() for parameter %i failed\n", i); -#endif - goto Lnomatch; - } - - if (m2 < m) - m = m2; - - if (!flag) - sparam->semantic(paramscope); - if (!paramscope->insert(sparam)) - goto Lnomatch; - } - - if (!flag) - { - /* Any parameter left without a type gets the type of - * its corresponding arg - */ - for (size_t i = 0; i < dedtypes_dim; i++) - { - if (!dedtypes->tdata()[i]) - { assert(i < ti->tiargs->dim); - dedtypes->tdata()[i] = (Type *)ti->tiargs->tdata()[i]; - } - } - } - -#if DMDV2 - if (m && constraint && !flag) - { /* Check to see if constraint is satisfied. - */ - makeParamNamesVisibleInConstraint(paramscope, fargs); - Expression *e = constraint->syntaxCopy(); - Scope *sc = paramscope->push(); - - /* There's a chicken-and-egg problem here. We don't know yet if this template - * instantiation will be a local one (isnested is set), and we won't know until - * after selecting the correct template. Thus, function we're nesting inside - * is not on the sc scope chain, and this can cause errors in FuncDeclaration::getLevel(). - * Workaround the problem by setting a flag to relax the checking on frame errors. - */ - sc->flags |= SCOPEstaticif; - - FuncDeclaration *fd = onemember && onemember->toAlias() ? - 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 (fd && fd->vthis) - fd->vthis = vthissave; - - sc->pop(); - e = e->optimize(WANTvalue | WANTinterpret); - if (e->isBool(TRUE)) - ; - else if (e->isBool(FALSE)) - goto Lnomatch; - else - { - e->error("constraint %s is not constant or does not evaluate to a bool", e->toChars()); - } - } -#endif - -#if LOGM - // Print out the results - printf("--------------------------\n"); - printf("template %s\n", toChars()); - printf("instance %s\n", ti->toChars()); - if (m) - { - for (size_t i = 0; i < dedtypes_dim; i++) - { - TemplateParameter *tp = parameters->tdata()[i]; - Object *oarg; - - printf(" [%d]", i); - - if (i < ti->tiargs->dim) - oarg = ti->tiargs->tdata()[i]; - else - oarg = NULL; - tp->print(oarg, dedtypes->tdata()[i]); - } - } - else - goto Lnomatch; -#endif - -#if LOGM - printf(" match = %d\n", m); -#endif - goto Lret; - -Lnomatch: -#if LOGM - printf(" no match\n"); -#endif - m = MATCHnomatch; - -Lret: - paramscope->pop(); -#if LOGM - printf("-TemplateDeclaration::matchWithInstance(this = %p, ti = %p) = %d\n", this, ti, m); -#endif - return m; -} - -/******************************************** - * Determine partial specialization order of 'this' vs td2. - * Returns: - * match this is at least as specialized as td2 - * 0 td2 is more specialized than this - */ - -MATCH TemplateDeclaration::leastAsSpecialized(TemplateDeclaration *td2, Expressions *fargs) -{ - /* This works by taking the template parameters to this template - * declaration and feeding them to td2 as if it were a template - * instance. - * If it works, then this template is at least as specialized - * as td2. - */ - - TemplateInstance ti(0, ident); // create dummy template instance - Objects dedtypes; - -#define LOG_LEASTAS 0 - -#if LOG_LEASTAS - printf("%s.leastAsSpecialized(%s)\n", toChars(), td2->toChars()); -#endif - - // Set type arguments to dummy template instance to be types - // generated from the parameters to this template declaration - ti.tiargs = new Objects(); - ti.tiargs->setDim(parameters->dim); - for (size_t i = 0; i < ti.tiargs->dim; i++) - { - TemplateParameter *tp = parameters->tdata()[i]; - - Object *p = (Object *)tp->dummyArg(); - if (p) - ti.tiargs->tdata()[i] = p; - else - ti.tiargs->setDim(i); - } - - // Temporary Array to hold deduced types - //dedtypes.setDim(parameters->dim); - dedtypes.setDim(td2->parameters->dim); - - // Attempt a type deduction - MATCH m = td2->matchWithInstance(&ti, &dedtypes, fargs, 1); - if (m) - { - /* A non-variadic template is more specialized than a - * variadic one. - */ - if (isVariadic() && !td2->isVariadic()) - goto L1; - -#if LOG_LEASTAS - printf(" matches %d, so is least as specialized\n", m); -#endif - return m; - } - L1: -#if LOG_LEASTAS - printf(" doesn't match, so is not as specialized\n"); -#endif - return MATCHnomatch; -} - - -/************************************************* - * Match function arguments against a specific template function. - * Input: - * loc instantiation location - * targsi Expression/Type initial list of template arguments - * ethis 'this' argument if !NULL - * fargs arguments to function - * Output: - * dedargs Expression/Type deduced template arguments - * Returns: - * match level - */ - -MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Scope *sc, Loc loc, Objects *targsi, - Expression *ethis, Expressions *fargs, - Objects *dedargs) -{ - size_t nfparams; - size_t nfargs; - size_t nargsi; // array size of targsi - int fptupindex = -1; - int tuple_dim = 0; - MATCH match = MATCHexact; - FuncDeclaration *fd = onemember->toAlias()->isFuncDeclaration(); - Parameters *fparameters; // function parameter list - int fvarargs; // function varargs - Objects dedtypes; // for T:T*, the dedargs is the T*, dedtypes is the T - unsigned wildmatch = 0; - - TypeFunction *tf = (TypeFunction *)fd->type; - -#if 0 - printf("\nTemplateDeclaration::deduceFunctionTemplateMatch() %s\n", toChars()); - for (size_t i = 0; i < fargs->dim; i++) - { Expression *e = fargs->tdata()[i]; - printf("\tfarg[%d] is %s, type is %s\n", i, e->toChars(), e->type->toChars()); - } - printf("fd = %s\n", fd->toChars()); - printf("fd->type = %s\n", fd->type->toChars()); - if (ethis) - printf("ethis->type = %s\n", ethis->type->toChars()); -#endif - - assert((size_t)scope > 0x10000); - - dedargs->setDim(parameters->dim); - dedargs->zero(); - - dedtypes.setDim(parameters->dim); - dedtypes.zero(); - - if (errors) - return MATCHnomatch; - - // Set up scope for parameters - ScopeDsymbol *paramsym = new ScopeDsymbol(); - paramsym->parent = scope->parent; - Scope *paramscope = scope->push(paramsym); - paramscope->stc = 0; - - TemplateTupleParameter *tp = isVariadic(); - int tp_is_declared = 0; - -#if 0 - for (size_t i = 0; i < dedargs->dim; i++) - { - printf("\tdedarg[%d] = ", i); - Object *oarg = dedargs->tdata()[i]; - if (oarg) printf("%s", oarg->toChars()); - printf("\n"); - } -#endif - - - nargsi = 0; - if (targsi) - { // Set initial template arguments - - nargsi = targsi->dim; - size_t n = parameters->dim; - if (tp) - n--; - if (nargsi > n) - { if (!tp) - goto Lnomatch; - - /* The extra initial template arguments - * now form the tuple argument. - */ - Tuple *t = new Tuple(); - assert(parameters->dim); - dedargs->tdata()[parameters->dim - 1] = t; - - tuple_dim = nargsi - n; - t->objects.setDim(tuple_dim); - for (size_t i = 0; i < tuple_dim; i++) - { - t->objects.tdata()[i] = targsi->tdata()[n + i]; - } - declareParameter(paramscope, tp, t); - tp_is_declared = 1; - } - else - n = nargsi; - - memcpy(dedargs->tdata(), targsi->tdata(), n * sizeof(*dedargs->tdata())); - - for (size_t i = 0; i < n; i++) - { assert(i < parameters->dim); - TemplateParameter *tp = parameters->tdata()[i]; - MATCH m; - Declaration *sparam = NULL; - - m = tp->matchArg(paramscope, dedargs, i, parameters, &dedtypes, &sparam); - //printf("\tdeduceType m = %d\n", m); - if (m == MATCHnomatch) - goto Lnomatch; - if (m < match) - match = m; - - sparam->semantic(paramscope); - if (!paramscope->insert(sparam)) - goto Lnomatch; - } - } -#if 0 - for (size_t i = 0; i < dedargs->dim; i++) - { - printf("\tdedarg[%d] = ", i); - Object *oarg = dedargs->tdata()[i]; - if (oarg) printf("%s", oarg->toChars()); - printf("\n"); - } -#endif - - fparameters = fd->getParameters(&fvarargs); - nfparams = Parameter::dim(fparameters); // number of function parameters - nfargs = fargs ? fargs->dim : 0; // number of function arguments - - /* Check for match of function arguments with variadic template - * parameter, such as: - * - * template Foo(T, A...) { void Foo(T t, A a); } - * void main() { Foo(1,2,3); } - */ - if (tp) // if variadic - { - if (nfparams == 0 && nfargs != 0) // if no function parameters - { - if (tp_is_declared) - goto L2; - Tuple *t = new Tuple(); - //printf("t = %p\n", t); - dedargs->tdata()[parameters->dim - 1] = t; - declareParameter(paramscope, tp, t); - goto L2; - } - else if (nfargs < nfparams - 1) - goto L1; - else - { - /* Figure out which of the function parameters matches - * the tuple template parameter. Do this by matching - * type identifiers. - * Set the index of this function parameter to fptupindex. - */ - for (fptupindex = 0; fptupindex < nfparams; fptupindex++) - { - Parameter *fparam = fparameters->tdata()[fptupindex]; - if (fparam->type->ty != Tident) - continue; - TypeIdentifier *tid = (TypeIdentifier *)fparam->type; - if (!tp->ident->equals(tid->ident) || tid->idents.dim) - continue; - - if (fvarargs) // variadic function doesn't - goto Lnomatch; // go with variadic template - - if (tp_is_declared) - goto L2; - - // Apply function parameter storage classes to parameter type - tid = (TypeIdentifier *)tid->addStorageClass(fparam->storageClass); - - /* The types of the function arguments - * now form the tuple argument. - */ - Tuple *t = new Tuple(); - dedargs->tdata()[parameters->dim - 1] = t; - - tuple_dim = nfargs - (nfparams - 1); - t->objects.setDim(tuple_dim); - for (size_t i = 0; i < tuple_dim; i++) - { Expression *farg = fargs->tdata()[fptupindex + i]; - - // Check invalid arguments to detect errors early. - if (farg->op == TOKerror || farg->type->ty == Terror) - goto Lnomatch; - - if (!(fparam->storageClass & STClazy) && farg->type->ty == Tvoid) - goto Lnomatch; - - unsigned mod = farg->type->mod; - Type *tt; - MATCH m; - - #define X(U,T) ((U) << 4) | (T) - if (tid->mod & MODwild) - { - switch (X(tid->mod, mod)) - { - case X(MODwild, MODwild): - case X(MODwild | MODshared, MODwild | MODshared): - case X(MODwild, 0): - case X(MODwild, MODconst): - case X(MODwild, MODimmutable): - case X(MODwild | MODshared, MODshared): - case X(MODwild | MODshared, MODconst | MODshared): - - if (mod & MODwild) - wildmatch |= MODwild; - else if (mod == 0) - wildmatch |= MODmutable; - else - wildmatch |= (mod & ~MODshared); - tt = farg->type->mutableOf(); - m = MATCHconst; - goto Lx; - - default: - break; - } - } - - switch (X(tid->mod, mod)) - { - case X(0, 0): - case X(0, MODconst): - case X(0, MODimmutable): - case X(0, MODshared): - case X(0, MODconst | MODshared): - case X(0, MODwild): - case X(0, MODwild | MODshared): - // foo(U:U) T => T - // foo(U:U) const(T) => const(T) - // foo(U:U) immutable(T) => immutable(T) - // foo(U:U) shared(T) => shared(T) - // foo(U:U) const(shared(T)) => const(shared(T)) - // foo(U:U) wild(T) => wild(T) - // foo(U:U) wild(shared(T)) => wild(shared(T)) - - tt = farg->type; - m = MATCHexact; - break; - - case X(MODconst, MODconst): - case X(MODimmutable, MODimmutable): - case X(MODshared, MODshared): - case X(MODconst | MODshared, MODconst | MODshared): - case X(MODwild, MODwild): - case X(MODwild | MODshared, MODwild | MODshared): - // foo(U:const(U)) const(T) => T - // foo(U:immutable(U)) immutable(T) => T - // foo(U:shared(U)) shared(T) => T - // foo(U:const(shared(U)) const(shared(T)) => T - // foo(U:wild(U)) wild(T) => T - // foo(U:wild(shared(U)) wild(shared(T)) => T - - tt = farg->type->mutableOf()->unSharedOf(); - m = MATCHexact; - break; - - case X(MODconst, 0): - case X(MODconst, MODimmutable): - case X(MODconst, MODconst | MODshared): - case X(MODconst | MODshared, MODimmutable): - case X(MODconst, MODwild): - case X(MODconst, MODwild | MODshared): - // foo(U:const(U)) T => T - // foo(U:const(U)) immutable(T) => T - // foo(U:const(U)) const(shared(T)) => shared(T) - // foo(U:const(shared(U)) immutable(T) => T - // foo(U:const(U)) wild(shared(T)) => shared(T) - - tt = farg->type->mutableOf(); - m = MATCHconst; - break; - - case X(MODshared, MODconst | MODshared): - case X(MODconst | MODshared, MODshared): - case X(MODshared, MODwild | MODshared): - // foo(U:shared(U)) const(shared(T)) => const(T) - // foo(U:const(shared(U)) shared(T) => T - // foo(U:shared(U)) wild(shared(T)) => wild(T) - tt = farg->type->unSharedOf(); - m = MATCHconst; - break; - - case X(MODimmutable, 0): - case X(MODimmutable, MODconst): - case X(MODimmutable, MODshared): - case X(MODimmutable, MODconst | MODshared): - case X(MODconst, MODshared): - case X(MODshared, 0): - case X(MODshared, MODconst): - case X(MODshared, MODimmutable): - case X(MODconst | MODshared, 0): - case X(MODconst | MODshared, MODconst): - case X(MODimmutable, MODwild): - case X(MODshared, MODwild): - case X(MODconst | MODshared, MODwild): - case X(MODwild, 0): - case X(MODwild, MODconst): - case X(MODwild, MODimmutable): - case X(MODwild, MODshared): - case X(MODwild, MODconst | MODshared): - case X(MODwild | MODshared, 0): - case X(MODwild | MODshared, MODconst): - case X(MODwild | MODshared, MODimmutable): - case X(MODwild | MODshared, MODshared): - case X(MODwild | MODshared, MODconst | MODshared): - case X(MODwild | MODshared, MODwild): - case X(MODimmutable, MODwild | MODshared): - case X(MODconst | MODshared, MODwild | MODshared): - case X(MODwild, MODwild | MODshared): - - // foo(U:immutable(U)) T => nomatch - // foo(U:immutable(U)) const(T) => nomatch - // foo(U:immutable(U)) shared(T) => nomatch - // foo(U:immutable(U)) const(shared(T)) => nomatch - // foo(U:const(U)) shared(T) => nomatch - // foo(U:shared(U)) T => nomatch - // foo(U:shared(U)) const(T) => nomatch - // foo(U:shared(U)) immutable(T) => nomatch - // foo(U:const(shared(U)) T => nomatch - // foo(U:const(shared(U)) const(T) => nomatch - // foo(U:immutable(U)) wild(T) => nomatch - // foo(U:shared(U)) wild(T) => nomatch - // foo(U:const(shared(U)) wild(T) => nomatch - // foo(U:wild(U)) T => nomatch - // foo(U:wild(U)) const(T) => nomatch - // foo(U:wild(U)) immutable(T) => nomatch - // foo(U:wild(U)) shared(T) => nomatch - // foo(U:wild(U)) const(shared(T)) => nomatch - // foo(U:wild(shared(U)) T => nomatch - // foo(U:wild(shared(U)) const(T) => nomatch - // foo(U:wild(shared(U)) immutable(T) => nomatch - // foo(U:wild(shared(U)) shared(T) => nomatch - // foo(U:wild(shared(U)) const(shared(T)) => nomatch - // foo(U:wild(shared(U)) wild(T) => nomatch - // foo(U:immutable(U)) wild(shared(T)) => nomatch - // foo(U:const(shared(U))) wild(shared(T)) => nomatch - // foo(U:wild(U)) wild(shared(T)) => nomatch - m = MATCHnomatch; - break; - - default: - assert(0); - } - #undef X - - Lx: - if (m == MATCHnomatch) - goto Lnomatch; - if (m < match) - match = m; - - t->objects.tdata()[i] = tt; - } - declareParameter(paramscope, tp, t); - goto L2; - } - fptupindex = -1; - } - } - -L1: - if (nfparams == nfargs) - ; - else if (nfargs > nfparams) - { - if (fvarargs == 0) - goto Lnomatch; // too many args, no match - match = MATCHconvert; // match ... with a conversion - } - -L2: -#if DMDV2 - if (ethis) - { - // Match 'ethis' to any TemplateThisParameter's - for (size_t i = 0; i < parameters->dim; i++) - { TemplateParameter *tp = parameters->tdata()[i]; - TemplateThisParameter *ttp = tp->isTemplateThisParameter(); - if (ttp) - { MATCH m; - - Type *t = new TypeIdentifier(0, ttp->ident); - m = ethis->type->deduceType(paramscope, t, parameters, &dedtypes); - if (!m) - goto Lnomatch; - if (m < match) - match = m; // pick worst match - } - } - - // Match attributes of ethis against attributes of fd - if (fd->type) - { - Type *tthis = ethis->type; - unsigned mod = fd->type->mod; - StorageClass stc = scope->stc | fd->storage_class2; - // Propagate parent storage class (see bug 5504) - Dsymbol *p = parent; - while (p->isTemplateDeclaration() || p->isTemplateInstance()) - p = p->parent; - AggregateDeclaration *ad = p->isAggregateDeclaration(); - if (ad) - stc |= ad->storage_class; - - if (stc & (STCshared | STCsynchronized)) - mod |= MODshared; - if (stc & STCimmutable) - mod |= MODimmutable; - if (stc & STCconst) - mod |= MODconst; - if (stc & STCwild) - mod |= MODwild; - // Fix mod - if (mod & MODimmutable) - mod = MODimmutable; - if (mod & MODconst) - mod &= ~STCwild; - if (tthis->mod != mod) - { - if (!MODmethodConv(tthis->mod, mod)) - goto Lnomatch; - if (MATCHconst < match) - match = MATCHconst; - } - } - } -#endif - - // Loop through the function parameters - for (size_t parami = 0; parami < nfparams; parami++) - { - /* Skip over function parameters which wound up - * as part of a template tuple parameter. - */ - if (parami == fptupindex) - continue; - /* Set i = index into function arguments - * Function parameters correspond to function arguments as follows. - * Note that tuple_dim may be zero, and there may be default or - * variadic arguments at the end. - * arg [0..fptupindex] == param[0..fptupindex] - * arg [fptupindex..fptupindex+tuple_dim] == param[fptupindex] - * arg[fputupindex+dim.. ] == param[fptupindex+1.. ] - */ - size_t i = parami; - if (fptupindex >= 0 && parami > fptupindex) - i += tuple_dim - 1; - - Parameter *fparam = Parameter::getNth(fparameters, parami); - - if (i >= nfargs) // if not enough arguments - { - if (fparam->defaultArg) - { /* Default arguments do not participate in template argument - * deduction. - */ - goto Lmatch; - } - } - else - { - Expression *farg = fargs->tdata()[i]; - - // Check invalid arguments to detect errors early. - if (farg->op == TOKerror || farg->type->ty == Terror) - goto Lnomatch; - -Lretry: -#if 0 - printf("\tfarg->type = %s\n", farg->type->toChars()); - printf("\tfparam->type = %s\n", fparam->type->toChars()); -#endif - Type *argtype = farg->type; - - // Apply function parameter storage classes to parameter types - fparam->type = fparam->type->addStorageClass(fparam->storageClass); - -#if DMDV2 - /* Allow string literals which are type [] to match with [dim] - */ - if (farg->op == TOKstring) - { StringExp *se = (StringExp *)farg; - if (!se->committed && argtype->ty == Tarray && - fparam->type->toBasetype()->ty == Tsarray) - { - argtype = new TypeSArray(argtype->nextOf(), new IntegerExp(se->loc, se->len, Type::tindex)); - argtype = argtype->semantic(se->loc, NULL); - argtype = argtype->invariantOf(); - } - } - - /* Allow implicit function literals to delegate conversion - */ - if (farg->op == TOKfunction) - { FuncExp *fe = (FuncExp *)farg; - Type *tp = fparam->type; - Expression *e = fe->inferType(tp, 1, parameters); - if (!e) - goto Lvarargs; - farg = e; - argtype = farg->type; - } - - if (!(fparam->storageClass & STClazy) && argtype->ty == Tvoid) - goto Lnomatch; - - /* Remove top const for dynamic array types and pointer types - */ - if ((argtype->ty == Tarray || argtype->ty == Tpointer) && - !argtype->isMutable() && - (!(fparam->storageClass & STCref) || - (fparam->storageClass & STCauto) && !farg->isLvalue())) - { - argtype = argtype->mutableOf(); - } -#endif - - if (fvarargs == 2 && i + 1 == nfparams && i + 1 < nfargs) - goto Lvarargs; - - unsigned wm = 0; - MATCH m = argtype->deduceType(paramscope, fparam->type, parameters, &dedtypes, &wm); - //printf("\tdeduceType m = %d\n", m); - //printf("\twildmatch = x%x m = %d\n", wildmatch, m); - wildmatch |= wm; - - /* If no match, see if there's a conversion to a delegate - */ - if (!m) - { Type *tbp = fparam->type->toBasetype(); - Type *tba = farg->type->toBasetype(); - AggregateDeclaration *ad; - if (tbp->ty == Tdelegate) - { - TypeDelegate *td = (TypeDelegate *)fparam->type->toBasetype(); - TypeFunction *tf = (TypeFunction *)td->next; - - if (!tf->varargs && Parameter::dim(tf->parameters) == 0) - { - m = farg->type->deduceType(paramscope, tf->next, parameters, &dedtypes); - if (!m && tf->next->toBasetype()->ty == Tvoid) - m = MATCHconvert; - } - //printf("\tm2 = %d\n", m); - } - else if (tba->ty == Tclass) - { - ad = ((TypeClass *)tba)->sym; - goto Lad; - } - else if (tba->ty == Tstruct) - { - ad = ((TypeStruct *)tba)->sym; - Lad: - if (ad->aliasthis) - { /* If a semantic error occurs while doing alias this, - * eg purity(bug 7295), just regard it as not a match. - */ - unsigned olderrors = global.startGagging(); - Expression *e = resolveAliasThis(sc, farg); - if (!global.endGagging(olderrors)) - { farg = e; - goto Lretry; - } - } - } - } - - if (m && (fparam->storageClass & (STCref | STCauto)) == STCref) - { if (!farg->isLvalue()) - { - if (farg->op == TOKstructliteral) - m = MATCHconvert; - else if (farg->op == TOKcall) - { - CallExp *ce = (CallExp *)farg; - if (ce->e1->op == TOKdotvar && - ((DotVarExp *)ce->e1)->var->isCtorDeclaration()) - { - m = MATCHconvert; - } - else - goto Lnomatch; - } - else - goto Lnomatch; - } - } - if (m && (fparam->storageClass & STCout)) - { if (!farg->isLvalue()) - goto Lnomatch; - } - if (!m && (fparam->storageClass & STClazy) && fparam->type->ty == Tvoid && - farg->type->ty != Tvoid) - m = MATCHconvert; - - if (m) - { if (m < match) - match = m; // pick worst match - continue; - } - } - - Lvarargs: - /* The following code for variadic arguments closely - * matches TypeFunction::callMatch() - */ - if (!(fvarargs == 2 && i + 1 == nfparams)) - goto Lnomatch; - - /* Check for match with function parameter T... - */ - Type *tb = fparam->type->toBasetype(); - switch (tb->ty) - { - // Perhaps we can do better with this, see TypeFunction::callMatch() - case Tsarray: - { TypeSArray *tsa = (TypeSArray *)tb; - dinteger_t sz = tsa->dim->toInteger(); - if (sz != nfargs - i) - goto Lnomatch; - } - case Tarray: - { TypeArray *ta = (TypeArray *)tb; - for (; i < nfargs; i++) - { - Expression *arg = fargs->tdata()[i]; - assert(arg); - - if (arg->op == TOKfunction) - { FuncExp *fe = (FuncExp *)arg; - Type *tp = tb->nextOf(); - - Expression *e = fe->inferType(tp, 1, parameters); - if (!e) - goto Lnomatch; - arg = e; - } - - MATCH m; - /* If lazy array of delegates, - * convert arg(s) to delegate(s) - */ - Type *tret = fparam->isLazyArray(); - if (tret) - { - if (ta->next->equals(arg->type)) - { m = MATCHexact; - } - else - { - m = arg->implicitConvTo(tret); - if (m == MATCHnomatch) - { - if (tret->toBasetype()->ty == Tvoid) - m = MATCHconvert; - } - } - } - else - { - m = arg->type->deduceType(paramscope, ta->next, parameters, &dedtypes); - //m = arg->implicitConvTo(ta->next); - } - if (m == MATCHnomatch) - goto Lnomatch; - if (m < match) - match = m; - } - goto Lmatch; - } - case Tclass: - case Tident: - goto Lmatch; - - default: - goto Lnomatch; - } - } - -Lmatch: - - for (size_t i = nargsi; i < dedargs->dim; i++) - { - TemplateParameter *tparam = parameters->tdata()[i]; - //printf("tparam[%d] = %s\n", i, tparam->ident->toChars()); - /* For T:T*, the dedargs is the T*, dedtypes is the T - * But for function templates, we really need them to match - */ - Object *oarg = dedargs->tdata()[i]; - Object *oded = dedtypes.tdata()[i]; - //printf("1dedargs[%d] = %p, dedtypes[%d] = %p\n", i, oarg, i, oded); - //if (oarg) printf("oarg: %s\n", oarg->toChars()); - //if (oded) printf("oded: %s\n", oded->toChars()); - if (!oarg) - { - if (oded) - { - if (tparam->specialization()) - { /* The specialization can work as long as afterwards - * the oded == oarg - */ - Declaration *sparam; - dedargs->tdata()[i] = oded; - MATCH m2 = tparam->matchArg(paramscope, dedargs, i, parameters, &dedtypes, &sparam); - //printf("m2 = %d\n", m2); - if (!m2) - goto Lnomatch; - if (m2 < match) - match = m2; // pick worst match - if (dedtypes.tdata()[i] != oded) - error("specialization not allowed for deduced parameter %s", tparam->ident->toChars()); - } - } - else - { oded = tparam->defaultArg(loc, paramscope); - if (!oded) - { - if (tp && // if tuple parameter and - fptupindex < 0 && // tuple parameter was not in function parameter list and - nargsi == dedargs->dim - 1) // we're one argument short (i.e. no tuple argument) - { // make tuple argument an empty tuple - oded = (Object *)new Tuple(); - } - else - goto Lnomatch; - } - } - declareParameter(paramscope, tparam, oded); - dedargs->tdata()[i] = oded; - } - } - -#if DMDV2 - if (constraint) - { /* Check to see if constraint is satisfied. - * Most of this code appears twice; this is a good candidate for refactoring. - */ - makeParamNamesVisibleInConstraint(paramscope, fargs); - Expression *e = constraint->syntaxCopy(); - paramscope->ignoreTemplates++; - 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); - - 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; - - e = e->optimize(WANTvalue | WANTinterpret); - if (e->isBool(TRUE)) - ; - else if (e->isBool(FALSE)) - goto Lnomatch; - else - { - e->error("constraint %s is not constant or does not evaluate to a bool", e->toChars()); - } - } -#endif - -#if 0 - for (i = 0; i < dedargs->dim; i++) - { Type *t = dedargs->tdata()[i]; - printf("\tdedargs[%d] = %d, %s\n", i, t->dyncast(), t->toChars()); - } -#endif - - paramscope->pop(); - //printf("\tmatch %d\n", match); - return match; - -Lnomatch: - paramscope->pop(); - //printf("\tnomatch\n"); - return MATCHnomatch; -} - -/************************************************** - * Declare template parameter tp with value o, and install it in the scope sc. - */ - -void TemplateDeclaration::declareParameter(Scope *sc, TemplateParameter *tp, Object *o) -{ - //printf("TemplateDeclaration::declareParameter('%s', o = %p)\n", tp->ident->toChars(), o); - - Type *targ = isType(o); - Expression *ea = isExpression(o); - Dsymbol *sa = isDsymbol(o); - Tuple *va = isTuple(o); - - Dsymbol *s; - - // See if tp->ident already exists with a matching definition - Dsymbol *scopesym; - s = sc->search(loc, tp->ident, &scopesym); - if (s && scopesym == sc->scopesym) - { - TupleDeclaration *td = s->isTupleDeclaration(); - if (va && td) - { Tuple tup; - tup.objects = *td->objects; - if (match(va, &tup, this, sc)) - { - return; - } - } - } - - if (targ) - { - //printf("type %s\n", targ->toChars()); - s = new AliasDeclaration(0, tp->ident, targ); - } - else if (sa) - { - //printf("Alias %s %s;\n", sa->ident->toChars(), tp->ident->toChars()); - s = new AliasDeclaration(0, tp->ident, sa); - } - else if (ea) - { - // tdtypes.data[i] always matches ea here - Initializer *init = new ExpInitializer(loc, ea); - TemplateValueParameter *tvp = tp->isTemplateValueParameter(); - - Type *t = tvp ? tvp->valType : NULL; - - VarDeclaration *v = new VarDeclaration(loc, t, tp->ident, init); - v->storage_class = STCmanifest; - s = v; - } - else if (va) - { - //printf("\ttuple\n"); - s = new TupleDeclaration(loc, tp->ident, &va->objects); - } - else - { -#ifdef DEBUG - o->print(); -#endif - assert(0); - } - if (!sc->insert(s)) - error("declaration %s is already defined", tp->ident->toChars()); - s->semantic(sc); -} - -/************************************** - * Determine if TemplateDeclaration is variadic. - */ - -TemplateTupleParameter *isVariadic(TemplateParameters *parameters) -{ size_t dim = parameters->dim; - TemplateTupleParameter *tp = NULL; - - if (dim) - tp = (parameters->tdata()[dim - 1])->isTemplateTupleParameter(); - return tp; -} - -TemplateTupleParameter *TemplateDeclaration::isVariadic() -{ - return ::isVariadic(parameters); -} - -/*********************************** - * We can overload templates. - */ - -int TemplateDeclaration::isOverloadable() -{ - return 1; -} - -/************************************************* - * Given function arguments, figure out which template function - * to expand, and return that function. - * If no match, give error message and return NULL. - * Input: - * sc instantiation scope - * loc instantiation location - * targsi initial list of template arguments - * ethis if !NULL, the 'this' pointer argument - * fargs arguments to function - * flags 1: do not issue error message on no match, just return NULL - */ - -FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Scope *sc, Loc loc, - Objects *targsi, Expression *ethis, Expressions *fargs, int flags) -{ - MATCH m_best = MATCHnomatch; - TemplateDeclaration *td_ambig = NULL; - TemplateDeclaration *td_best = NULL; - Objects *tdargs = new Objects(); - TemplateInstance *ti; - FuncDeclaration *fd_best; - -#if 0 - printf("TemplateDeclaration::deduceFunctionTemplate() %s\n", toChars()); - printf(" targsi:\n"); - if (targsi) - { for (size_t i = 0; i < targsi->dim; i++) - { Object *arg = targsi->tdata()[i]; - printf("\t%s\n", arg->toChars()); - } - } - printf(" fargs:\n"); - for (size_t i = 0; i < fargs->dim; i++) - { Expression *arg = fargs->tdata()[i]; - printf("\t%s %s\n", arg->type->toChars(), arg->toChars()); - //printf("\tty = %d\n", arg->type->ty); - } - printf("stc = %llx\n", scope->stc); -#endif - - for (TemplateDeclaration *td = this; td; td = td->overnext) - { - if (!td->semanticRun) - { - error("forward reference to template %s", td->toChars()); - goto Lerror; - } - if (!td->onemember || !td->onemember->toAlias()->isFuncDeclaration()) - { - error("is not a function template"); - goto Lerror; - } - - Objects dedargs; - FuncDeclaration *fd = NULL; - - MATCH m = td->deduceFunctionTemplateMatch(sc, loc, targsi, ethis, fargs, &dedargs); - //printf("deduceFunctionTemplateMatch = %d\n", m); - if (!m) // if no match - continue; - - if (m < m_best) - goto Ltd_best; - if (m > m_best) - goto Ltd; - - { - // Disambiguate by picking the most specialized TemplateDeclaration - MATCH c1 = td->leastAsSpecialized(td_best, fargs); - MATCH c2 = td_best->leastAsSpecialized(td, fargs); - //printf("1: c1 = %d, c2 = %d\n", c1, c2); - - if (c1 > c2) - goto Ltd; - else if (c1 < c2) - goto Ltd_best; - } - - if (!fd_best) - { - fd_best = td_best->doHeaderInstantiation(sc, tdargs, fargs); - if (!fd_best) - goto Lerror; - } - { - fd = td->doHeaderInstantiation(sc, &dedargs, fargs); - if (!fd) - goto Lerror; - } - assert(fd && fd_best); - - { - // Disambiguate by tf->callMatch - TypeFunction *tf1 = (TypeFunction *)fd->type; - TypeFunction *tf2 = (TypeFunction *)fd_best->type; - MATCH c1 = (MATCH) tf1->callMatch(fd->needThis() && !fd->isCtorDeclaration() ? ethis : NULL, fargs); - MATCH c2 = (MATCH) tf2->callMatch(fd_best->needThis() && !fd->isCtorDeclaration() ? ethis : NULL, fargs); - //printf("2: c1 = %d, c2 = %d\n", c1, c2); - - if (c1 > c2) - goto Ltd; - if (c1 < c2) - goto Ltd_best; - } - - { - // Disambiguate by picking the most specialized FunctionDeclaration - MATCH c1 = fd->leastAsSpecialized(fd_best); - MATCH c2 = fd_best->leastAsSpecialized(fd); - //printf("3: c1 = %d, c2 = %d\n", c1, c2); - - if (c1 > c2) - goto Ltd; - if (c1 < c2) - goto Ltd_best; - } - - Lambig: // td_best and td are ambiguous - td_ambig = td; - continue; - - Ltd_best: // td_best is the best match so far - td_ambig = NULL; - continue; - - Ltd: // td is the new best match - td_ambig = NULL; - assert((size_t)td->scope > 0x10000); - td_best = td; - fd_best = fd; - m_best = m; - tdargs->setDim(dedargs.dim); - memcpy(tdargs->tdata(), dedargs.tdata(), tdargs->dim * sizeof(void *)); - continue; - } - if (!td_best) - { - if (!(flags & 1)) - ::error(loc, "%s %s.%s does not match any function template declaration", - kind(), parent->toPrettyChars(), ident->toChars()); - goto Lerror; - } - if (td_ambig) - { - ::error(loc, "%s %s.%s matches more than one template declaration, %s(%d):%s and %s(%d):%s", - kind(), parent->toPrettyChars(), ident->toChars(), - td_best->loc.filename, td_best->loc.linnum, td_best->toChars(), - td_ambig->loc.filename, td_ambig->loc.linnum, td_ambig->toChars()); - } - - /* The best match is td_best with arguments tdargs. - * Now instantiate the template. - */ - assert((size_t)td_best->scope > 0x10000); - ti = new TemplateInstance(loc, td_best, tdargs); - ti->semantic(sc, fargs); - fd_best = ti->toAlias()->isFuncDeclaration(); - if (!fd_best || !((TypeFunction*)fd_best->type)->callMatch(ethis, fargs, flags)) - goto Lerror; - - /* As Bugzilla 3682 shows, a template instance can be matched while instantiating - * that same template. Thus, the function type can be incomplete. Complete it. - */ - { TypeFunction *tf = (TypeFunction *)fd_best->type; - assert(tf->ty == Tfunction); - if (tf->next) - fd_best->type = tf->semantic(loc, sc); - } - - return fd_best; - - Lerror: -#if DMDV2 - if (!(flags & 1)) -#endif - { - HdrGenState hgs; - - OutBuffer bufa; - Objects *args = targsi; - if (args) - { for (size_t i = 0; i < args->dim; i++) - { - if (i) - bufa.writeByte(','); - Object *oarg = args->tdata()[i]; - ObjectToCBuffer(&bufa, &hgs, oarg); - } - } - - OutBuffer buf; - argExpTypesToCBuffer(&buf, fargs, &hgs); - if (this->overnext) - ::error(loc, "%s %s.%s cannot deduce template function from argument types !(%s)(%s)", - kind(), parent->toPrettyChars(), ident->toChars(), - bufa.toChars(), buf.toChars()); - else - error("cannot deduce template function from argument types !(%s)(%s)", - bufa.toChars(), buf.toChars()); - } - return NULL; -} - -/************************************************* - * Limited function template instantiation for using fd->leastAsSpecialized() - */ -FuncDeclaration *TemplateDeclaration::doHeaderInstantiation(Scope *sc, - Objects *tdargs, Expressions *fargs) -{ - FuncDeclaration *fd = onemember->toAlias()->isFuncDeclaration(); - if (!fd) - return NULL; - -#if 0 - printf("doHeaderInstantiation this = %s\n", toChars()); - for (size_t i = 0; i < tdargs->dim; ++i) - printf("\ttdargs[%d] = %s\n", i, ((Object *)tdargs->data[i])->toChars()); -#endif - - assert((size_t)scope > 0x10000); - TemplateInstance *ti = new TemplateInstance(loc, this, tdargs); - ti->tinst = sc->tinst; - { - ti->tdtypes.setDim(ti->tempdecl->parameters->dim); - if (!ti->tempdecl->matchWithInstance(ti, &ti->tdtypes, fargs, 2)) - return NULL; - } - - ti->parent = parent; - - // function body and contracts are not need - //fd = fd->syntaxCopy(NULL)->isFuncDeclaration(); - fd = new FuncDeclaration(fd->loc, fd->endloc, fd->ident, fd->storage_class, fd->type->syntaxCopy()); - fd->parent = ti; - - Scope *scope = this->scope; - - ti->argsym = new ScopeDsymbol(); - ti->argsym->parent = scope->parent; - scope = scope->push(ti->argsym); - - Scope *paramscope = scope->push(); - paramscope->stc = 0; - ti->declareParameters(paramscope); - paramscope->pop(); - - { - TypeFunction *tf = (TypeFunction *)fd->type; - if (tf && tf->ty == Tfunction) - tf->fargs = fargs; - } - - Scope *sc2; - sc2 = scope->push(ti); - sc2->parent = /*isnested ? sc->parent :*/ ti; - sc2->tinst = ti; - - { - Scope *sc = sc2; - sc = sc->push(); - - if (fd->isCtorDeclaration()) - sc->flags |= SCOPEctor; - fd->type = fd->type->semantic(fd->loc, sc); - sc = sc->pop(); - } - //printf("\t[%s] fd->type = %s, mod = %x, ", loc.toChars(), fd->type->toChars(), fd->type->mod); - //printf("fd->needThis() = %d\n", fd->needThis()); - - sc2->pop(); - scope->pop(); - - return fd; -} - -bool TemplateDeclaration::hasStaticCtorOrDtor() -{ - return FALSE; // don't scan uninstantiated templates -} - -void TemplateDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ -#if 0 // Should handle template functions for doc generation - if (onemember && onemember->isFuncDeclaration()) - buf->writestring("foo "); -#endif - if (hgs->ddoc) - buf->writestring(kind()); - else - buf->writestring("template"); - buf->writeByte(' '); - buf->writestring(ident->toChars()); - buf->writeByte('('); - for (size_t i = 0; i < parameters->dim; i++) - { - TemplateParameter *tp = parameters->tdata()[i]; - if (hgs->ddoc) - tp = origParameters->tdata()[i]; - if (i) - buf->writeByte(','); - tp->toCBuffer(buf, hgs); - } - buf->writeByte(')'); -#if DMDV2 - if (constraint) - { buf->writestring(" if ("); - constraint->toCBuffer(buf, hgs); - buf->writeByte(')'); - } -#endif - - if (hgs->hdrgen) - { - hgs->tpltMember++; - buf->writenl(); - buf->writebyte('{'); - buf->writenl(); - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = members->tdata()[i]; - s->toCBuffer(buf, hgs); - } - buf->writebyte('}'); - buf->writenl(); - hgs->tpltMember--; - } -} - - -char *TemplateDeclaration::toChars() -{ OutBuffer buf; - HdrGenState hgs; - - memset(&hgs, 0, sizeof(hgs)); - buf.writestring(ident->toChars()); - buf.writeByte('('); - for (size_t i = 0; i < parameters->dim; i++) - { - TemplateParameter *tp = parameters->tdata()[i]; - if (i) - buf.writeByte(','); - tp->toCBuffer(&buf, &hgs); - } - buf.writeByte(')'); -#if DMDV2 - if (constraint) - { buf.writestring(" if ("); - constraint->toCBuffer(&buf, &hgs); - buf.writeByte(')'); - } -#endif - buf.writeByte(0); - return (char *)buf.extractData(); -} - -/* ======================== Type ============================================ */ - -/**** - * Given an identifier, figure out which TemplateParameter it is. - * Return -1 if not found. - */ - -int templateIdentifierLookup(Identifier *id, TemplateParameters *parameters) -{ - for (size_t i = 0; i < parameters->dim; i++) - { TemplateParameter *tp = parameters->tdata()[i]; - - if (tp->ident->equals(id)) - return i; - } - return -1; -} - -int templateParameterLookup(Type *tparam, TemplateParameters *parameters) -{ - assert(tparam->ty == Tident); - TypeIdentifier *tident = (TypeIdentifier *)tparam; - //printf("\ttident = '%s'\n", tident->toChars()); - if (tident->idents.dim == 0) - { - return templateIdentifierLookup(tident->ident, parameters); - } - return -1; -} - -/* These form the heart of template argument deduction. - * Given 'this' being the type argument to the template instance, - * it is matched against the template declaration parameter specialization - * 'tparam' to determine the type to be used for the parameter. - * Example: - * template Foo(T:T*) // template declaration - * Foo!(int*) // template instantiation - * Input: - * this = int* - * tparam = T* - * parameters = [ T:T* ] // Array of TemplateParameter's - * Output: - * dedtypes = [ int ] // Array of Expression/Type's - */ - -MATCH Type::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, - Objects *dedtypes, unsigned *wildmatch) -{ -#if 0 - printf("Type::deduceType()\n"); - printf("\tthis = %d, ", ty); print(); - printf("\ttparam = %d, ", tparam->ty); tparam->print(); -#endif - if (!tparam) - goto Lnomatch; - - if (this == tparam) - goto Lexact; - - if (tparam->ty == Tident) - { - // Determine which parameter tparam is - int i = templateParameterLookup(tparam, parameters); - if (i == -1) - { - if (!sc) - goto Lnomatch; - - /* Need a loc to go with the semantic routine. - */ - Loc loc; - if (parameters->dim) - { - TemplateParameter *tp = parameters->tdata()[0]; - loc = tp->loc; - } - - /* BUG: what if tparam is a template instance, that - * has as an argument another Tident? - */ - tparam = tparam->semantic(loc, sc); - assert(tparam->ty != Tident); - return deduceType(sc, tparam, parameters, dedtypes, wildmatch); - } - - TemplateParameter *tp = parameters->tdata()[i]; - - // Found the corresponding parameter tp - if (!tp->isTemplateTypeParameter()) - goto Lnomatch; - Type *tt = this; - Type *at = (Type *)dedtypes->tdata()[i]; - - // 7*7 == 49 cases - - #define X(U,T) ((U) << 4) | (T) - - if (wildmatch && (tparam->mod & MODwild)) - { - switch (X(tparam->mod, mod)) - { - case X(MODwild, 0): - case X(MODwild, MODshared): - case X(MODwild, MODconst): - case X(MODwild, MODconst | MODshared): - case X(MODwild, MODimmutable): - case X(MODwild, MODwild): - case X(MODwild, MODwild | MODshared): - case X(MODwild | MODshared, MODshared): - case X(MODwild | MODshared, MODconst | MODshared): - case X(MODwild | MODshared, MODimmutable): - case X(MODwild | MODshared, MODwild | MODshared): - - if (!at) - { - if (mod & MODwild) - *wildmatch |= MODwild; - else if (mod == 0) - *wildmatch |= MODmutable; - else - *wildmatch |= (mod & ~MODshared); - tt = mutableOf()->substWildTo(MODmutable); - dedtypes->tdata()[i] = tt; - goto Lconst; - } - - //printf("\t> tt = %s, at = %s\n", tt->toChars(), at->toChars()); - //printf("\t> tt->implicitConvTo(at->constOf()) = %d\n", tt->implicitConvTo(at->constOf())); - //printf("\t> at->implicitConvTo(tt->constOf()) = %d\n", at->implicitConvTo(tt->constOf())); - - if (tt->equals(at)) - { - goto Lconst; - } - else if (tt->implicitConvTo(at->constOf())) - { - dedtypes->tdata()[i] = at->constOf()->mutableOf(); - *wildmatch |= MODconst; - goto Lconst; - } - else if (at->implicitConvTo(tt->constOf())) - { - dedtypes->tdata()[i] = tt->constOf()->mutableOf(); - *wildmatch |= MODconst; - goto Lconst; - } - goto Lnomatch; - - default: - break; - } - } - - switch (X(tparam->mod, mod)) - { - case X(0, 0): - case X(0, MODconst): - case X(0, MODimmutable): - case X(0, MODshared): - case X(0, MODconst | MODshared): - case X(0, MODwild): - case X(0, MODwild | MODshared): - // foo(U:U) T => T - // foo(U:U) const(T) => const(T) - // foo(U:U) immutable(T) => immutable(T) - // foo(U:U) shared(T) => shared(T) - // foo(U:U) const(shared(T)) => const(shared(T)) - // foo(U:U) wild(T) => wild(T) - // foo(U:U) wild(shared(T)) => wild(shared(T)) - if (!at) - { dedtypes->tdata()[i] = tt; - goto Lexact; - } - break; - - case X(MODconst, MODconst): - case X(MODimmutable, MODimmutable): - case X(MODshared, MODshared): - case X(MODconst | MODshared, MODconst | MODshared): - case X(MODwild, MODwild): - case X(MODwild | MODshared, MODwild | MODshared): - // foo(U:const(U)) const(T) => T - // foo(U:immutable(U)) immutable(T) => T - // foo(U:shared(U)) shared(T) => T - // foo(U:const(shared(U)) const(shared(T)) => T - // foo(U:wild(U)) wild(T) => T - // foo(U:wild(shared(U)) wild(shared(T)) => T - tt = mutableOf()->unSharedOf(); - if (!at) - { dedtypes->tdata()[i] = tt; - goto Lexact; - } - break; - - case X(MODconst, 0): - case X(MODconst, MODimmutable): - case X(MODconst, MODconst | MODshared): - case X(MODconst | MODshared, MODimmutable): - case X(MODconst, MODwild): - case X(MODconst, MODwild | MODshared): - // foo(U:const(U)) T => T - // foo(U:const(U)) immutable(T) => T - // foo(U:const(U)) const(shared(T)) => shared(T) - // foo(U:const(shared(U)) immutable(T) => T - // foo(U:const(U)) wild(shared(T)) => shared(T) - tt = mutableOf(); - if (!at) - { dedtypes->tdata()[i] = tt; - goto Lconst; - } - break; - - case X(MODshared, MODconst | MODshared): - case X(MODconst | MODshared, MODshared): - case X(MODshared, MODwild | MODshared): - // foo(U:shared(U)) const(shared(T)) => const(T) - // foo(U:const(shared(U)) shared(T) => T - // foo(U:shared(U)) wild(shared(T)) => wild(T) - tt = unSharedOf(); - if (!at) - { dedtypes->tdata()[i] = tt; - goto Lconst; - } - break; - - case X(MODconst, MODshared): - // foo(U:const(U)) shared(T) => shared(T) - if (!at) - { (*dedtypes)[i] = tt; - goto Lconst; - } - break; - - case X(MODimmutable, 0): - case X(MODimmutable, MODconst): - case X(MODimmutable, MODshared): - case X(MODimmutable, MODconst | MODshared): - case X(MODshared, 0): - case X(MODshared, MODconst): - case X(MODshared, MODimmutable): - case X(MODconst | MODshared, 0): - case X(MODconst | MODshared, MODconst): - case X(MODimmutable, MODwild): - case X(MODshared, MODwild): - case X(MODconst | MODshared, MODwild): - case X(MODwild, 0): - case X(MODwild, MODconst): - case X(MODwild, MODimmutable): - case X(MODwild, MODshared): - case X(MODwild, MODconst | MODshared): - case X(MODwild | MODshared, 0): - case X(MODwild | MODshared, MODconst): - case X(MODwild | MODshared, MODimmutable): - case X(MODwild | MODshared, MODshared): - case X(MODwild | MODshared, MODconst | MODshared): - case X(MODwild | MODshared, MODwild): - case X(MODimmutable, MODwild | MODshared): - case X(MODconst | MODshared, MODwild | MODshared): - case X(MODwild, MODwild | MODshared): - - // foo(U:immutable(U)) T => nomatch - // foo(U:immutable(U)) const(T) => nomatch - // foo(U:immutable(U)) shared(T) => nomatch - // foo(U:immutable(U)) const(shared(T)) => nomatch - // foo(U:const(U)) shared(T) => nomatch - // foo(U:shared(U)) T => nomatch - // foo(U:shared(U)) const(T) => nomatch - // foo(U:shared(U)) immutable(T) => nomatch - // foo(U:const(shared(U)) T => nomatch - // foo(U:const(shared(U)) const(T) => nomatch - // foo(U:immutable(U)) wild(T) => nomatch - // foo(U:shared(U)) wild(T) => nomatch - // foo(U:const(shared(U)) wild(T) => nomatch - // foo(U:wild(U)) T => nomatch - // foo(U:wild(U)) const(T) => nomatch - // foo(U:wild(U)) immutable(T) => nomatch - // foo(U:wild(U)) shared(T) => nomatch - // foo(U:wild(U)) const(shared(T)) => nomatch - // foo(U:wild(shared(U)) T => nomatch - // foo(U:wild(shared(U)) const(T) => nomatch - // foo(U:wild(shared(U)) immutable(T) => nomatch - // foo(U:wild(shared(U)) shared(T) => nomatch - // foo(U:wild(shared(U)) const(shared(T)) => nomatch - // foo(U:wild(shared(U)) wild(T) => nomatch - // foo(U:immutable(U)) wild(shared(T)) => nomatch - // foo(U:const(shared(U))) wild(shared(T)) => nomatch - // foo(U:wild(U)) wild(shared(T)) => nomatch - //if (!at) - goto Lnomatch; - break; - - default: - assert(0); - } - #undef X - - if (tt->equals(at)) - goto Lexact; - else if (tt->ty == Tclass && at->ty == Tclass) - { - return tt->implicitConvTo(at); - } - else if (tt->ty == Tsarray && at->ty == Tarray && - tt->nextOf()->implicitConvTo(at->nextOf()) >= MATCHconst) - { - goto Lexact; - } - else - goto Lnomatch; - } - else if (tparam->ty == Ttypeof) - { - /* Need a loc to go with the semantic routine. - */ - Loc loc; - if (parameters->dim) - { - TemplateParameter *tp = parameters->tdata()[0]; - loc = tp->loc; - } - - tparam = tparam->semantic(loc, sc); - } - - if (ty != tparam->ty) - { -#if DMDV2 - // Can't instantiate AssociativeArray!() without a scope - if (tparam->ty == Taarray && !((TypeAArray*)tparam)->sc) - ((TypeAArray*)tparam)->sc = sc; - - MATCH m = implicitConvTo(tparam); - if (m == MATCHnomatch) - { - Type *at = aliasthisOf(); - if (at) - m = at->deduceType(sc, tparam, parameters, dedtypes, wildmatch); - } - return m; -#else - return implicitConvTo(tparam); -#endif - } - - if (nextOf()) - return nextOf()->deduceType(sc, tparam->nextOf(), parameters, dedtypes, wildmatch); - -Lexact: - return MATCHexact; - -Lnomatch: - return MATCHnomatch; - -#if DMDV2 -Lconst: - return MATCHconst; -#endif -} - -#if DMDV2 -MATCH TypeVector::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, - Objects *dedtypes, unsigned *wildmatch) -{ -#if 0 - printf("TypeVector::deduceType()\n"); - printf("\tthis = %d, ", ty); print(); - printf("\ttparam = %d, ", tparam->ty); tparam->print(); -#endif - if (tparam->ty == Tvector) - { TypeVector *tp = (TypeVector *)tparam; - return basetype->deduceType(sc, tp->basetype, parameters, dedtypes, wildmatch); - } - return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); -} -#endif - -#if DMDV2 -MATCH TypeDArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, - Objects *dedtypes, unsigned *wildmatch) -{ -#if 0 - printf("TypeDArray::deduceType()\n"); - printf("\tthis = %d, ", ty); print(); - printf("\ttparam = %d, ", tparam->ty); tparam->print(); -#endif - return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); -} -#endif - -MATCH TypeSArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, - Objects *dedtypes, unsigned *wildmatch) -{ -#if 0 - printf("TypeSArray::deduceType()\n"); - printf("\tthis = %d, ", ty); print(); - printf("\ttparam = %d, ", tparam->ty); tparam->print(); -#endif - - // Extra check that array dimensions must match - if (tparam) - { - if (tparam->ty == Tarray) - { MATCH m; - - m = next->deduceType(sc, tparam->nextOf(), parameters, dedtypes, wildmatch); - if (m == MATCHexact) - m = MATCHconvert; - return m; - } - - Identifier *id = NULL; - if (tparam->ty == Tsarray) - { - TypeSArray *tp = (TypeSArray *)tparam; - if (tp->dim->op == TOKvar && - ((VarExp *)tp->dim)->var->storage_class & STCtemplateparameter) - { - id = ((VarExp *)tp->dim)->var->ident; - } - else if (dim->toInteger() != tp->dim->toInteger()) - return MATCHnomatch; - } - else if (tparam->ty == Taarray) - { - TypeAArray *tp = (TypeAArray *)tparam; - if (tp->index->ty == Tident && - ((TypeIdentifier *)tp->index)->idents.dim == 0) - { - id = ((TypeIdentifier *)tp->index)->ident; - } - } - if (id) - { - // This code matches code in TypeInstance::deduceType() - int i = templateIdentifierLookup(id, parameters); - if (i == -1) - goto Lnomatch; - TemplateParameter *tprm = parameters->tdata()[i]; - TemplateValueParameter *tvp = tprm->isTemplateValueParameter(); - if (!tvp) - goto Lnomatch; - Expression *e = (Expression *)dedtypes->tdata()[i]; - if (e) - { - if (!dim->equals(e)) - goto Lnomatch; - } - else - { - Type *vt = tvp->valType->semantic(0, sc); - MATCH m = (MATCH)dim->implicitConvTo(vt); - if (!m) - goto Lnomatch; - dedtypes->tdata()[i] = dim; - } - return next->deduceType(sc, tparam->nextOf(), parameters, dedtypes, wildmatch); - } - } - return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); - - Lnomatch: - return MATCHnomatch; -} - -MATCH TypeAArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch) -{ -#if 0 - printf("TypeAArray::deduceType()\n"); - printf("\tthis = %d, ", ty); print(); - printf("\ttparam = %d, ", tparam->ty); tparam->print(); -#endif - - // Extra check that index type must match - if (tparam && tparam->ty == Taarray) - { - TypeAArray *tp = (TypeAArray *)tparam; - if (!index->deduceType(sc, tp->index, parameters, dedtypes, wildmatch)) - { - return MATCHnomatch; - } - } - return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); -} - -MATCH TypeFunction::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch) -{ - //printf("TypeFunction::deduceType()\n"); - //printf("\tthis = %d, ", ty); print(); - //printf("\ttparam = %d, ", tparam->ty); tparam->print(); - - // Extra check that function characteristics must match - if (tparam && tparam->ty == Tfunction) - { - TypeFunction *tp = (TypeFunction *)tparam; - if (varargs != tp->varargs || - linkage != tp->linkage) - return MATCHnomatch; - - size_t nfargs = Parameter::dim(this->parameters); - size_t nfparams = Parameter::dim(tp->parameters); - - // bug 2579 fix: Apply function parameter storage classes to parameter types - for (size_t i = 0; i < nfparams; i++) - { - Parameter *fparam = Parameter::getNth(tp->parameters, i); - fparam->type = fparam->type->addStorageClass(fparam->storageClass); - fparam->storageClass &= ~(STC_TYPECTOR | STCin); - } - //printf("\t-> this = %d, ", ty); print(); - //printf("\t-> tparam = %d, ", tparam->ty); tparam->print(); - - /* See if tuple match - */ - if (nfparams > 0 && nfargs >= nfparams - 1) - { - /* See if 'A' of the template parameter matches 'A' - * of the type of the last function parameter. - */ - Parameter *fparam = Parameter::getNth(tp->parameters, nfparams - 1); - assert(fparam); - assert(fparam->type); - if (fparam->type->ty != Tident) - goto L1; - TypeIdentifier *tid = (TypeIdentifier *)fparam->type; - if (tid->idents.dim) - goto L1; - - /* Look through parameters to find tuple matching tid->ident - */ - size_t tupi = 0; - for (; 1; tupi++) - { if (tupi == parameters->dim) - goto L1; - TemplateParameter *t = parameters->tdata()[tupi]; - TemplateTupleParameter *tup = t->isTemplateTupleParameter(); - if (tup && tup->ident->equals(tid->ident)) - break; - } - - /* The types of the function arguments [nfparams - 1 .. nfargs] - * now form the tuple argument. - */ - size_t tuple_dim = nfargs - (nfparams - 1); - - /* See if existing tuple, and whether it matches or not - */ - Object *o = dedtypes->tdata()[tupi]; - if (o) - { // Existing deduced argument must be a tuple, and must match - Tuple *t = isTuple(o); - if (!t || t->objects.dim != tuple_dim) - return MATCHnomatch; - for (size_t i = 0; i < tuple_dim; i++) - { Parameter *arg = Parameter::getNth(this->parameters, nfparams - 1 + i); - if (!arg->type->equals(t->objects.tdata()[i])) - return MATCHnomatch; - } - } - else - { // Create new tuple - Tuple *t = new Tuple(); - 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.tdata()[i] = arg->type; - } - dedtypes->tdata()[tupi] = t; - } - nfparams--; // don't consider the last parameter for type deduction - goto L2; - } - - L1: - if (nfargs != nfparams) - return MATCHnomatch; - L2: - for (size_t i = 0; i < nfparams; i++) - { - Parameter *a = Parameter::getNth(this->parameters, i); - Parameter *ap = Parameter::getNth(tp->parameters, i); - if (a->storageClass != ap->storageClass || - !a->type->deduceType(sc, ap->type, parameters, dedtypes, wildmatch)) - return MATCHnomatch; - } - } - return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); -} - -MATCH TypeIdentifier::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch) -{ - // Extra check - if (tparam && tparam->ty == Tident) - { - TypeIdentifier *tp = (TypeIdentifier *)tparam; - - for (size_t i = 0; i < idents.dim; i++) - { - Identifier *id1 = idents.tdata()[i]; - Identifier *id2 = tp->idents.tdata()[i]; - - if (!id1->equals(id2)) - return MATCHnomatch; - } - } - return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); -} - -MATCH TypeInstance::deduceType(Scope *sc, - Type *tparam, TemplateParameters *parameters, - Objects *dedtypes, unsigned *wildmatch) -{ -#if 0 - printf("TypeInstance::deduceType()\n"); - printf("\tthis = %d, ", ty); print(); - printf("\ttparam = %d, ", tparam->ty); tparam->print(); -#endif - - // Extra check - if (tparam && tparam->ty == Tinstance) - { - TypeInstance *tp = (TypeInstance *)tparam; - - //printf("tempinst->tempdecl = %p\n", tempinst->tempdecl); - //printf("tp->tempinst->tempdecl = %p\n", tp->tempinst->tempdecl); - if (!tp->tempinst->tempdecl) - { //printf("tp->tempinst->name = '%s'\n", tp->tempinst->name->toChars()); - if (!tp->tempinst->name->equals(tempinst->name)) - { - /* Handle case of: - * template Foo(T : sa!(T), alias sa) - */ - int i = templateIdentifierLookup(tp->tempinst->name, parameters); - if (i == -1) - { /* 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); - if (s) - { - s = s->toAlias(); - TemplateDeclaration *td = s->isTemplateDeclaration(); - if (td && td == tempinst->tempdecl) - goto L2; - } - goto Lnomatch; - } - TemplateParameter *tpx = parameters->tdata()[i]; - // This logic duplicates tpx->matchArg() - TemplateAliasParameter *ta = tpx->isTemplateAliasParameter(); - if (!ta) - goto Lnomatch; - Object *sa = tempinst->tempdecl; - if (!sa) - goto Lnomatch; - if (ta->specAlias && sa != ta->specAlias) - goto Lnomatch; - if (dedtypes->tdata()[i]) - { // Must match already deduced symbol - Object *s = dedtypes->tdata()[i]; - - if (s != sa) - goto Lnomatch; - } - dedtypes->tdata()[i] = sa; - } - } - else if (tempinst->tempdecl != tp->tempinst->tempdecl) - goto Lnomatch; - - L2: - - for (size_t i = 0; 1; i++) - { - //printf("\ttest: tempinst->tiargs[%d]\n", i); - Object *o1; - if (i < tempinst->tiargs->dim) - o1 = tempinst->tiargs->tdata()[i]; - else if (i < tempinst->tdtypes.dim && i < tp->tempinst->tiargs->dim) - // Pick up default arg - o1 = tempinst->tdtypes.tdata()[i]; - else - break; - - if (i >= tp->tempinst->tiargs->dim) - goto Lnomatch; - - Object *o2 = tp->tempinst->tiargs->tdata()[i]; - - Type *t1 = isType(o1); - Type *t2 = isType(o2); - - Expression *e1 = isExpression(o1); - Expression *e2 = isExpression(o2); - - Dsymbol *s1 = isDsymbol(o1); - Dsymbol *s2 = isDsymbol(o2); - - Tuple *v1 = isTuple(o1); - Tuple *v2 = isTuple(o2); -#if 0 - if (t1) printf("t1 = %s\n", t1->toChars()); - if (t2) printf("t2 = %s\n", t2->toChars()); - if (e1) printf("e1 = %s\n", e1->toChars()); - if (e2) printf("e2 = %s\n", e2->toChars()); - if (s1) printf("s1 = %s\n", s1->toChars()); - if (s2) printf("s2 = %s\n", s2->toChars()); - if (v1) printf("v1 = %s\n", v1->toChars()); - 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.tdata()[k] = tempinst->tiargs->tdata()[i + k]; - - Tuple *v = (Tuple *)dedtypes->tdata()[j]; - if (v) - { - if (!match(v, vt, tempinst->tempdecl, sc)) - goto Lnomatch; - } - else - dedtypes->tdata()[j] = vt; - break; //return MATCHexact; - } - - if (t1 && t2) - { - if (!t1->deduceType(sc, t2, parameters, dedtypes, wildmatch)) - goto Lnomatch; - } - else if (e1 && e2) - { - if (!e1->equals(e2)) - { if (e2->op == TOKvar) - { - /* - * (T:Number!(e2), int e2) - */ - j = templateIdentifierLookup(((VarExp *)e2)->var->ident, parameters); - goto L1; - } - goto Lnomatch; - } - } - else if (e1 && t2 && t2->ty == Tident) - { - j = templateParameterLookup(t2, parameters); - L1: - if (j == -1) - goto Lnomatch; - TemplateParameter *tp = parameters->tdata()[j]; - // BUG: use tp->matchArg() instead of the following - TemplateValueParameter *tv = tp->isTemplateValueParameter(); - if (!tv) - goto Lnomatch; - Expression *e = (Expression *)dedtypes->tdata()[j]; - if (e) - { - if (!e1->equals(e)) - goto Lnomatch; - } - else - { Type *vt = tv->valType->semantic(0, sc); - MATCH m = (MATCH)e1->implicitConvTo(vt); - if (!m) - goto Lnomatch; - dedtypes->tdata()[j] = e1; - } - } - else if (s1 && t2 && t2->ty == Tident) - { - j = templateParameterLookup(t2, parameters); - if (j == -1) - goto Lnomatch; - TemplateParameter *tp = parameters->tdata()[j]; - // BUG: use tp->matchArg() instead of the following - TemplateAliasParameter *ta = tp->isTemplateAliasParameter(); - if (!ta) - goto Lnomatch; - Dsymbol *s = (Dsymbol *)dedtypes->tdata()[j]; - if (s) - { - if (!s1->equals(s)) - goto Lnomatch; - } - else - { - dedtypes->tdata()[j] = s1; - } - } - else if (s1 && s2) - { - if (!s1->equals(s2)) - goto Lnomatch; - } - // BUG: Need to handle tuple parameters - else - goto Lnomatch; - } - } - return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); - -Lnomatch: - //printf("no match\n"); - return MATCHnomatch; -} - -MATCH TypeStruct::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch) -{ - //printf("TypeStruct::deduceType()\n"); - //printf("\tthis->parent = %s, ", sym->parent->toChars()); print(); - //printf("\ttparam = %d, ", tparam->ty); tparam->print(); - - /* If this struct is a template struct, and we're matching - * it against a template instance, convert the struct type - * to a template instance, too, and try again. - */ - TemplateInstance *ti = sym->parent->isTemplateInstance(); - - if (tparam && tparam->ty == Tinstance) - { - if (ti && ti->toAlias() == sym) - { - TypeInstance *t = new TypeInstance(0, ti); - return t->deduceType(sc, tparam, parameters, dedtypes, wildmatch); - } - - /* Match things like: - * S!(T).foo - */ - TypeInstance *tpi = (TypeInstance *)tparam; - if (tpi->idents.dim) - { Identifier *id = tpi->idents.tdata()[tpi->idents.dim - 1]; - if (id->dyncast() == DYNCAST_IDENTIFIER && sym->ident->equals(id)) - { - Type *tparent = sym->parent->getType(); - if (tparent) - { - /* Slice off the .foo in S!(T).foo - */ - tpi->idents.dim--; - MATCH m = tparent->deduceType(sc, tpi, parameters, dedtypes, wildmatch); - tpi->idents.dim++; - return m; - } - } - } - } - - // Extra check - if (tparam && tparam->ty == Tstruct) - { - TypeStruct *tp = (TypeStruct *)tparam; - - //printf("\t%d\n", (MATCH) implicitConvTo(tp)); - return implicitConvTo(tp); - } - return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); -} - -MATCH TypeEnum::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch) -{ - // Extra check - if (tparam && tparam->ty == Tenum) - { - TypeEnum *tp = (TypeEnum *)tparam; - - if (sym != tp->sym) - return MATCHnomatch; - } - return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); -} - -MATCH TypeTypedef::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch) -{ - // Extra check - if (tparam && tparam->ty == Ttypedef) - { - TypeTypedef *tp = (TypeTypedef *)tparam; - - if (sym != tp->sym) - return MATCHnomatch; - } - return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); -} - -/* Helper for TypeClass::deduceType(). - * Classes can match with implicit conversion to a base class or interface. - * This is complicated, because there may be more than one base class which - * matches. In such cases, one or more parameters remain ambiguous. - * For example, - * - * interface I(X, Y) {} - * class C : I(uint, double), I(char, double) {} - * C x; - * foo(T, U)( I!(T, U) x) - * - * deduces that U is double, but T remains ambiguous (could be char or uint). - * - * Given a baseclass b, and initial deduced types 'dedtypes', this function - * tries to match tparam with b, and also tries all base interfaces of b. - * If a match occurs, numBaseClassMatches is incremented, and the new deduced - * types are ANDed with the current 'best' estimate for dedtypes. - */ -void deduceBaseClassParameters(BaseClass *b, - Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, - Objects *best, int &numBaseClassMatches) -{ - TemplateInstance *parti = b->base ? b->base->parent->isTemplateInstance() : NULL; - if (parti) - { - // Make a temporary copy of dedtypes so we don't destroy it - Objects *tmpdedtypes = new Objects(); - tmpdedtypes->setDim(dedtypes->dim); - memcpy(tmpdedtypes->tdata(), dedtypes->tdata(), dedtypes->dim * sizeof(void *)); - - TypeInstance *t = new TypeInstance(0, parti); - MATCH m = t->deduceType(sc, tparam, parameters, tmpdedtypes); - if (m != MATCHnomatch) - { - // If this is the first ever match, it becomes our best estimate - if (numBaseClassMatches==0) - memcpy(best->tdata(), tmpdedtypes->tdata(), tmpdedtypes->dim * sizeof(void *)); - else for (size_t k = 0; k < tmpdedtypes->dim; ++k) - { - // If we've found more than one possible type for a parameter, - // mark it as unknown. - if (tmpdedtypes->tdata()[k] != best->tdata()[k]) - best->tdata()[k] = dedtypes->tdata()[k]; - } - ++numBaseClassMatches; - } - } - // Now recursively test the inherited interfaces - for (size_t j = 0; j < b->baseInterfaces_dim; ++j) - { - deduceBaseClassParameters( &(b->baseInterfaces)[j], - sc, tparam, parameters, dedtypes, - best, numBaseClassMatches); - } - -} - -MATCH TypeClass::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch) -{ - //printf("TypeClass::deduceType(this = %s)\n", toChars()); - - /* If this class is a template class, and we're matching - * it against a template instance, convert the class type - * to a template instance, too, and try again. - */ - TemplateInstance *ti = sym->parent->isTemplateInstance(); - - if (tparam && tparam->ty == Tinstance) - { - if (ti && ti->toAlias() == sym) - { - TypeInstance *t = new TypeInstance(0, ti); - MATCH m = t->deduceType(sc, tparam, parameters, dedtypes, wildmatch); - // Even if the match fails, there is still a chance it could match - // a base class. - if (m != MATCHnomatch) - return m; - } - - /* Match things like: - * S!(T).foo - */ - TypeInstance *tpi = (TypeInstance *)tparam; - if (tpi->idents.dim) - { Identifier *id = tpi->idents.tdata()[tpi->idents.dim - 1]; - if (id->dyncast() == DYNCAST_IDENTIFIER && sym->ident->equals(id)) - { - Type *tparent = sym->parent->getType(); - if (tparent) - { - /* Slice off the .foo in S!(T).foo - */ - tpi->idents.dim--; - MATCH m = tparent->deduceType(sc, tpi, parameters, dedtypes, wildmatch); - tpi->idents.dim++; - return m; - } - } - } - - // If it matches exactly or via implicit conversion, we're done - MATCH m = Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); - if (m != MATCHnomatch) - return m; - - /* There is still a chance to match via implicit conversion to - * a base class or interface. Because there could be more than one such - * match, we need to check them all. - */ - - int numBaseClassMatches = 0; // Have we found an interface match? - - // Our best guess at dedtypes - Objects *best = new Objects(); - best->setDim(dedtypes->dim); - - ClassDeclaration *s = sym; - while(s && s->baseclasses->dim > 0) - { - // Test the base class - deduceBaseClassParameters((s->baseclasses->tdata()[0]), - sc, tparam, parameters, dedtypes, - best, numBaseClassMatches); - - // Test the interfaces inherited by the base class - for (size_t i = 0; i < s->interfaces_dim; ++i) - { - BaseClass *b = s->interfaces[i]; - deduceBaseClassParameters(b, sc, tparam, parameters, dedtypes, - best, numBaseClassMatches); - } - s = ((s->baseclasses->tdata()[0]))->base; - } - - if (numBaseClassMatches == 0) - return MATCHnomatch; - - // If we got at least one match, copy the known types into dedtypes - memcpy(dedtypes->tdata(), best->tdata(), best->dim * sizeof(void *)); - return MATCHconvert; - } - - // Extra check - if (tparam && tparam->ty == Tclass) - { - TypeClass *tp = (TypeClass *)tparam; - - //printf("\t%d\n", (MATCH) implicitConvTo(tp)); - return implicitConvTo(tp); - } - return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); -} - -/* ======================== TemplateParameter =============================== */ - -TemplateParameter::TemplateParameter(Loc loc, Identifier *ident) -{ - this->loc = loc; - this->ident = ident; - this->sparam = NULL; -} - -TemplateTypeParameter *TemplateParameter::isTemplateTypeParameter() -{ - return NULL; -} - -TemplateValueParameter *TemplateParameter::isTemplateValueParameter() -{ - return NULL; -} - -TemplateAliasParameter *TemplateParameter::isTemplateAliasParameter() -{ - return NULL; -} - -TemplateTupleParameter *TemplateParameter::isTemplateTupleParameter() -{ - return NULL; -} - -#if DMDV2 -TemplateThisParameter *TemplateParameter::isTemplateThisParameter() -{ - return NULL; -} -#endif - -/* ======================== TemplateTypeParameter =========================== */ - -// type-parameter - -Type *TemplateTypeParameter::tdummy = NULL; - -TemplateTypeParameter::TemplateTypeParameter(Loc loc, Identifier *ident, Type *specType, - Type *defaultType) - : TemplateParameter(loc, ident) -{ - this->ident = ident; - this->specType = specType; - this->defaultType = defaultType; -} - -TemplateTypeParameter *TemplateTypeParameter::isTemplateTypeParameter() -{ - return this; -} - -TemplateParameter *TemplateTypeParameter::syntaxCopy() -{ - TemplateTypeParameter *tp = new TemplateTypeParameter(loc, ident, specType, defaultType); - if (tp->specType) - tp->specType = specType->syntaxCopy(); - if (defaultType) - tp->defaultType = defaultType->syntaxCopy(); - return tp; -} - -void TemplateTypeParameter::declareParameter(Scope *sc) -{ - //printf("TemplateTypeParameter::declareParameter('%s')\n", ident->toChars()); - TypeIdentifier *ti = new TypeIdentifier(loc, ident); - sparam = new AliasDeclaration(loc, ident, ti); - if (!sc->insert(sparam)) - error(loc, "parameter '%s' multiply defined", ident->toChars()); -} - -void TemplateTypeParameter::semantic(Scope *sc) -{ - //printf("TemplateTypeParameter::semantic('%s')\n", ident->toChars()); - if (specType) - { - specType = specType->semantic(loc, sc); - } -#if 0 // Don't do semantic() until instantiation - if (defaultType) - { - defaultType = defaultType->semantic(loc, sc); - } -#endif -} - -/**************************************** - * Determine if two TemplateParameters are the same - * as far as TemplateDeclaration overloading goes. - * Returns: - * 1 match - * 0 no match - */ - -int TemplateTypeParameter::overloadMatch(TemplateParameter *tp) -{ - TemplateTypeParameter *ttp = tp->isTemplateTypeParameter(); - - if (ttp) - { - if (specType != ttp->specType) - goto Lnomatch; - - if (specType && !specType->equals(ttp->specType)) - goto Lnomatch; - - return 1; // match - } - -Lnomatch: - return 0; -} - -/******************************************* - * Match to a particular TemplateParameter. - * Input: - * i i'th argument - * tiargs[] actual arguments to template instance - * parameters[] template parameters - * dedtypes[] deduced arguments to template instance - * *psparam set to symbol declared and initialized to dedtypes[i] - */ - -MATCH TemplateTypeParameter::matchArg(Scope *sc, Objects *tiargs, - size_t i, TemplateParameters *parameters, Objects *dedtypes, - Declaration **psparam) -{ - //printf("TemplateTypeParameter::matchArg()\n"); - Object *oarg; - MATCH m = MATCHexact; - Type *ta; - - if (i < tiargs->dim) - oarg = tiargs->tdata()[i]; - else - { // Get default argument instead - oarg = defaultArg(loc, sc); - if (!oarg) - { assert(i < dedtypes->dim); - // It might have already been deduced - oarg = dedtypes->tdata()[i]; - if (!oarg) - { - goto Lnomatch; - } - } - } - - ta = isType(oarg); - if (!ta) - { - //printf("%s %p %p %p\n", oarg->toChars(), isExpression(oarg), isDsymbol(oarg), isTuple(oarg)); - goto Lnomatch; - } - //printf("ta is %s\n", ta->toChars()); - - if (specType) - { - if (!ta || ta == tdummy) - goto Lnomatch; - - //printf("\tcalling deduceType(): ta is %s, specType is %s\n", ta->toChars(), specType->toChars()); - MATCH m2 = ta->deduceType(sc, specType, parameters, dedtypes); - if (m2 == MATCHnomatch) - { //printf("\tfailed deduceType\n"); - goto Lnomatch; - } - - if (m2 < m) - m = m2; - if (dedtypes->tdata()[i]) - ta = (Type *)dedtypes->tdata()[i]; - } - else - { - if (dedtypes->tdata()[i]) - { // Must match already deduced type - Type *t = (Type *)dedtypes->tdata()[i]; - - if (!t->equals(ta)) - { //printf("t = %s ta = %s\n", t->toChars(), ta->toChars()); - goto Lnomatch; - } - } - else - { - // So that matches with specializations are better - m = MATCHconvert; - } - } - dedtypes->tdata()[i] = ta; - - *psparam = new AliasDeclaration(loc, ident, ta); - //printf("\tm = %d\n", m); - return m; - -Lnomatch: - *psparam = NULL; - //printf("\tm = %d\n", MATCHnomatch); - return MATCHnomatch; -} - - -void TemplateTypeParameter::print(Object *oarg, Object *oded) -{ - printf(" %s\n", ident->toChars()); - - Type *t = isType(oarg); - Type *ta = isType(oded); - - assert(ta); - - if (specType) - printf("\tSpecialization: %s\n", specType->toChars()); - if (defaultType) - printf("\tDefault: %s\n", defaultType->toChars()); - printf("\tParameter: %s\n", t ? t->toChars() : "NULL"); - printf("\tDeduced Type: %s\n", ta->toChars()); -} - - -void TemplateTypeParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(ident->toChars()); - if (specType) - { - buf->writestring(" : "); - specType->toCBuffer(buf, NULL, hgs); - } - if (defaultType) - { - buf->writestring(" = "); - defaultType->toCBuffer(buf, NULL, hgs); - } -} - - -void *TemplateTypeParameter::dummyArg() -{ Type *t; - - if (specType) - t = specType; - else - { // Use this for alias-parameter's too (?) - if (!tdummy) - tdummy = new TypeIdentifier(loc, ident); - t = tdummy; - } - return (void *)t; -} - - -Object *TemplateTypeParameter::specialization() -{ - return specType; -} - - -Object *TemplateTypeParameter::defaultArg(Loc loc, Scope *sc) -{ - Type *t; - - t = defaultType; - if (t) - { - t = t->syntaxCopy(); - t = t->semantic(loc, sc); - } - return t; -} - -/* ======================== TemplateThisParameter =========================== */ - -#if DMDV2 -// this-parameter - -TemplateThisParameter::TemplateThisParameter(Loc loc, Identifier *ident, - Type *specType, - Type *defaultType) - : TemplateTypeParameter(loc, ident, specType, defaultType) -{ -} - -TemplateThisParameter *TemplateThisParameter::isTemplateThisParameter() -{ - return this; -} - -TemplateParameter *TemplateThisParameter::syntaxCopy() -{ - TemplateThisParameter *tp = new TemplateThisParameter(loc, ident, specType, defaultType); - if (tp->specType) - tp->specType = specType->syntaxCopy(); - if (defaultType) - tp->defaultType = defaultType->syntaxCopy(); - return tp; -} - -void TemplateThisParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("this "); - TemplateTypeParameter::toCBuffer(buf, hgs); -} -#endif - -/* ======================== TemplateAliasParameter ========================== */ - -// alias-parameter - -Dsymbol *TemplateAliasParameter::sdummy = NULL; - -TemplateAliasParameter::TemplateAliasParameter(Loc loc, Identifier *ident, - Type *specType, Object *specAlias, Object *defaultAlias) - : TemplateParameter(loc, ident) -{ - this->ident = ident; - this->specType = specType; - this->specAlias = specAlias; - this->defaultAlias = defaultAlias; -} - -TemplateAliasParameter *TemplateAliasParameter::isTemplateAliasParameter() -{ - return this; -} - -TemplateParameter *TemplateAliasParameter::syntaxCopy() -{ - TemplateAliasParameter *tp = new TemplateAliasParameter(loc, ident, specType, specAlias, defaultAlias); - if (tp->specType) - tp->specType = specType->syntaxCopy(); - tp->specAlias = objectSyntaxCopy(specAlias); - tp->defaultAlias = objectSyntaxCopy(defaultAlias); - return tp; -} - -void TemplateAliasParameter::declareParameter(Scope *sc) -{ - TypeIdentifier *ti = new TypeIdentifier(loc, ident); - sparam = new AliasDeclaration(loc, ident, ti); - if (!sc->insert(sparam)) - error(loc, "parameter '%s' multiply defined", ident->toChars()); -} - -Object *aliasParameterSemantic(Loc loc, Scope *sc, Object *o) -{ - if (o) - { - Expression *ea = isExpression(o); - Type *ta = isType(o); - if (ta) - { Dsymbol *s = ta->toDsymbol(sc); - if (s) - o = s; - else - o = ta->semantic(loc, sc); - } - else if (ea) - { - ea = ea->semantic(sc); - o = ea->optimize(WANTvalue | WANTinterpret); - } - } - return o; -} - -void TemplateAliasParameter::semantic(Scope *sc) -{ - if (specType) - { - specType = specType->semantic(loc, sc); - } - specAlias = aliasParameterSemantic(loc, sc, specAlias); -#if 0 // Don't do semantic() until instantiation - if (defaultAlias) - defaultAlias = defaultAlias->semantic(loc, sc); -#endif -} - -int TemplateAliasParameter::overloadMatch(TemplateParameter *tp) -{ - TemplateAliasParameter *tap = tp->isTemplateAliasParameter(); - - if (tap) - { - if (specAlias != tap->specAlias) - goto Lnomatch; - - return 1; // match - } - -Lnomatch: - return 0; -} - -MATCH TemplateAliasParameter::matchArg(Scope *sc, Objects *tiargs, - size_t i, TemplateParameters *parameters, Objects *dedtypes, - Declaration **psparam) -{ - Object *sa; - Object *oarg; - Expression *ea; - Dsymbol *s; - - //printf("TemplateAliasParameter::matchArg()\n"); - - if (i < tiargs->dim) - oarg = tiargs->tdata()[i]; - else - { // Get default argument instead - oarg = defaultArg(loc, sc); - if (!oarg) - { assert(i < dedtypes->dim); - // It might have already been deduced - oarg = dedtypes->tdata()[i]; - if (!oarg) - goto Lnomatch; - } - } - - sa = getDsymbol(oarg); - if (sa) - { - /* specType means the alias must be a declaration with a type - * that matches specType. - */ - if (specType) - { Declaration *d = ((Dsymbol *)sa)->isDeclaration(); - if (!d) - goto Lnomatch; - if (!d->type->equals(specType)) - goto Lnomatch; - } - } - else - { - sa = oarg; - ea = isExpression(oarg); - if (ea) - { if (specType) - { - if (!ea->type->equals(specType)) - goto Lnomatch; - } - } - else - goto Lnomatch; - } - - if (specAlias) - { - if (sa == sdummy) - goto Lnomatch; - if (sa != specAlias) - goto Lnomatch; - } - else if (dedtypes->tdata()[i]) - { // Must match already deduced symbol - Object *si = dedtypes->tdata()[i]; - - if (!sa || si != sa) - goto Lnomatch; - } - dedtypes->tdata()[i] = sa; - - s = isDsymbol(sa); - if (s) - *psparam = new AliasDeclaration(loc, ident, s); - else - { - assert(ea); - - // Declare manifest constant - Initializer *init = new ExpInitializer(loc, ea); - VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init); - v->storage_class = STCmanifest; - v->semantic(sc); - *psparam = v; - } - return MATCHexact; - -Lnomatch: - *psparam = NULL; - //printf("\tm = %d\n", MATCHnomatch); - return MATCHnomatch; -} - - -void TemplateAliasParameter::print(Object *oarg, Object *oded) -{ - printf(" %s\n", ident->toChars()); - - Dsymbol *sa = isDsymbol(oded); - assert(sa); - - printf("\tParameter alias: %s\n", sa->toChars()); -} - -void TemplateAliasParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("alias "); - if (specType) - { HdrGenState hgs1; - specType->toCBuffer(buf, ident, &hgs1); - } - else - buf->writestring(ident->toChars()); - if (specAlias) - { - buf->writestring(" : "); - ObjectToCBuffer(buf, hgs, specAlias); - } - if (defaultAlias) - { - buf->writestring(" = "); - ObjectToCBuffer(buf, hgs, defaultAlias); - } -} - - -void *TemplateAliasParameter::dummyArg() -{ Object *s; - - s = specAlias; - if (!s) - { - if (!sdummy) - sdummy = new Dsymbol(); - s = sdummy; - } - return (void*)s; -} - - -Object *TemplateAliasParameter::specialization() -{ - return specAlias; -} - - -Object *TemplateAliasParameter::defaultArg(Loc loc, Scope *sc) -{ - Object *da = defaultAlias; - Type *ta = isType(defaultAlias); - if (ta) - { - if (ta->ty == Tinstance) - { - // If the default arg is a template, instantiate for each type - da = ta->syntaxCopy(); - } - } - - Object *o = aliasParameterSemantic(loc, sc, da); - return o; -} - -/* ======================== TemplateValueParameter ========================== */ - -// value-parameter - -AA *TemplateValueParameter::edummies = NULL; - -TemplateValueParameter::TemplateValueParameter(Loc loc, Identifier *ident, Type *valType, - Expression *specValue, Expression *defaultValue) - : TemplateParameter(loc, ident) -{ - this->ident = ident; - this->valType = valType; - this->specValue = specValue; - this->defaultValue = defaultValue; -} - -TemplateValueParameter *TemplateValueParameter::isTemplateValueParameter() -{ - return this; -} - -TemplateParameter *TemplateValueParameter::syntaxCopy() -{ - TemplateValueParameter *tp = - new TemplateValueParameter(loc, ident, valType, specValue, defaultValue); - tp->valType = valType->syntaxCopy(); - if (specValue) - tp->specValue = specValue->syntaxCopy(); - if (defaultValue) - tp->defaultValue = defaultValue->syntaxCopy(); - return tp; -} - -void TemplateValueParameter::declareParameter(Scope *sc) -{ - VarDeclaration *v = new VarDeclaration(loc, valType, ident, NULL); - v->storage_class = STCtemplateparameter; - if (!sc->insert(v)) - error(loc, "parameter '%s' multiply defined", ident->toChars()); - sparam = v; -} - -void TemplateValueParameter::semantic(Scope *sc) -{ - bool wasSame = (sparam->type == valType); - sparam->semantic(sc); - if (sparam->type == Type::terror && wasSame) - { /* If sparam has a type error, avoid duplicate errors - * The simple solution of leaving that function if sparam->type == Type::terror - * doesn't quite work because it causes failures in xtest46 for bug 6295 - */ - valType = Type::terror; - return; - } - valType = valType->semantic(loc, sc); - if (!(valType->isintegral() || valType->isfloating() || valType->isString()) && - valType->ty != Tident) - { - if (valType != Type::terror) - error(loc, "arithmetic/string type expected for value-parameter, not %s", valType->toChars()); - } - -#if 0 // defer semantic analysis to arg match - if (specValue) - { Expression *e = specValue; - - e = e->semantic(sc); - e = e->implicitCastTo(sc, valType); - e = e->optimize(WANTvalue | WANTinterpret); - if (e->op == TOKint64 || e->op == TOKfloat64 || - e->op == TOKcomplex80 || e->op == TOKnull || e->op == TOKstring) - specValue = e; - //e->toInteger(); - } - - if (defaultValue) - { Expression *e = defaultValue; - - e = e->semantic(sc); - e = e->implicitCastTo(sc, valType); - e = e->optimize(WANTvalue | WANTinterpret); - if (e->op == TOKint64) - defaultValue = e; - //e->toInteger(); - } -#endif -} - -int TemplateValueParameter::overloadMatch(TemplateParameter *tp) -{ - TemplateValueParameter *tvp = tp->isTemplateValueParameter(); - - if (tvp) - { - if (valType != tvp->valType) - goto Lnomatch; - - if (valType && !valType->equals(tvp->valType)) - goto Lnomatch; - - if (specValue != tvp->specValue) - goto Lnomatch; - - return 1; // match - } - -Lnomatch: - return 0; -} - - -MATCH TemplateValueParameter::matchArg(Scope *sc, - Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, - Declaration **psparam) -{ - //printf("TemplateValueParameter::matchArg()\n"); - - Initializer *init; - Declaration *sparam; - MATCH m = MATCHexact; - Expression *ei; - Object *oarg; - - if (i < tiargs->dim) - oarg = tiargs->tdata()[i]; - else - { // Get default argument instead - oarg = defaultArg(loc, sc); - if (!oarg) - { assert(i < dedtypes->dim); - // It might have already been deduced - oarg = dedtypes->tdata()[i]; - if (!oarg) - goto Lnomatch; - } - } - - ei = isExpression(oarg); - Type *vt; - - if (!ei && oarg) - goto Lnomatch; - - if (ei && ei->op == TOKvar) - { // Resolve const variables that we had skipped earlier - ei = ei->optimize(WANTvalue | WANTinterpret); - } - - //printf("\tvalType: %s, ty = %d\n", valType->toChars(), valType->ty); - vt = valType->semantic(0, sc); - //printf("ei: %s, ei->type: %s\n", ei->toChars(), ei->type->toChars()); - //printf("vt = %s\n", vt->toChars()); - - if (ei->type) - { - m = (MATCH)ei->implicitConvTo(vt); - //printf("m: %d\n", m); - if (!m) - goto Lnomatch; - } - - if (specValue) - { - if (!ei || _aaGetRvalue(edummies, ei->type) == ei) - goto Lnomatch; - - Expression *e = specValue; - - e = e->semantic(sc); - e = e->implicitCastTo(sc, vt); - e = e->optimize(WANTvalue | WANTinterpret); - - ei = ei->syntaxCopy(); - ei = ei->semantic(sc); - ei = ei->implicitCastTo(sc, vt); - ei = ei->optimize(WANTvalue | WANTinterpret); - //printf("\tei: %s, %s\n", ei->toChars(), ei->type->toChars()); - //printf("\te : %s, %s\n", e->toChars(), e->type->toChars()); - if (!ei->equals(e)) - goto Lnomatch; - } - else - { - if (dedtypes->tdata()[i]) - { // Must match already deduced value - Expression *e = (Expression *)dedtypes->tdata()[i]; - - if (!ei || !ei->equals(e)) - goto Lnomatch; - } - else if (m != MATCHexact) - { - ei = ei->implicitCastTo(sc, vt); - ei = ei->optimize(WANTvalue | WANTinterpret); - } - } - dedtypes->tdata()[i] = ei; - - init = new ExpInitializer(loc, ei); - sparam = new VarDeclaration(loc, vt, ident, init); - sparam->storage_class = STCmanifest; - *psparam = sparam; - return m; - -Lnomatch: - //printf("\tno match\n"); - *psparam = NULL; - return MATCHnomatch; -} - - -void TemplateValueParameter::print(Object *oarg, Object *oded) -{ - printf(" %s\n", ident->toChars()); - - Expression *ea = isExpression(oded); - - if (specValue) - printf("\tSpecialization: %s\n", specValue->toChars()); - printf("\tParameter Value: %s\n", ea ? ea->toChars() : "NULL"); -} - - -void TemplateValueParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - valType->toCBuffer(buf, ident, hgs); - if (specValue) - { - buf->writestring(" : "); - specValue->toCBuffer(buf, hgs); - } - if (defaultValue) - { - buf->writestring(" = "); - defaultValue->toCBuffer(buf, hgs); - } -} - - -void *TemplateValueParameter::dummyArg() -{ Expression *e; - - e = specValue; - if (!e) - { - // Create a dummy value - Expression **pe = (Expression **)_aaGet(&edummies, valType); - if (!*pe) - *pe = valType->defaultInit(); - e = *pe; - } - return (void *)e; -} - - -Object *TemplateValueParameter::specialization() -{ - return specValue; -} - - -Object *TemplateValueParameter::defaultArg(Loc loc, Scope *sc) -{ - Expression *e = defaultValue; - if (e) - { - e = e->syntaxCopy(); - e = e->semantic(sc); -#if DMDV2 - e = e->resolveLoc(loc, sc); -#endif - } - return e; -} - -/* ======================== TemplateTupleParameter ========================== */ - -// variadic-parameter - -TemplateTupleParameter::TemplateTupleParameter(Loc loc, Identifier *ident) - : TemplateParameter(loc, ident) -{ - this->ident = ident; -} - -TemplateTupleParameter *TemplateTupleParameter::isTemplateTupleParameter() -{ - return this; -} - -TemplateParameter *TemplateTupleParameter::syntaxCopy() -{ - TemplateTupleParameter *tp = new TemplateTupleParameter(loc, ident); - return tp; -} - -void TemplateTupleParameter::declareParameter(Scope *sc) -{ - TypeIdentifier *ti = new TypeIdentifier(loc, ident); - sparam = new AliasDeclaration(loc, ident, ti); - if (!sc->insert(sparam)) - error(loc, "parameter '%s' multiply defined", ident->toChars()); -} - -void TemplateTupleParameter::semantic(Scope *sc) -{ -} - -int TemplateTupleParameter::overloadMatch(TemplateParameter *tp) -{ - TemplateTupleParameter *tvp = tp->isTemplateTupleParameter(); - - if (tvp) - { - return 1; // match - } - - return 0; -} - -MATCH TemplateTupleParameter::matchArg(Scope *sc, Objects *tiargs, - size_t i, TemplateParameters *parameters, Objects *dedtypes, - Declaration **psparam) -{ - //printf("TemplateTupleParameter::matchArg()\n"); - - /* The rest of the actual arguments (tiargs[]) form the match - * for the variadic parameter. - */ - assert(i + 1 == dedtypes->dim); // must be the last one - Tuple *ovar; - - if (dedtypes->tdata()[i] && isTuple(dedtypes->tdata()[i])) - // It was already been deduced - ovar = isTuple(dedtypes->tdata()[i]); - else if (i + 1 == tiargs->dim && isTuple(tiargs->tdata()[i])) - ovar = isTuple(tiargs->tdata()[i]); - else - { - ovar = new Tuple(); - //printf("ovar = %p\n", ovar); - if (i < tiargs->dim) - { - //printf("i = %d, tiargs->dim = %d\n", i, tiargs->dim); - ovar->objects.setDim(tiargs->dim - i); - for (size_t j = 0; j < ovar->objects.dim; j++) - ovar->objects.tdata()[j] = tiargs->tdata()[i + j]; - } - } - *psparam = new TupleDeclaration(loc, ident, &ovar->objects); - dedtypes->tdata()[i] = ovar; - return MATCHexact; -} - - -void TemplateTupleParameter::print(Object *oarg, Object *oded) -{ - printf(" %s... [", ident->toChars()); - Tuple *v = isTuple(oded); - assert(v); - - //printf("|%d| ", v->objects.dim); - for (size_t i = 0; i < v->objects.dim; i++) - { - if (i) - printf(", "); - - Object *o = v->objects.tdata()[i]; - - Dsymbol *sa = isDsymbol(o); - if (sa) - printf("alias: %s", sa->toChars()); - - Type *ta = isType(o); - if (ta) - printf("type: %s", ta->toChars()); - - Expression *ea = isExpression(o); - if (ea) - printf("exp: %s", ea->toChars()); - - assert(!isTuple(o)); // no nested Tuple arguments - } - - printf("]\n"); -} - -void TemplateTupleParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(ident->toChars()); - buf->writestring("..."); -} - - -void *TemplateTupleParameter::dummyArg() -{ - return NULL; -} - - -Object *TemplateTupleParameter::specialization() -{ - return NULL; -} - - -Object *TemplateTupleParameter::defaultArg(Loc loc, Scope *sc) -{ - return NULL; -} - -/* ======================== TemplateInstance ================================ */ - -TemplateInstance::TemplateInstance(Loc loc, Identifier *ident) - : ScopeDsymbol(NULL) -{ -#if LOG - printf("TemplateInstance(this = %p, ident = '%s')\n", this, ident ? ident->toChars() : "null"); -#endif - this->loc = loc; - this->name = ident; - this->tiargs = NULL; - this->tempdecl = NULL; - this->inst = NULL; - this->tinst = NULL; - this->argsym = NULL; - this->aliasdecl = NULL; - this->semanticRun = PASSinit; - this->semantictiargsdone = 0; - this->withsym = NULL; - this->nest = 0; - this->havetempdecl = 0; - this->isnested = NULL; - this->speculative = 0; - this->ignore = true; - -#if IN_LLVM - this->emittedInModule = NULL; - this->tmodule = NULL; -#endif -} - -/***************** - * This constructor is only called when we figured out which function - * template to instantiate. - */ - -TemplateInstance::TemplateInstance(Loc loc, TemplateDeclaration *td, Objects *tiargs) - : ScopeDsymbol(NULL) -{ -#if LOG - printf("TemplateInstance(this = %p, tempdecl = '%s')\n", this, td->toChars()); -#endif - this->loc = loc; - this->name = td->ident; - this->tiargs = tiargs; - this->tempdecl = td; - this->inst = NULL; - this->tinst = NULL; - this->argsym = NULL; - this->aliasdecl = NULL; - this->semanticRun = PASSinit; - this->semantictiargsdone = 1; - this->withsym = NULL; - this->nest = 0; - this->havetempdecl = 1; - this->isnested = NULL; - this->speculative = 0; - this->ignore = true; - -#if IN_LLVM - this->tinst = NULL; - this->emittedInModule = NULL; - this->tmodule = NULL; -#endif - - assert((size_t)tempdecl->scope > 0x10000); -} - - -Objects *TemplateInstance::arraySyntaxCopy(Objects *objs) -{ - Objects *a = NULL; - if (objs) - { a = new Objects(); - a->setDim(objs->dim); - for (size_t i = 0; i < objs->dim; i++) - { - a->tdata()[i] = objectSyntaxCopy(objs->tdata()[i]); - } - } - return a; -} - -Dsymbol *TemplateInstance::syntaxCopy(Dsymbol *s) -{ - TemplateInstance *ti; - - if (s) - ti = (TemplateInstance *)s; - else - ti = new TemplateInstance(loc, name); - - ti->tiargs = arraySyntaxCopy(tiargs); - - ScopeDsymbol::syntaxCopy(ti); - return ti; -} - - -void TemplateInstance::semantic(Scope *sc) -{ - semantic(sc, NULL); -} - -void TemplateInstance::expandMembers(Scope *sc2) -{ - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = (*members)[i]; - s->setScope(sc2); - } - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = members->tdata()[i]; - //printf("\t[%d] semantic on '%s' %p kind %s in '%s'\n", i, s->toChars(), s, s->kind(), this->toChars()); - //printf("test: isnested = %d, sc2->parent = %s\n", isnested, sc2->parent->toChars()); -// if (isnested) -// s->parent = sc->parent; - //printf("test3: isnested = %d, s->parent = %s\n", isnested, s->parent->toChars()); - s->semantic(sc2); - //printf("test4: isnested = %d, s->parent = %s\n", isnested, s->parent->toChars()); - sc2->module->runDeferredSemantic(); - } -} - -void TemplateInstance::tryExpandMembers(Scope *sc2) -{ - static int nest; - // extracted to a function to allow windows SEH to work without destructors in the same function - //printf("%d\n", nest); - if (++nest > 500) - { - global.gag = 0; // ensure error message gets printed - error("recursive expansion"); - fatal(); - } - -#if WINDOWS_SEH - if(nest == 1) - { - // do not catch at every nesting level, because generating the output error might cause more stack - // errors in the __except block otherwise - __try - { - expandMembers(sc2); - } - __except (__ehfilter(GetExceptionInformation())) - { - global.gag = 0; // ensure error message gets printed - error("recursive expansion"); - fatal(); - } - } - else -#endif - expandMembers(sc2); - nest--; -} - -void TemplateInstance::trySemantic3(Scope *sc2) -{ - // extracted to a function to allow windows SEH to work without destructors in the same function - static int nest; - if (++nest > 300) - { - global.gag = 0; // ensure error message gets printed - error("recursive expansion"); - fatal(); - } -#if WINDOWS_SEH - if(nest == 1) - { - // do not catch at every nesting level, because generating the output error might cause more stack - // errors in the __except block otherwise - __try - { - semantic3(sc2); - } - __except (__ehfilter(GetExceptionInformation())) - { - global.gag = 0; // ensure error message gets printed - error("recursive expansion"); - fatal(); - } - } - else -#endif - semantic3(sc2); - - --nest; -} - -void TemplateInstance::semantic(Scope *sc, Expressions *fargs) -{ - //printf("TemplateInstance::semantic('%s', this=%p, gag = %d, sc = %p)\n", toChars(), this, global.gag, sc); -#if LOG - printf("\n+TemplateInstance::semantic('%s', this=%p)\n", toChars(), this); -#endif - if (inst) // if semantic() was already run - { -#if LOG - printf("-TemplateInstance::semantic('%s', this=%p) already run\n", inst->toChars(), inst); -#endif - return; - } - - if (!sc->ignoreTemplates) - ignore = false; - - - // get the enclosing template instance from the scope tinst - tinst = sc->tinst; - - if (semanticRun != PASSinit) - { -#if LOG - printf("Recursive template expansion\n"); -#endif - error(loc, "recursive template expansion"); -// inst = this; - return; - } - semanticRun = PASSsemantic; -#if IN_LLVM - // get the enclosing template instance from the scope tinst - tinst = sc->tinst; - - // get the module of the outermost enclosing instantiation - if (tinst) - tmodule = tinst->tmodule; - else - tmodule = sc->module; - //printf("%s in %s\n", toChars(), tmodule->toChars()); -#endif - -#if LOG - printf("\tdo semantic\n"); -#endif - if (havetempdecl) - { - assert((size_t)tempdecl->scope > 0x10000); - // Deduce tdtypes - tdtypes.setDim(tempdecl->parameters->dim); - if (!tempdecl->matchWithInstance(this, &tdtypes, fargs, 2)) - { - error("incompatible arguments for template instantiation"); - inst = this; - return; - } - } - else - { - /* Run semantic on each argument, place results in tiargs[] - * (if we havetempdecl, then tiargs is already evaluated) - */ - semanticTiargs(sc); - if (arrayObjectIsError(tiargs)) - { inst = this; - //printf("error return %p, %d\n", tempdecl, global.errors); - return; // error recovery - } - unsigned errs = global.errors; - tempdecl = findTemplateDeclaration(sc); - if (tempdecl) - tempdecl = findBestMatch(sc, fargs); - if (!tempdecl || (errs != global.errors)) - { inst = this; - //printf("error return %p, %d\n", tempdecl, global.errors); - return; // error recovery - } - } - - // If tempdecl is a mixin, disallow it - if (tempdecl->ismixin) - error("mixin templates are not regular templates"); - - hasNestedArgs(tiargs); - - /* See if there is an existing TemplateInstantiation that already - * implements the typeargs. If so, just refer to that one instead. - */ - - for (size_t i = 0; i < tempdecl->instances.dim; i++) - { - TemplateInstance *ti = tempdecl->instances.tdata()[i]; -#if LOG - printf("\t%s: checking for match with instance %d (%p): '%s'\n", toChars(), i, ti, ti->toChars()); -#endif - assert(tdtypes.dim == ti->tdtypes.dim); - - // Nesting must match - if (isnested != ti->isnested) - { - //printf("test2 isnested %s ti->isnested %s\n", isnested ? isnested->toChars() : "", ti->isnested ? ti->isnested->toChars() : ""); - continue; - } - //printf("parent = %s, ti->parent = %s\n", tempdecl->parent->toPrettyChars(), ti->parent->toPrettyChars()); - - if (!arrayObjectMatch(&tdtypes, &ti->tdtypes, tempdecl, sc)) - goto L1; - - /* Template functions may have different instantiations based on - * "auto ref" parameters. - */ - if (fargs) - { - FuncDeclaration *fd = ti->toAlias()->isFuncDeclaration(); - if (fd) - { - Parameters *fparameters = fd->getParameters(NULL); - size_t nfparams = Parameter::dim(fparameters); // Num function parameters - for (size_t j = 0; j < nfparams && j < fargs->dim; j++) - { Parameter *fparam = Parameter::getNth(fparameters, j); - Expression *farg = fargs->tdata()[j]; - if (fparam->storageClass & STCauto) // if "auto ref" - { - if (farg->isLvalue()) - { if (!(fparam->storageClass & STCref)) - goto L1; // auto ref's don't match - } - else - { if (fparam->storageClass & STCref) - goto L1; // auto ref's don't match - } - } - } - } - } - - // It's a match - inst = ti; - parent = ti->parent; - - // If both this and the previous instantiation were speculative, - // use the number of errors that happened last time. - if (inst->speculative && global.gag) - { - global.errors += inst->errors; - global.gaggedErrors += inst->errors; - } - - // If the first instantiation was speculative, but this is not: - if (inst->speculative && !global.gag) - { - // If the first instantiation had failed, re-run semantic, - // so that error messages are shown. - if (inst->errors) - goto L1; - // It had succeeded, mark it is a non-speculative instantiation, - // and reuse it. - inst->speculative = 0; - } - -#if LOG - printf("\tit's a match with instance %p, %d\n", inst, inst->semanticRun); -#endif - return; - - L1: - ; - } - - /* So, we need to implement 'this' instance. - */ -#if LOG - printf("\timplement template instance %s '%s'\n", tempdecl->parent->toChars(), toChars()); - printf("\ttempdecl %s\n", tempdecl->toChars()); -#endif - unsigned errorsave = global.errors; - inst = this; - // Mark as speculative if we are instantiated from inside is(typeof()) - if (global.gag && sc->speculative) - speculative = 1; - - int tempdecl_instance_idx = tempdecl->instances.dim; - tempdecl->instances.push(this); - parent = tempdecl->parent; - //printf("parent = '%s'\n", parent->kind()); - - ident = genIdent(tiargs); // need an identifier for name mangling purposes. - -#if 1 - if (isnested) - parent = isnested; -#endif - //printf("parent = '%s'\n", parent->kind()); - - // Add 'this' to the enclosing scope's members[] so the semantic routines - // will get called on the instance members. Store the place we added it to - // in target_symbol_list(_idx) so we can remove it later if we encounter - // an error. -#if 1 - int dosemantic3 = 0; - Dsymbols *target_symbol_list = NULL; - int target_symbol_list_idx; - - if (!sc->parameterSpecialization) - { Dsymbols *a; - - Scope *scx = sc; -#if 0 - for (scx = sc; scx; scx = scx->enclosing) - if (scx->scopesym) - break; -#endif - - //if (scx && scx->scopesym) printf("3: scx is %s %s\n", scx->scopesym->kind(), scx->scopesym->toChars()); - if (scx && scx->scopesym && - scx->scopesym->members && !scx->scopesym->isTemplateMixin() -#if 0 // removed because it bloated compile times - /* The problem is if A imports B, and B imports A, and both A - * and B instantiate the same template, does the compilation of A - * or the compilation of B do the actual instantiation? - * - * see bugzilla 2500. - */ - && !scx->module->selfImports() -#endif - ) - { - //printf("\t1: adding to %s %s\n", scx->scopesym->kind(), scx->scopesym->toChars()); - a = scx->scopesym->members; - } - else - { Module *m = sc->module->importedFrom; - //printf("\t2: adding to module %s instead of module %s\n", m->toChars(), sc->module->toChars()); - a = m->members; - if (m->semanticRun >= 3) - { - dosemantic3 = 1; - } - } - for (int i = 0; 1; i++) - { - if (i == a->dim) - { - target_symbol_list = a; - target_symbol_list_idx = i; - a->push(this); - break; - } - if (this == a->tdata()[i]) // if already in Array - break; - } - } -#endif - - // Copy the syntax trees from the TemplateDeclaration - members = Dsymbol::arraySyntaxCopy(tempdecl->members); - - // Create our own scope for the template parameters - Scope *scope = tempdecl->scope; - if (!tempdecl->semanticRun) - { - error("template instantiation %s forward references template declaration %s\n", toChars(), tempdecl->toChars()); - return; - } - -#if LOG - printf("\tcreate scope for template parameters '%s'\n", toChars()); -#endif - argsym = new ScopeDsymbol(); - argsym->parent = scope->parent; - scope = scope->push(argsym); -// scope->stc = 0; - - // Declare each template parameter as an alias for the argument type - Scope *paramscope = scope->push(); - paramscope->stc = 0; - declareParameters(paramscope); - paramscope->pop(); - - // Add members of template instance to template instance symbol table -// parent = scope->scopesym; - symtab = new DsymbolTable(); - int memnum = 0; - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = members->tdata()[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 - memnum |= s->addMember(scope, this, memnum); - } -#if LOG - printf("adding members done\n"); -#endif - - /* See if there is only one member of template instance, and that - * member has the same name as the template instance. - * If so, this template instance becomes an alias for that member. - */ - //printf("members->dim = %d\n", members->dim); - if (members->dim) - { - Dsymbol *s; - if (Dsymbol::oneMembers(members, &s, tempdecl->ident) && s) - { - //printf("s->kind = '%s'\n", s->kind()); - //s->print(); - //printf("'%s', '%s'\n", s->ident->toChars(), tempdecl->ident->toChars()); - //printf("setting aliasdecl\n"); - aliasdecl = new AliasDeclaration(loc, s->ident, s); - -#if IN_LLVM - // LDC propagate internal information - if (tempdecl->llvmInternal) { - s->llvmInternal = tempdecl->llvmInternal; - if (FuncDeclaration* fd = s->isFuncDeclaration()) { - fd->intrinsicName = tempdecl->intrinsicName; - } - } -#endif - } - } - - /* If function template declaration - */ - if (fargs && aliasdecl) - { - FuncDeclaration *fd = aliasdecl->toAlias()->isFuncDeclaration(); - if (fd) - { - /* Transmit fargs to type so that TypeFunction::semantic() can - * resolve any "auto ref" storage classes. - */ - TypeFunction *tf = (TypeFunction *)fd->type; - if (tf && tf->ty == Tfunction) - tf->fargs = fargs; - } - } - - // Do semantic() analysis on template instance members -#if LOG - printf("\tdo semantic() on template instance members '%s'\n", toChars()); -#endif - Scope *sc2; - sc2 = scope->push(this); - //printf("isnested = %d, sc->parent = %s\n", isnested, sc->parent->toChars()); - sc2->parent = /*isnested ? sc->parent :*/ this; - sc2->tinst = this; - - tryExpandMembers(sc2); - - semanticRun = PASSsemanticdone; - - /* If any of the instantiation members didn't get semantic() run - * on them due to forward references, we cannot run semantic2() - * or semantic3() yet. - */ - for (size_t i = 0; i < Module::deferred.dim; i++) - { Dsymbol *sd = Module::deferred.tdata()[i]; - - if (sd->parent == this) - { - //printf("deferred %s %s\n", sd->parent->toChars(), sd->toChars()); - AggregateDeclaration *ad = sd->isAggregateDeclaration(); - if (ad) - ad->deferred = this; - goto Laftersemantic; - } - } - - /* ConditionalDeclaration may introduce eponymous declaration, - * so we should find it once again after semantic. - */ - if (members->dim) - { - Dsymbol *s; - if (Dsymbol::oneMembers(members, &s, tempdecl->ident) && s) - { - if (!aliasdecl || aliasdecl->toAlias() != s) - { - //printf("s->kind = '%s'\n", s->kind()); - //s->print(); - //printf("'%s', '%s'\n", s->ident->toChars(), tempdecl->ident->toChars()); - //printf("setting aliasdecl 2\n"); - aliasdecl = new AliasDeclaration(loc, s->ident, s); - } - } - else if (aliasdecl) - aliasdecl = NULL; - } - - /* The problem is when to parse the initializer for a variable. - * Perhaps VarDeclaration::semantic() should do it like it does - * for initializers inside a function. - */ -// if (sc->parent->isFuncDeclaration()) - - /* BUG 782: this has problems if the classes this depends on - * are forward referenced. Find a way to defer semantic() - * on this template. - */ - semantic2(sc2); - - if (sc->func || dosemantic3) - { - trySemantic3(sc2); - } - - Laftersemantic: - sc2->pop(); - - scope->pop(); - - // Give additional context info if error occurred during instantiation - if (global.errors != errorsave) - { - error(loc, "error instantiating"); - if (tinst) - { tinst->printInstantiationTrace(); - } - errors = 1; - if (global.gag) - { - // Errors are gagged, so remove the template instance from the - // instance/symbol lists we added it to and reset our state to - // finish clean and so we can try to instantiate it again later - // (see bugzilla 4302 and 6602). - tempdecl->instances.remove(tempdecl_instance_idx); - if (target_symbol_list) - { - // 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); - target_symbol_list->remove(target_symbol_list_idx); - } - semanticRun = PASSinit; - inst = NULL; - } - } - -#if LOG - printf("-TemplateInstance::semantic('%s', this=%p)\n", toChars(), this); -#endif -} - - -void TemplateInstance::semanticTiargs(Scope *sc) -{ - //printf("+TemplateInstance::semanticTiargs() %s\n", toChars()); - if (semantictiargsdone) - return; - semantictiargsdone = 1; - semanticTiargs(loc, sc, tiargs, 0); -} - -/********************************** - * Input: - * flags 1: replace const variables with their initializers - */ - -void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int flags) -{ - // Run semantic on each argument, place results in tiargs[] - //printf("+TemplateInstance::semanticTiargs()\n"); - if (!tiargs) - return; - for (size_t j = 0; j < tiargs->dim; j++) - { - Object *o = tiargs->tdata()[j]; - Type *ta = isType(o); - Expression *ea = isExpression(o); - Dsymbol *sa = isDsymbol(o); - - //printf("1: tiargs->tdata()[%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()); - // It might really be an Expression or an Alias - ta->resolve(loc, sc, &ea, &ta, &sa); - if (ea) - { - ea = ea->semantic(sc); - /* This test is to skip substituting a const var with - * its initializer. The problem is the initializer won't - * match with an 'alias' parameter. Instead, do the - * const substitution in TemplateValueParameter::matchArg(). - */ - if (flags & 1) // only used by __traits, must not interpret the args - ea = ea->optimize(WANTvalue); - else if (ea->op != TOKvar) - ea = ea->optimize(WANTvalue | WANTinterpret); - tiargs->tdata()[j] = ea; - } - else if (sa) - { - Ldsym: - tiargs->tdata()[j] = sa; - TupleDeclaration *d = sa->toAlias()->isTupleDeclaration(); - if (d) - { - size_t dim = d->objects->dim; - tiargs->remove(j); - tiargs->insert(j, d->objects); - j--; - } - } - else if (ta) - { - Ltype: - if (ta->ty == Ttuple) - { // Expand tuple - TypeTuple *tt = (TypeTuple *)ta; - size_t dim = tt->arguments->dim; - tiargs->remove(j); - if (dim) - { tiargs->reserve(dim); - for (size_t i = 0; i < dim; i++) - { Parameter *arg = tt->arguments->tdata()[i]; - tiargs->insert(j + i, arg->type); - } - } - j--; - } - else - tiargs->tdata()[j] = ta; - } - else - { - assert(global.errors); - tiargs->tdata()[j] = Type::terror; - } - } - else if (ea) - { - if (!ea) - { assert(global.errors); - ea = new ErrorExp(); - } - assert(ea); - ea = ea->semantic(sc); - if (flags & 1) // only used by __traits, must not interpret the args - ea = ea->optimize(WANTvalue); - else if (ea->op != TOKvar && ea->op != TOKtuple) - ea = ea->optimize(WANTvalue | WANTinterpret); - tiargs->tdata()[j] = ea; - if (ea->op == TOKtype) - { ta = ea->type; - goto Ltype; - } - if (ea->op == TOKimport) - { sa = ((ScopeExp *)ea)->sds; - goto Ldsym; - } - if (ea->op == TOKtuple) - { // Expand tuple - TupleExp *te = (TupleExp *)ea; - size_t dim = te->exps->dim; - tiargs->remove(j); - if (dim) - { tiargs->reserve(dim); - for (size_t i = 0; i < dim; i++) - tiargs->insert(j + i, te->exps->tdata()[i]); - } - j--; - } - } - else if (sa) - { - TemplateDeclaration *td = sa->isTemplateDeclaration(); - if (td && !td->semanticRun && td->literal) - td->semantic(sc); - } - else - { - assert(0); - } - //printf("1: tiargs->tdata()[%d] = %p\n", j, tiargs->tdata()[j]); - } -#if 0 - printf("-TemplateInstance::semanticTiargs()\n"); - for (size_t j = 0; j < tiargs->dim; j++) - { - Object *o = tiargs->tdata()[j]; - Type *ta = isType(o); - Expression *ea = isExpression(o); - Dsymbol *sa = isDsymbol(o); - Tuple *va = isTuple(o); - - printf("\ttiargs[%d] = ta %p, ea %p, sa %p, va %p\n", j, ta, ea, sa, va); - } -#endif -} - -/********************************************** - * Find template declaration corresponding to template instance. - */ - -TemplateDeclaration *TemplateInstance::findTemplateDeclaration(Scope *sc) -{ - //printf("TemplateInstance::findTemplateDeclaration() %s\n", toChars()); - if (!tempdecl) - { - /* Given: - * foo!( ... ) - * figure out which TemplateDeclaration foo refers to. - */ - Dsymbol *s; - Dsymbol *scopesym; - Identifier *id; - - id = name; - s = sc->search(loc, id, &scopesym); - if (!s) - { - s = sc->search_correct(id); - if (s) - error("template '%s' is not defined, did you mean %s?", id->toChars(), s->toChars()); - else - error("template '%s' is not defined", id->toChars()); - return NULL; - } - - /* If an OverloadSet, look for a unique member that is a template declaration - */ - OverloadSet *os = s->isOverloadSet(); - if (os) - { s = NULL; - for (size_t i = 0; i < os->a.dim; i++) - { Dsymbol *s2 = os->a.tdata()[i]; - if (s2->isTemplateDeclaration()) - { - if (s) - error("ambiguous template declaration %s and %s", s->toPrettyChars(), s2->toPrettyChars()); - s = s2; - } - } - if (!s) - { error("template '%s' is not defined", id->toChars()); - return NULL; - } - } - -#if LOG - printf("It's an instance of '%s' kind '%s'\n", s->toChars(), s->kind()); - if (s->parent) - printf("s->parent = '%s'\n", s->parent->toChars()); -#endif - withsym = scopesym->isWithScopeSymbol(); - - /* We might have found an alias within a template when - * we really want the template. - */ - TemplateInstance *ti; - if (s->parent && - (ti = s->parent->isTemplateInstance()) != NULL) - { - if (ti->tempdecl && ti->tempdecl->ident == id) - { - /* This is so that one can refer to the enclosing - * template, even if it has the same name as a member - * of the template, if it has a !(arguments) - */ - tempdecl = ti->tempdecl; - if (tempdecl->overroot) // if not start of overloaded list of TemplateDeclaration's - tempdecl = tempdecl->overroot; // then get the start - s = tempdecl; - } - } - - s = s->toAlias(); - - /* It should be a TemplateDeclaration, not some other symbol - */ - tempdecl = s->isTemplateDeclaration(); - if (!tempdecl) - { - if (!s->parent && global.errors) - return NULL; - if (!s->parent && s->getType()) - { Dsymbol *s2 = s->getType()->toDsymbol(sc); - if (!s2) - { - error("%s is not a template declaration, it is a %s", id->toChars(), s->kind()); - return NULL; - } - s = s2; - } -#ifdef DEBUG - //if (!s->parent) printf("s = %s %s\n", s->kind(), s->toChars()); -#endif - //assert(s->parent); - TemplateInstance *ti = s->parent ? s->parent->isTemplateInstance() : NULL; - if (ti && - (ti->name == id || - ti->toAlias()->ident == id) - && - ti->tempdecl) - { - /* This is so that one can refer to the enclosing - * template, even if it has the same name as a member - * of the template, if it has a !(arguments) - */ - tempdecl = ti->tempdecl; - if (tempdecl->overroot) // if not start of overloaded list of TemplateDeclaration's - tempdecl = tempdecl->overroot; // then get the start - } - else - { - error("%s is not a template declaration, it is a %s", id->toChars(), s->kind()); - return NULL; - } - } - } - else - assert(tempdecl->isTemplateDeclaration()); - return tempdecl; -} - -TemplateDeclaration *TemplateInstance::findBestMatch(Scope *sc, Expressions *fargs) -{ - /* Since there can be multiple TemplateDeclaration's with the same - * name, look for the best match. - */ - TemplateDeclaration *td_ambig = NULL; - TemplateDeclaration *td_best = NULL; - MATCH m_best = MATCHnomatch; - Objects dedtypes; - -#if LOG - printf("TemplateInstance::findBestMatch()\n"); -#endif - // First look for forward references - for (TemplateDeclaration *td = tempdecl; td; td = td->overnext) - { - if (!td->semanticRun) - { - if (td->scope) - { // Try to fix forward reference - td->semantic(td->scope); - } - if (!td->semanticRun) - { - error("%s forward references template declaration %s\n", toChars(), td->toChars()); - return NULL; - } - } - } - - for (TemplateDeclaration *td = tempdecl; td; td = td->overnext) - { - MATCH m; - -//if (tiargs->dim) printf("2: tiargs->dim = %d, data[0] = %p\n", tiargs->dim, tiargs->tdata()[0]); - - // If more arguments than parameters, - // then this is no match. - if (td->parameters->dim < tiargs->dim) - { - if (!td->isVariadic()) - continue; - } - - dedtypes.setDim(td->parameters->dim); - dedtypes.zero(); - assert(td->semanticRun); - m = td->matchWithInstance(this, &dedtypes, fargs, 0); - //printf("matchWithInstance = %d\n", m); - if (!m) // no match at all - continue; - - if (m < m_best) - goto Ltd_best; - if (m > m_best) - goto Ltd; - - { - // Disambiguate by picking the most specialized TemplateDeclaration - MATCH c1 = td->leastAsSpecialized(td_best, fargs); - MATCH c2 = td_best->leastAsSpecialized(td, fargs); - //printf("c1 = %d, c2 = %d\n", c1, c2); - - if (c1 > c2) - goto Ltd; - else if (c1 < c2) - goto Ltd_best; - else - goto Lambig; - } - - Lambig: // td_best and td are ambiguous - td_ambig = td; - continue; - - Ltd_best: // td_best is the best match so far - td_ambig = NULL; - continue; - - Ltd: // td is the new best match - td_ambig = NULL; - td_best = td; - m_best = m; - tdtypes.setDim(dedtypes.dim); - memcpy(tdtypes.tdata(), dedtypes.tdata(), tdtypes.dim * sizeof(void *)); - continue; - } - - if (!td_best) - { - if (tempdecl && !tempdecl->overnext) - // Only one template, so we can give better error message - error("%s does not match template declaration %s", toChars(), tempdecl->toChars()); - else - ::error(loc, "%s %s.%s does not match any template declaration", - tempdecl->kind(), tempdecl->parent->toPrettyChars(), tempdecl->ident->toChars()); - return NULL; - } - if (td_ambig) - { - ::error(loc, "%s %s.%s matches more than one template declaration, %s(%d):%s and %s(%d):%s", - td_best->kind(), td_best->parent->toPrettyChars(), td_best->ident->toChars(), - td_best->loc.filename, td_best->loc.linnum, td_best->toChars(), - td_ambig->loc.filename, td_ambig->loc.linnum, td_ambig->toChars()); - } - - /* The best match is td_best - */ - tempdecl = td_best; - -#if 0 - /* Cast any value arguments to be same type as value parameter - */ - for (size_t i = 0; i < tiargs->dim; i++) - { Object *o = tiargs->tdata()[i]; - Expression *ea = isExpression(o); // value argument - TemplateParameter *tp = tempdecl->parameters->tdata()[i]; - assert(tp); - TemplateValueParameter *tvp = tp->isTemplateValueParameter(); - if (tvp) - { - assert(ea); - ea = ea->castTo(tvp->valType); - ea = ea->optimize(WANTvalue | WANTinterpret); - tiargs->tdata()[i] = (Object *)ea; - } - } -#endif - -#if LOG - printf("\tIt's a match with template declaration '%s'\n", tempdecl->toChars()); -#endif - return tempdecl; -} - - -/***************************************** - * Determines if a TemplateInstance will need a nested - * generation of the TemplateDeclaration. - */ - -int TemplateInstance::hasNestedArgs(Objects *args) -{ int nested = 0; - //printf("TemplateInstance::hasNestedArgs('%s')\n", tempdecl->ident->toChars()); - - /* A nested instance happens when an argument references a local - * symbol that is on the stack. - */ - for (size_t i = 0; i < args->dim; i++) - { Object *o = args->tdata()[i]; - Expression *ea = isExpression(o); - Dsymbol *sa = isDsymbol(o); - Tuple *va = isTuple(o); - if (ea) - { - if (ea->op == TOKvar) - { - sa = ((VarExp *)ea)->var; - goto Lsa; - } - if (ea->op == TOKthis) - { - sa = ((ThisExp *)ea)->var; - goto Lsa; - } - if (ea->op == TOKfunction) - { - sa = ((FuncExp *)ea)->fd; - goto Lsa; - } - } - else if (sa) - { - Lsa: - TemplateDeclaration *td = sa->isTemplateDeclaration(); - Declaration *d = sa->isDeclaration(); - if ((td && td->literal) || - (d && !d->isDataseg() && -#if DMDV2 - !(d->storage_class & STCmanifest) && -#endif - (!d->isFuncDeclaration() || d->isFuncDeclaration()->isNested()) && - !isTemplateMixin() - )) - { - // if module level template - if (tempdecl->toParent()->isModule()) - { Dsymbol *dparent = sa->toParent(); - if (!isnested) - isnested = dparent; - else if (isnested != dparent) - { - /* Select the more deeply nested of the two. - * Error if one is not nested inside the other. - */ - for (Dsymbol *p = isnested; p; p = p->parent) - { - if (p == dparent) - goto L1; // isnested is most nested - } - for (Dsymbol *p = dparent; p; p = p->parent) - { - if (p == isnested) - { isnested = dparent; - goto L1; // dparent is most nested - } - } - error("%s is nested in both %s and %s", - toChars(), isnested->toChars(), dparent->toChars()); - } - L1: - //printf("\tnested inside %s\n", isnested->toChars()); - nested |= 1; - } - else - error("cannot use local '%s' as parameter to non-global template %s", sa->toChars(), tempdecl->toChars()); - } - } - else if (va) - { - nested |= hasNestedArgs(&va->objects); - } - } - return nested; -} - -/**************************************** - * This instance needs an identifier for name mangling purposes. - * Create one by taking the template declaration name and adding - * the type signature for it. - */ - -Identifier *TemplateInstance::genIdent(Objects *args) -{ OutBuffer buf; - - //printf("TemplateInstance::genIdent('%s')\n", tempdecl->ident->toChars()); - char *id = tempdecl->ident->toChars(); - buf.printf("__T%llu%s", (ulonglong)strlen(id), id); - for (size_t i = 0; i < args->dim; i++) - { Object *o = args->tdata()[i]; - Type *ta = isType(o); - Expression *ea = isExpression(o); - Dsymbol *sa = isDsymbol(o); - Tuple *va = isTuple(o); - //printf("\to [%d] %p ta %p ea %p sa %p va %p\n", i, o, ta, ea, sa, va); - if (ta) - { - buf.writeByte('T'); - if (ta->deco) - buf.writestring(ta->deco); - else - { -#ifdef DEBUG - if (!global.errors) - printf("ta = %d, %s\n", ta->ty, ta->toChars()); -#endif - assert(global.errors); - } - } - else if (ea) - { - // Don't interpret it yet, it might actually be an alias - ea = ea->optimize(WANTvalue); - if (ea->op == TOKvar) - { - sa = ((VarExp *)ea)->var; - ea = NULL; - goto Lsa; - } - if (ea->op == TOKthis) - { - sa = ((ThisExp *)ea)->var; - ea = NULL; - goto Lsa; - } - if (ea->op == TOKfunction) - { - sa = ((FuncExp *)ea)->fd; - ea = NULL; - goto Lsa; - } - buf.writeByte('V'); - if (ea->op == TOKtuple) - { ea->error("tuple is not a valid template value argument"); - continue; - } - // Now that we know it is not an alias, we MUST obtain a value - unsigned olderr = global.errors; - ea = ea->optimize(WANTvalue | WANTinterpret); - if (ea->op == TOKerror || olderr != global.errors) - continue; -#if 1 - /* Use deco that matches what it would be for a function parameter - */ - buf.writestring(ea->type->deco); -#else - // Use type of parameter, not type of argument - TemplateParameter *tp = tempdecl->parameters->tdata()[i]; - assert(tp); - TemplateValueParameter *tvp = tp->isTemplateValueParameter(); - assert(tvp); - buf.writestring(tvp->valType->deco); -#endif - ea->toMangleBuffer(&buf); - } - else if (sa) - { - Lsa: - buf.writeByte('S'); - Declaration *d = sa->isDeclaration(); - if (d && (!d->type || !d->type->deco)) - { error("forward reference of %s", d->toChars()); - continue; - } -#if 0 - VarDeclaration *v = sa->isVarDeclaration(); - if (v && v->storage_class & STCmanifest) - { ExpInitializer *ei = v->init->isExpInitializer(); - if (ei) - { - ea = ei->exp; - goto Lea; - } - } -#endif - const char *p = sa->mangle(); - - /* Bugzilla 3043: if the first character of p is a digit this - * causes ambiguity issues because the digits of the two numbers are adjacent. - * Current demanglers resolve this by trying various places to separate the - * numbers until one gets a successful demangle. - * Unfortunately, fixing this ambiguity will break existing binary - * compatibility and the demanglers, so we'll leave it as is. - */ - buf.printf("%llu%s", (ulonglong)strlen(p), p); - } - else if (va) - { - assert(i + 1 == args->dim); // must be last one - args = &va->objects; - i = -1; - } - else - assert(0); - } - buf.writeByte('Z'); - id = buf.toChars(); - //buf.data = NULL; // we can free the string after call to idPool() - //printf("\tgenIdent = %s\n", id); - return Lexer::idPool(id); -} - - -/**************************************************** - * Declare parameters of template instance, initialize them with the - * template instance arguments. - */ - -void TemplateInstance::declareParameters(Scope *sc) -{ - //printf("TemplateInstance::declareParameters()\n"); - for (size_t i = 0; i < tdtypes.dim; i++) - { - TemplateParameter *tp = tempdecl->parameters->tdata()[i]; - //Object *o = tiargs->tdata()[i]; - Object *o = tdtypes.tdata()[i]; // initializer for tp - - //printf("\ttdtypes[%d] = %p\n", i, o); - tempdecl->declareParameter(sc, tp, o); - } -} - -/***************************************************** - * Determine if template instance is really a template function, - * and that template function needs to infer types from the function - * arguments. - */ - -int TemplateInstance::needsTypeInference(Scope *sc) -{ - //printf("TemplateInstance::needsTypeInference() %s\n", toChars()); - if (!tempdecl) - tempdecl = findTemplateDeclaration(sc); - int multipleMatches = FALSE; - for (TemplateDeclaration *td = tempdecl; td; td = td->overnext) - { - /* If any of the overloaded template declarations need inference, - * then return TRUE - */ - FuncDeclaration *fd; - if (!td->onemember || - (fd = td->onemember->toAlias()->isFuncDeclaration()) == NULL || - fd->type->ty != Tfunction) - { - /* Not a template function, therefore type inference is not possible. - */ - //printf("false\n"); - return FALSE; - } - - for (size_t i = 0; i < td->parameters->dim; i++) - if (td->parameters->tdata()[i]->isTemplateThisParameter()) - return TRUE; - - /* Determine if the instance arguments, tiargs, are all that is necessary - * to instantiate the template. - */ - //printf("tp = %p, td->parameters->dim = %d, tiargs->dim = %d\n", tp, td->parameters->dim, tiargs->dim); - TypeFunction *fdtype = (TypeFunction *)fd->type; - if (Parameter::dim(fdtype->parameters)) - { - TemplateParameter *tp = td->isVariadic(); - if (tp && td->parameters->dim > 1) - return TRUE; - - if (tiargs->dim < td->parameters->dim) - { // Can remain tiargs be filled by default arguments? - for (size_t i = tiargs->dim; i < td->parameters->dim; i++) - { tp = (*td->parameters)[i]; - if (TemplateTypeParameter *ttp = tp->isTemplateTypeParameter()) - { if (!ttp->defaultType) - return TRUE; - } - else if (TemplateAliasParameter *tap = tp->isTemplateAliasParameter()) - { if (!tap->defaultAlias) - return TRUE; - } - else if (TemplateValueParameter *tvp = tp->isTemplateValueParameter()) - { if (!tvp->defaultValue) - return TRUE; - } - } - } - } - /* If there is more than one function template which matches, we may - * need type inference (see Bugzilla 4430) - */ - if (td != tempdecl) - multipleMatches = TRUE; - } - //printf("false\n"); - return multipleMatches; -} - -void TemplateInstance::semantic2(Scope *sc) -{ int i; - - if (semanticRun >= PASSsemantic2) - return; - semanticRun = PASSsemantic2; -#if LOG - printf("+TemplateInstance::semantic2('%s')\n", toChars()); -#endif - if (!errors && members) - { - sc = tempdecl->scope; - assert(sc); - sc = sc->push(argsym); - sc = sc->push(this); - sc->tinst = this; - for (i = 0; i < members->dim; i++) - { - Dsymbol *s = members->tdata()[i]; -#if LOG -printf("\tmember '%s', kind = '%s'\n", s->toChars(), s->kind()); -#endif - s->semantic2(sc); - } - sc = sc->pop(); - sc->pop(); - } -#if LOG - printf("-TemplateInstance::semantic2('%s')\n", toChars()); -#endif -} - -void TemplateInstance::semantic3(Scope *sc) -{ -#if LOG - printf("TemplateInstance::semantic3('%s'), semanticRun = %d\n", toChars(), semanticRun); -#endif -//if (toChars()[0] == 'D') *(char*)0=0; - if (semanticRun >= PASSsemantic3) - return; - semanticRun = PASSsemantic3; - if (!errors && members) - { - sc = tempdecl->scope; - sc = sc->push(argsym); - sc = sc->push(this); - sc->tinst = this; - if (ignore) - sc->ignoreTemplates++; - int oldgag = global.gag; - int olderrors = global.errors; - /* If this is a speculative instantiation, gag errors. - * Future optimisation: If the results are actually needed, errors - * would already be gagged, so we don't really need to run semantic - * on the members. - */ - if (speculative && !oldgag) - olderrors = global.startGagging(); - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = members->tdata()[i]; - s->semantic3(sc); - if (speculative && global.errors != olderrors) - break; - } - if (speculative && !oldgag) - { // If errors occurred, this instantiation failed - errors += global.errors - olderrors; - global.endGagging(olderrors); - } - sc = sc->pop(); - sc->pop(); - } -} - -#if IN_DMD - -/************************************** - * Given an error instantiating the TemplateInstance, - * give the nested TemplateInstance instantiations that got - * us here. Those are a list threaded into the nested scopes. - */ -void TemplateInstance::printInstantiationTrace() -{ - if (global.gag) - return; - - const unsigned max_shown = 6; - const char format[] = "instantiated from here: %s"; - - // determine instantiation depth and number of recursive instantiations - int n_instantiations = 1; - int n_totalrecursions = 0; - for (TemplateInstance *cur = this; cur; cur = cur->tinst) - { - ++n_instantiations; - // If two instantiations use the same declaration, they are recursive. - // (this works even if they are instantiated from different places in the - // same template). - // In principle, we could also check for multiple-template recursion, but it's - // probably not worthwhile. - if (cur->tinst && cur->tempdecl && cur->tinst->tempdecl - && cur->tempdecl->loc.equals(cur->tinst->tempdecl->loc)) - ++n_totalrecursions; - } - - // show full trace only if it's short or verbose is on - if (n_instantiations <= max_shown || global.params.verbose) - { - for (TemplateInstance *cur = this; cur; cur = cur->tinst) - { - errorSupplemental(cur->loc, format, cur->toChars()); - } - } - else if (n_instantiations - n_totalrecursions <= max_shown) - { - // By collapsing recursive instantiations into a single line, - // we can stay under the limit. - int recursionDepth=0; - for (TemplateInstance *cur = this; cur; cur = cur->tinst) - { - if (cur->tinst && cur->tempdecl && cur->tinst->tempdecl - && cur->tempdecl->loc.equals(cur->tinst->tempdecl->loc)) - { - ++recursionDepth; - } - else - { - if (recursionDepth) - errorSupplemental(cur->loc, "%d recursive instantiations from here: %s", recursionDepth+2, cur->toChars()); - else - errorSupplemental(cur->loc, format, cur->toChars()); - recursionDepth = 0; - } - } - } - else - { - // Even after collapsing the recursions, the depth is too deep. - // Just display the first few and last few instantiations. - unsigned i = 0; - for (TemplateInstance *cur = this; cur; cur = cur->tinst) - { - if (i == max_shown / 2) - errorSupplemental(cur->loc, "... (%d instantiations, -v to show) ...", n_instantiations - max_shown); - - if (i < max_shown / 2 || - i >= n_instantiations - max_shown + max_shown / 2) - errorSupplemental(cur->loc, format, cur->toChars()); - ++i; - } - } -} - -void TemplateInstance::toObjFile(int multiobj) -{ -#if LOG - printf("TemplateInstance::toObjFile('%s', this = %p)\n", toChars(), this); -#endif - if (!errors && members) - { - if (multiobj) - // Append to list of object files to be written later - obj_append(this); - else - { - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = members->tdata()[i]; - s->toObjFile(multiobj); - } - } - } -} - -#endif - -void TemplateInstance::inlineScan() -{ -#if LOG - printf("TemplateInstance::inlineScan('%s')\n", toChars()); -#endif - if (!errors && members) - { - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = members->tdata()[i]; - s->inlineScan(); - } - } -} - -void TemplateInstance::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - int i; - - Identifier *id = name; - buf->writestring(id->toChars()); - buf->writestring("!("); - if (nest) - buf->writestring("..."); - else - { - nest++; - Objects *args = tiargs; - for (i = 0; i < args->dim; i++) - { - if (i) - buf->writeByte(','); - Object *oarg = (*args)[i]; - ObjectToCBuffer(buf, hgs, oarg); - } - nest--; - } - buf->writeByte(')'); -} - - -Dsymbol *TemplateInstance::toAlias() -{ -#if LOG - printf("TemplateInstance::toAlias()\n"); -#endif - if (!inst) - { - // Maybe we can resolve it - if (scope) - { - /* Anything that affects scope->offset must be - * done in lexical order. Fwd ref error if it is affected, otherwise allow. - */ - unsigned offset = scope->offset; - Scope *sc = scope; - semantic(scope); -// if (offset != sc->offset) -// inst = NULL; // trigger fwd ref error - } - if (!inst) - { error("cannot resolve forward reference"); - errors = 1; - return this; - } - } - - if (inst != this) - return inst->toAlias(); - - if (aliasdecl) - { - return aliasdecl->toAlias(); - } - - return inst; -} - -AliasDeclaration *TemplateInstance::isAliasDeclaration() -{ - return aliasdecl; -} - -const char *TemplateInstance::kind() -{ - return "template instance"; -} - -int TemplateInstance::oneMember(Dsymbol **ps, Identifier *ident) -{ - *ps = NULL; - return TRUE; -} - -char *TemplateInstance::toChars() -{ - OutBuffer buf; - HdrGenState hgs; - char *s; - - toCBuffer(&buf, &hgs); - s = buf.toChars(); - buf.data = NULL; - return s; -} - -#if IN_LLVM - -void TemplateInstance::printInstantiationTrace() -{ - if(global.gag) - return; - - const int max_shown = 6; - - // determine instantiation depth - int n_instantiations = 1; - TemplateInstance* cur = this; - while(cur = cur->tinst) - ++n_instantiations; - - // show full trace only if it's short or verbose is on - if(n_instantiations <= max_shown || global.params.verbose) - { - cur = this; - while(cur) - { - fprintf(stdmsg," instantiatied in %s: %s\n", cur->loc.toChars(), cur->toChars()); - cur = cur->tinst; - } - } - else - { - cur = this; - size_t i = 0; - for(; i < max_shown/2; ++i, cur = cur->tinst) - fprintf(stdmsg," instantiatied in %s: %s\n", cur->loc.toChars(), cur->toChars()); - fprintf(stdmsg," ... (%d instantiations, -v to show) ...\n", n_instantiations - max_shown); - for(; i < n_instantiations - max_shown + max_shown/2; ++i, cur = cur->tinst) - {} - for(; i < n_instantiations; ++i, cur = cur->tinst) - fprintf(stdmsg," instantiatied in %s: %s\n", cur->loc.toChars(), cur->toChars()); - } -} - -#endif - -/* ======================== TemplateMixin ================================ */ - -TemplateMixin::TemplateMixin(Loc loc, Identifier *ident, Type *tqual, - Identifiers *idents, Objects *tiargs) - : TemplateInstance(loc, idents->tdata()[idents->dim - 1]) -{ - //printf("TemplateMixin(ident = '%s')\n", ident ? ident->toChars() : ""); - this->ident = ident; - this->tqual = tqual; - this->idents = idents; - this->tiargs = tiargs ? tiargs : new Objects(); -} - -Dsymbol *TemplateMixin::syntaxCopy(Dsymbol *s) -{ TemplateMixin *tm; - - Identifiers *ids = new Identifiers(); - ids->setDim(idents->dim); - for (size_t i = 0; i < idents->dim; i++) - { // Matches TypeQualified::syntaxCopyHelper() - Identifier *id = idents->tdata()[i]; - if (id->dyncast() == DYNCAST_DSYMBOL) - { - TemplateInstance *ti = (TemplateInstance *)id; - - ti = (TemplateInstance *)ti->syntaxCopy(NULL); - id = (Identifier *)ti; - } - ids->tdata()[i] = id; - } - - tm = new TemplateMixin(loc, ident, - (Type *)(tqual ? tqual->syntaxCopy() : NULL), - ids, tiargs); - TemplateInstance::syntaxCopy(tm); - return tm; -} - -void TemplateMixin::semantic(Scope *sc) -{ -#if LOG - printf("+TemplateMixin::semantic('%s', this=%p)\n", toChars(), this); - fflush(stdout); -#endif - if (semanticRun) - { - // This for when a class/struct contains mixin members, and - // is done over because of forward references - if (parent && toParent()->isAggregateDeclaration()) - semanticRun = PASSsemantic; // do over - else - { -#if LOG - printf("\tsemantic done\n"); -#endif - return; - } - } - if (!semanticRun) - semanticRun = PASSsemantic; -#if LOG - printf("\tdo semantic\n"); -#endif - -#if !IN_LLVM && !IN_GCC - // dont know what this is - util_progress(); -#endif - - Scope *scx = NULL; - if (scope) - { sc = scope; - scx = scope; // save so we don't make redundant copies - scope = NULL; - } - - // Follow qualifications to find the TemplateDeclaration - if (!tempdecl) - { Dsymbol *s; - size_t i; - Identifier *id; - - if (tqual) - { s = tqual->toDsymbol(sc); - i = 0; - } - else - { - i = 1; - id = idents->tdata()[0]; - switch (id->dyncast()) - { - case DYNCAST_IDENTIFIER: - s = sc->search(loc, id, NULL); - break; - - case DYNCAST_DSYMBOL: - { - TemplateInstance *ti = (TemplateInstance *)id; - ti->semantic(sc); - s = ti; - break; - } - default: - assert(0); - } - } - - for (; i < idents->dim; i++) - { - if (!s) - break; - id = idents->tdata()[i]; - s = s->searchX(loc, sc, id); - } - if (!s) - { - error("is not defined"); - inst = this; - return; - } - tempdecl = s->toAlias()->isTemplateDeclaration(); - if (!tempdecl) - { - error("%s isn't a template", s->toChars()); - inst = this; - return; - } - } - - // Look for forward reference - assert(tempdecl); - for (TemplateDeclaration *td = tempdecl; td; td = td->overnext) - { - if (!td->semanticRun) - { - /* Cannot handle forward references if mixin is a struct member, - * because addField must happen during struct's semantic, not - * during the mixin semantic. - * runDeferred will re-run mixin's semantic outside of the struct's - * semantic. - */ - semanticRun = PASSinit; - AggregateDeclaration *ad = toParent()->isAggregateDeclaration(); - if (ad) - ad->sizeok = SIZEOKfwd; - else - { - // Forward reference - //printf("forward reference - deferring\n"); - scope = scx ? scx : new Scope(*sc); - scope->setNoFree(); - scope->module->addDeferredSemantic(this); - } - return; - } - } - - // Run semantic on each argument, place results in tiargs[] - semanticTiargs(sc); - if (errors || arrayObjectIsError(tiargs)) - return; - - tempdecl = findBestMatch(sc, NULL); - if (!tempdecl) - { inst = this; - return; // error recovery - } - - if (!ident) - ident = genIdent(tiargs); - - inst = this; - parent = sc->parent; - - /* Detect recursive mixin instantiations. - */ - for (Dsymbol *s = parent; s; s = s->parent) - { - //printf("\ts = '%s'\n", s->toChars()); - TemplateMixin *tm = s->isTemplateMixin(); - if (!tm || tempdecl != tm->tempdecl) - continue; - - /* Different argument list lengths happen with variadic args - */ - if (tiargs->dim != tm->tiargs->dim) - continue; - - for (size_t i = 0; i < tiargs->dim; i++) - { Object *o = (*tiargs)[i]; - Type *ta = isType(o); - Expression *ea = isExpression(o); - Dsymbol *sa = isDsymbol(o); - Object *tmo = (*tm->tiargs)[i]; - if (ta) - { - Type *tmta = isType(tmo); - if (!tmta) - goto Lcontinue; - if (!ta->equals(tmta)) - goto Lcontinue; - } - else if (ea) - { Expression *tme = isExpression(tmo); - if (!tme || !ea->equals(tme)) - goto Lcontinue; - } - else if (sa) - { - Dsymbol *tmsa = isDsymbol(tmo); - if (sa != tmsa) - goto Lcontinue; - } - else - assert(0); - } - error("recursive mixin instantiation"); - return; - - Lcontinue: - continue; - } - - // Copy the syntax trees from the TemplateDeclaration - members = Dsymbol::arraySyntaxCopy(tempdecl->members); - if (!members) - return; - - symtab = new DsymbolTable(); - - for (Scope *sce = sc; 1; sce = sce->enclosing) - { - ScopeDsymbol *sds = (ScopeDsymbol *)sce->scopesym; - if (sds) - { - sds->importScope(this, PROTpublic); - break; - } - } - -#if LOG - printf("\tcreate scope for template parameters '%s'\n", toChars()); -#endif - Scope *scy = sc; - scy = sc->push(this); - scy->parent = this; - - argsym = new ScopeDsymbol(); - argsym->parent = scy->parent; - Scope *argscope = scy->push(argsym); - - unsigned errorsave = global.errors; - - // Declare each template parameter as an alias for the argument type - declareParameters(argscope); - - // Add members to enclosing scope, as well as this scope - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = (*members)[i]; - s->addMember(argscope, this, i); - //sc->insert(s); - //printf("sc->parent = %p, sc->scopesym = %p\n", sc->parent, sc->scopesym); - //printf("s->parent = %s\n", s->parent->toChars()); - } - - // Do semantic() analysis on template instance members -#if LOG - printf("\tdo semantic() on template instance members '%s'\n", toChars()); -#endif - Scope *sc2; - sc2 = argscope->push(this); - sc2->offset = sc->offset; - - static int nest; - //printf("%d\n", nest); - if (++nest > 500) - { - global.gag = 0; // ensure error message gets printed - error("recursive expansion"); - fatal(); - } - - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = (*members)[i]; - s->semantic(sc2); - } - - nest--; - - sc->offset = sc2->offset; - - /* The problem is when to parse the initializer for a variable. - * Perhaps VarDeclaration::semantic() should do it like it does - * for initializers inside a function. - */ -// if (sc->parent->isFuncDeclaration()) - - semantic2(sc2); - - if (sc->func) - { - semantic3(sc2); - } - - // Give additional context info if error occurred during instantiation - if (global.errors != errorsave) - { - error("error instantiating"); - } - - sc2->pop(); - - argscope->pop(); - -// if (!isAnonymous()) - { - scy->pop(); - } -#if LOG - printf("-TemplateMixin::semantic('%s', this=%p)\n", toChars(), this); -#endif -} - -void TemplateMixin::semantic2(Scope *sc) -{ - if (semanticRun >= PASSsemantic2) - return; - semanticRun = PASSsemantic2; -#if LOG - printf("+TemplateMixin::semantic2('%s')\n", toChars()); -#endif - if (members) - { - assert(sc); - sc = sc->push(argsym); - sc = sc->push(this); - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = (*members)[i]; -#if LOG - printf("\tmember '%s', kind = '%s'\n", s->toChars(), s->kind()); -#endif - s->semantic2(sc); - } - sc = sc->pop(); - sc->pop(); - } -#if LOG - printf("-TemplateMixin::semantic2('%s')\n", toChars()); -#endif -} - -void TemplateMixin::semantic3(Scope *sc) -{ - if (semanticRun >= PASSsemantic3) - return; - semanticRun = PASSsemantic3; -#if LOG - printf("TemplateMixin::semantic3('%s')\n", toChars()); -#endif - if (members) - { - sc = sc->push(argsym); - sc = sc->push(this); - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = members->tdata()[i]; - s->semantic3(sc); - } - sc = sc->pop(); - sc->pop(); - } -} - -void TemplateMixin::inlineScan() -{ - TemplateInstance::inlineScan(); -} - -const char *TemplateMixin::kind() -{ - return "mixin"; -} - -int TemplateMixin::oneMember(Dsymbol **ps, Identifier *ident) -{ - return Dsymbol::oneMember(ps, ident); -} - -int TemplateMixin::apply(Dsymbol_apply_ft_t fp, void *param) -{ - if (members) - { - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = (*members)[i]; - if (s) - { - if (s->apply(fp, param)) - return 1; - } - } - } - return 0; -} - -int TemplateMixin::hasPointers() -{ - //printf("TemplateMixin::hasPointers() %s\n", toChars()); - - if (members) - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = (*members)[i]; - //printf(" s = %s %s\n", s->kind(), s->toChars()); - if (s->hasPointers()) - { - return 1; - } - } - return 0; -} - -void TemplateMixin::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion) -{ - if (members) - { - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = (*members)[i]; - s->setFieldOffset(ad, poffset, isunion); - } - } -} - -char *TemplateMixin::toChars() -{ - OutBuffer buf; - HdrGenState hgs; - char *s; - - TemplateInstance::toCBuffer(&buf, &hgs); - s = buf.toChars(); - buf.data = NULL; - return s; -} - -void TemplateMixin::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("mixin "); - - for (size_t i = 0; i < idents->dim; i++) - { Identifier *id = idents->tdata()[i]; - - if (i) - buf->writeByte('.'); - buf->writestring(id->toChars()); - } - buf->writestring("!("); - if (tiargs) - { - for (size_t i = 0; i < tiargs->dim; i++) - { if (i) - buf->writebyte(','); - Object *oarg = tiargs->tdata()[i]; - Type *t = isType(oarg); - Expression *e = isExpression(oarg); - Dsymbol *s = isDsymbol(oarg); - if (t) - t->toCBuffer(buf, NULL, hgs); - else if (e) - e->toCBuffer(buf, hgs); - else if (s) - { - char *p = s->ident ? s->ident->toChars() : s->toChars(); - buf->writestring(p); - } - else if (!oarg) - { - buf->writestring("NULL"); - } - else - { - assert(0); - } - } - } - buf->writebyte(')'); - if (ident) - { - buf->writebyte(' '); - buf->writestring(ident->toChars()); - } - buf->writebyte(';'); - buf->writenl(); -} - - -#if IN_DMD -void TemplateMixin::toObjFile(int multiobj) -{ - //printf("TemplateMixin::toObjFile('%s')\n", toChars()); - TemplateInstance::toObjFile(multiobj); -} -#endif - + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2012 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +// Handle template implementation + +#include +#include + +#include "root.h" +#include "aav.h" +#include "rmem.h" +#include "stringtable.h" +#include "mars.h" +#include "identifier.h" +#include "mtype.h" +#include "template.h" +#include "init.h" +#include "expression.h" +#include "scope.h" +#include "module.h" +#include "aggregate.h" +#include "declaration.h" +#include "dsymbol.h" +#include "hdrgen.h" +#include "id.h" + +#if WINDOWS_SEH +#include +long __cdecl __ehfilter(LPEXCEPTION_POINTERS ep); +#endif + +#define LOG 0 + +/******************************************** + * These functions substitute for dynamic_cast. dynamic_cast does not work + * on earlier versions of gcc. + */ + +Expression *isExpression(Object *o) +{ + //return dynamic_cast(o); + if (!o || o->dyncast() != DYNCAST_EXPRESSION) + return NULL; + return (Expression *)o; +} + +Dsymbol *isDsymbol(Object *o) +{ + //return dynamic_cast(o); + if (!o || o->dyncast() != DYNCAST_DSYMBOL) + return NULL; + return (Dsymbol *)o; +} + +Type *isType(Object *o) +{ + //return dynamic_cast(o); + if (!o || o->dyncast() != DYNCAST_TYPE) + return NULL; + return (Type *)o; +} + +Tuple *isTuple(Object *o) +{ + //return dynamic_cast(o); + if (!o || o->dyncast() != DYNCAST_TUPLE) + return NULL; + return (Tuple *)o; +} + +/************************************** + * Is this Object an error? + */ +int isError(Object *o) +{ + Type *t = isType(o); + if (t) + return (t->ty == Terror); + Expression *e = isExpression(o); + if (e) + return (e->op == TOKerror || !e->type || e->type->ty== Terror); + Tuple *v = isTuple(o); + if (v) + return arrayObjectIsError(&v->objects); + return 0; +} + +/************************************** + * Are any of the Objects an error? + */ +int arrayObjectIsError(Objects *args) +{ + for (size_t i = 0; i < args->dim; i++) + { + Object *o = (*args)[i]; + if (isError(o)) + return 1; + } + return 0; +} + +/*********************** + * Try to get arg as a type. + */ + +Type *getType(Object *o) +{ + Type *t = isType(o); + if (!t) + { Expression *e = isExpression(o); + if (e) + t = e->type; + } + return t; +} + +Dsymbol *getDsymbol(Object *oarg) +{ + Dsymbol *sa; + Expression *ea = isExpression(oarg); + if (ea) + { // Try to convert Expression to symbol + if (ea->op == TOKvar) + sa = ((VarExp *)ea)->var; + else if (ea->op == TOKfunction) + { + if (((FuncExp *)ea)->td) + sa = ((FuncExp *)ea)->td; + else + sa = ((FuncExp *)ea)->fd; + } + else + sa = NULL; + } + else + { // Try to convert Type to symbol + Type *ta = isType(oarg); + if (ta) + sa = ta->toDsymbol(NULL); + else + sa = isDsymbol(oarg); // if already a symbol + } + return sa; +} + +/****************************** + * If o1 matches o2, return 1. + * Else, return 0. + */ + +int match(Object *o1, Object *o2, TemplateDeclaration *tempdecl, Scope *sc) +{ + Type *t1 = isType(o1); + Type *t2 = isType(o2); + Expression *e1 = isExpression(o1); + Expression *e2 = isExpression(o2); + Dsymbol *s1 = isDsymbol(o1); + Dsymbol *s2 = isDsymbol(o2); + Tuple *u1 = isTuple(o1); + Tuple *u2 = isTuple(o2); + + //printf("\t match t1 %p t2 %p, e1 %p e2 %p, s1 %p s2 %p, u1 %p u2 %p\n", t1,t2,e1,e2,s1,s2,u1,u2); + + /* A proper implementation of the various equals() overrides + * should make it possible to just do o1->equals(o2), but + * we'll do that another day. + */ + + if (s1) + { + VarDeclaration *v1 = s1->isVarDeclaration(); + if (v1 && v1->storage_class & STCmanifest) + { ExpInitializer *ei1 = v1->init->isExpInitializer(); + if (ei1) + e1 = ei1->exp, s1 = NULL; + } + } + if (s2) + { + VarDeclaration *v2 = s2->isVarDeclaration(); + if (v2 && v2->storage_class & STCmanifest) + { ExpInitializer *ei2 = v2->init->isExpInitializer(); + if (ei2) + e2 = ei2->exp, s2 = NULL; + } + } + + if (t1) + { + /* if t1 is an instance of ti, then give error + * about recursive expansions. + */ + Dsymbol *s = t1->toDsymbol(sc); + if (s && s->parent) + { TemplateInstance *ti1 = s->parent->isTemplateInstance(); + if (ti1 && ti1->tempdecl == tempdecl) + { + for (Scope *sc1 = sc; sc1; sc1 = sc1->enclosing) + { + if (sc1->scopesym == ti1) + { + tempdecl->error("recursive template expansion for template argument %s", t1->toChars()); + return 1; // fake a match + } + } + } + } + + //printf("t1 = %s\n", t1->toChars()); + //printf("t2 = %s\n", t2->toChars()); + if (!t2 || !t1->equals(t2)) + goto Lnomatch; + } + else if (e1) + { +#if 0 + if (e1 && e2) + { + printf("match %d\n", e1->equals(e2)); + e1->print(); + e2->print(); + e1->type->print(); + e2->type->print(); + } +#endif + if (!e2) + goto Lnomatch; + if (!e1->equals(e2)) + goto Lnomatch; + } + else if (s1) + { + if (!s2 || !s1->equals(s2) || s1->parent != s2->parent) + goto Lnomatch; + } + else if (u1) + { + if (!u2) + goto Lnomatch; + if (u1->objects.dim != u2->objects.dim) + goto Lnomatch; + for (size_t i = 0; i < u1->objects.dim; i++) + { + if (!match(u1->objects[i], + u2->objects[i], + tempdecl, sc)) + goto Lnomatch; + } + } + //printf("match\n"); + return 1; // match + +Lnomatch: + //printf("nomatch\n"); + return 0; // nomatch; +} + + +/************************************ + * Match an array of them. + */ +int arrayObjectMatch(Objects *oa1, Objects *oa2, TemplateDeclaration *tempdecl, Scope *sc) +{ + if (oa1 == oa2) + return 1; + if (oa1->dim != oa2->dim) + return 0; + for (size_t j = 0; j < oa1->dim; j++) + { Object *o1 = (*oa1)[j]; + Object *o2 = (*oa2)[j]; + if (!match(o1, o2, tempdecl, sc)) + { + return 0; + } + } + return 1; +} + +/**************************************** + * This makes a 'pretty' version of the template arguments. + * It's analogous to genIdent() which makes a mangled version. + */ + +void ObjectToCBuffer(OutBuffer *buf, HdrGenState *hgs, Object *oarg) +{ + //printf("ObjectToCBuffer()\n"); + Type *t = isType(oarg); + Expression *e = isExpression(oarg); + Dsymbol *s = isDsymbol(oarg); + Tuple *v = isTuple(oarg); + /* The logic of this should match what genIdent() does. The _dynamic_cast() + * function relies on all the pretty strings to be unique for different classes + * (see Bugzilla 7375). + * Perhaps it would be better to demangle what genIdent() does. + */ + if (t) + { //printf("\tt: %s ty = %d\n", t->toChars(), t->ty); + t->toCBuffer(buf, NULL, hgs); + } + else if (e) + { + if (e->op == TOKvar) + e = e->optimize(WANTvalue); // added to fix Bugzilla 7375 + e->toCBuffer(buf, hgs); + } + else if (s) + { + char *p = s->ident ? s->ident->toChars() : s->toChars(); + buf->writestring(p); + } + else if (v) + { + Objects *args = &v->objects; + for (size_t i = 0; i < args->dim; i++) + { + if (i) + buf->writeByte(','); + Object *o = (*args)[i]; + ObjectToCBuffer(buf, hgs, o); + } + } + else if (!oarg) + { + buf->writestring("NULL"); + } + else + { +#ifdef DEBUG + printf("bad Object = %p\n", oarg); +#endif + assert(0); + } +} + +#if DMDV2 +Object *objectSyntaxCopy(Object *o) +{ + if (!o) + return NULL; + Type *t = isType(o); + if (t) + return t->syntaxCopy(); + Expression *e = isExpression(o); + if (e) + return e->syntaxCopy(); + return o; +} +#endif + + +/* ======================== TemplateDeclaration ============================= */ + +TemplateDeclaration::TemplateDeclaration(Loc loc, Identifier *id, + TemplateParameters *parameters, Expression *constraint, Dsymbols *decldefs, int ismixin) + : ScopeDsymbol(id) +{ +#if LOG + printf("TemplateDeclaration(this = %p, id = '%s')\n", this, id->toChars()); +#endif +#if 0 + if (parameters) + for (int i = 0; i < parameters->dim; i++) + { TemplateParameter *tp = (*parameters)[i]; + //printf("\tparameter[%d] = %p\n", i, tp); + TemplateTypeParameter *ttp = tp->isTemplateTypeParameter(); + + if (ttp) + { + printf("\tparameter[%d] = %s : %s\n", i, tp->ident->toChars(), ttp->specType ? ttp->specType->toChars() : ""); + } + } +#endif + this->loc = loc; + this->parameters = parameters; + this->origParameters = parameters; + this->constraint = constraint; + this->members = decldefs; + this->overnext = NULL; + this->overroot = NULL; + this->semanticRun = PASSinit; + this->onemember = NULL; + this->literal = 0; + this->ismixin = ismixin; + this->previous = NULL; + + // Compute in advance for Ddoc's use + if (members) + { + Dsymbol *s; + if (Dsymbol::oneMembers(members, &s, ident) && s) + { + onemember = s; + s->parent = this; + } + } +} + +Dsymbol *TemplateDeclaration::syntaxCopy(Dsymbol *) +{ + //printf("TemplateDeclaration::syntaxCopy()\n"); + TemplateDeclaration *td; + TemplateParameters *p; + + p = NULL; + if (parameters) + { + p = new TemplateParameters(); + p->setDim(parameters->dim); + for (size_t i = 0; i < p->dim; i++) + { TemplateParameter *tp = (*parameters)[i]; + (*p)[i] = tp->syntaxCopy(); + } + } + Expression *e = NULL; + if (constraint) + e = constraint->syntaxCopy(); + Dsymbols *d = Dsymbol::arraySyntaxCopy(members); + td = new TemplateDeclaration(loc, ident, p, e, d, ismixin); + +#if IN_LLVM + td->intrinsicName = intrinsicName; +#endif + + return td; +} + +void TemplateDeclaration::semantic(Scope *sc) +{ +#if LOG + printf("TemplateDeclaration::semantic(this = %p, id = '%s')\n", this, ident->toChars()); + printf("sc->stc = %llx\n", sc->stc); + printf("sc->module = %s\n", sc->module->toChars()); +#endif + if (semanticRun) + return; // semantic() already run + semanticRun = PASSsemantic; + + // Remember templates defined in module object that we need to know about + if (sc->module && sc->module->ident == Id::object) + { + if (ident == Id::AssociativeArray) + Type::associativearray = this; + else if (ident == Id::RTInfo) + Type::rtinfo = this; + } + + if (sc->func) + { +#if DMDV1 + error("cannot declare template at function scope %s", sc->func->toChars()); +#endif + } + + if (/*global.params.useArrayBounds &&*/ sc->module) + { + // Generate this function as it may be used + // when template is instantiated in other modules + // FIXME: LDC + //sc->module->toModuleArray(); + } + + if (/*global.params.useAssert &&*/ sc->module) + { + // Generate this function as it may be used + // when template is instantiated in other modules + // FIXME: LDC + //sc->module->toModuleAssert(); + } + +#if DMDV2 + if (sc->module) + { + // Generate this function as it may be used + // when template is instantiated in other modules + // FIXME: LDC + // sc->module->toModuleUnittest(); + } +#endif + + /* Remember Scope for later instantiations, but make + * a copy since attributes can change. + */ + if (!this->scope) + { this->scope = new Scope(*sc); + this->scope->setNoFree(); + } + + // Set up scope for parameters + ScopeDsymbol *paramsym = new ScopeDsymbol(); + paramsym->parent = sc->parent; + Scope *paramscope = sc->push(paramsym); + paramscope->parameterSpecialization = 1; + paramscope->stc = 0; + + if (!parent) + parent = sc->parent; + + if (global.params.doDocComments) + { + origParameters = new TemplateParameters(); + origParameters->setDim(parameters->dim); + for (size_t i = 0; i < parameters->dim; i++) + { + TemplateParameter *tp = (*parameters)[i]; + (*origParameters)[i] = tp->syntaxCopy(); + } + } + + for (size_t i = 0; i < parameters->dim; i++) + { + TemplateParameter *tp = (*parameters)[i]; + + tp->declareParameter(paramscope); + } + + for (size_t i = 0; i < parameters->dim; i++) + { + TemplateParameter *tp = (*parameters)[i]; + + tp->semantic(paramscope); + if (i + 1 != parameters->dim && tp->isTemplateTupleParameter()) + { error("template tuple parameter must be last one"); + errors = true; + } + } + + paramscope->pop(); + + // Compute again + onemember = NULL; + if (members) + { + Dsymbol *s; + if (Dsymbol::oneMembers(members, &s, ident) && s) + { + onemember = s; + s->parent = this; + } + } + + /* BUG: should check: + * o no virtual functions or non-static data members of classes + */ +} + +const char *TemplateDeclaration::kind() +{ + return (onemember && onemember->isAggregateDeclaration()) + ? onemember->kind() + : (char *)"template"; +} + +/********************************** + * Overload existing TemplateDeclaration 'this' with the new one 's'. + * Return !=0 if successful; i.e. no conflict. + */ + +int TemplateDeclaration::overloadInsert(Dsymbol *s) +{ + TemplateDeclaration **pf; + TemplateDeclaration *f; + +#if LOG + printf("TemplateDeclaration::overloadInsert('%s')\n", s->toChars()); +#endif + f = s->isTemplateDeclaration(); + if (!f) + return FALSE; + TemplateDeclaration *pthis = this; + for (pf = &pthis; *pf; pf = &(*pf)->overnext) + { +#if 0 + // Conflict if TemplateParameter's match + // Will get caught anyway later with TemplateInstance, but + // should check it now. + TemplateDeclaration *f2 = *pf; + + if (f->parameters->dim != f2->parameters->dim) + goto Lcontinue; + + for (size_t i = 0; i < f->parameters->dim; i++) + { TemplateParameter *p1 = (*f->parameters)[i]; + TemplateParameter *p2 = (*f2->parameters)[i]; + + if (!p1->overloadMatch(p2)) + goto Lcontinue; + } + +#if LOG + printf("\tfalse: conflict\n"); +#endif + return FALSE; + + Lcontinue: + ; +#endif + } + + f->overroot = this; + *pf = f; +#if LOG + printf("\ttrue: no conflict\n"); +#endif + return TRUE; +} + +/**************************** + * Declare all the function parameters as variables + * and add them to the scope + */ +void TemplateDeclaration::makeParamNamesVisibleInConstraint(Scope *paramscope, Expressions *fargs) +{ + /* We do this ONLY if there is only one function in the template. + */ + FuncDeclaration *fd = onemember && onemember->toAlias() ? + onemember->toAlias()->isFuncDeclaration() : NULL; + if (fd) + { + /* + Making parameters is similar to FuncDeclaration::semantic3 + */ + paramscope->parent = fd; + + TypeFunction *tf = (TypeFunction *)fd->type->syntaxCopy(); + + // Shouldn't run semantic on default arguments and return type. + for (int i = 0; iparameters->dim; i++) + (*tf->parameters)[i]->defaultArg = NULL; + tf->next = NULL; + + // Resolve parameter types and 'auto ref's. + tf->fargs = fargs; + tf = (TypeFunction *)tf->semantic(loc, paramscope); + + Parameters *fparameters = tf->parameters; + int fvarargs = tf->varargs; + + size_t nfparams = Parameter::dim(fparameters); // Num function parameters + for (size_t i = 0; i < nfparams; i++) + { + Parameter *fparam = Parameter::getNth(fparameters, i); + // Remove addMod same as func.d L1065 of FuncDeclaration::semantic3 + //Type *vtype = fparam->type; + //if (fd->type && fd->isPure()) + // vtype = vtype->addMod(MODconst); + fparam->storageClass &= (STCin | STCout | STCref | STClazy | STCfinal | STC_TYPECTOR | STCnodtor); + fparam->storageClass |= STCparameter; + if (fvarargs == 2 && i + 1 == nfparams) + fparam->storageClass |= STCvariadic; + } + for (size_t i = 0; i < fparameters->dim; i++) + { + Parameter *fparam = (*fparameters)[i]; + if (!fparam->ident) + continue; // don't add it, if it has no name + VarDeclaration *v = new VarDeclaration(loc, fparam->type, fparam->ident, NULL); + v->storage_class = fparam->storageClass; + v->semantic(paramscope); + if (!paramscope->insert(v)) + error("parameter %s.%s is already defined", toChars(), v->toChars()); + else + v->parent = this; + } + } +} + +/*************************************** + * Given that ti is an instance of this TemplateDeclaration, + * deduce the types of the parameters to this, and store + * those deduced types in dedtypes[]. + * Input: + * flag 1: don't do semantic() because of dummy types + * 2: don't change types in matchArg() + * Output: + * dedtypes deduced arguments + * Return match level. + */ + +MATCH TemplateDeclaration::matchWithInstance(TemplateInstance *ti, + Objects *dedtypes, Expressions *fargs, int flag) +{ MATCH m; + size_t dedtypes_dim = dedtypes->dim; + +#define LOGM 0 +#if LOGM + printf("\n+TemplateDeclaration::matchWithInstance(this = %s, ti = %s, flag = %d)\n", toChars(), ti->toChars(), flag); +#endif + +#if 0 + printf("dedtypes->dim = %d, parameters->dim = %d\n", dedtypes_dim, parameters->dim); + if (ti->tiargs->dim) + printf("ti->tiargs->dim = %d, [0] = %p\n", + ti->tiargs->dim, + (*ti->tiargs)[0]); +#endif + dedtypes->zero(); + + if (errors) + return MATCHnomatch; + + size_t parameters_dim = parameters->dim; + int variadic = isVariadic() != NULL; + + // If more arguments than parameters, no match + if (ti->tiargs->dim > parameters_dim && !variadic) + { +#if LOGM + printf(" no match: more arguments than parameters\n"); +#endif + return MATCHnomatch; + } + + assert(dedtypes_dim == parameters_dim); + assert(dedtypes_dim >= ti->tiargs->dim || variadic); + + // Set up scope for parameters + assert((size_t)scope > 0x10000); + ScopeDsymbol *paramsym = new ScopeDsymbol(); + paramsym->parent = scope->parent; + Scope *paramscope = scope->push(paramsym); + paramscope->stc = 0; + + // Attempt type deduction + m = MATCHexact; + for (size_t i = 0; i < dedtypes_dim; i++) + { MATCH m2; + TemplateParameter *tp = (*parameters)[i]; + Declaration *sparam; + + //printf("\targument [%d]\n", i); +#if LOGM + //printf("\targument [%d] is %s\n", i, oarg ? oarg->toChars() : "null"); + TemplateTypeParameter *ttp = tp->isTemplateTypeParameter(); + if (ttp) + printf("\tparameter[%d] is %s : %s\n", i, tp->ident->toChars(), ttp->specType ? ttp->specType->toChars() : ""); +#endif + + m2 = tp->matchArg(paramscope, ti->tiargs, i, parameters, dedtypes, &sparam); + //printf("\tm2 = %d\n", m2); + + if (m2 == MATCHnomatch) + { +#if 0 + printf("\tmatchArg() for parameter %i failed\n", i); +#endif + goto Lnomatch; + } + + if (m2 < m) + m = m2; + + if (!flag) + sparam->semantic(paramscope); + if (!paramscope->insert(sparam)) + goto Lnomatch; + } + + if (!flag) + { + /* Any parameter left without a type gets the type of + * its corresponding arg + */ + for (size_t i = 0; i < dedtypes_dim; i++) + { + if (!(*dedtypes)[i]) + { assert(i < ti->tiargs->dim); + (*dedtypes)[i] = (Type *)(*ti->tiargs)[i]; + } + } + } + +#if DMDV2 + if (m && constraint && !flag) + { /* Check to see if constraint is satisfied. + */ + makeParamNamesVisibleInConstraint(paramscope, fargs); + Expression *e = constraint->syntaxCopy(); + Scope *sc = paramscope->push(); + + /* There's a chicken-and-egg problem here. We don't know yet if this template + * instantiation will be a local one (isnested is set), and we won't know until + * after selecting the correct template. Thus, function we're nesting inside + * is not on the sc scope chain, and this can cause errors in FuncDeclaration::getLevel(). + * Workaround the problem by setting a flag to relax the checking on frame errors. + */ + sc->flags |= SCOPEstaticif; + + FuncDeclaration *fd = onemember && onemember->toAlias() ? + 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)) + goto Lnomatch; + else + { + e->error("constraint %s is not constant or does not evaluate to a bool", e->toChars()); + } + } +#endif + +#if LOGM + // Print out the results + printf("--------------------------\n"); + printf("template %s\n", toChars()); + printf("instance %s\n", ti->toChars()); + if (m) + { + for (size_t i = 0; i < dedtypes_dim; i++) + { + TemplateParameter *tp = (*parameters)[i]; + Object *oarg; + + printf(" [%d]", i); + + if (i < ti->tiargs->dim) + oarg = (*ti->tiargs)[i]; + else + oarg = NULL; + tp->print(oarg, (*dedtypes)[i]); + } + } + else + goto Lnomatch; +#endif + +#if LOGM + printf(" match = %d\n", m); +#endif + goto Lret; + +Lnomatch: +#if LOGM + printf(" no match\n"); +#endif + m = MATCHnomatch; + +Lret: + paramscope->pop(); +#if LOGM + printf("-TemplateDeclaration::matchWithInstance(this = %p, ti = %p) = %d\n", this, ti, m); +#endif + return m; +} + +/******************************************** + * Determine partial specialization order of 'this' vs td2. + * Returns: + * match this is at least as specialized as td2 + * 0 td2 is more specialized than this + */ + +MATCH TemplateDeclaration::leastAsSpecialized(TemplateDeclaration *td2, Expressions *fargs) +{ + /* This works by taking the template parameters to this template + * declaration and feeding them to td2 as if it were a template + * instance. + * If it works, then this template is at least as specialized + * as td2. + */ + + TemplateInstance ti(0, ident); // create dummy template instance + Objects dedtypes; + +#define LOG_LEASTAS 0 + +#if LOG_LEASTAS + printf("%s.leastAsSpecialized(%s)\n", toChars(), td2->toChars()); +#endif + + // Set type arguments to dummy template instance to be types + // generated from the parameters to this template declaration + ti.tiargs = new Objects(); + ti.tiargs->setDim(parameters->dim); + for (size_t i = 0; i < ti.tiargs->dim; i++) + { + TemplateParameter *tp = (*parameters)[i]; + + Object *p = (Object *)tp->dummyArg(); + if (p) + (*ti.tiargs)[i] = p; + else + ti.tiargs->setDim(i); + } + + // Temporary Array to hold deduced types + //dedtypes.setDim(parameters->dim); + dedtypes.setDim(td2->parameters->dim); + + // Attempt a type deduction + MATCH m = td2->matchWithInstance(&ti, &dedtypes, fargs, 1); + if (m) + { + /* A non-variadic template is more specialized than a + * variadic one. + */ + if (isVariadic() && !td2->isVariadic()) + goto L1; + +#if LOG_LEASTAS + printf(" matches %d, so is least as specialized\n", m); +#endif + return m; + } + L1: +#if LOG_LEASTAS + printf(" doesn't match, so is not as specialized\n"); +#endif + return MATCHnomatch; +} + + +/************************************************* + * Match function arguments against a specific template function. + * Input: + * loc instantiation location + * targsi Expression/Type initial list of template arguments + * ethis 'this' argument if !NULL + * fargs arguments to function + * Output: + * dedargs Expression/Type deduced template arguments + * Returns: + * match level + * bit 0-3 Match template parameters by inferred template arguments + * bit 4-7 Match template parameters by initial template arguments + */ + +MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Scope *sc, Loc loc, Objects *targsi, + Expression *ethis, Expressions *fargs, + Objects *dedargs) +{ + size_t nfparams; + size_t nfargs; + size_t nargsi; // array size of targsi + int fptupindex = -1; + int tuple_dim = 0; + MATCH match = MATCHexact; + MATCH matchTargsi = MATCHexact; + FuncDeclaration *fd = onemember->toAlias()->isFuncDeclaration(); + Parameters *fparameters; // function parameter list + int fvarargs; // function varargs + Objects dedtypes; // for T:T*, the dedargs is the T*, dedtypes is the T + unsigned wildmatch = 0; + TemplateParameters *inferparams = parameters; + + TypeFunction *tf = (TypeFunction *)fd->type; + +#if 0 + printf("\nTemplateDeclaration::deduceFunctionTemplateMatch() %s\n", toChars()); + for (size_t i = 0; i < fargs->dim; i++) + { Expression *e = (*fargs)[i]; + printf("\tfarg[%d] is %s, type is %s\n", i, e->toChars(), e->type->toChars()); + } + printf("fd = %s\n", fd->toChars()); + printf("fd->type = %s\n", fd->type->toChars()); + if (ethis) + printf("ethis->type = %s\n", ethis->type->toChars()); +#endif + + assert((size_t)scope > 0x10000); + + dedargs->setDim(parameters->dim); + dedargs->zero(); + + dedtypes.setDim(parameters->dim); + dedtypes.zero(); + + if (errors) + return MATCHnomatch; + + // Set up scope for parameters + ScopeDsymbol *paramsym = new ScopeDsymbol(); + paramsym->parent = scope->parent; + Scope *paramscope = scope->push(paramsym); + paramscope->stc = 0; + + TemplateTupleParameter *tp = isVariadic(); + int tp_is_declared = 0; + +#if 0 + for (size_t i = 0; i < dedargs->dim; i++) + { + printf("\tdedarg[%d] = ", i); + Object *oarg = (*dedargs)[i]; + if (oarg) printf("%s", oarg->toChars()); + printf("\n"); + } +#endif + + + nargsi = 0; + if (targsi) + { // Set initial template arguments + + nargsi = targsi->dim; + size_t n = parameters->dim; + if (tp) + n--; + if (nargsi > n) + { if (!tp) + goto Lnomatch; + + /* The extra initial template arguments + * now form the tuple argument. + */ + Tuple *t = new Tuple(); + assert(parameters->dim); + (*dedargs)[parameters->dim - 1] = t; + + tuple_dim = nargsi - n; + t->objects.setDim(tuple_dim); + for (size_t i = 0; i < tuple_dim; i++) + { + t->objects[i] = (*targsi)[n + i]; + } + declareParameter(paramscope, tp, t); + tp_is_declared = 1; + } + else + n = nargsi; + + memcpy(dedargs->tdata(), targsi->tdata(), n * sizeof(*dedargs->tdata())); + + for (size_t i = 0; i < n; i++) + { assert(i < parameters->dim); + TemplateParameter *tp = (*parameters)[i]; + MATCH m; + Declaration *sparam = NULL; + + m = tp->matchArg(paramscope, dedargs, i, parameters, &dedtypes, &sparam); + //printf("\tdeduceType m = %d\n", m); + if (m == MATCHnomatch) + goto Lnomatch; + if (m < matchTargsi) + matchTargsi = m; + + sparam->semantic(paramscope); + if (!paramscope->insert(sparam)) + goto Lnomatch; + } + if (n < parameters->dim) + { + inferparams = new TemplateParameters(); + inferparams->setDim(parameters->dim - n); + memcpy(inferparams->tdata(), + parameters->tdata() + n, + inferparams->dim * sizeof(*inferparams->tdata())); + } + else + inferparams = NULL; + } +#if 0 + for (size_t i = 0; i < dedargs->dim; i++) + { + printf("\tdedarg[%d] = ", i); + Object *oarg = (*dedargs)[i]; + if (oarg) printf("%s", oarg->toChars()); + printf("\n"); + } +#endif + + fparameters = fd->getParameters(&fvarargs); + nfparams = Parameter::dim(fparameters); // number of function parameters + nfargs = fargs ? fargs->dim : 0; // number of function arguments + + /* Check for match of function arguments with variadic template + * parameter, such as: + * + * template Foo(T, A...) { void Foo(T t, A a); } + * void main() { Foo(1,2,3); } + */ + if (tp) // if variadic + { + if (nfparams == 0 && nfargs != 0) // if no function parameters + { + if (tp_is_declared) + goto L2; + Tuple *t = new Tuple(); + //printf("t = %p\n", t); + (*dedargs)[parameters->dim - 1] = t; + declareParameter(paramscope, tp, t); + goto L2; + } + else if (nfargs < nfparams - 1) + goto L1; + else + { + /* Figure out which of the function parameters matches + * the tuple template parameter. Do this by matching + * type identifiers. + * Set the index of this function parameter to fptupindex. + */ + for (fptupindex = 0; fptupindex < nfparams; fptupindex++) + { + Parameter *fparam = (*fparameters)[fptupindex]; + if (fparam->type->ty != Tident) + continue; + TypeIdentifier *tid = (TypeIdentifier *)fparam->type; + if (!tp->ident->equals(tid->ident) || tid->idents.dim) + continue; + + if (fvarargs) // variadic function doesn't + goto Lnomatch; // go with variadic template + + if (tp_is_declared) + goto L2; + + // Apply function parameter storage classes to parameter type + tid = (TypeIdentifier *)tid->addStorageClass(fparam->storageClass); + + /* The types of the function arguments + * now form the tuple argument. + */ + Tuple *t = new Tuple(); + (*dedargs)[parameters->dim - 1] = t; + + tuple_dim = nfargs - (nfparams - 1); + t->objects.setDim(tuple_dim); + for (size_t i = 0; i < tuple_dim; i++) + { Expression *farg = (*fargs)[fptupindex + i]; + + // Check invalid arguments to detect errors early. + if (farg->op == TOKerror || farg->type->ty == Terror) + goto Lnomatch; + + if (!(fparam->storageClass & STClazy) && farg->type->ty == Tvoid) + goto Lnomatch; + + unsigned mod = farg->type->mod; + Type *tt; + MATCH m; + + #define X(U,T) ((U) << 4) | (T) + if (tid->mod & MODwild) + { + switch (X(tid->mod, mod)) + { + case X(MODwild, MODwild): + case X(MODwild | MODshared, MODwild | MODshared): + case X(MODwild, 0): + case X(MODwild, MODconst): + case X(MODwild, MODimmutable): + case X(MODwild | MODshared, MODshared): + case X(MODwild | MODshared, MODconst | MODshared): + + if (mod & MODwild) + wildmatch |= MODwild; + else if (mod == 0) + wildmatch |= MODmutable; + else + wildmatch |= (mod & ~MODshared); + tt = farg->type->mutableOf(); + m = MATCHconst; + goto Lx; + + default: + break; + } + } + + switch (X(tid->mod, mod)) + { + case X(0, 0): + case X(0, MODconst): + case X(0, MODimmutable): + case X(0, MODshared): + case X(0, MODconst | MODshared): + case X(0, MODwild): + case X(0, MODwild | MODshared): + // foo(U:U) T => T + // foo(U:U) const(T) => const(T) + // foo(U:U) immutable(T) => immutable(T) + // foo(U:U) shared(T) => shared(T) + // foo(U:U) const(shared(T)) => const(shared(T)) + // foo(U:U) wild(T) => wild(T) + // foo(U:U) wild(shared(T)) => wild(shared(T)) + + tt = farg->type; + m = MATCHexact; + break; + + case X(MODconst, MODconst): + case X(MODimmutable, MODimmutable): + case X(MODshared, MODshared): + case X(MODconst | MODshared, MODconst | MODshared): + case X(MODwild, MODwild): + case X(MODwild | MODshared, MODwild | MODshared): + // foo(U:const(U)) const(T) => T + // foo(U:immutable(U)) immutable(T) => T + // foo(U:shared(U)) shared(T) => T + // foo(U:const(shared(U)) const(shared(T)) => T + // foo(U:wild(U)) wild(T) => T + // foo(U:wild(shared(U)) wild(shared(T)) => T + + tt = farg->type->mutableOf()->unSharedOf(); + m = MATCHexact; + break; + + case X(MODconst, 0): + case X(MODconst, MODimmutable): + case X(MODconst, MODconst | MODshared): + case X(MODconst | MODshared, MODimmutable): + case X(MODconst, MODwild): + case X(MODconst, MODwild | MODshared): + // foo(U:const(U)) T => T + // foo(U:const(U)) immutable(T) => T + // foo(U:const(U)) const(shared(T)) => shared(T) + // foo(U:const(shared(U)) immutable(T) => T + // foo(U:const(U)) wild(shared(T)) => shared(T) + + tt = farg->type->mutableOf(); + m = MATCHconst; + break; + + case X(MODshared, MODconst | MODshared): + case X(MODconst | MODshared, MODshared): + case X(MODshared, MODwild | MODshared): + // foo(U:shared(U)) const(shared(T)) => const(T) + // foo(U:const(shared(U)) shared(T) => T + // foo(U:shared(U)) wild(shared(T)) => wild(T) + tt = farg->type->unSharedOf(); + m = MATCHconst; + break; + + case X(MODimmutable, 0): + case X(MODimmutable, MODconst): + case X(MODimmutable, MODshared): + case X(MODimmutable, MODconst | MODshared): + case X(MODconst, MODshared): + case X(MODshared, 0): + case X(MODshared, MODconst): + case X(MODshared, MODimmutable): + case X(MODconst | MODshared, 0): + case X(MODconst | MODshared, MODconst): + case X(MODimmutable, MODwild): + case X(MODshared, MODwild): + case X(MODconst | MODshared, MODwild): + case X(MODwild, 0): + case X(MODwild, MODconst): + case X(MODwild, MODimmutable): + case X(MODwild, MODshared): + case X(MODwild, MODconst | MODshared): + case X(MODwild | MODshared, 0): + case X(MODwild | MODshared, MODconst): + case X(MODwild | MODshared, MODimmutable): + case X(MODwild | MODshared, MODshared): + case X(MODwild | MODshared, MODconst | MODshared): + case X(MODwild | MODshared, MODwild): + case X(MODimmutable, MODwild | MODshared): + case X(MODconst | MODshared, MODwild | MODshared): + case X(MODwild, MODwild | MODshared): + + // foo(U:immutable(U)) T => nomatch + // foo(U:immutable(U)) const(T) => nomatch + // foo(U:immutable(U)) shared(T) => nomatch + // foo(U:immutable(U)) const(shared(T)) => nomatch + // foo(U:const(U)) shared(T) => nomatch + // foo(U:shared(U)) T => nomatch + // foo(U:shared(U)) const(T) => nomatch + // foo(U:shared(U)) immutable(T) => nomatch + // foo(U:const(shared(U)) T => nomatch + // foo(U:const(shared(U)) const(T) => nomatch + // foo(U:immutable(U)) wild(T) => nomatch + // foo(U:shared(U)) wild(T) => nomatch + // foo(U:const(shared(U)) wild(T) => nomatch + // foo(U:wild(U)) T => nomatch + // foo(U:wild(U)) const(T) => nomatch + // foo(U:wild(U)) immutable(T) => nomatch + // foo(U:wild(U)) shared(T) => nomatch + // foo(U:wild(U)) const(shared(T)) => nomatch + // foo(U:wild(shared(U)) T => nomatch + // foo(U:wild(shared(U)) const(T) => nomatch + // foo(U:wild(shared(U)) immutable(T) => nomatch + // foo(U:wild(shared(U)) shared(T) => nomatch + // foo(U:wild(shared(U)) const(shared(T)) => nomatch + // foo(U:wild(shared(U)) wild(T) => nomatch + // foo(U:immutable(U)) wild(shared(T)) => nomatch + // foo(U:const(shared(U))) wild(shared(T)) => nomatch + // foo(U:wild(U)) wild(shared(T)) => nomatch + m = MATCHnomatch; + break; + + default: + assert(0); + } + #undef X + + Lx: + if (m == MATCHnomatch) + goto Lnomatch; + if (m < match) + match = m; + + t->objects[i] = tt; + } + declareParameter(paramscope, tp, t); + goto L2; + } + fptupindex = -1; + } + } + +L1: + if (nfparams == nfargs) + ; + else if (nfargs > nfparams) + { + if (fvarargs == 0) + goto Lnomatch; // too many args, no match + match = MATCHconvert; // match ... with a conversion + } + +L2: +#if DMDV2 + if (ethis) + { + // Match 'ethis' to any TemplateThisParameter's + for (size_t i = 0; i < parameters->dim; i++) + { TemplateParameter *tp = (*parameters)[i]; + TemplateThisParameter *ttp = tp->isTemplateThisParameter(); + if (ttp) + { MATCH m; + + Type *t = new TypeIdentifier(0, ttp->ident); + m = ethis->type->deduceType(paramscope, t, parameters, &dedtypes); + if (!m) + goto Lnomatch; + if (m < match) + match = m; // pick worst match + } + } + + // Match attributes of ethis against attributes of fd + if (fd->type && !fd->isCtorDeclaration()) + { + Type *tthis = ethis->type; + unsigned mod = fd->type->mod; + StorageClass stc = scope->stc | fd->storage_class2; + // Propagate parent storage class (see bug 5504) + Dsymbol *p = parent; + while (p->isTemplateDeclaration() || p->isTemplateInstance()) + p = p->parent; + AggregateDeclaration *ad = p->isAggregateDeclaration(); + if (ad) + stc |= ad->storage_class; + + if (stc & (STCshared | STCsynchronized)) + mod |= MODshared; + if (stc & STCimmutable) + mod |= MODimmutable; + if (stc & STCconst) + mod |= MODconst; + if (stc & STCwild) + mod |= MODwild; + // Fix mod + if (mod & MODimmutable) + mod = MODimmutable; + if (mod & MODconst) + mod &= ~STCwild; + if (tthis->mod != mod) + { + if (!MODmethodConv(tthis->mod, mod)) + goto Lnomatch; + if (MATCHconst < match) + match = MATCHconst; + } + } + } +#endif + + // Loop through the function parameters + for (size_t parami = 0; parami < nfparams; parami++) + { + /* Skip over function parameters which wound up + * as part of a template tuple parameter. + */ + if (parami == fptupindex) + continue; + /* Set i = index into function arguments + * Function parameters correspond to function arguments as follows. + * Note that tuple_dim may be zero, and there may be default or + * variadic arguments at the end. + * arg [0..fptupindex] == param[0..fptupindex] + * arg [fptupindex..fptupindex+tuple_dim] == param[fptupindex] + * arg[fputupindex+dim.. ] == param[fptupindex+1.. ] + */ + size_t i = parami; + if (fptupindex >= 0 && parami > fptupindex) + i += tuple_dim - 1; + + Parameter *fparam = Parameter::getNth(fparameters, parami); + Type *prmtype = fparam->type; + + if (i >= nfargs) // if not enough arguments + { + if (fparam->defaultArg) + { /* Default arguments do not participate in template argument + * deduction. + */ + goto Lmatch; + } + } + else + { + Expression *farg = (*fargs)[i]; + + // Check invalid arguments to detect errors early. + if (farg->op == TOKerror || farg->type->ty == Terror) + goto Lnomatch; + +Lretry: +#if 0 + printf("\tfarg->type = %s\n", farg->type->toChars()); + printf("\tfparam->type = %s\n", prmtype->toChars()); +#endif + Type *argtype = farg->type; + + // Apply function parameter storage classes to parameter types + prmtype = prmtype->addStorageClass(fparam->storageClass); + + // If parameter type doesn't depend on inferred template parameters, + // semantic it to get actual type. + if (!inferparams || !prmtype->reliesOnTident(inferparams)) + { + // should copy prmtype to avoid affecting semantic result + prmtype = prmtype->syntaxCopy()->semantic(loc, paramscope); + } + +#if DMDV2 + /* Allow string literals which are type [] to match with [dim] + */ + if (farg->op == TOKstring) + { StringExp *se = (StringExp *)farg; + if (!se->committed && argtype->ty == Tarray && + prmtype->toBasetype()->ty == Tsarray) + { + argtype = new TypeSArray(argtype->nextOf(), new IntegerExp(se->loc, se->len, Type::tindex)); + argtype = argtype->semantic(se->loc, NULL); + argtype = argtype->invariantOf(); + } + } + + /* Allow implicit function literals to delegate conversion + */ + if (farg->op == TOKfunction) + { FuncExp *fe = (FuncExp *)farg; + Type *tp = prmtype; + Expression *e = fe->inferType(tp, 1, parameters); + if (!e) + goto Lvarargs; + farg = e; + argtype = farg->type; + } + + if (!(fparam->storageClass & STClazy) && argtype->ty == Tvoid) + goto Lnomatch; + + /* Remove top const for dynamic array types and pointer types + */ + if ((argtype->ty == Tarray || argtype->ty == Tpointer) && + !argtype->isMutable() && + (!(fparam->storageClass & STCref) || + (fparam->storageClass & STCauto) && !farg->isLvalue())) + { + argtype = argtype->mutableOf(); + } +#endif + + if (fvarargs == 2 && i + 1 == nfparams && i + 1 < nfargs) + goto Lvarargs; + + unsigned wm = 0; + MATCH m = argtype->deduceType(paramscope, prmtype, parameters, &dedtypes, &wm); + //printf("\tdeduceType m = %d\n", m); + //printf("\twildmatch = x%x m = %d\n", wildmatch, m); + wildmatch |= wm; + + /* If no match, see if the argument can be matched by using + * implicit conversions. + */ + if (!m) + m = farg->implicitConvTo(prmtype); + + /* If no match, see if there's a conversion to a delegate + */ + if (!m) + { Type *tbp = prmtype->toBasetype(); + Type *tba = farg->type->toBasetype(); + AggregateDeclaration *ad; + if (tbp->ty == Tdelegate) + { + TypeDelegate *td = (TypeDelegate *)prmtype->toBasetype(); + TypeFunction *tf = (TypeFunction *)td->next; + + if (!tf->varargs && Parameter::dim(tf->parameters) == 0) + { + m = farg->type->deduceType(paramscope, tf->next, parameters, &dedtypes); + if (!m && tf->next->toBasetype()->ty == Tvoid) + m = MATCHconvert; + } + //printf("\tm2 = %d\n", m); + } + else if (tba->ty == Tclass) + { + ad = ((TypeClass *)tba)->sym; + goto Lad; + } + else if (tba->ty == Tstruct) + { + ad = ((TypeStruct *)tba)->sym; + Lad: + if (ad->aliasthis) + { /* If a semantic error occurs while doing alias this, + * eg purity(bug 7295), just regard it as not a match. + */ + unsigned olderrors = global.startGagging(); + Expression *e = resolveAliasThis(sc, farg); + if (!global.endGagging(olderrors)) + { farg = e; + goto Lretry; + } + } + } + } + + if (m && (fparam->storageClass & (STCref | STCauto)) == STCref) + { if (!farg->isLvalue()) + { + if (farg->op == TOKstructliteral) + m = MATCHconvert; + else if (farg->op == TOKcall) + { + CallExp *ce = (CallExp *)farg; + if (ce->e1->op == TOKdotvar && + ((DotVarExp *)ce->e1)->var->isCtorDeclaration()) + { + m = MATCHconvert; + } + else + goto Lnomatch; + } + else + goto Lnomatch; + } + } + if (m && (fparam->storageClass & STCout)) + { if (!farg->isLvalue()) + goto Lnomatch; + } + if (!m && (fparam->storageClass & STClazy) && prmtype->ty == Tvoid && + farg->type->ty != Tvoid) + m = MATCHconvert; + + if (m) + { if (m < match) + match = m; // pick worst match + continue; + } + } + + Lvarargs: + /* The following code for variadic arguments closely + * matches TypeFunction::callMatch() + */ + if (!(fvarargs == 2 && i + 1 == nfparams)) + goto Lnomatch; + + /* Check for match with function parameter T... + */ + Type *tb = prmtype->toBasetype(); + switch (tb->ty) + { + // Perhaps we can do better with this, see TypeFunction::callMatch() + case Tsarray: + { TypeSArray *tsa = (TypeSArray *)tb; + dinteger_t sz = tsa->dim->toInteger(); + if (sz != nfargs - i) + goto Lnomatch; + } + case Tarray: + { TypeArray *ta = (TypeArray *)tb; + for (; i < nfargs; i++) + { + Expression *arg = (*fargs)[i]; + assert(arg); + + if (arg->op == TOKfunction) + { FuncExp *fe = (FuncExp *)arg; + Type *tp = tb->nextOf(); + + Expression *e = fe->inferType(tp, 1, parameters); + if (!e) + goto Lnomatch; + arg = e; + } + + MATCH m; + /* If lazy array of delegates, + * convert arg(s) to delegate(s) + */ + Type *tret = fparam->isLazyArray(); + if (tret) + { + if (ta->next->equals(arg->type)) + { m = MATCHexact; + } + else + { + m = arg->implicitConvTo(tret); + if (m == MATCHnomatch) + { + if (tret->toBasetype()->ty == Tvoid) + m = MATCHconvert; + } + } + } + else + { + m = arg->type->deduceType(paramscope, ta->next, parameters, &dedtypes); + //m = arg->implicitConvTo(ta->next); + } + if (m == MATCHnomatch) + goto Lnomatch; + if (m < match) + match = m; + } + goto Lmatch; + } + case Tclass: + case Tident: + goto Lmatch; + + default: + goto Lnomatch; + } + } + +Lmatch: + + for (size_t i = nargsi; i < dedargs->dim; i++) + { + TemplateParameter *tparam = (*parameters)[i]; + //printf("tparam[%d] = %s\n", i, tparam->ident->toChars()); + /* For T:T*, the dedargs is the T*, dedtypes is the T + * But for function templates, we really need them to match + */ + Object *oarg = (*dedargs)[i]; + Object *oded = dedtypes[i]; + //printf("1dedargs[%d] = %p, dedtypes[%d] = %p\n", i, oarg, i, oded); + //if (oarg) printf("oarg: %s\n", oarg->toChars()); + //if (oded) printf("oded: %s\n", oded->toChars()); + if (!oarg) + { + if (oded) + { + if (tparam->specialization()) + { /* The specialization can work as long as afterwards + * the oded == oarg + */ + Declaration *sparam; + (*dedargs)[i] = oded; + MATCH m2 = tparam->matchArg(paramscope, dedargs, i, parameters, &dedtypes, &sparam); + //printf("m2 = %d\n", m2); + if (!m2) + goto Lnomatch; + if (m2 < match) + match = m2; // pick worst match + if (dedtypes[i] != oded) + error("specialization not allowed for deduced parameter %s", tparam->ident->toChars()); + } + } + else + { oded = tparam->defaultArg(loc, paramscope); + if (!oded) + { + if (tp && // if tuple parameter and + fptupindex < 0 && // tuple parameter was not in function parameter list and + nargsi == dedargs->dim - 1) // we're one argument short (i.e. no tuple argument) + { // make tuple argument an empty tuple + oded = (Object *)new Tuple(); + } + else + goto Lnomatch; + } + } + declareParameter(paramscope, tparam, oded); + (*dedargs)[i] = oded; + } + } + +#if DMDV2 + if (constraint) + { /* Check to see if constraint is satisfied. + * Most of this code appears twice; this is a good candidate for refactoring. + */ + makeParamNamesVisibleInConstraint(paramscope, fargs); + Expression *e = constraint->syntaxCopy(); + paramscope->ignoreTemplates++; + 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); + + 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)) + goto Lnomatch; + else + { + e->error("constraint %s is not constant or does not evaluate to a bool", e->toChars()); + } + } +#endif + +#if 0 + for (i = 0; i < dedargs->dim; i++) + { Type *t = (*dedargs)[i]; + printf("\tdedargs[%d] = %d, %s\n", i, t->dyncast(), t->toChars()); + } +#endif + + paramscope->pop(); + //printf("\tmatch %d\n", match); + return (MATCH)(match | (matchTargsi<<4)); + +Lnomatch: + paramscope->pop(); + //printf("\tnomatch\n"); + return MATCHnomatch; +} + +/************************************************** + * Declare template parameter tp with value o, and install it in the scope sc. + */ + +void TemplateDeclaration::declareParameter(Scope *sc, TemplateParameter *tp, Object *o) +{ + //printf("TemplateDeclaration::declareParameter('%s', o = %p)\n", tp->ident->toChars(), o); + + Type *targ = isType(o); + Expression *ea = isExpression(o); + Dsymbol *sa = isDsymbol(o); + Tuple *va = isTuple(o); + + Dsymbol *s; + + // See if tp->ident already exists with a matching definition + Dsymbol *scopesym; + s = sc->search(loc, tp->ident, &scopesym); + if (s && scopesym == sc->scopesym) + { + TupleDeclaration *td = s->isTupleDeclaration(); + if (va && td) + { Tuple tup; + tup.objects = *td->objects; + if (match(va, &tup, this, sc)) + { + return; + } + } + } + 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) + { + //printf("type %s\n", targ->toChars()); + s = new AliasDeclaration(0, tp->ident, targ); + } + else if (sa) + { + //printf("Alias %s %s;\n", sa->ident->toChars(), tp->ident->toChars()); + s = new AliasDeclaration(0, tp->ident, sa); + } + else if (ea && ea->op == TOKfunction) + { + if (((FuncExp *)ea)->td) + sa = ((FuncExp *)ea)->td; + else + sa = ((FuncExp *)ea)->fd; + s = new AliasDeclaration(0, tp->ident, sa); + } + else if (ea) + { + // tdtypes.data[i] always matches ea here + Initializer *init = new ExpInitializer(loc, ea); + TemplateValueParameter *tvp = tp->isTemplateValueParameter(); + + Type *t = tvp ? tvp->valType : NULL; + + VarDeclaration *v = new VarDeclaration(loc, t, tp->ident, init); + v->storage_class = STCmanifest; + s = v; + } + else if (va) + { + //printf("\ttuple\n"); + s = new TupleDeclaration(loc, tp->ident, &va->objects); + } + else + { +#ifdef DEBUG + o->print(); +#endif + assert(0); + } + if (!sc->insert(s)) + error("declaration %s is already defined", tp->ident->toChars()); + s->semantic(sc); +} + +/************************************** + * Determine if TemplateDeclaration is variadic. + */ + +TemplateTupleParameter *isVariadic(TemplateParameters *parameters) +{ size_t dim = parameters->dim; + TemplateTupleParameter *tp = NULL; + + if (dim) + tp = ((*parameters)[dim - 1])->isTemplateTupleParameter(); + return tp; +} + +TemplateTupleParameter *TemplateDeclaration::isVariadic() +{ + return ::isVariadic(parameters); +} + +/*********************************** + * We can overload templates. + */ + +int TemplateDeclaration::isOverloadable() +{ + return 1; +} + +/************************************************* + * Given function arguments, figure out which template function + * to expand, and return that function. + * If no match, give error message and return NULL. + * Input: + * sc instantiation scope + * loc instantiation location + * targsi initial list of template arguments + * ethis if !NULL, the 'this' pointer argument + * fargs arguments to function + * flags 1: do not issue error message on no match, just return NULL + */ + +FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Scope *sc, Loc loc, + Objects *targsi, Expression *ethis, Expressions *fargs, int flags) +{ + MATCH m_best = MATCHnomatch; + MATCH m_best2 = MATCHnomatch; + TemplateDeclaration *td_ambig = NULL; + TemplateDeclaration *td_best = NULL; + Objects *tdargs = new Objects(); + TemplateInstance *ti; + FuncDeclaration *fd_best; + +#if 0 + printf("TemplateDeclaration::deduceFunctionTemplate() %s\n", toChars()); + printf(" targsi:\n"); + if (targsi) + { for (size_t i = 0; i < targsi->dim; 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)[i]; + printf("\t%s %s\n", arg->type->toChars(), arg->toChars()); + //printf("\tty = %d\n", arg->type->ty); + } + printf("stc = %llx\n", scope->stc); +#endif + + for (TemplateDeclaration *td = this; td; td = td->overnext) + { + if (!td->semanticRun) + { + error("forward reference to template %s", td->toChars()); + goto Lerror; + } + if (!td->onemember || !td->onemember->toAlias()->isFuncDeclaration()) + { + error("is not a function template"); + goto Lerror; + } + + MATCH m, m2; + Objects dedargs; + FuncDeclaration *fd = NULL; + + m = td->deduceFunctionTemplateMatch(sc, loc, targsi, ethis, fargs, &dedargs); + m2 = (MATCH)(m >> 4); + m = (MATCH)(m & 0xF); + //printf("deduceFunctionTemplateMatch = %d, m2 = %d\n", m, m2); + if (!m) // if no match + continue; + + if (m2 < m_best2) + goto Ltd_best; + if (m2 > m_best2) + goto Ltd; + + if (m < m_best) + goto Ltd_best; + if (m > m_best) + goto Ltd; + + { + // Disambiguate by picking the most specialized TemplateDeclaration + MATCH c1 = td->leastAsSpecialized(td_best, fargs); + MATCH c2 = td_best->leastAsSpecialized(td, fargs); + //printf("1: c1 = %d, c2 = %d\n", c1, c2); + + if (c1 > c2) + goto Ltd; + else if (c1 < c2) + goto Ltd_best; + } + + if (!fd_best) + { + fd_best = td_best->doHeaderInstantiation(sc, tdargs, fargs); + if (!fd_best) + goto Lerror; + } + { + fd = td->doHeaderInstantiation(sc, &dedargs, fargs); + if (!fd) + goto Lerror; + } + assert(fd && fd_best); + + { + // Disambiguate by tf->callMatch + TypeFunction *tf1 = (TypeFunction *)fd->type; + TypeFunction *tf2 = (TypeFunction *)fd_best->type; + MATCH c1 = (MATCH) tf1->callMatch(fd->needThis() && !fd->isCtorDeclaration() ? ethis : NULL, fargs); + MATCH c2 = (MATCH) tf2->callMatch(fd_best->needThis() && !fd_best->isCtorDeclaration() ? ethis : NULL, fargs); + //printf("2: c1 = %d, c2 = %d\n", c1, c2); + + if (c1 > c2) + goto Ltd; + if (c1 < c2) + goto Ltd_best; + } + + { + // Disambiguate by picking the most specialized FunctionDeclaration + MATCH c1 = fd->leastAsSpecialized(fd_best); + MATCH c2 = fd_best->leastAsSpecialized(fd); + //printf("3: c1 = %d, c2 = %d\n", c1, c2); + + if (c1 > c2) + goto Ltd; + if (c1 < c2) + goto Ltd_best; + } + + Lambig: // td_best and td are ambiguous + td_ambig = td; + continue; + + Ltd_best: // td_best is the best match so far + td_ambig = NULL; + continue; + + Ltd: // td is the new best match + td_ambig = NULL; + assert((size_t)td->scope > 0x10000); + td_best = td; + fd_best = fd; + m_best = m; + m_best2 = m2; + tdargs->setDim(dedargs.dim); + memcpy(tdargs->tdata(), dedargs.tdata(), tdargs->dim * sizeof(void *)); + continue; + } + if (!td_best) + { + if (!(flags & 1)) + ::error(loc, "%s %s.%s does not match any function template declaration", + kind(), parent->toPrettyChars(), ident->toChars()); + goto Lerror; + } + if (td_ambig) + { + ::error(loc, "%s %s.%s matches more than one template declaration, %s(%d):%s and %s(%d):%s", + kind(), parent->toPrettyChars(), ident->toChars(), + td_best->loc.filename, td_best->loc.linnum, td_best->toChars(), + td_ambig->loc.filename, td_ambig->loc.linnum, td_ambig->toChars()); + } + + /* The best match is td_best with arguments tdargs. + * Now instantiate the template. + */ + assert((size_t)td_best->scope > 0x10000); + ti = new TemplateInstance(loc, td_best, tdargs); + ti->semantic(sc, fargs); + fd_best = ti->toAlias()->isFuncDeclaration(); + if (!fd_best) + goto Lerror; + if (!((TypeFunction*)fd_best->type)->callMatch(fd_best->needThis() && !fd_best->isCtorDeclaration() ? ethis : NULL, fargs)) + goto Lerror; + + if (FuncLiteralDeclaration *fld = fd_best->isFuncLiteralDeclaration()) + { + // Inside template constraint, nested reference check doesn't work correctly. + if (!(sc->flags & SCOPEstaticif) && fld->tok == TOKreserved) + { // change to non-nested + fld->tok = TOKfunction; + fld->vthis = NULL; + } + } + + /* As Bugzilla 3682 shows, a template instance can be matched while instantiating + * that same template. Thus, the function type can be incomplete. Complete it. + */ + { TypeFunction *tf = (TypeFunction *)fd_best->type; + assert(tf->ty == Tfunction); + if (tf->next) + fd_best->type = tf->semantic(loc, sc); + } + + return fd_best; + + Lerror: +#if DMDV2 + if (!(flags & 1)) +#endif + { + HdrGenState hgs; + + OutBuffer bufa; + Objects *args = targsi; + if (args) + { for (size_t i = 0; i < args->dim; i++) + { + if (i) + bufa.writeByte(','); + Object *oarg = (*args)[i]; + ObjectToCBuffer(&bufa, &hgs, oarg); + } + } + + OutBuffer buf; + argExpTypesToCBuffer(&buf, fargs, &hgs); + if (this->overnext) + ::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 + error("cannot deduce template function from argument types !(%s)(%s)", + bufa.toChars(), buf.toChars()); + } + return NULL; +} + +/************************************************* + * Limited function template instantiation for using fd->leastAsSpecialized() + */ +FuncDeclaration *TemplateDeclaration::doHeaderInstantiation(Scope *sc, + Objects *tdargs, Expressions *fargs) +{ + FuncDeclaration *fd = onemember->toAlias()->isFuncDeclaration(); + if (!fd) + return NULL; + +#if 0 + printf("doHeaderInstantiation this = %s\n", toChars()); + for (size_t i = 0; i < tdargs->dim; ++i) + printf("\ttdargs[%d] = %s\n", i, ((Object *)tdargs->data[i])->toChars()); +#endif + + assert((size_t)scope > 0x10000); + TemplateInstance *ti = new TemplateInstance(loc, this, tdargs); + ti->tinst = sc->tinst; + { + ti->tdtypes.setDim(ti->tempdecl->parameters->dim); + if (!ti->tempdecl->matchWithInstance(ti, &ti->tdtypes, fargs, 2)) + return NULL; + } + + ti->parent = parent; + + // function body and contracts are not need + //fd = fd->syntaxCopy(NULL)->isFuncDeclaration(); + fd = new FuncDeclaration(fd->loc, fd->endloc, fd->ident, fd->storage_class, fd->type->syntaxCopy()); + fd->parent = ti; + + Scope *scope = this->scope; + + ti->argsym = new ScopeDsymbol(); + ti->argsym->parent = scope->parent; + scope = scope->push(ti->argsym); + + Scope *paramscope = scope->push(); + paramscope->stc = 0; + ti->declareParameters(paramscope); + paramscope->pop(); + + { + TypeFunction *tf = (TypeFunction *)fd->type; + if (tf && tf->ty == Tfunction) + tf->fargs = fargs; + } + + Scope *sc2; + sc2 = scope->push(ti); + sc2->parent = /*isnested ? sc->parent :*/ ti; + sc2->tinst = ti; + + { + Scope *sc = sc2; + sc = sc->push(); + + if (fd->isCtorDeclaration()) + sc->flags |= SCOPEctor; + fd->type = fd->type->semantic(fd->loc, sc); + sc = sc->pop(); + } + //printf("\t[%s] fd->type = %s, mod = %x, ", loc.toChars(), fd->type->toChars(), fd->type->mod); + //printf("fd->needThis() = %d\n", fd->needThis()); + + sc2->pop(); + scope->pop(); + + return fd; +} + +bool TemplateDeclaration::hasStaticCtorOrDtor() +{ + return FALSE; // don't scan uninstantiated templates +} + +void TemplateDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ +#if 0 // Should handle template functions for doc generation + if (onemember && onemember->isFuncDeclaration()) + buf->writestring("foo "); +#endif + if (hgs->ddoc) + buf->writestring(kind()); + else + buf->writestring("template"); + buf->writeByte(' '); + buf->writestring(ident->toChars()); + buf->writeByte('('); + for (size_t i = 0; i < parameters->dim; i++) + { + TemplateParameter *tp = (*parameters)[i]; + if (hgs->ddoc) + tp = (*origParameters)[i]; + if (i) + buf->writeByte(','); + tp->toCBuffer(buf, hgs); + } + buf->writeByte(')'); +#if DMDV2 + if (constraint) + { buf->writestring(" if ("); + constraint->toCBuffer(buf, hgs); + buf->writeByte(')'); + } +#endif + + if (hgs->hdrgen) + { + hgs->tpltMember++; + buf->writenl(); + buf->writebyte('{'); + buf->writenl(); + for (size_t i = 0; i < members->dim; i++) + { + Dsymbol *s = (*members)[i]; + s->toCBuffer(buf, hgs); + } + buf->writebyte('}'); + buf->writenl(); + hgs->tpltMember--; + } +} + + +char *TemplateDeclaration::toChars() +{ OutBuffer buf; + HdrGenState hgs; + + memset(&hgs, 0, sizeof(hgs)); + buf.writestring(ident->toChars()); + buf.writeByte('('); + for (size_t i = 0; i < parameters->dim; i++) + { + TemplateParameter *tp = (*parameters)[i]; + if (i) + buf.writeByte(','); + tp->toCBuffer(&buf, &hgs); + } + buf.writeByte(')'); +#if DMDV2 + if (constraint) + { buf.writestring(" if ("); + constraint->toCBuffer(&buf, &hgs); + buf.writeByte(')'); + } +#endif + buf.writeByte(0); + return (char *)buf.extractData(); +} + +/* ======================== Type ============================================ */ + +/**** + * Given an identifier, figure out which TemplateParameter it is. + * Return -1 if not found. + */ + +int templateIdentifierLookup(Identifier *id, TemplateParameters *parameters) +{ + for (size_t i = 0; i < parameters->dim; i++) + { TemplateParameter *tp = (*parameters)[i]; + + if (tp->ident->equals(id)) + return i; + } + return -1; +} + +int templateParameterLookup(Type *tparam, TemplateParameters *parameters) +{ + assert(tparam->ty == Tident); + TypeIdentifier *tident = (TypeIdentifier *)tparam; + //printf("\ttident = '%s'\n", tident->toChars()); + if (tident->idents.dim == 0) + { + return templateIdentifierLookup(tident->ident, parameters); + } + return -1; +} + +/* These form the heart of template argument deduction. + * Given 'this' being the type argument to the template instance, + * it is matched against the template declaration parameter specialization + * 'tparam' to determine the type to be used for the parameter. + * Example: + * template Foo(T:T*) // template declaration + * Foo!(int*) // template instantiation + * Input: + * this = int* + * tparam = T* + * parameters = [ T:T* ] // Array of TemplateParameter's + * Output: + * dedtypes = [ int ] // Array of Expression/Type's + */ + +MATCH Type::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, + Objects *dedtypes, unsigned *wildmatch) +{ +#if 0 + printf("Type::deduceType()\n"); + printf("\tthis = %d, ", ty); print(); + printf("\ttparam = %d, ", tparam->ty); tparam->print(); +#endif + if (!tparam) + goto Lnomatch; + + if (this == tparam) + goto Lexact; + + if (tparam->ty == Tident) + { + // Determine which parameter tparam is + int i = templateParameterLookup(tparam, parameters); + if (i == -1) + { + if (!sc) + goto Lnomatch; + + /* Need a loc to go with the semantic routine. + */ + Loc loc; + if (parameters->dim) + { + TemplateParameter *tp = (*parameters)[0]; + loc = tp->loc; + } + + /* BUG: what if tparam is a template instance, that + * has as an argument another Tident? + */ + tparam = tparam->semantic(loc, sc); + assert(tparam->ty != Tident); + return deduceType(sc, tparam, parameters, dedtypes, wildmatch); + } + + TemplateParameter *tp = (*parameters)[i]; + + // Found the corresponding parameter tp + if (!tp->isTemplateTypeParameter()) + goto Lnomatch; + Type *tt = this; + Type *at = (Type *)(*dedtypes)[i]; + + // 7*7 == 49 cases + + #define X(U,T) ((U) << 4) | (T) + + if (wildmatch && (tparam->mod & MODwild)) + { + switch (X(tparam->mod, mod)) + { + case X(MODwild, 0): + case X(MODwild, MODshared): + case X(MODwild, MODconst): + case X(MODwild, MODconst | MODshared): + case X(MODwild, MODimmutable): + case X(MODwild, MODwild): + case X(MODwild, MODwild | MODshared): + case X(MODwild | MODshared, MODshared): + case X(MODwild | MODshared, MODconst | MODshared): + case X(MODwild | MODshared, MODimmutable): + case X(MODwild | MODshared, MODwild | MODshared): + + if (!at) + { + if (mod & MODwild) + *wildmatch |= MODwild; + else if (mod == 0) + *wildmatch |= MODmutable; + else + *wildmatch |= (mod & ~MODshared); + tt = mutableOf()->substWildTo(MODmutable); + (*dedtypes)[i] = tt; + goto Lconst; + } + + //printf("\t> tt = %s, at = %s\n", tt->toChars(), at->toChars()); + //printf("\t> tt->implicitConvTo(at->constOf()) = %d\n", tt->implicitConvTo(at->constOf())); + //printf("\t> at->implicitConvTo(tt->constOf()) = %d\n", at->implicitConvTo(tt->constOf())); + + if (tt->equals(at)) + { + goto Lconst; + } + else if (tt->implicitConvTo(at->constOf())) + { + (*dedtypes)[i] = at->constOf()->mutableOf(); + *wildmatch |= MODconst; + goto Lconst; + } + else if (at->implicitConvTo(tt->constOf())) + { + (*dedtypes)[i] = tt->constOf()->mutableOf(); + *wildmatch |= MODconst; + goto Lconst; + } + goto Lnomatch; + + default: + break; + } + } + + switch (X(tparam->mod, mod)) + { + case X(0, 0): + case X(0, MODconst): + case X(0, MODimmutable): + case X(0, MODshared): + case X(0, MODconst | MODshared): + case X(0, MODwild): + case X(0, MODwild | MODshared): + // foo(U:U) T => T + // foo(U:U) const(T) => const(T) + // foo(U:U) immutable(T) => immutable(T) + // foo(U:U) shared(T) => shared(T) + // foo(U:U) const(shared(T)) => const(shared(T)) + // foo(U:U) wild(T) => wild(T) + // foo(U:U) wild(shared(T)) => wild(shared(T)) + if (!at) + { (*dedtypes)[i] = tt; + goto Lexact; + } + break; + + case X(MODconst, MODconst): + case X(MODimmutable, MODimmutable): + case X(MODshared, MODshared): + case X(MODconst | MODshared, MODconst | MODshared): + case X(MODwild, MODwild): + case X(MODwild | MODshared, MODwild | MODshared): + // foo(U:const(U)) const(T) => T + // foo(U:immutable(U)) immutable(T) => T + // foo(U:shared(U)) shared(T) => T + // foo(U:const(shared(U)) const(shared(T)) => T + // foo(U:wild(U)) wild(T) => T + // foo(U:wild(shared(U)) wild(shared(T)) => T + tt = mutableOf()->unSharedOf(); + if (!at) + { (*dedtypes)[i] = tt; + goto Lexact; + } + break; + + case X(MODconst, 0): + case X(MODconst, MODimmutable): + case X(MODconst, MODconst | MODshared): + case X(MODconst | MODshared, MODimmutable): + case X(MODconst, MODwild): + case X(MODconst, MODwild | MODshared): + // foo(U:const(U)) T => T + // foo(U:const(U)) immutable(T) => T + // foo(U:const(U)) const(shared(T)) => shared(T) + // foo(U:const(shared(U)) immutable(T) => T + // foo(U:const(U)) wild(shared(T)) => shared(T) + tt = mutableOf(); + if (!at) + { (*dedtypes)[i] = tt; + goto Lconst; + } + break; + + case X(MODshared, MODconst | MODshared): + case X(MODconst | MODshared, MODshared): + case X(MODshared, MODwild | MODshared): + // foo(U:shared(U)) const(shared(T)) => const(T) + // foo(U:const(shared(U)) shared(T) => T + // foo(U:shared(U)) wild(shared(T)) => wild(T) + tt = unSharedOf(); + if (!at) + { (*dedtypes)[i] = tt; + goto Lconst; + } + break; + + case X(MODconst, MODshared): + // foo(U:const(U)) shared(T) => shared(T) + if (!at) + { (*dedtypes)[i] = tt; + goto Lconst; + } + break; + + case X(MODimmutable, 0): + case X(MODimmutable, MODconst): + case X(MODimmutable, MODshared): + case X(MODimmutable, MODconst | MODshared): + case X(MODshared, 0): + case X(MODshared, MODconst): + case X(MODshared, MODimmutable): + case X(MODconst | MODshared, 0): + case X(MODconst | MODshared, MODconst): + case X(MODimmutable, MODwild): + case X(MODshared, MODwild): + case X(MODconst | MODshared, MODwild): + case X(MODwild, 0): + case X(MODwild, MODconst): + case X(MODwild, MODimmutable): + case X(MODwild, MODshared): + case X(MODwild, MODconst | MODshared): + case X(MODwild | MODshared, 0): + case X(MODwild | MODshared, MODconst): + case X(MODwild | MODshared, MODimmutable): + case X(MODwild | MODshared, MODshared): + case X(MODwild | MODshared, MODconst | MODshared): + case X(MODwild | MODshared, MODwild): + case X(MODimmutable, MODwild | MODshared): + case X(MODconst | MODshared, MODwild | MODshared): + case X(MODwild, MODwild | MODshared): + + // foo(U:immutable(U)) T => nomatch + // foo(U:immutable(U)) const(T) => nomatch + // foo(U:immutable(U)) shared(T) => nomatch + // foo(U:immutable(U)) const(shared(T)) => nomatch + // foo(U:const(U)) shared(T) => nomatch + // foo(U:shared(U)) T => nomatch + // foo(U:shared(U)) const(T) => nomatch + // foo(U:shared(U)) immutable(T) => nomatch + // foo(U:const(shared(U)) T => nomatch + // foo(U:const(shared(U)) const(T) => nomatch + // foo(U:immutable(U)) wild(T) => nomatch + // foo(U:shared(U)) wild(T) => nomatch + // foo(U:const(shared(U)) wild(T) => nomatch + // foo(U:wild(U)) T => nomatch + // foo(U:wild(U)) const(T) => nomatch + // foo(U:wild(U)) immutable(T) => nomatch + // foo(U:wild(U)) shared(T) => nomatch + // foo(U:wild(U)) const(shared(T)) => nomatch + // foo(U:wild(shared(U)) T => nomatch + // foo(U:wild(shared(U)) const(T) => nomatch + // foo(U:wild(shared(U)) immutable(T) => nomatch + // foo(U:wild(shared(U)) shared(T) => nomatch + // foo(U:wild(shared(U)) const(shared(T)) => nomatch + // foo(U:wild(shared(U)) wild(T) => nomatch + // foo(U:immutable(U)) wild(shared(T)) => nomatch + // foo(U:const(shared(U))) wild(shared(T)) => nomatch + // foo(U:wild(U)) wild(shared(T)) => nomatch + //if (!at) + goto Lnomatch; + break; + + default: + assert(0); + } + #undef X + + if (tt->equals(at)) + goto Lexact; + else if (tt->ty == Tclass && at->ty == Tclass) + { + return tt->implicitConvTo(at); + } + else if (tt->ty == Tsarray && at->ty == Tarray && + tt->nextOf()->implicitConvTo(at->nextOf()) >= MATCHconst) + { + goto Lexact; + } + else + goto Lnomatch; + } + else if (tparam->ty == Ttypeof) + { + /* Need a loc to go with the semantic routine. + */ + Loc loc; + if (parameters->dim) + { + TemplateParameter *tp = (*parameters)[0]; + loc = tp->loc; + } + + tparam = tparam->semantic(loc, sc); + } + + if (ty != tparam->ty) + { +#if DMDV2 + // Can't instantiate AssociativeArray!() without a scope + if (tparam->ty == Taarray && !((TypeAArray*)tparam)->sc) + ((TypeAArray*)tparam)->sc = sc; + + MATCH m = implicitConvTo(tparam); + if (m == MATCHnomatch) + { + Type *at = aliasthisOf(); + if (at) + m = at->deduceType(sc, tparam, parameters, dedtypes, wildmatch); + } + return m; +#else + return implicitConvTo(tparam); +#endif + } + + if (nextOf()) + return nextOf()->deduceType(sc, tparam->nextOf(), parameters, dedtypes, wildmatch); + +Lexact: + return MATCHexact; + +Lnomatch: + return MATCHnomatch; + +#if DMDV2 +Lconst: + return MATCHconst; +#endif +} + +#if DMDV2 +MATCH TypeVector::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, + Objects *dedtypes, unsigned *wildmatch) +{ +#if 0 + printf("TypeVector::deduceType()\n"); + printf("\tthis = %d, ", ty); print(); + printf("\ttparam = %d, ", tparam->ty); tparam->print(); +#endif + if (tparam->ty == Tvector) + { TypeVector *tp = (TypeVector *)tparam; + return basetype->deduceType(sc, tp->basetype, parameters, dedtypes, wildmatch); + } + return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); +} +#endif + +#if DMDV2 +MATCH TypeDArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, + Objects *dedtypes, unsigned *wildmatch) +{ +#if 0 + printf("TypeDArray::deduceType()\n"); + printf("\tthis = %d, ", ty); print(); + printf("\ttparam = %d, ", tparam->ty); tparam->print(); +#endif + return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); +} +#endif + +MATCH TypeSArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, + Objects *dedtypes, unsigned *wildmatch) +{ +#if 0 + printf("TypeSArray::deduceType()\n"); + printf("\tthis = %d, ", ty); print(); + printf("\ttparam = %d, ", tparam->ty); tparam->print(); +#endif + + // Extra check that array dimensions must match + if (tparam) + { + if (tparam->ty == Tarray) + { MATCH m; + + m = next->deduceType(sc, tparam->nextOf(), parameters, dedtypes, wildmatch); + if (m == MATCHexact) + m = MATCHconvert; + return m; + } + + Identifier *id = NULL; + if (tparam->ty == Tsarray) + { + TypeSArray *tp = (TypeSArray *)tparam; + if (tp->dim->op == TOKvar && + ((VarExp *)tp->dim)->var->storage_class & STCtemplateparameter) + { + id = ((VarExp *)tp->dim)->var->ident; + } + else if (dim->toInteger() != tp->dim->toInteger()) + return MATCHnomatch; + } + else if (tparam->ty == Taarray) + { + TypeAArray *tp = (TypeAArray *)tparam; + if (tp->index->ty == Tident && + ((TypeIdentifier *)tp->index)->idents.dim == 0) + { + id = ((TypeIdentifier *)tp->index)->ident; + } + } + if (id) + { + // This code matches code in TypeInstance::deduceType() + int i = templateIdentifierLookup(id, parameters); + if (i == -1) + goto Lnomatch; + TemplateParameter *tprm = (*parameters)[i]; + TemplateValueParameter *tvp = tprm->isTemplateValueParameter(); + if (!tvp) + goto Lnomatch; + Expression *e = (Expression *)(*dedtypes)[i]; + if (e) + { + if (!dim->equals(e)) + goto Lnomatch; + } + else + { + Type *vt = tvp->valType->semantic(0, sc); + MATCH m = (MATCH)dim->implicitConvTo(vt); + if (!m) + goto Lnomatch; + (*dedtypes)[i] = dim; + } + return next->deduceType(sc, tparam->nextOf(), parameters, dedtypes, wildmatch); + } + } + return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); + + Lnomatch: + return MATCHnomatch; +} + +MATCH TypeAArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch) +{ +#if 0 + printf("TypeAArray::deduceType()\n"); + printf("\tthis = %d, ", ty); print(); + printf("\ttparam = %d, ", tparam->ty); tparam->print(); +#endif + + // Extra check that index type must match + if (tparam && tparam->ty == Taarray) + { + TypeAArray *tp = (TypeAArray *)tparam; + if (!index->deduceType(sc, tp->index, parameters, dedtypes, wildmatch)) + { + return MATCHnomatch; + } + } + return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); +} + +MATCH TypeFunction::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch) +{ + //printf("TypeFunction::deduceType()\n"); + //printf("\tthis = %d, ", ty); print(); + //printf("\ttparam = %d, ", tparam->ty); tparam->print(); + + // Extra check that function characteristics must match + if (tparam && tparam->ty == Tfunction) + { + TypeFunction *tp = (TypeFunction *)tparam; + if (varargs != tp->varargs || + linkage != tp->linkage) + return MATCHnomatch; + + size_t nfargs = Parameter::dim(this->parameters); + size_t nfparams = Parameter::dim(tp->parameters); + + // bug 2579 fix: Apply function parameter storage classes to parameter types + for (size_t i = 0; i < nfparams; i++) + { + Parameter *fparam = Parameter::getNth(tp->parameters, i); + fparam->type = fparam->type->addStorageClass(fparam->storageClass); + fparam->storageClass &= ~(STC_TYPECTOR | STCin); + } + //printf("\t-> this = %d, ", ty); print(); + //printf("\t-> tparam = %d, ", tparam->ty); tparam->print(); + + /* See if tuple match + */ + if (nfparams > 0 && nfargs >= nfparams - 1) + { + /* See if 'A' of the template parameter matches 'A' + * of the type of the last function parameter. + */ + Parameter *fparam = Parameter::getNth(tp->parameters, nfparams - 1); + assert(fparam); + assert(fparam->type); + if (fparam->type->ty != Tident) + goto L1; + TypeIdentifier *tid = (TypeIdentifier *)fparam->type; + if (tid->idents.dim) + goto L1; + + /* Look through parameters to find tuple matching tid->ident + */ + size_t tupi = 0; + for (; 1; tupi++) + { if (tupi == parameters->dim) + goto L1; + TemplateParameter *t = (*parameters)[tupi]; + TemplateTupleParameter *tup = t->isTemplateTupleParameter(); + if (tup && tup->ident->equals(tid->ident)) + break; + } + + /* The types of the function arguments [nfparams - 1 .. nfargs] + * now form the tuple argument. + */ + size_t tuple_dim = nfargs - (nfparams - 1); + + /* See if existing tuple, and whether it matches or not + */ + Object *o = (*dedtypes)[tupi]; + if (o) + { // Existing deduced argument must be a tuple, and must match + Tuple *t = isTuple(o); + if (!t || t->objects.dim != tuple_dim) + return MATCHnomatch; + for (size_t i = 0; i < tuple_dim; i++) + { Parameter *arg = Parameter::getNth(this->parameters, nfparams - 1 + i); + if (!arg->type->equals(t->objects[i])) + return MATCHnomatch; + } + } + else + { // Create new tuple + Tuple *t = new Tuple(); + 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[i] = arg->type; + } + (*dedtypes)[tupi] = t; + } + nfparams--; // don't consider the last parameter for type deduction + goto L2; + } + + L1: + if (nfargs != nfparams) + return MATCHnomatch; + L2: + for (size_t i = 0; i < nfparams; i++) + { + Parameter *a = Parameter::getNth(this->parameters, i); + Parameter *ap = Parameter::getNth(tp->parameters, i); + if (a->storageClass != ap->storageClass || + !a->type->deduceType(sc, ap->type, parameters, dedtypes, wildmatch)) + return MATCHnomatch; + } + } + return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); +} + +MATCH TypeIdentifier::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch) +{ + // Extra check + if (tparam && tparam->ty == Tident) + { + TypeIdentifier *tp = (TypeIdentifier *)tparam; + + for (size_t i = 0; i < idents.dim; i++) + { + Identifier *id1 = idents[i]; + Identifier *id2 = tp->idents[i]; + + if (!id1->equals(id2)) + return MATCHnomatch; + } + } + return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); +} + +MATCH TypeInstance::deduceType(Scope *sc, + Type *tparam, TemplateParameters *parameters, + Objects *dedtypes, unsigned *wildmatch) +{ +#if 0 + printf("TypeInstance::deduceType()\n"); + printf("\tthis = %d, ", ty); print(); + printf("\ttparam = %d, ", tparam->ty); tparam->print(); +#endif + + // Extra check + if (tparam && tparam->ty == Tinstance) + { + TypeInstance *tp = (TypeInstance *)tparam; + + //printf("tempinst->tempdecl = %p\n", tempinst->tempdecl); + //printf("tp->tempinst->tempdecl = %p\n", tp->tempinst->tempdecl); + if (!tp->tempinst->tempdecl) + { //printf("tp->tempinst->name = '%s'\n", tp->tempinst->name->toChars()); + if (!tp->tempinst->name->equals(tempinst->name)) + { + /* Handle case of: + * template Foo(T : sa!(T), alias sa) + */ + int i = templateIdentifierLookup(tp->tempinst->name, parameters); + if (i == -1) + { /* Didn't find it as a parameter identifier. Try looking + * it up and seeing if is an alias. See Bugzilla 1454 + */ + 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(); + TemplateDeclaration *td = s->isTemplateDeclaration(); + if (td && td == tempinst->tempdecl) + goto L2; + } + goto Lnomatch; + } + TemplateParameter *tpx = (*parameters)[i]; + // This logic duplicates tpx->matchArg() + TemplateAliasParameter *ta = tpx->isTemplateAliasParameter(); + if (!ta) + goto Lnomatch; + Object *sa = tempinst->tempdecl; + if (!sa) + goto Lnomatch; + if (ta->specAlias && sa != ta->specAlias) + goto Lnomatch; + if ((*dedtypes)[i]) + { // Must match already deduced symbol + Object *s = (*dedtypes)[i]; + + if (s != sa) + goto Lnomatch; + } + (*dedtypes)[i] = sa; + } + } + else if (tempinst->tempdecl != tp->tempinst->tempdecl) + goto Lnomatch; + + L2: + + for (size_t i = 0; 1; i++) + { + //printf("\ttest: tempinst->tiargs[%d]\n", i); + Object *o1 = NULL; + if (i < tempinst->tiargs->dim) + o1 = (*tempinst->tiargs)[i]; + else if (i < tempinst->tdtypes.dim && i < tp->tempinst->tiargs->dim) + // Pick up default arg + o1 = tempinst->tdtypes[i]; + else if (i >= tp->tempinst->tiargs->dim) + break; + + if (i >= tp->tempinst->tiargs->dim) + goto Lnomatch; + + 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); + + Expression *e1 = isExpression(o1); + Expression *e2 = isExpression(o2); + + Dsymbol *s1 = isDsymbol(o1); + Dsymbol *s2 = isDsymbol(o2); + + Tuple *v1 = isTuple(o1); + Tuple *v2 = isTuple(o2); +#if 0 + if (t1) printf("t1 = %s\n", t1->toChars()); + if (t2) printf("t2 = %s\n", t2->toChars()); + if (e1) printf("e1 = %s\n", e1->toChars()); + if (e2) printf("e2 = %s\n", e2->toChars()); + if (s1) printf("s1 = %s\n", s1->toChars()); + if (s2) printf("s2 = %s\n", s2->toChars()); + if (v1) printf("v1 = %s\n", v1->toChars()); + if (v2) printf("v2 = %s\n", v2->toChars()); +#endif + + if (t1 && t2) + { + if (!t1->deduceType(sc, t2, parameters, dedtypes, wildmatch)) + goto Lnomatch; + } + 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) + { + /* + * (T:Number!(e2), int e2) + */ + 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; + } + } + else if (e1 && t2 && t2->ty == Tident) + { + j = templateParameterLookup(t2, parameters); + L1: + if (j == -1) + { + t2->resolve(loc, sc, &e2, &t2, &s2); + if (e2) + goto Le; + goto Lnomatch; + } + TemplateParameter *tp = (*parameters)[j]; + // BUG: use tp->matchArg() instead of the following + TemplateValueParameter *tv = tp->isTemplateValueParameter(); + if (!tv) + goto Lnomatch; + Expression *e = (Expression *)(*dedtypes)[j]; + if (e) + { + if (!e1->equals(e)) + goto Lnomatch; + } + else + { Type *vt = tv->valType->semantic(0, sc); + MATCH m = (MATCH)e1->implicitConvTo(vt); + if (!m) + goto Lnomatch; + (*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 = (*parameters)[j]; + // BUG: use tp->matchArg() instead of the following + TemplateAliasParameter *ta = tp->isTemplateAliasParameter(); + if (!ta) + goto Lnomatch; + Dsymbol *s = (Dsymbol *)(*dedtypes)[j]; + if (s) + { + if (!s1->equals(s)) + goto Lnomatch; + } + else + { + (*dedtypes)[j] = s1; + } + } + else + goto Lnomatch; + } + } + return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); + +Lnomatch: + //printf("no match\n"); + return MATCHnomatch; +} + +MATCH TypeStruct::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch) +{ + //printf("TypeStruct::deduceType()\n"); + //printf("\tthis->parent = %s, ", sym->parent->toChars()); print(); + //printf("\ttparam = %d, ", tparam->ty); tparam->print(); + + /* If this struct is a template struct, and we're matching + * it against a template instance, convert the struct type + * to a template instance, too, and try again. + */ + TemplateInstance *ti = sym->parent->isTemplateInstance(); + + if (tparam && tparam->ty == Tinstance) + { + if (ti && ti->toAlias() == sym) + { + TypeInstance *t = new TypeInstance(0, ti); + return t->deduceType(sc, tparam, parameters, dedtypes, wildmatch); + } + + /* Match things like: + * S!(T).foo + */ + TypeInstance *tpi = (TypeInstance *)tparam; + if (tpi->idents.dim) + { Identifier *id = tpi->idents[tpi->idents.dim - 1]; + if (id->dyncast() == DYNCAST_IDENTIFIER && sym->ident->equals(id)) + { + Type *tparent = sym->parent->getType(); + if (tparent) + { + /* Slice off the .foo in S!(T).foo + */ + tpi->idents.dim--; + MATCH m = tparent->deduceType(sc, tpi, parameters, dedtypes, wildmatch); + tpi->idents.dim++; + return m; + } + } + } + } + + // Extra check + if (tparam && tparam->ty == Tstruct) + { + TypeStruct *tp = (TypeStruct *)tparam; + + //printf("\t%d\n", (MATCH) implicitConvTo(tp)); + return implicitConvTo(tp); + } + return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); +} + +MATCH TypeEnum::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch) +{ + // Extra check + if (tparam && tparam->ty == Tenum) + { + TypeEnum *tp = (TypeEnum *)tparam; + + if (sym != tp->sym) + return MATCHnomatch; + } + return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); +} + +MATCH TypeTypedef::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch) +{ + // Extra check + if (tparam && tparam->ty == Ttypedef) + { + TypeTypedef *tp = (TypeTypedef *)tparam; + + if (sym != tp->sym) + return MATCHnomatch; + } + return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); +} + +/* Helper for TypeClass::deduceType(). + * Classes can match with implicit conversion to a base class or interface. + * This is complicated, because there may be more than one base class which + * matches. In such cases, one or more parameters remain ambiguous. + * For example, + * + * interface I(X, Y) {} + * class C : I(uint, double), I(char, double) {} + * C x; + * foo(T, U)( I!(T, U) x) + * + * deduces that U is double, but T remains ambiguous (could be char or uint). + * + * Given a baseclass b, and initial deduced types 'dedtypes', this function + * tries to match tparam with b, and also tries all base interfaces of b. + * If a match occurs, numBaseClassMatches is incremented, and the new deduced + * types are ANDed with the current 'best' estimate for dedtypes. + */ +void deduceBaseClassParameters(BaseClass *b, + Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, + Objects *best, int &numBaseClassMatches) +{ + TemplateInstance *parti = b->base ? b->base->parent->isTemplateInstance() : NULL; + if (parti) + { + // Make a temporary copy of dedtypes so we don't destroy it + Objects *tmpdedtypes = new Objects(); + tmpdedtypes->setDim(dedtypes->dim); + memcpy(tmpdedtypes->tdata(), dedtypes->tdata(), dedtypes->dim * sizeof(void *)); + + TypeInstance *t = new TypeInstance(0, parti); + MATCH m = t->deduceType(sc, tparam, parameters, tmpdedtypes); + if (m != MATCHnomatch) + { + // If this is the first ever match, it becomes our best estimate + if (numBaseClassMatches==0) + memcpy(best->tdata(), tmpdedtypes->tdata(), tmpdedtypes->dim * sizeof(void *)); + else for (size_t k = 0; k < tmpdedtypes->dim; ++k) + { + // If we've found more than one possible type for a parameter, + // mark it as unknown. + if ((*tmpdedtypes)[k] != (*best)[k]) + (*best)[k] = (*dedtypes)[k]; + } + ++numBaseClassMatches; + } + } + // Now recursively test the inherited interfaces + for (size_t j = 0; j < b->baseInterfaces_dim; ++j) + { + deduceBaseClassParameters( &(b->baseInterfaces)[j], + sc, tparam, parameters, dedtypes, + best, numBaseClassMatches); + } + +} + +MATCH TypeClass::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch) +{ + //printf("TypeClass::deduceType(this = %s)\n", toChars()); + + /* If this class is a template class, and we're matching + * it against a template instance, convert the class type + * to a template instance, too, and try again. + */ + TemplateInstance *ti = sym->parent->isTemplateInstance(); + + if (tparam && tparam->ty == Tinstance) + { + if (ti && ti->toAlias() == sym) + { + TypeInstance *t = new TypeInstance(0, ti); + MATCH m = t->deduceType(sc, tparam, parameters, dedtypes, wildmatch); + // Even if the match fails, there is still a chance it could match + // a base class. + if (m != MATCHnomatch) + return m; + } + + /* Match things like: + * S!(T).foo + */ + TypeInstance *tpi = (TypeInstance *)tparam; + if (tpi->idents.dim) + { Identifier *id = tpi->idents[tpi->idents.dim - 1]; + if (id->dyncast() == DYNCAST_IDENTIFIER && sym->ident->equals(id)) + { + Type *tparent = sym->parent->getType(); + if (tparent) + { + /* Slice off the .foo in S!(T).foo + */ + tpi->idents.dim--; + MATCH m = tparent->deduceType(sc, tpi, parameters, dedtypes, wildmatch); + tpi->idents.dim++; + return m; + } + } + } + + // If it matches exactly or via implicit conversion, we're done + MATCH m = Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); + if (m != MATCHnomatch) + return m; + + /* There is still a chance to match via implicit conversion to + * a base class or interface. Because there could be more than one such + * match, we need to check them all. + */ + + int numBaseClassMatches = 0; // Have we found an interface match? + + // Our best guess at dedtypes + Objects *best = new Objects(); + best->setDim(dedtypes->dim); + + ClassDeclaration *s = sym; + while(s && s->baseclasses->dim > 0) + { + // Test the base class + deduceBaseClassParameters((*s->baseclasses)[0], + sc, tparam, parameters, dedtypes, + best, numBaseClassMatches); + + // Test the interfaces inherited by the base class + for (size_t i = 0; i < s->interfaces_dim; ++i) + { + BaseClass *b = s->interfaces[i]; + deduceBaseClassParameters(b, sc, tparam, parameters, dedtypes, + best, numBaseClassMatches); + } + s = (*s->baseclasses)[0]->base; + } + + if (numBaseClassMatches == 0) + return MATCHnomatch; + + // If we got at least one match, copy the known types into dedtypes + memcpy(dedtypes->tdata(), best->tdata(), best->dim * sizeof(void *)); + return MATCHconvert; + } + + // Extra check + if (tparam && tparam->ty == Tclass) + { + TypeClass *tp = (TypeClass *)tparam; + + //printf("\t%d\n", (MATCH) implicitConvTo(tp)); + return implicitConvTo(tp); + } + return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); +} + +/* ======================== TemplateParameter =============================== */ + +TemplateParameter::TemplateParameter(Loc loc, Identifier *ident) +{ + this->loc = loc; + this->ident = ident; + this->sparam = NULL; +} + +TemplateTypeParameter *TemplateParameter::isTemplateTypeParameter() +{ + return NULL; +} + +TemplateValueParameter *TemplateParameter::isTemplateValueParameter() +{ + return NULL; +} + +TemplateAliasParameter *TemplateParameter::isTemplateAliasParameter() +{ + return NULL; +} + +TemplateTupleParameter *TemplateParameter::isTemplateTupleParameter() +{ + return NULL; +} + +#if DMDV2 +TemplateThisParameter *TemplateParameter::isTemplateThisParameter() +{ + return NULL; +} +#endif + +/* ======================== TemplateTypeParameter =========================== */ + +// type-parameter + +Type *TemplateTypeParameter::tdummy = NULL; + +TemplateTypeParameter::TemplateTypeParameter(Loc loc, Identifier *ident, Type *specType, + Type *defaultType) + : TemplateParameter(loc, ident) +{ + this->ident = ident; + this->specType = specType; + this->defaultType = defaultType; +} + +TemplateTypeParameter *TemplateTypeParameter::isTemplateTypeParameter() +{ + return this; +} + +TemplateParameter *TemplateTypeParameter::syntaxCopy() +{ + TemplateTypeParameter *tp = new TemplateTypeParameter(loc, ident, specType, defaultType); + if (tp->specType) + tp->specType = specType->syntaxCopy(); + if (defaultType) + tp->defaultType = defaultType->syntaxCopy(); + return tp; +} + +void TemplateTypeParameter::declareParameter(Scope *sc) +{ + //printf("TemplateTypeParameter::declareParameter('%s')\n", ident->toChars()); + TypeIdentifier *ti = new TypeIdentifier(loc, ident); + sparam = new AliasDeclaration(loc, ident, ti); + if (!sc->insert(sparam)) + error(loc, "parameter '%s' multiply defined", ident->toChars()); +} + +void TemplateTypeParameter::semantic(Scope *sc) +{ + //printf("TemplateTypeParameter::semantic('%s')\n", ident->toChars()); + if (specType) + { + specType = specType->semantic(loc, sc); + } +#if 0 // Don't do semantic() until instantiation + if (defaultType) + { + defaultType = defaultType->semantic(loc, sc); + } +#endif +} + +/**************************************** + * Determine if two TemplateParameters are the same + * as far as TemplateDeclaration overloading goes. + * Returns: + * 1 match + * 0 no match + */ + +int TemplateTypeParameter::overloadMatch(TemplateParameter *tp) +{ + TemplateTypeParameter *ttp = tp->isTemplateTypeParameter(); + + if (ttp) + { + if (specType != ttp->specType) + goto Lnomatch; + + if (specType && !specType->equals(ttp->specType)) + goto Lnomatch; + + return 1; // match + } + +Lnomatch: + return 0; +} + +/******************************************* + * Match to a particular TemplateParameter. + * Input: + * i i'th argument + * tiargs[] actual arguments to template instance + * parameters[] template parameters + * dedtypes[] deduced arguments to template instance + * *psparam set to symbol declared and initialized to dedtypes[i] + */ + +MATCH TemplateTypeParameter::matchArg(Scope *sc, Objects *tiargs, + size_t i, TemplateParameters *parameters, Objects *dedtypes, + Declaration **psparam) +{ + //printf("TemplateTypeParameter::matchArg()\n"); + Object *oarg; + MATCH m = MATCHexact; + Type *ta; + + if (i < tiargs->dim) + 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)[i]; + if (!oarg) + { + goto Lnomatch; + } + } + } + + ta = isType(oarg); + if (!ta) + { + //printf("%s %p %p %p\n", oarg->toChars(), isExpression(oarg), isDsymbol(oarg), isTuple(oarg)); + goto Lnomatch; + } + //printf("ta is %s\n", ta->toChars()); + + if (specType) + { + if (!ta || ta == tdummy) + goto Lnomatch; + + //printf("\tcalling deduceType(): ta is %s, specType is %s\n", ta->toChars(), specType->toChars()); + MATCH m2 = ta->deduceType(sc, specType, parameters, dedtypes); + if (m2 == MATCHnomatch) + { //printf("\tfailed deduceType\n"); + goto Lnomatch; + } + + if (m2 < m) + m = m2; + if ((*dedtypes)[i]) + ta = (Type *)(*dedtypes)[i]; + } + else + { + if ((*dedtypes)[i]) + { // Must match already deduced type + Type *t = (Type *)(*dedtypes)[i]; + + if (!t->equals(ta)) + { //printf("t = %s ta = %s\n", t->toChars(), ta->toChars()); + goto Lnomatch; + } + } + else + { + // So that matches with specializations are better + m = MATCHconvert; + } + } + (*dedtypes)[i] = ta; + + *psparam = new AliasDeclaration(loc, ident, ta); + //printf("\tm = %d\n", m); + return m; + +Lnomatch: + *psparam = NULL; + //printf("\tm = %d\n", MATCHnomatch); + return MATCHnomatch; +} + + +void TemplateTypeParameter::print(Object *oarg, Object *oded) +{ + printf(" %s\n", ident->toChars()); + + Type *t = isType(oarg); + Type *ta = isType(oded); + + assert(ta); + + if (specType) + printf("\tSpecialization: %s\n", specType->toChars()); + if (defaultType) + printf("\tDefault: %s\n", defaultType->toChars()); + printf("\tParameter: %s\n", t ? t->toChars() : "NULL"); + printf("\tDeduced Type: %s\n", ta->toChars()); +} + + +void TemplateTypeParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring(ident->toChars()); + if (specType) + { + buf->writestring(" : "); + specType->toCBuffer(buf, NULL, hgs); + } + if (defaultType) + { + buf->writestring(" = "); + defaultType->toCBuffer(buf, NULL, hgs); + } +} + + +void *TemplateTypeParameter::dummyArg() +{ Type *t; + + if (specType) + t = specType; + else + { // Use this for alias-parameter's too (?) + if (!tdummy) + tdummy = new TypeIdentifier(loc, ident); + t = tdummy; + } + return (void *)t; +} + + +Object *TemplateTypeParameter::specialization() +{ + return specType; +} + + +Object *TemplateTypeParameter::defaultArg(Loc loc, Scope *sc) +{ + Type *t; + + t = defaultType; + if (t) + { + t = t->syntaxCopy(); + t = t->semantic(loc, sc); + } + return t; +} + +/* ======================== TemplateThisParameter =========================== */ + +#if DMDV2 +// this-parameter + +TemplateThisParameter::TemplateThisParameter(Loc loc, Identifier *ident, + Type *specType, + Type *defaultType) + : TemplateTypeParameter(loc, ident, specType, defaultType) +{ +} + +TemplateThisParameter *TemplateThisParameter::isTemplateThisParameter() +{ + return this; +} + +TemplateParameter *TemplateThisParameter::syntaxCopy() +{ + TemplateThisParameter *tp = new TemplateThisParameter(loc, ident, specType, defaultType); + if (tp->specType) + tp->specType = specType->syntaxCopy(); + if (defaultType) + tp->defaultType = defaultType->syntaxCopy(); + return tp; +} + +void TemplateThisParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("this "); + TemplateTypeParameter::toCBuffer(buf, hgs); +} +#endif + +/* ======================== TemplateAliasParameter ========================== */ + +// alias-parameter + +Dsymbol *TemplateAliasParameter::sdummy = NULL; + +TemplateAliasParameter::TemplateAliasParameter(Loc loc, Identifier *ident, + Type *specType, Object *specAlias, Object *defaultAlias) + : TemplateParameter(loc, ident) +{ + this->ident = ident; + this->specType = specType; + this->specAlias = specAlias; + this->defaultAlias = defaultAlias; +} + +TemplateAliasParameter *TemplateAliasParameter::isTemplateAliasParameter() +{ + return this; +} + +TemplateParameter *TemplateAliasParameter::syntaxCopy() +{ + TemplateAliasParameter *tp = new TemplateAliasParameter(loc, ident, specType, specAlias, defaultAlias); + if (tp->specType) + tp->specType = specType->syntaxCopy(); + tp->specAlias = objectSyntaxCopy(specAlias); + tp->defaultAlias = objectSyntaxCopy(defaultAlias); + return tp; +} + +void TemplateAliasParameter::declareParameter(Scope *sc) +{ + TypeIdentifier *ti = new TypeIdentifier(loc, ident); + sparam = new AliasDeclaration(loc, ident, ti); + if (!sc->insert(sparam)) + error(loc, "parameter '%s' multiply defined", ident->toChars()); +} + +Object *aliasParameterSemantic(Loc loc, Scope *sc, Object *o) +{ + if (o) + { + Expression *ea = isExpression(o); + Type *ta = isType(o); + if (ta) + { Dsymbol *s = ta->toDsymbol(sc); + if (s) + o = s; + else + o = ta->semantic(loc, sc); + } + else if (ea) + { + ea = ea->semantic(sc); + o = ea->ctfeInterpret(); + } + } + return o; +} + +void TemplateAliasParameter::semantic(Scope *sc) +{ + if (specType) + { + specType = specType->semantic(loc, sc); + } + specAlias = aliasParameterSemantic(loc, sc, specAlias); +#if 0 // Don't do semantic() until instantiation + if (defaultAlias) + defaultAlias = defaultAlias->semantic(loc, sc); +#endif +} + +int TemplateAliasParameter::overloadMatch(TemplateParameter *tp) +{ + TemplateAliasParameter *tap = tp->isTemplateAliasParameter(); + + if (tap) + { + if (specAlias != tap->specAlias) + goto Lnomatch; + + return 1; // match + } + +Lnomatch: + return 0; +} + +MATCH TemplateAliasParameter::matchArg(Scope *sc, Objects *tiargs, + size_t i, TemplateParameters *parameters, Objects *dedtypes, + Declaration **psparam) +{ + Object *sa; + Object *oarg; + Expression *ea; + Dsymbol *s; + + //printf("TemplateAliasParameter::matchArg()\n"); + + if (i < tiargs->dim) + 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)[i]; + if (!oarg) + goto Lnomatch; + } + } + + sa = getDsymbol(oarg); + ea = isExpression(oarg); + if (ea && (ea->op == TOKthis || ea->op == TOKsuper)) + sa = ((ThisExp *)ea)->var; + else if (ea && ea->op == TOKimport) + sa = ((ScopeExp *)ea)->sds; + if (sa) + { + /* specType means the alias must be a declaration with a type + * that matches specType. + */ + if (specType) + { Declaration *d = ((Dsymbol *)sa)->isDeclaration(); + if (!d) + goto Lnomatch; + if (!d->type->equals(specType)) + goto Lnomatch; + } + } + else + { + sa = oarg; + if (ea) + { if (specType) + { + if (!ea->type->equals(specType)) + goto Lnomatch; + } + } + else + goto Lnomatch; + } + + if (specAlias) + { + if (sa == sdummy) + goto Lnomatch; + 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)[i]) + { // Must match already deduced symbol + Object *si = (*dedtypes)[i]; + + if (!sa || si != sa) + goto Lnomatch; + } + (*dedtypes)[i] = sa; + + s = isDsymbol(sa); + if (s) + *psparam = new AliasDeclaration(loc, ident, s); + else + { + assert(ea); + + // Declare manifest constant + Initializer *init = new ExpInitializer(loc, ea); + VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init); + v->storage_class = STCmanifest; + v->semantic(sc); + *psparam = v; + } + return MATCHexact; + +Lnomatch: + *psparam = NULL; + //printf("\tm = %d\n", MATCHnomatch); + return MATCHnomatch; +} + + +void TemplateAliasParameter::print(Object *oarg, Object *oded) +{ + printf(" %s\n", ident->toChars()); + + Dsymbol *sa = isDsymbol(oded); + assert(sa); + + printf("\tParameter alias: %s\n", sa->toChars()); +} + +void TemplateAliasParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("alias "); + if (specType) + { HdrGenState hgs1; + specType->toCBuffer(buf, ident, &hgs1); + } + else + buf->writestring(ident->toChars()); + if (specAlias) + { + buf->writestring(" : "); + ObjectToCBuffer(buf, hgs, specAlias); + } + if (defaultAlias) + { + buf->writestring(" = "); + ObjectToCBuffer(buf, hgs, defaultAlias); + } +} + + +void *TemplateAliasParameter::dummyArg() +{ Object *s; + + s = specAlias; + if (!s) + { + if (!sdummy) + sdummy = new Dsymbol(); + s = sdummy; + } + return (void*)s; +} + + +Object *TemplateAliasParameter::specialization() +{ + return specAlias; +} + + +Object *TemplateAliasParameter::defaultArg(Loc loc, Scope *sc) +{ + Object *da = defaultAlias; + Type *ta = isType(defaultAlias); + if (ta) + { + if (ta->ty == Tinstance) + { + // If the default arg is a template, instantiate for each type + da = ta->syntaxCopy(); + } + } + + Object *o = aliasParameterSemantic(loc, sc, da); + return o; +} + +/* ======================== TemplateValueParameter ========================== */ + +// value-parameter + +AA *TemplateValueParameter::edummies = NULL; + +TemplateValueParameter::TemplateValueParameter(Loc loc, Identifier *ident, Type *valType, + Expression *specValue, Expression *defaultValue) + : TemplateParameter(loc, ident) +{ + this->ident = ident; + this->valType = valType; + this->specValue = specValue; + this->defaultValue = defaultValue; +} + +TemplateValueParameter *TemplateValueParameter::isTemplateValueParameter() +{ + return this; +} + +TemplateParameter *TemplateValueParameter::syntaxCopy() +{ + TemplateValueParameter *tp = + new TemplateValueParameter(loc, ident, valType, specValue, defaultValue); + tp->valType = valType->syntaxCopy(); + if (specValue) + tp->specValue = specValue->syntaxCopy(); + if (defaultValue) + tp->defaultValue = defaultValue->syntaxCopy(); + return tp; +} + +void TemplateValueParameter::declareParameter(Scope *sc) +{ + VarDeclaration *v = new VarDeclaration(loc, valType, ident, NULL); + v->storage_class = STCtemplateparameter; + if (!sc->insert(v)) + error(loc, "parameter '%s' multiply defined", ident->toChars()); + sparam = v; +} + +void TemplateValueParameter::semantic(Scope *sc) +{ + bool wasSame = (sparam->type == valType); + sparam->semantic(sc); + if (sparam->type == Type::terror && wasSame) + { /* If sparam has a type error, avoid duplicate errors + * The simple solution of leaving that function if sparam->type == Type::terror + * doesn't quite work because it causes failures in xtest46 for bug 6295 + */ + valType = Type::terror; + return; + } + valType = valType->semantic(loc, sc); + if (!(valType->isintegral() || valType->isfloating() || valType->isString()) && + valType->ty != Tident) + { + if (valType != Type::terror) + error(loc, "arithmetic/string type expected for value-parameter, not %s", valType->toChars()); + } + +#if 0 // defer semantic analysis to arg match + if (specValue) + { Expression *e = specValue; + + e = e->semantic(sc); + e = e->implicitCastTo(sc, valType); + e = e->ctfeInterpret(); + if (e->op == TOKint64 || e->op == TOKfloat64 || + e->op == TOKcomplex80 || e->op == TOKnull || e->op == TOKstring) + specValue = e; + //e->toInteger(); + } + + if (defaultValue) + { Expression *e = defaultValue; + + e = e->semantic(sc); + e = e->implicitCastTo(sc, valType); + e = e->ctfeInterpret(); + if (e->op == TOKint64) + defaultValue = e; + //e->toInteger(); + } +#endif +} + +int TemplateValueParameter::overloadMatch(TemplateParameter *tp) +{ + TemplateValueParameter *tvp = tp->isTemplateValueParameter(); + + if (tvp) + { + if (valType != tvp->valType) + goto Lnomatch; + + if (valType && !valType->equals(tvp->valType)) + goto Lnomatch; + + if (specValue != tvp->specValue) + goto Lnomatch; + + return 1; // match + } + +Lnomatch: + return 0; +} + + +MATCH TemplateValueParameter::matchArg(Scope *sc, + Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, + Declaration **psparam) +{ + //printf("TemplateValueParameter::matchArg()\n"); + + Initializer *init; + Declaration *sparam; + MATCH m = MATCHexact; + Expression *ei; + Object *oarg; + + if (i < tiargs->dim) + 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)[i]; + if (!oarg) + goto Lnomatch; + } + } + + ei = isExpression(oarg); + Type *vt; + + if (!ei && oarg) + goto Lnomatch; + + if (ei && ei->op == TOKvar) + { // Resolve const variables that we had skipped earlier + ei = ei->ctfeInterpret(); + } + + //printf("\tvalType: %s, ty = %d\n", valType->toChars(), valType->ty); + vt = valType->semantic(0, sc); + //printf("ei: %s, ei->type: %s\n", ei->toChars(), ei->type->toChars()); + //printf("vt = %s\n", vt->toChars()); + + if (ei->type) + { + m = (MATCH)ei->implicitConvTo(vt); + //printf("m: %d\n", m); + if (!m) + goto Lnomatch; + } + + if (specValue) + { + if (!ei || _aaGetRvalue(edummies, ei->type) == ei) + goto Lnomatch; + + Expression *e = specValue; + + e = e->semantic(sc); + e = e->implicitCastTo(sc, vt); + e = e->ctfeInterpret(); + + ei = ei->syntaxCopy(); + ei = ei->semantic(sc); + ei = ei->implicitCastTo(sc, vt); + ei = ei->ctfeInterpret(); + //printf("\tei: %s, %s\n", ei->toChars(), ei->type->toChars()); + //printf("\te : %s, %s\n", e->toChars(), e->type->toChars()); + if (!ei->equals(e)) + goto Lnomatch; + } + else + { + if ((*dedtypes)[i]) + { // Must match already deduced value + Expression *e = (Expression *)(*dedtypes)[i]; + + if (!ei || !ei->equals(e)) + goto Lnomatch; + } + else if (m != MATCHexact) + { + ei = ei->implicitCastTo(sc, vt); + ei = ei->ctfeInterpret(); + } + } + (*dedtypes)[i] = ei; + + init = new ExpInitializer(loc, ei); + sparam = new VarDeclaration(loc, vt, ident, init); + sparam->storage_class = STCmanifest; + *psparam = sparam; + return m; + +Lnomatch: + //printf("\tno match\n"); + *psparam = NULL; + return MATCHnomatch; +} + + +void TemplateValueParameter::print(Object *oarg, Object *oded) +{ + printf(" %s\n", ident->toChars()); + + Expression *ea = isExpression(oded); + + if (specValue) + printf("\tSpecialization: %s\n", specValue->toChars()); + printf("\tParameter Value: %s\n", ea ? ea->toChars() : "NULL"); +} + + +void TemplateValueParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + valType->toCBuffer(buf, ident, hgs); + if (specValue) + { + buf->writestring(" : "); + specValue->toCBuffer(buf, hgs); + } + if (defaultValue) + { + buf->writestring(" = "); + defaultValue->toCBuffer(buf, hgs); + } +} + + +void *TemplateValueParameter::dummyArg() +{ Expression *e; + + e = specValue; + if (!e) + { + // Create a dummy value + Expression **pe = (Expression **)_aaGet(&edummies, valType); + if (!*pe) + *pe = valType->defaultInit(); + e = *pe; + } + return (void *)e; +} + + +Object *TemplateValueParameter::specialization() +{ + return specValue; +} + + +Object *TemplateValueParameter::defaultArg(Loc loc, Scope *sc) +{ + Expression *e = defaultValue; + if (e) + { + e = e->syntaxCopy(); + e = e->semantic(sc); +#if DMDV2 + e = e->resolveLoc(loc, sc); +#endif + } + return e; +} + +/* ======================== TemplateTupleParameter ========================== */ + +// variadic-parameter + +TemplateTupleParameter::TemplateTupleParameter(Loc loc, Identifier *ident) + : TemplateParameter(loc, ident) +{ + this->ident = ident; +} + +TemplateTupleParameter *TemplateTupleParameter::isTemplateTupleParameter() +{ + return this; +} + +TemplateParameter *TemplateTupleParameter::syntaxCopy() +{ + TemplateTupleParameter *tp = new TemplateTupleParameter(loc, ident); + return tp; +} + +void TemplateTupleParameter::declareParameter(Scope *sc) +{ + TypeIdentifier *ti = new TypeIdentifier(loc, ident); + sparam = new AliasDeclaration(loc, ident, ti); + if (!sc->insert(sparam)) + error(loc, "parameter '%s' multiply defined", ident->toChars()); +} + +void TemplateTupleParameter::semantic(Scope *sc) +{ +} + +int TemplateTupleParameter::overloadMatch(TemplateParameter *tp) +{ + TemplateTupleParameter *tvp = tp->isTemplateTupleParameter(); + + if (tvp) + { + return 1; // match + } + + return 0; +} + +MATCH TemplateTupleParameter::matchArg(Scope *sc, Objects *tiargs, + size_t i, TemplateParameters *parameters, Objects *dedtypes, + Declaration **psparam) +{ + //printf("TemplateTupleParameter::matchArg()\n"); + + /* The rest of the actual arguments (tiargs[]) form the match + * for the variadic parameter. + */ + assert(i + 1 == dedtypes->dim); // must be the last one + Tuple *ovar; + + if ((*dedtypes)[i] && isTuple((*dedtypes)[i])) + // It was already been deduced + ovar = isTuple((*dedtypes)[i]); + else if (i + 1 == tiargs->dim && isTuple((*tiargs)[i])) + ovar = isTuple((*tiargs)[i]); + else + { + ovar = new Tuple(); + //printf("ovar = %p\n", ovar); + if (i < tiargs->dim) + { + //printf("i = %d, tiargs->dim = %d\n", i, tiargs->dim); + ovar->objects.setDim(tiargs->dim - i); + for (size_t j = 0; j < ovar->objects.dim; j++) + ovar->objects[j] = (*tiargs)[i + j]; + } + } + *psparam = new TupleDeclaration(loc, ident, &ovar->objects); + (*dedtypes)[i] = ovar; + return MATCHexact; +} + + +void TemplateTupleParameter::print(Object *oarg, Object *oded) +{ + printf(" %s... [", ident->toChars()); + Tuple *v = isTuple(oded); + assert(v); + + //printf("|%d| ", v->objects.dim); + for (size_t i = 0; i < v->objects.dim; i++) + { + if (i) + printf(", "); + + Object *o = v->objects[i]; + + Dsymbol *sa = isDsymbol(o); + if (sa) + printf("alias: %s", sa->toChars()); + + Type *ta = isType(o); + if (ta) + printf("type: %s", ta->toChars()); + + Expression *ea = isExpression(o); + if (ea) + printf("exp: %s", ea->toChars()); + + assert(!isTuple(o)); // no nested Tuple arguments + } + + printf("]\n"); +} + +void TemplateTupleParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring(ident->toChars()); + buf->writestring("..."); +} + + +void *TemplateTupleParameter::dummyArg() +{ + return NULL; +} + + +Object *TemplateTupleParameter::specialization() +{ + return NULL; +} + + +Object *TemplateTupleParameter::defaultArg(Loc loc, Scope *sc) +{ + return NULL; +} + +/* ======================== TemplateInstance ================================ */ + +TemplateInstance::TemplateInstance(Loc loc, Identifier *ident) + : ScopeDsymbol(NULL) +{ +#if LOG + printf("TemplateInstance(this = %p, ident = '%s')\n", this, ident ? ident->toChars() : "null"); +#endif + this->loc = loc; + this->name = ident; + this->tiargs = NULL; + this->tempdecl = NULL; + this->inst = NULL; + this->tinst = NULL; + this->argsym = NULL; + this->aliasdecl = NULL; + this->semanticRun = PASSinit; + this->semantictiargsdone = 0; + this->withsym = NULL; + this->nest = 0; + this->havetempdecl = 0; + this->isnested = NULL; + this->speculative = 0; + this->ignore = true; + +#if IN_LLVM + this->emittedInModule = NULL; + this->tmodule = NULL; +#endif +} + +/***************** + * This constructor is only called when we figured out which function + * template to instantiate. + */ + +TemplateInstance::TemplateInstance(Loc loc, TemplateDeclaration *td, Objects *tiargs) + : ScopeDsymbol(NULL) +{ +#if LOG + printf("TemplateInstance(this = %p, tempdecl = '%s')\n", this, td->toChars()); +#endif + this->loc = loc; + this->name = td->ident; + this->tiargs = tiargs; + this->tempdecl = td; + this->inst = NULL; + this->tinst = NULL; + this->argsym = NULL; + this->aliasdecl = NULL; + this->semanticRun = PASSinit; + this->semantictiargsdone = 1; + this->withsym = NULL; + this->nest = 0; + this->havetempdecl = 1; + this->isnested = NULL; + this->speculative = 0; + this->ignore = true; + +#if IN_LLVM + this->tinst = NULL; + this->emittedInModule = NULL; + this->tmodule = NULL; +#endif + + assert((size_t)tempdecl->scope > 0x10000); +} + + +Objects *TemplateInstance::arraySyntaxCopy(Objects *objs) +{ + Objects *a = NULL; + if (objs) + { a = new Objects(); + a->setDim(objs->dim); + for (size_t i = 0; i < objs->dim; i++) + { + (*a)[i] = objectSyntaxCopy((*objs)[i]); + } + } + return a; +} + +Dsymbol *TemplateInstance::syntaxCopy(Dsymbol *s) +{ + TemplateInstance *ti; + + if (s) + ti = (TemplateInstance *)s; + else + ti = new TemplateInstance(loc, name); + + ti->tiargs = arraySyntaxCopy(tiargs); + + ScopeDsymbol::syntaxCopy(ti); + return ti; +} + + +void TemplateInstance::semantic(Scope *sc) +{ + semantic(sc, NULL); +} + +void TemplateInstance::expandMembers(Scope *sc2) +{ + for (size_t i = 0; i < members->dim; i++) + { Dsymbol *s = (*members)[i]; + s->setScope(sc2); + } + for (size_t i = 0; i < members->dim; i++) + { + Dsymbol *s = (*members)[i]; + //printf("\t[%d] semantic on '%s' %p kind %s in '%s'\n", i, s->toChars(), s, s->kind(), this->toChars()); + //printf("test: isnested = %d, sc2->parent = %s\n", isnested, sc2->parent->toChars()); +// if (isnested) +// s->parent = sc->parent; + //printf("test3: isnested = %d, s->parent = %s\n", isnested, s->parent->toChars()); + s->semantic(sc2); + //printf("test4: isnested = %d, s->parent = %s\n", isnested, s->parent->toChars()); + sc2->module->runDeferredSemantic(); + } +} + +void TemplateInstance::tryExpandMembers(Scope *sc2) +{ + static int nest; + // extracted to a function to allow windows SEH to work without destructors in the same function + //printf("%d\n", nest); + if (++nest > 500) + { + global.gag = 0; // ensure error message gets printed + error("recursive expansion"); + fatal(); + } + +#if WINDOWS_SEH + if(nest == 1) + { + // do not catch at every nesting level, because generating the output error might cause more stack + // errors in the __except block otherwise + __try + { + expandMembers(sc2); + } + __except (__ehfilter(GetExceptionInformation())) + { + global.gag = 0; // ensure error message gets printed + error("recursive expansion"); + fatal(); + } + } + else +#endif + expandMembers(sc2); + nest--; +} + +void TemplateInstance::trySemantic3(Scope *sc2) +{ + // extracted to a function to allow windows SEH to work without destructors in the same function + static int nest; + if (++nest > 300) + { + global.gag = 0; // ensure error message gets printed + error("recursive expansion"); + fatal(); + } +#if WINDOWS_SEH + if(nest == 1) + { + // do not catch at every nesting level, because generating the output error might cause more stack + // errors in the __except block otherwise + __try + { + semantic3(sc2); + } + __except (__ehfilter(GetExceptionInformation())) + { + global.gag = 0; // ensure error message gets printed + error("recursive expansion"); + fatal(); + } + } + else +#endif + semantic3(sc2); + + --nest; +} + +void TemplateInstance::semantic(Scope *sc, Expressions *fargs) +{ + //printf("TemplateInstance::semantic('%s', this=%p, gag = %d, sc = %p)\n", toChars(), this, global.gag, sc); +#if LOG + printf("\n+TemplateInstance::semantic('%s', this=%p)\n", toChars(), this); +#endif + if (inst) // if semantic() was already run + { +#if LOG + printf("-TemplateInstance::semantic('%s', this=%p) already run\n", inst->toChars(), inst); +#endif + return; + } + + if (!sc->ignoreTemplates) + ignore = false; + + + // get the enclosing template instance from the scope tinst + tinst = sc->tinst; + + if (semanticRun != PASSinit) + { +#if LOG + printf("Recursive template expansion\n"); +#endif + error(loc, "recursive template expansion"); +// inst = this; + return; + } + semanticRun = PASSsemantic; +#if IN_LLVM + // get the enclosing template instance from the scope tinst + tinst = sc->tinst; + + // get the module of the outermost enclosing instantiation + if (tinst) + tmodule = tinst->tmodule; + else + tmodule = sc->module; + //printf("%s in %s\n", toChars(), tmodule->toChars()); +#endif + +#if LOG + printf("\tdo semantic\n"); +#endif + if (havetempdecl) + { + assert((size_t)tempdecl->scope > 0x10000); + // Deduce tdtypes + tdtypes.setDim(tempdecl->parameters->dim); + if (!tempdecl->matchWithInstance(this, &tdtypes, fargs, 2)) + { + error("incompatible arguments for template instantiation"); + inst = this; + return; + } + } + else + { + /* Find template declaration first. + */ + tempdecl = findTemplateDeclaration(sc); + if (!tempdecl) + { if (!sc->parameterSpecialization) + inst = this; + //printf("error return %p, %d\n", tempdecl, global.errors); + return; // error recovery + } + + /* 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); + if (inst) + ++inst->errors; + return; // error recovery + } + + unsigned errs = global.errors; + tempdecl = findBestMatch(sc, fargs); + if (!tempdecl || (errs != global.errors)) + { if (!sc->parameterSpecialization) + inst = this; + //printf("error return %p, %d\n", tempdecl, global.errors); + return; // error recovery + } + } + + // If tempdecl is a mixin, disallow it + if (tempdecl->ismixin) + error("mixin templates are not regular templates"); + + hasNestedArgs(tiargs); + + /* See if there is an existing TemplateInstantiation that already + * implements the typeargs. If so, just refer to that one instead. + */ + + for (size_t i = 0; i < tempdecl->instances.dim; 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 + assert(tdtypes.dim == ti->tdtypes.dim); + + // Nesting must match + if (isnested != ti->isnested) + { + //printf("test2 isnested %s ti->isnested %s\n", isnested ? isnested->toChars() : "", ti->isnested ? ti->isnested->toChars() : ""); + continue; + } + //printf("parent = %s, ti->parent = %s\n", tempdecl->parent->toPrettyChars(), ti->parent->toPrettyChars()); + + if (!arrayObjectMatch(&tdtypes, &ti->tdtypes, tempdecl, sc)) + goto L1; + + /* Template functions may have different instantiations based on + * "auto ref" parameters. + */ + if (fargs) + { + FuncDeclaration *fd = ti->toAlias()->isFuncDeclaration(); + if (fd) + { + Parameters *fparameters = fd->getParameters(NULL); + size_t nfparams = Parameter::dim(fparameters); // Num function parameters + for (size_t j = 0; j < nfparams && j < fargs->dim; j++) + { Parameter *fparam = Parameter::getNth(fparameters, j); + Expression *farg = (*fargs)[j]; + if (fparam->storageClass & STCauto) // if "auto ref" + { + if (farg->isLvalue()) + { if (!(fparam->storageClass & STCref)) + goto L1; // auto ref's don't match + } + else + { if (fparam->storageClass & STCref) + goto L1; // auto ref's don't match + } + } + } + } + } + + // It's a match + inst = ti; + parent = ti->parent; + + // If both this and the previous instantiation were speculative, + // use the number of errors that happened last time. + if (inst->speculative && global.gag) + { + global.errors += inst->errors; + global.gaggedErrors += inst->errors; + } + + // If the first instantiation was speculative, but this is not: + if (inst->speculative && !global.gag) + { + // If the first instantiation had failed, re-run semantic, + // so that error messages are shown. + if (inst->errors) + goto L1; + // It had succeeded, mark it is a non-speculative instantiation, + // and reuse it. + inst->speculative = 0; + } + +#if LOG + printf("\tit's a match with instance %p, %d\n", inst, inst->semanticRun); +#endif + return; + + L1: + ; + } + + /* So, we need to implement 'this' instance. + */ +#if LOG + printf("\timplement template instance %s '%s'\n", tempdecl->parent->toChars(), toChars()); + printf("\ttempdecl %s\n", tempdecl->toChars()); +#endif + unsigned errorsave = global.errors; + inst = this; + // Mark as speculative if we are instantiated from inside is(typeof()) + if (global.gag && sc->speculative) + speculative = 1; + + int tempdecl_instance_idx = tempdecl->instances.dim; + tempdecl->instances.push(this); + parent = tempdecl->parent; + //printf("parent = '%s'\n", parent->kind()); + + ident = genIdent(tiargs); // need an identifier for name mangling purposes. + +#if 1 + if (isnested) + parent = isnested; +#endif + //printf("parent = '%s'\n", parent->kind()); + + // Add 'this' to the enclosing scope's members[] so the semantic routines + // will get called on the instance members. Store the place we added it to + // in target_symbol_list(_idx) so we can remove it later if we encounter + // an error. +#if 1 + int dosemantic3 = 0; + Dsymbols *target_symbol_list = NULL; + int target_symbol_list_idx; + + if (!sc->parameterSpecialization) + { Dsymbols *a; + + Scope *scx = sc; +#if 0 + for (scx = sc; scx; scx = scx->enclosing) + if (scx->scopesym) + break; +#endif + + //if (scx && scx->scopesym) printf("3: scx is %s %s\n", scx->scopesym->kind(), scx->scopesym->toChars()); + if (scx && scx->scopesym && + scx->scopesym->members && !scx->scopesym->isTemplateMixin() +#if 0 // removed because it bloated compile times + /* The problem is if A imports B, and B imports A, and both A + * and B instantiate the same template, does the compilation of A + * or the compilation of B do the actual instantiation? + * + * see bugzilla 2500. + */ + && !scx->module->selfImports() +#endif + ) + { + //printf("\t1: adding to %s %s\n", scx->scopesym->kind(), scx->scopesym->toChars()); + a = scx->scopesym->members; + } + else + { Module *m = sc->module->importedFrom; + //printf("\t2: adding to module %s instead of module %s\n", m->toChars(), sc->module->toChars()); + a = m->members; + if (m->semanticRun >= 3) + { + dosemantic3 = 1; + } + } + for (int i = 0; 1; i++) + { + if (i == a->dim) + { + target_symbol_list = a; + target_symbol_list_idx = i; + a->push(this); + break; + } + if (this == (*a)[i]) // if already in Array + break; + } + } +#endif + + // Copy the syntax trees from the TemplateDeclaration + members = Dsymbol::arraySyntaxCopy(tempdecl->members); + + // Create our own scope for the template parameters + Scope *scope = tempdecl->scope; + if (!tempdecl->semanticRun) + { + error("template instantiation %s forward references template declaration %s\n", toChars(), tempdecl->toChars()); + return; + } + +#if LOG + printf("\tcreate scope for template parameters '%s'\n", toChars()); +#endif + argsym = new ScopeDsymbol(); + argsym->parent = scope->parent; + scope = scope->push(argsym); +// scope->stc = 0; + + // Declare each template parameter as an alias for the argument type + Scope *paramscope = scope->push(); + paramscope->stc = 0; + declareParameters(paramscope); + paramscope->pop(); + + // Add members of template instance to template instance symbol table +// parent = scope->scopesym; + symtab = new DsymbolTable(); + int memnum = 0; + for (size_t i = 0; i < members->dim; 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 + memnum |= s->addMember(scope, this, memnum); + } +#if LOG + printf("adding members done\n"); +#endif + + /* See if there is only one member of template instance, and that + * member has the same name as the template instance. + * If so, this template instance becomes an alias for that member. + */ + //printf("members->dim = %d\n", members->dim); + if (members->dim) + { + Dsymbol *s; + if (Dsymbol::oneMembers(members, &s, tempdecl->ident) && s) + { + //printf("s->kind = '%s'\n", s->kind()); + //s->print(); + //printf("'%s', '%s'\n", s->ident->toChars(), tempdecl->ident->toChars()); + //printf("setting aliasdecl\n"); + aliasdecl = new AliasDeclaration(loc, s->ident, s); + +#if IN_LLVM + // LDC propagate internal information + if (tempdecl->llvmInternal) { + s->llvmInternal = tempdecl->llvmInternal; + if (FuncDeclaration* fd = s->isFuncDeclaration()) { + fd->intrinsicName = tempdecl->intrinsicName; + } + } +#endif + } + } + + /* If function template declaration + */ + if (fargs && aliasdecl) + { + FuncDeclaration *fd = aliasdecl->toAlias()->isFuncDeclaration(); + if (fd) + { + /* Transmit fargs to type so that TypeFunction::semantic() can + * resolve any "auto ref" storage classes. + */ + TypeFunction *tf = (TypeFunction *)fd->type; + if (tf && tf->ty == Tfunction) + tf->fargs = fargs; + } + } + + // Do semantic() analysis on template instance members +#if LOG + printf("\tdo semantic() on template instance members '%s'\n", toChars()); +#endif + Scope *sc2; + sc2 = scope->push(this); + //printf("isnested = %d, sc->parent = %s\n", isnested, sc->parent->toChars()); + sc2->parent = /*isnested ? sc->parent :*/ this; + sc2->tinst = this; + + tryExpandMembers(sc2); + + semanticRun = PASSsemanticdone; + + /* If any of the instantiation members didn't get semantic() run + * on them due to forward references, we cannot run semantic2() + * or semantic3() yet. + */ + for (size_t i = 0; i < Module::deferred.dim; i++) + { Dsymbol *sd = Module::deferred[i]; + + if (sd->parent == this) + { + //printf("deferred %s %s\n", sd->parent->toChars(), sd->toChars()); + AggregateDeclaration *ad = sd->isAggregateDeclaration(); + if (ad) + ad->deferred = this; + goto Laftersemantic; + } + } + + /* ConditionalDeclaration may introduce eponymous declaration, + * so we should find it once again after semantic. + */ + if (members->dim) + { + Dsymbol *s; + if (Dsymbol::oneMembers(members, &s, tempdecl->ident) && s) + { + if (!aliasdecl || aliasdecl->toAlias() != s) + { + //printf("s->kind = '%s'\n", s->kind()); + //s->print(); + //printf("'%s', '%s'\n", s->ident->toChars(), tempdecl->ident->toChars()); + //printf("setting aliasdecl 2\n"); + aliasdecl = new AliasDeclaration(loc, s->ident, s); + } + } + else if (aliasdecl) + aliasdecl = NULL; + } + + /* The problem is when to parse the initializer for a variable. + * Perhaps VarDeclaration::semantic() should do it like it does + * for initializers inside a function. + */ +// if (sc->parent->isFuncDeclaration()) + + /* BUG 782: this has problems if the classes this depends on + * are forward referenced. Find a way to defer semantic() + * on this template. + */ + semantic2(sc2); + + if (sc->func || dosemantic3) + { + trySemantic3(sc2); + } + + Laftersemantic: + sc2->pop(); + + scope->pop(); + + // Give additional context info if error occurred during instantiation + if (global.errors != errorsave) + { + error(loc, "error instantiating"); + if (tinst) + { tinst->printInstantiationTrace(); + } + errors = 1; + if (global.gag) + { + // Errors are gagged, so remove the template instance from the + // instance/symbol lists we added it to and reset our state to + // finish clean and so we can try to instantiate it again later + // (see bugzilla 4302 and 6602). + tempdecl->instances.remove(tempdecl_instance_idx); + if (target_symbol_list) + { + // 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)[target_symbol_list_idx] == this); + target_symbol_list->remove(target_symbol_list_idx); + } + semanticRun = PASSinit; + inst = NULL; + } + } + +#if LOG + printf("-TemplateInstance::semantic('%s', this=%p)\n", toChars(), this); +#endif +} + + +void TemplateInstance::semanticTiargs(Scope *sc) +{ + //printf("+TemplateInstance::semanticTiargs() %s\n", toChars()); + if (semantictiargsdone) + return; + semantictiargsdone = 1; + semanticTiargs(loc, sc, tiargs, 0); +} + +/********************************** + * Input: + * flags 1: replace const variables with their initializers + */ + +void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int flags) +{ + // Run semantic on each argument, place results in tiargs[] + //printf("+TemplateInstance::semanticTiargs()\n"); + if (!tiargs) + return; + for (size_t j = 0; j < tiargs->dim; j++) + { + Object *o = (*tiargs)[j]; + Type *ta = isType(o); + Expression *ea = isExpression(o); + Dsymbol *sa = isDsymbol(o); + + //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()); + // It might really be an Expression or an Alias + ta->resolve(loc, sc, &ea, &ta, &sa); + if (ea) + { + ea = ea->semantic(sc); + /* This test is to skip substituting a const var with + * its initializer. The problem is the initializer won't + * match with an 'alias' parameter. Instead, do the + * const substitution in TemplateValueParameter::matchArg(). + */ + if (flags & 1) // only used by __traits, must not interpret the args + ea = ea->optimize(WANTvalue); + else if (ea->op != TOKvar) + ea = ea->ctfeInterpret(); + (*tiargs)[j] = ea; + } + else if (sa) + { + Ldsym: + (*tiargs)[j] = sa; + TupleDeclaration *d = sa->toAlias()->isTupleDeclaration(); + if (d) + { + size_t dim = d->objects->dim; + tiargs->remove(j); + tiargs->insert(j, d->objects); + j--; + } + } + else if (ta) + { + Ltype: + if (ta->ty == Ttuple) + { // Expand tuple + TypeTuple *tt = (TypeTuple *)ta; + size_t dim = tt->arguments->dim; + tiargs->remove(j); + if (dim) + { tiargs->reserve(dim); + for (size_t i = 0; i < dim; i++) + { Parameter *arg = (*tt->arguments)[i]; + tiargs->insert(j + i, arg->type); + } + } + j--; + } + else + (*tiargs)[j] = ta; + } + else + { + assert(global.errors); + (*tiargs)[j] = Type::terror; + } + } + else if (ea) + { + if (!ea) + { assert(global.errors); + ea = new ErrorExp(); + } + assert(ea); + ea = ea->semantic(sc); + if (flags & 1) // only used by __traits, must not interpret the args + ea = ea->optimize(WANTvalue); + else if (ea->op != TOKvar && ea->op != TOKtuple && + ea->op != TOKimport && ea->op != TOKtype && + ea->op != TOKfunction && ea->op != TOKerror && + ea->op != TOKthis && ea->op != TOKsuper) + ea = ea->ctfeInterpret(); + (*tiargs)[j] = ea; + if (ea->op == TOKtype) + { ta = ea->type; + goto Ltype; + } + if (ea->op == TOKimport) + { sa = ((ScopeExp *)ea)->sds; + goto Ldsym; + } + if (ea->op == TOKfunction) + { FuncExp *fe = (FuncExp *)ea; + /* A function literal, that is passed to template and + * already semanticed as function pointer, never requires + * outer frame. So convert it to global function is valid. + */ + if (fe->fd->tok == TOKreserved && fe->type->ty == Tpointer) + { // change to non-nested + fe->fd->tok = TOKfunction; + fe->fd->vthis = NULL; + } + } + if (ea->op == TOKtuple) + { // Expand tuple + TupleExp *te = (TupleExp *)ea; + size_t dim = te->exps->dim; + tiargs->remove(j); + if (dim) + { tiargs->reserve(dim); + for (size_t i = 0; i < dim; i++) + tiargs->insert(j + i, (*te->exps)[i]); + } + j--; + } + } + else if (sa) + { + TemplateDeclaration *td = sa->isTemplateDeclaration(); + if (td && !td->semanticRun && td->literal) + td->semantic(sc); + } + else + { + assert(0); + } + //printf("1: (*tiargs)[%d] = %p\n", j, (*tiargs)[j]); + } +#if 0 + printf("-TemplateInstance::semanticTiargs()\n"); + for (size_t j = 0; j < tiargs->dim; j++) + { + Object *o = (*tiargs)[j]; + Type *ta = isType(o); + Expression *ea = isExpression(o); + Dsymbol *sa = isDsymbol(o); + Tuple *va = isTuple(o); + + printf("\ttiargs[%d] = ta %p, ea %p, sa %p, va %p\n", j, ta, ea, sa, va); + } +#endif +} + +/********************************************** + * Find template declaration corresponding to template instance. + */ + +TemplateDeclaration *TemplateInstance::findTemplateDeclaration(Scope *sc) +{ + //printf("TemplateInstance::findTemplateDeclaration() %s\n", toChars()); + if (!tempdecl) + { + /* Given: + * foo!( ... ) + * figure out which TemplateDeclaration foo refers to. + */ + Dsymbol *s; + Dsymbol *scopesym; + Identifier *id; + + id = name; + s = sc->search(loc, id, &scopesym); + if (!s) + { + s = sc->search_correct(id); + if (s) + error("template '%s' is not defined, did you mean %s?", id->toChars(), s->toChars()); + else + error("template '%s' is not defined", id->toChars()); + return NULL; + } + + /* If an OverloadSet, look for a unique member that is a template declaration + */ + OverloadSet *os = s->isOverloadSet(); + if (os) + { s = NULL; + for (size_t i = 0; i < os->a.dim; i++) + { Dsymbol *s2 = os->a[i]; + if (s2->isTemplateDeclaration()) + { + if (s) + error("ambiguous template declaration %s and %s", s->toPrettyChars(), s2->toPrettyChars()); + s = s2; + } + } + if (!s) + { error("template '%s' is not defined", id->toChars()); + return NULL; + } + } + +#if LOG + printf("It's an instance of '%s' kind '%s'\n", s->toChars(), s->kind()); + if (s->parent) + printf("s->parent = '%s'\n", s->parent->toChars()); +#endif + withsym = scopesym->isWithScopeSymbol(); + + /* We might have found an alias within a template when + * we really want the template. + */ + TemplateInstance *ti; + if (s->parent && + (ti = s->parent->isTemplateInstance()) != NULL) + { + if (ti->tempdecl && ti->tempdecl->ident == id) + { + /* This is so that one can refer to the enclosing + * template, even if it has the same name as a member + * of the template, if it has a !(arguments) + */ + tempdecl = ti->tempdecl; + if (tempdecl->overroot) // if not start of overloaded list of TemplateDeclaration's + tempdecl = tempdecl->overroot; // then get the start + s = tempdecl; + } + } + + s = s->toAlias(); + + /* It should be a TemplateDeclaration, not some other symbol + */ + tempdecl = s->isTemplateDeclaration(); + if (!tempdecl) + { + if (!s->parent && global.errors) + return NULL; + if (!s->parent && s->getType()) + { Dsymbol *s2 = s->getType()->toDsymbol(sc); + if (!s2) + { + error("%s is not a template declaration, it is a %s", id->toChars(), s->kind()); + return NULL; + } + s = s2; + } +#ifdef DEBUG + //if (!s->parent) printf("s = %s %s\n", s->kind(), s->toChars()); +#endif + //assert(s->parent); + TemplateInstance *ti = s->parent ? s->parent->isTemplateInstance() : NULL; + if (ti && + (ti->name == id || + ti->toAlias()->ident == id) + && + ti->tempdecl) + { + /* This is so that one can refer to the enclosing + * template, even if it has the same name as a member + * of the template, if it has a !(arguments) + */ + tempdecl = ti->tempdecl; + if (tempdecl->overroot) // if not start of overloaded list of TemplateDeclaration's + tempdecl = tempdecl->overroot; // then get the start + } + else + { + error("%s is not a template declaration, it is a %s", id->toChars(), s->kind()); + return NULL; + } + } + } + else + assert(tempdecl->isTemplateDeclaration()); + return tempdecl; +} + +TemplateDeclaration *TemplateInstance::findBestMatch(Scope *sc, Expressions *fargs) +{ + /* Since there can be multiple TemplateDeclaration's with the same + * name, look for the best match. + */ + TemplateDeclaration *td_ambig = NULL; + TemplateDeclaration *td_best = NULL; + MATCH m_best = MATCHnomatch; + Objects dedtypes; + +#if LOG + printf("TemplateInstance::findBestMatch()\n"); +#endif + // First look for forward references + for (TemplateDeclaration *td = tempdecl; td; td = td->overnext) + { + if (!td->semanticRun) + { + if (td->scope) + { // Try to fix forward reference + td->semantic(td->scope); + } + if (!td->semanticRun) + { + error("%s forward references template declaration %s\n", toChars(), td->toChars()); + return NULL; + } + } + } + + for (TemplateDeclaration *td = tempdecl; td; td = td->overnext) + { + MATCH m; + +//if (tiargs->dim) printf("2: tiargs->dim = %d, data[0] = %p\n", tiargs->dim, (*tiargs)[0]); + + // If more arguments than parameters, + // then this is no match. + if (td->parameters->dim < tiargs->dim) + { + if (!td->isVariadic()) + continue; + } + + dedtypes.setDim(td->parameters->dim); + dedtypes.zero(); + assert(td->semanticRun); + m = td->matchWithInstance(this, &dedtypes, fargs, 0); + //printf("matchWithInstance = %d\n", m); + if (!m) // no match at all + continue; + + if (m < m_best) + goto Ltd_best; + if (m > m_best) + goto Ltd; + + { + // Disambiguate by picking the most specialized TemplateDeclaration + MATCH c1 = td->leastAsSpecialized(td_best, fargs); + MATCH c2 = td_best->leastAsSpecialized(td, fargs); + //printf("c1 = %d, c2 = %d\n", c1, c2); + + if (c1 > c2) + goto Ltd; + else if (c1 < c2) + goto Ltd_best; + else + goto Lambig; + } + + Lambig: // td_best and td are ambiguous + td_ambig = td; + continue; + + Ltd_best: // td_best is the best match so far + td_ambig = NULL; + continue; + + Ltd: // td is the new best match + td_ambig = NULL; + td_best = td; + m_best = m; + tdtypes.setDim(dedtypes.dim); + memcpy(tdtypes.tdata(), dedtypes.tdata(), tdtypes.dim * sizeof(void *)); + continue; + } + + if (!td_best) + { + if (tempdecl && !tempdecl->overnext) + // Only one template, so we can give better error message + error("%s does not match template declaration %s", toChars(), tempdecl->toChars()); + else + ::error(loc, "%s %s.%s does not match any template declaration", + tempdecl->kind(), tempdecl->parent->toPrettyChars(), tempdecl->ident->toChars()); + return NULL; + } + if (td_ambig) + { + ::error(loc, "%s %s.%s matches more than one template declaration, %s(%d):%s and %s(%d):%s", + td_best->kind(), td_best->parent->toPrettyChars(), td_best->ident->toChars(), + td_best->loc.filename, td_best->loc.linnum, td_best->toChars(), + td_ambig->loc.filename, td_ambig->loc.linnum, td_ambig->toChars()); + } + + /* The best match is td_best + */ + tempdecl = td_best; + +#if 0 + /* Cast any value arguments to be same type as value parameter + */ + for (size_t i = 0; i < tiargs->dim; i++) + { Object *o = (*tiargs)[i]; + Expression *ea = isExpression(o); // value argument + TemplateParameter *tp = (*tempdecl->parameters)[i]; + assert(tp); + TemplateValueParameter *tvp = tp->isTemplateValueParameter(); + if (tvp) + { + assert(ea); + ea = ea->castTo(tvp->valType); + ea = ea->ctfeInterpret(); + (*tiargs)[i] = (Object *)ea; + } + } +#endif + +#if LOG + printf("\tIt's a match with template declaration '%s'\n", tempdecl->toChars()); +#endif + return tempdecl; +} + + +/***************************************** + * Determines if a TemplateInstance will need a nested + * generation of the TemplateDeclaration. + */ + +int TemplateInstance::hasNestedArgs(Objects *args) +{ int nested = 0; + //printf("TemplateInstance::hasNestedArgs('%s')\n", tempdecl->ident->toChars()); + + /* A nested instance happens when an argument references a local + * symbol that is on the stack. + */ + for (size_t i = 0; i < args->dim; i++) + { Object *o = (*args)[i]; + Expression *ea = isExpression(o); + Dsymbol *sa = isDsymbol(o); + Tuple *va = isTuple(o); + if (ea) + { + if (ea->op == TOKvar) + { + sa = ((VarExp *)ea)->var; + goto Lsa; + } + if (ea->op == TOKthis) + { + sa = ((ThisExp *)ea)->var; + goto Lsa; + } + if (ea->op == TOKfunction) + { + if (((FuncExp *)ea)->td) + sa = ((FuncExp *)ea)->td; + else + sa = ((FuncExp *)ea)->fd; + goto Lsa; + } + } + else if (sa) + { + Lsa: + TemplateDeclaration *td = sa->isTemplateDeclaration(); + Declaration *d = sa->isDeclaration(); + if ((td && td->literal) || + (d && !d->isDataseg() && +#if DMDV2 + !(d->storage_class & STCmanifest) && +#endif + (!d->isFuncDeclaration() || d->isFuncDeclaration()->isNested()) && + !isTemplateMixin() + )) + { + // if module level template + if (tempdecl->toParent()->isModule()) + { Dsymbol *dparent = sa->toParent(); + if (!isnested) + isnested = dparent; + else if (isnested != dparent) + { + /* Select the more deeply nested of the two. + * Error if one is not nested inside the other. + */ + for (Dsymbol *p = isnested; p; p = p->parent) + { + if (p == dparent) + goto L1; // isnested is most nested + } + for (Dsymbol *p = dparent; p; p = p->parent) + { + if (p == isnested) + { isnested = dparent; + goto L1; // dparent is most nested + } + } + error("%s is nested in both %s and %s", + toChars(), isnested->toChars(), dparent->toChars()); + } + L1: + //printf("\tnested inside %s\n", isnested->toChars()); + nested |= 1; + } + else + error("cannot use local '%s' as parameter to non-global template %s", sa->toChars(), tempdecl->toChars()); + } + } + else if (va) + { + nested |= hasNestedArgs(&va->objects); + } + } + return nested; +} + +/**************************************** + * This instance needs an identifier for name mangling purposes. + * Create one by taking the template declaration name and adding + * the type signature for it. + */ + +Identifier *TemplateInstance::genIdent(Objects *args) +{ OutBuffer buf; + + //printf("TemplateInstance::genIdent('%s')\n", tempdecl->ident->toChars()); + char *id = tempdecl->ident->toChars(); + buf.printf("__T%llu%s", (ulonglong)strlen(id), id); + for (size_t i = 0; i < args->dim; i++) + { Object *o = (*args)[i]; + Type *ta = isType(o); + Expression *ea = isExpression(o); + Dsymbol *sa = isDsymbol(o); + Tuple *va = isTuple(o); + //printf("\to [%d] %p ta %p ea %p sa %p va %p\n", i, o, ta, ea, sa, va); + if (ta) + { + buf.writeByte('T'); + if (ta->deco) + buf.writestring(ta->deco); + else + { +#ifdef DEBUG + if (!global.errors) + printf("ta = %d, %s\n", ta->ty, ta->toChars()); +#endif + assert(global.errors); + } + } + else if (ea) + { + // Don't interpret it yet, it might actually be an alias + ea = ea->optimize(WANTvalue); + if (ea->op == TOKvar) + { + sa = ((VarExp *)ea)->var; + ea = NULL; + goto Lsa; + } + if (ea->op == TOKthis) + { + sa = ((ThisExp *)ea)->var; + ea = NULL; + goto Lsa; + } + if (ea->op == TOKfunction) + { + if (((FuncExp *)ea)->td) + sa = ((FuncExp *)ea)->td; + else + sa = ((FuncExp *)ea)->fd; + ea = NULL; + goto Lsa; + } + buf.writeByte('V'); + if (ea->op == TOKtuple) + { ea->error("tuple is not a valid template value argument"); + continue; + } + // Now that we know it is not an alias, we MUST obtain a value + unsigned olderr = global.errors; + ea = ea->ctfeInterpret(); + if (ea->op == TOKerror || olderr != global.errors) + continue; +#if 1 + /* Use deco that matches what it would be for a function parameter + */ + buf.writestring(ea->type->deco); +#else + // Use type of parameter, not type of argument + TemplateParameter *tp = (*tempdecl->parameters)[i]; + assert(tp); + TemplateValueParameter *tvp = tp->isTemplateValueParameter(); + assert(tvp); + buf.writestring(tvp->valType->deco); +#endif + ea->toMangleBuffer(&buf); + } + else if (sa) + { + Lsa: + buf.writeByte('S'); + Declaration *d = sa->isDeclaration(); + if (d && (!d->type || !d->type->deco)) + { error("forward reference of %s", d->toChars()); + continue; + } +#if 0 + VarDeclaration *v = sa->isVarDeclaration(); + if (v && v->storage_class & STCmanifest) + { ExpInitializer *ei = v->init->isExpInitializer(); + if (ei) + { + ea = ei->exp; + goto Lea; + } + } +#endif + const char *p = sa->mangle(); + + /* Bugzilla 3043: if the first character of p is a digit this + * causes ambiguity issues because the digits of the two numbers are adjacent. + * Current demanglers resolve this by trying various places to separate the + * numbers until one gets a successful demangle. + * Unfortunately, fixing this ambiguity will break existing binary + * compatibility and the demanglers, so we'll leave it as is. + */ + buf.printf("%llu%s", (ulonglong)strlen(p), p); + } + else if (va) + { + assert(i + 1 == args->dim); // must be last one + args = &va->objects; + i = -1; + } + else + assert(0); + } + buf.writeByte('Z'); + id = buf.toChars(); + //buf.data = NULL; // we can free the string after call to idPool() + //printf("\tgenIdent = %s\n", id); + return Lexer::idPool(id); +} + + +/**************************************************** + * Declare parameters of template instance, initialize them with the + * template instance arguments. + */ + +void TemplateInstance::declareParameters(Scope *sc) +{ + //printf("TemplateInstance::declareParameters()\n"); + for (size_t i = 0; i < tdtypes.dim; i++) + { + TemplateParameter *tp = (*tempdecl->parameters)[i]; + //Object *o = (*tiargs)[i]; + Object *o = tdtypes[i]; // initializer for tp + + //printf("\ttdtypes[%d] = %p\n", i, o); + tempdecl->declareParameter(sc, tp, o); + } +} + +/***************************************************** + * Determine if template instance is really a template function, + * and that template function needs to infer types from the function + * arguments. + */ + +int TemplateInstance::needsTypeInference(Scope *sc) +{ + //printf("TemplateInstance::needsTypeInference() %s\n", toChars()); + if (!tempdecl) + tempdecl = findTemplateDeclaration(sc); + int multipleMatches = FALSE; + for (TemplateDeclaration *td = tempdecl; td; td = td->overnext) + { + /* If any of the overloaded template declarations need inference, + * then return TRUE + */ + FuncDeclaration *fd; + if (!td->onemember || + (fd = td->onemember->toAlias()->isFuncDeclaration()) == NULL || + fd->type->ty != Tfunction) + { + /* Not a template function, therefore type inference is not possible. + */ + //printf("false\n"); + return FALSE; + } + + for (size_t i = 0; i < td->parameters->dim; i++) + if ((*td->parameters)[i]->isTemplateThisParameter()) + return TRUE; + + /* Determine if the instance arguments, tiargs, are all that is necessary + * to instantiate the template. + */ + //printf("tp = %p, td->parameters->dim = %d, tiargs->dim = %d\n", tp, td->parameters->dim, tiargs->dim); + TypeFunction *fdtype = (TypeFunction *)fd->type; + if (Parameter::dim(fdtype->parameters)) + { + TemplateParameter *tp = td->isVariadic(); + if (tp && td->parameters->dim > 1) + return TRUE; + + if (tiargs->dim < td->parameters->dim) + { // Can remain tiargs be filled by default arguments? + for (size_t i = tiargs->dim; i < td->parameters->dim; i++) + { tp = (*td->parameters)[i]; + if (TemplateTypeParameter *ttp = tp->isTemplateTypeParameter()) + { if (!ttp->defaultType) + return TRUE; + } + else if (TemplateAliasParameter *tap = tp->isTemplateAliasParameter()) + { if (!tap->defaultAlias) + return TRUE; + } + else if (TemplateValueParameter *tvp = tp->isTemplateValueParameter()) + { if (!tvp->defaultValue) + return TRUE; + } + } + } + } + /* If there is more than one function template which matches, we may + * need type inference (see Bugzilla 4430) + */ + if (td != tempdecl) + multipleMatches = TRUE; + } + //printf("false\n"); + return multipleMatches; +} + +void TemplateInstance::semantic2(Scope *sc) +{ int i; + + if (semanticRun >= PASSsemantic2) + return; + semanticRun = PASSsemantic2; +#if LOG + printf("+TemplateInstance::semantic2('%s')\n", toChars()); +#endif + if (!errors && members) + { + sc = tempdecl->scope; + assert(sc); + sc = sc->push(argsym); + sc = sc->push(this); + sc->tinst = this; + for (i = 0; i < members->dim; i++) + { + Dsymbol *s = (*members)[i]; +#if LOG +printf("\tmember '%s', kind = '%s'\n", s->toChars(), s->kind()); +#endif + s->semantic2(sc); + } + sc = sc->pop(); + sc->pop(); + } +#if LOG + printf("-TemplateInstance::semantic2('%s')\n", toChars()); +#endif +} + +void TemplateInstance::semantic3(Scope *sc) +{ +#if LOG + printf("TemplateInstance::semantic3('%s'), semanticRun = %d\n", toChars(), semanticRun); +#endif +//if (toChars()[0] == 'D') *(char*)0=0; + if (semanticRun >= PASSsemantic3) + return; + semanticRun = PASSsemantic3; + if (!errors && members) + { + sc = tempdecl->scope; + sc = sc->push(argsym); + sc = sc->push(this); + sc->tinst = this; + if (ignore) + sc->ignoreTemplates++; + int oldgag = global.gag; + int olderrors = global.errors; + /* If this is a speculative instantiation, gag errors. + * Future optimisation: If the results are actually needed, errors + * would already be gagged, so we don't really need to run semantic + * on the members. + */ + if (speculative && !oldgag) + olderrors = global.startGagging(); + for (size_t i = 0; i < members->dim; i++) + { + Dsymbol *s = (*members)[i]; + s->semantic3(sc); + if (speculative && global.errors != olderrors) + break; + } + if (speculative && !oldgag) + { // If errors occurred, this instantiation failed + errors += global.errors - olderrors; + global.endGagging(olderrors); + } + sc = sc->pop(); + sc->pop(); + } +} + +#if IN_DMD + +/************************************** + * Given an error instantiating the TemplateInstance, + * give the nested TemplateInstance instantiations that got + * us here. Those are a list threaded into the nested scopes. + */ +void TemplateInstance::printInstantiationTrace() +{ + if (global.gag) + return; + + const unsigned max_shown = 6; + const char format[] = "instantiated from here: %s"; + + // determine instantiation depth and number of recursive instantiations + int n_instantiations = 1; + int n_totalrecursions = 0; + for (TemplateInstance *cur = this; cur; cur = cur->tinst) + { + ++n_instantiations; + // If two instantiations use the same declaration, they are recursive. + // (this works even if they are instantiated from different places in the + // same template). + // In principle, we could also check for multiple-template recursion, but it's + // probably not worthwhile. + if (cur->tinst && cur->tempdecl && cur->tinst->tempdecl + && cur->tempdecl->loc.equals(cur->tinst->tempdecl->loc)) + ++n_totalrecursions; + } + + // show full trace only if it's short or verbose is on + if (n_instantiations <= max_shown || global.params.verbose) + { + for (TemplateInstance *cur = this; cur; cur = cur->tinst) + { + errorSupplemental(cur->loc, format, cur->toChars()); + } + } + else if (n_instantiations - n_totalrecursions <= max_shown) + { + // By collapsing recursive instantiations into a single line, + // we can stay under the limit. + int recursionDepth=0; + for (TemplateInstance *cur = this; cur; cur = cur->tinst) + { + if (cur->tinst && cur->tempdecl && cur->tinst->tempdecl + && cur->tempdecl->loc.equals(cur->tinst->tempdecl->loc)) + { + ++recursionDepth; + } + else + { + if (recursionDepth) + errorSupplemental(cur->loc, "%d recursive instantiations from here: %s", recursionDepth+2, cur->toChars()); + else + errorSupplemental(cur->loc, format, cur->toChars()); + recursionDepth = 0; + } + } + } + else + { + // Even after collapsing the recursions, the depth is too deep. + // Just display the first few and last few instantiations. + unsigned i = 0; + for (TemplateInstance *cur = this; cur; cur = cur->tinst) + { + if (i == max_shown / 2) + errorSupplemental(cur->loc, "... (%d instantiations, -v to show) ...", n_instantiations - max_shown); + + if (i < max_shown / 2 || + i >= n_instantiations - max_shown + max_shown / 2) + errorSupplemental(cur->loc, format, cur->toChars()); + ++i; + } + } +} + +void TemplateInstance::toObjFile(int multiobj) +{ +#if LOG + printf("TemplateInstance::toObjFile('%s', this = %p)\n", toChars(), this); +#endif + if (!errors && members) + { + if (multiobj) + // Append to list of object files to be written later + obj_append(this); + else + { + for (size_t i = 0; i < members->dim; i++) + { + Dsymbol *s = (*members)[i]; + s->toObjFile(multiobj); + } + } + } +} + +#endif + +void TemplateInstance::inlineScan() +{ +#if LOG + printf("TemplateInstance::inlineScan('%s')\n", toChars()); +#endif + if (!errors && members) + { + for (size_t i = 0; i < members->dim; i++) + { + Dsymbol *s = (*members)[i]; + s->inlineScan(); + } + } +} + +void TemplateInstance::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + int i; + + Identifier *id = name; + buf->writestring(id->toChars()); + buf->writestring("!("); + if (nest) + buf->writestring("..."); + else + { + nest++; + Objects *args = tiargs; + for (i = 0; i < args->dim; i++) + { + if (i) + buf->writeByte(','); + Object *oarg = (*args)[i]; + ObjectToCBuffer(buf, hgs, oarg); + } + nest--; + } + buf->writeByte(')'); +} + + +Dsymbol *TemplateInstance::toAlias() +{ +#if LOG + printf("TemplateInstance::toAlias()\n"); +#endif + if (!inst) + { + // Maybe we can resolve it + if (scope) + { + /* Anything that affects scope->offset must be + * done in lexical order. Fwd ref error if it is affected, otherwise allow. + */ + unsigned offset = scope->offset; + Scope *sc = scope; + semantic(scope); +// if (offset != sc->offset) +// inst = NULL; // trigger fwd ref error + } + if (!inst) + { error("cannot resolve forward reference"); + errors = 1; + return this; + } + } + + if (inst != this) + return inst->toAlias(); + + if (aliasdecl) + { + return aliasdecl->toAlias(); + } + + return inst; +} + +AliasDeclaration *TemplateInstance::isAliasDeclaration() +{ + return aliasdecl; +} + +const char *TemplateInstance::kind() +{ + return "template instance"; +} + +int TemplateInstance::oneMember(Dsymbol **ps, Identifier *ident) +{ + *ps = NULL; + return TRUE; +} + +char *TemplateInstance::toChars() +{ + OutBuffer buf; + HdrGenState hgs; + char *s; + + toCBuffer(&buf, &hgs); + s = buf.toChars(); + buf.data = NULL; + return s; +} + +#if IN_LLVM + +void TemplateInstance::printInstantiationTrace() +{ + if(global.gag) + return; + + const int max_shown = 6; + + // determine instantiation depth + int n_instantiations = 1; + TemplateInstance* cur = this; + while(cur = cur->tinst) + ++n_instantiations; + + // show full trace only if it's short or verbose is on + if(n_instantiations <= max_shown || global.params.verbose) + { + cur = this; + while(cur) + { + fprintf(stdmsg," instantiatied in %s: %s\n", cur->loc.toChars(), cur->toChars()); + cur = cur->tinst; + } + } + else + { + cur = this; + size_t i = 0; + for(; i < max_shown/2; ++i, cur = cur->tinst) + fprintf(stdmsg," instantiatied in %s: %s\n", cur->loc.toChars(), cur->toChars()); + fprintf(stdmsg," ... (%d instantiations, -v to show) ...\n", n_instantiations - max_shown); + for(; i < n_instantiations - max_shown + max_shown/2; ++i, cur = cur->tinst) + {} + for(; i < n_instantiations; ++i, cur = cur->tinst) + fprintf(stdmsg," instantiatied in %s: %s\n", cur->loc.toChars(), cur->toChars()); + } +} + +#endif + +/* ======================== TemplateMixin ================================ */ + +TemplateMixin::TemplateMixin(Loc loc, Identifier *ident, Type *tqual, + Identifiers *idents, Objects *tiargs) + : TemplateInstance(loc, (*idents)[idents->dim - 1]) +{ + //printf("TemplateMixin(ident = '%s')\n", ident ? ident->toChars() : ""); + this->ident = ident; + this->tqual = tqual; + this->idents = idents; + this->tiargs = tiargs ? tiargs : new Objects(); +} + +Dsymbol *TemplateMixin::syntaxCopy(Dsymbol *s) +{ TemplateMixin *tm; + + Identifiers *ids = new Identifiers(); + ids->setDim(idents->dim); + for (size_t i = 0; i < idents->dim; i++) + { // Matches TypeQualified::syntaxCopyHelper() + Identifier *id = (*idents)[i]; + if (id->dyncast() == DYNCAST_DSYMBOL) + { + TemplateInstance *ti = (TemplateInstance *)id; + + ti = (TemplateInstance *)ti->syntaxCopy(NULL); + id = (Identifier *)ti; + } + (*ids)[i] = id; + } + + tm = new TemplateMixin(loc, ident, + (Type *)(tqual ? tqual->syntaxCopy() : NULL), + ids, tiargs); + TemplateInstance::syntaxCopy(tm); + return tm; +} + +void TemplateMixin::semantic(Scope *sc) +{ +#if LOG + printf("+TemplateMixin::semantic('%s', this=%p)\n", toChars(), this); + fflush(stdout); +#endif + if (semanticRun) + { + // This for when a class/struct contains mixin members, and + // is done over because of forward references + if (parent && toParent()->isAggregateDeclaration()) + semanticRun = PASSsemantic; // do over + else + { +#if LOG + printf("\tsemantic done\n"); +#endif + return; + } + } + if (!semanticRun) + semanticRun = PASSsemantic; +#if LOG + printf("\tdo semantic\n"); +#endif + +#if !IN_LLVM && !IN_GCC + // dont know what this is + util_progress(); +#endif + + Scope *scx = NULL; + if (scope) + { sc = scope; + scx = scope; // save so we don't make redundant copies + scope = NULL; + } + + // Follow qualifications to find the TemplateDeclaration + if (!tempdecl) + { Dsymbol *s; + size_t i; + Identifier *id; + + if (tqual) + { s = tqual->toDsymbol(sc); + i = 0; + } + else + { + i = 1; + id = (*idents)[0]; + switch (id->dyncast()) + { + case DYNCAST_IDENTIFIER: + s = sc->search(loc, id, NULL); + break; + + case DYNCAST_DSYMBOL: + { + TemplateInstance *ti = (TemplateInstance *)id; + ti->semantic(sc); + s = ti; + break; + } + default: + assert(0); + } + } + + for (; i < idents->dim; i++) + { + if (!s) + break; + id = (*idents)[i]; + s = s->searchX(loc, sc, id); + } + if (!s) + { + error("is not defined"); + inst = this; + return; + } + tempdecl = s->toAlias()->isTemplateDeclaration(); + if (!tempdecl) + { + error("%s isn't a template", s->toChars()); + inst = this; + return; + } + } + + // Look for forward reference + assert(tempdecl); + for (TemplateDeclaration *td = tempdecl; td; td = td->overnext) + { + if (!td->semanticRun) + { + /* Cannot handle forward references if mixin is a struct member, + * because addField must happen during struct's semantic, not + * during the mixin semantic. + * runDeferred will re-run mixin's semantic outside of the struct's + * semantic. + */ + semanticRun = PASSinit; + AggregateDeclaration *ad = toParent()->isAggregateDeclaration(); + if (ad) + ad->sizeok = SIZEOKfwd; + else + { + // Forward reference + //printf("forward reference - deferring\n"); + scope = scx ? scx : new Scope(*sc); + scope->setNoFree(); + scope->module->addDeferredSemantic(this); + } + return; + } + } + + // Run semantic on each argument, place results in tiargs[] + semanticTiargs(sc); + if (errors || arrayObjectIsError(tiargs)) + return; + + tempdecl = findBestMatch(sc, NULL); + if (!tempdecl) + { inst = this; + return; // error recovery + } + + if (!ident) + ident = genIdent(tiargs); + + inst = this; + parent = sc->parent; + + /* Detect recursive mixin instantiations. + */ + for (Dsymbol *s = parent; s; s = s->parent) + { + //printf("\ts = '%s'\n", s->toChars()); + TemplateMixin *tm = s->isTemplateMixin(); + if (!tm || tempdecl != tm->tempdecl) + continue; + + /* Different argument list lengths happen with variadic args + */ + if (tiargs->dim != tm->tiargs->dim) + continue; + + for (size_t i = 0; i < tiargs->dim; i++) + { Object *o = (*tiargs)[i]; + Type *ta = isType(o); + Expression *ea = isExpression(o); + Dsymbol *sa = isDsymbol(o); + Object *tmo = (*tm->tiargs)[i]; + if (ta) + { + Type *tmta = isType(tmo); + if (!tmta) + goto Lcontinue; + if (!ta->equals(tmta)) + goto Lcontinue; + } + else if (ea) + { Expression *tme = isExpression(tmo); + if (!tme || !ea->equals(tme)) + goto Lcontinue; + } + else if (sa) + { + Dsymbol *tmsa = isDsymbol(tmo); + if (sa != tmsa) + goto Lcontinue; + } + else + assert(0); + } + error("recursive mixin instantiation"); + return; + + Lcontinue: + continue; + } + + // Copy the syntax trees from the TemplateDeclaration + members = Dsymbol::arraySyntaxCopy(tempdecl->members); + if (!members) + return; + + symtab = new DsymbolTable(); + + for (Scope *sce = sc; 1; sce = sce->enclosing) + { + ScopeDsymbol *sds = (ScopeDsymbol *)sce->scopesym; + if (sds) + { + sds->importScope(this, PROTpublic); + break; + } + } + +#if LOG + printf("\tcreate scope for template parameters '%s'\n", toChars()); +#endif + Scope *scy = sc; + scy = sc->push(this); + scy->parent = this; + + argsym = new ScopeDsymbol(); + argsym->parent = scy->parent; + Scope *argscope = scy->push(argsym); + + unsigned errorsave = global.errors; + + // Declare each template parameter as an alias for the argument type + declareParameters(argscope); + + // Add members to enclosing scope, as well as this scope + for (size_t i = 0; i < members->dim; i++) + { Dsymbol *s = (*members)[i]; + s->addMember(argscope, this, i); + //sc->insert(s); + //printf("sc->parent = %p, sc->scopesym = %p\n", sc->parent, sc->scopesym); + //printf("s->parent = %s\n", s->parent->toChars()); + } + + // Do semantic() analysis on template instance members +#if LOG + printf("\tdo semantic() on template instance members '%s'\n", toChars()); +#endif + Scope *sc2; + sc2 = argscope->push(this); + sc2->offset = sc->offset; + + static int nest; + //printf("%d\n", nest); + if (++nest > 500) + { + global.gag = 0; // ensure error message gets printed + error("recursive expansion"); + fatal(); + } + + for (size_t i = 0; i < members->dim; i++) + { + Dsymbol *s = (*members)[i]; + s->semantic(sc2); + } + + nest--; + + sc->offset = sc2->offset; + + /* The problem is when to parse the initializer for a variable. + * Perhaps VarDeclaration::semantic() should do it like it does + * for initializers inside a function. + */ +// if (sc->parent->isFuncDeclaration()) + + semantic2(sc2); + + if (sc->func) + { + semantic3(sc2); + } + + // Give additional context info if error occurred during instantiation + if (global.errors != errorsave) + { + error("error instantiating"); + } + + sc2->pop(); + + argscope->pop(); + +// if (!isAnonymous()) + { + scy->pop(); + } +#if LOG + printf("-TemplateMixin::semantic('%s', this=%p)\n", toChars(), this); +#endif +} + +void TemplateMixin::semantic2(Scope *sc) +{ + if (semanticRun >= PASSsemantic2) + return; + semanticRun = PASSsemantic2; +#if LOG + printf("+TemplateMixin::semantic2('%s')\n", toChars()); +#endif + if (members) + { + assert(sc); + sc = sc->push(argsym); + sc = sc->push(this); + for (size_t i = 0; i < members->dim; i++) + { + Dsymbol *s = (*members)[i]; +#if LOG + printf("\tmember '%s', kind = '%s'\n", s->toChars(), s->kind()); +#endif + s->semantic2(sc); + } + sc = sc->pop(); + sc->pop(); + } +#if LOG + printf("-TemplateMixin::semantic2('%s')\n", toChars()); +#endif +} + +void TemplateMixin::semantic3(Scope *sc) +{ + if (semanticRun >= PASSsemantic3) + return; + semanticRun = PASSsemantic3; +#if LOG + printf("TemplateMixin::semantic3('%s')\n", toChars()); +#endif + if (members) + { + sc = sc->push(argsym); + sc = sc->push(this); + for (size_t i = 0; i < members->dim; i++) + { + Dsymbol *s = (*members)[i]; + s->semantic3(sc); + } + sc = sc->pop(); + sc->pop(); + } +} + +void TemplateMixin::inlineScan() +{ + TemplateInstance::inlineScan(); +} + +const char *TemplateMixin::kind() +{ + return "mixin"; +} + +int TemplateMixin::oneMember(Dsymbol **ps, Identifier *ident) +{ + return Dsymbol::oneMember(ps, ident); +} + +int TemplateMixin::apply(Dsymbol_apply_ft_t fp, void *param) +{ + if (members) + { + for (size_t i = 0; i < members->dim; i++) + { Dsymbol *s = (*members)[i]; + if (s) + { + if (s->apply(fp, param)) + return 1; + } + } + } + return 0; +} + +int TemplateMixin::hasPointers() +{ + //printf("TemplateMixin::hasPointers() %s\n", toChars()); + + if (members) + for (size_t i = 0; i < members->dim; i++) + { + Dsymbol *s = (*members)[i]; + //printf(" s = %s %s\n", s->kind(), s->toChars()); + if (s->hasPointers()) + { + return 1; + } + } + return 0; +} + +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); + } + } +} + +char *TemplateMixin::toChars() +{ + OutBuffer buf; + HdrGenState hgs; + char *s; + + TemplateInstance::toCBuffer(&buf, &hgs); + s = buf.toChars(); + buf.data = NULL; + return s; +} + +void TemplateMixin::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("mixin "); + + for (size_t i = 0; i < idents->dim; i++) + { Identifier *id = (*idents)[i]; + + if (i) + buf->writeByte('.'); + buf->writestring(id->toChars()); + } + buf->writestring("!("); + if (tiargs) + { + for (size_t i = 0; i < tiargs->dim; i++) + { if (i) + buf->writebyte(','); + Object *oarg = (*tiargs)[i]; + Type *t = isType(oarg); + Expression *e = isExpression(oarg); + Dsymbol *s = isDsymbol(oarg); + if (t) + t->toCBuffer(buf, NULL, hgs); + else if (e) + e->toCBuffer(buf, hgs); + else if (s) + { + char *p = s->ident ? s->ident->toChars() : s->toChars(); + buf->writestring(p); + } + else if (!oarg) + { + buf->writestring("NULL"); + } + else + { + assert(0); + } + } + } + buf->writebyte(')'); + if (ident) + { + buf->writebyte(' '); + buf->writestring(ident->toChars()); + } + buf->writebyte(';'); + buf->writenl(); +} + + +#if IN_DMD +void TemplateMixin::toObjFile(int multiobj) +{ + //printf("TemplateMixin::toObjFile('%s')\n", toChars()); + TemplateInstance::toObjFile(multiobj); +} +#endif + diff --git a/dmd2/total.h b/dmd2/total.h index 1a0c9a89..42f38765 100644 --- a/dmd2/total.h +++ b/dmd2/total.h @@ -1,46 +1,46 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2006 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_TOTAL_H -#define DMD_TOTAL_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include -#include -#include -#include -#include - -#include "root.h" -#include "stringtable.h" - -#include "arraytypes.h" -#include "mars.h" -#include "lexer.h" -#include "parse.h" -#include "identifier.h" -#include "enum.h" -#include "aggregate.h" -#include "mtype.h" -#include "expression.h" -#include "declaration.h" -#include "statement.h" -#include "scope.h" -#include "import.h" -#include "module.h" -#include "id.h" -#include "cond.h" -#include "version.h" -#include "lib.h" - -#endif /* DMD_TOTAL_H */ + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2006 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#ifndef DMD_TOTAL_H +#define DMD_TOTAL_H + +#ifdef __DMC__ +#pragma once +#endif /* __DMC__ */ + +#include +#include +#include +#include +#include + +#include "root.h" +#include "stringtable.h" + +#include "arraytypes.h" +#include "mars.h" +#include "lexer.h" +#include "parse.h" +#include "identifier.h" +#include "enum.h" +#include "aggregate.h" +#include "mtype.h" +#include "expression.h" +#include "declaration.h" +#include "statement.h" +#include "scope.h" +#include "import.h" +#include "module.h" +#include "id.h" +#include "cond.h" +#include "version.h" +#include "lib.h" + +#endif /* DMD_TOTAL_H */ diff --git a/dmd2/traits.c b/dmd2/traits.c index 68f7b2a1..7a678920 100644 --- a/dmd2/traits.c +++ b/dmd2/traits.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 @@ -89,7 +89,7 @@ Expression *TraitsExp::semantic(Scope *sc) #define ISTYPE(cond) \ for (size_t i = 0; i < dim; i++) \ - { Type *t = getType(args->tdata()[i]); \ + { Type *t = getType((*args)[i]); \ if (!t) \ goto Lfalse; \ if (!(cond)) \ @@ -101,7 +101,7 @@ Expression *TraitsExp::semantic(Scope *sc) #define ISDSYMBOL(cond) \ for (size_t i = 0; i < dim; i++) \ - { Dsymbol *s = getDsymbol(args->tdata()[i]); \ + { Dsymbol *s = getDsymbol((*args)[i]); \ if (!s) \ goto Lfalse; \ if (!(cond)) \ @@ -196,7 +196,7 @@ Expression *TraitsExp::semantic(Scope *sc) if (dim != 1) goto Ldimerror; - Object *o = args->tdata()[0]; + Object *o = (*args)[0]; Dsymbol *s = getDsymbol(o); if (!s || !s->ident) { @@ -210,7 +210,7 @@ Expression *TraitsExp::semantic(Scope *sc) { if (dim != 1) goto Ldimerror; - Object *o = args->tdata()[0]; + Object *o = (*args)[0]; Dsymbol *s = getDsymbol(o); if (s) s = s->toParent(); @@ -231,13 +231,13 @@ Expression *TraitsExp::semantic(Scope *sc) { if (dim != 2) goto Ldimerror; - Object *o = args->tdata()[0]; - Expression *e = isExpression(args->tdata()[1]); + Object *o = (*args)[0]; + Expression *e = isExpression((*args)[1]); if (!e) { error("expression expected as second argument of __traits %s", ident->toChars()); goto Lfalse; } - e = e->optimize(WANTvalue | WANTinterpret); + e = e->ctfeInterpret(); StringExp *se = e->toString(); if (!se || se->length() == 0) { error("string expected as second argument of __traits %s instead of %s", ident->toChars(), e->toChars()); @@ -336,7 +336,7 @@ Expression *TraitsExp::semantic(Scope *sc) { if (dim != 1) goto Ldimerror; - Object *o = args->tdata()[0]; + Object *o = (*args)[0]; Dsymbol *s = getDsymbol(o); ClassDeclaration *cd; if (!s || (cd = s->isClassDeclaration()) == NULL) @@ -350,7 +350,7 @@ Expression *TraitsExp::semantic(Scope *sc) { if (dim != 1) goto Ldimerror; - Object *o = args->tdata()[0]; + Object *o = (*args)[0]; Dsymbol *s = getDsymbol(o); ScopeDsymbol *sd; if (!s) @@ -380,7 +380,7 @@ Expression *TraitsExp::semantic(Scope *sc) /* Skip if already present in idents[] */ for (size_t j = 0; j < idents->dim; j++) - { Identifier *id = idents->tdata()[j]; + { Identifier *id = (*idents)[j]; if (id == sm->ident) return 0; #ifdef DEBUG @@ -421,9 +421,9 @@ Expression *TraitsExp::semantic(Scope *sc) assert(sizeof(Expressions) == sizeof(Identifiers)); Expressions *exps = (Expressions *)idents; for (size_t i = 0; i < idents->dim; i++) - { Identifier *id = idents->tdata()[i]; + { Identifier *id = (*idents)[i]; StringExp *se = new StringExp(loc, id->toChars()); - exps->tdata()[i] = se; + (*exps)[i] = se; } #if DMDV1 @@ -448,7 +448,7 @@ Expression *TraitsExp::semantic(Scope *sc) goto Lfalse; for (size_t i = 0; i < dim; i++) - { Object *o = args->tdata()[i]; + { Object *o = (*args)[i]; Expression *e; unsigned errors = global.startGagging(); @@ -491,8 +491,8 @@ Expression *TraitsExp::semantic(Scope *sc) if (dim != 2) goto Ldimerror; TemplateInstance::semanticTiargs(loc, sc, args, 0); - Object *o1 = args->tdata()[0]; - Object *o2 = args->tdata()[1]; + Object *o1 = (*args)[0]; + Object *o2 = (*args)[1]; Dsymbol *s1 = getDsymbol(o1); Dsymbol *s2 = getDsymbol(o2); diff --git a/dmd2/unialpha.c b/dmd2/unialpha.c deleted file mode 100644 index 5c407180..00000000 --- a/dmd2/unialpha.c +++ /dev/null @@ -1,323 +0,0 @@ - -// Copyright (c) 2003 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include - -/******************************* - * Return !=0 if unicode alpha. - * Use table from C99 Appendix D. - */ - -int isUniAlpha(unsigned u) -{ - static unsigned short table[][2] = - { - { 0x00AA, 0x00AA }, - { 0x00B5, 0x00B5 }, - { 0x00B7, 0x00B7 }, - { 0x00BA, 0x00BA }, - { 0x00C0, 0x00D6 }, - { 0x00D8, 0x00F6 }, - { 0x00F8, 0x01F5 }, - { 0x01FA, 0x0217 }, - { 0x0250, 0x02A8 }, - { 0x02B0, 0x02B8 }, - { 0x02BB, 0x02BB }, - { 0x02BD, 0x02C1 }, - { 0x02D0, 0x02D1 }, - { 0x02E0, 0x02E4 }, - { 0x037A, 0x037A }, - { 0x0386, 0x0386 }, - { 0x0388, 0x038A }, - { 0x038C, 0x038C }, - { 0x038E, 0x03A1 }, - { 0x03A3, 0x03CE }, - { 0x03D0, 0x03D6 }, - { 0x03DA, 0x03DA }, - { 0x03DC, 0x03DC }, - { 0x03DE, 0x03DE }, - { 0x03E0, 0x03E0 }, - { 0x03E2, 0x03F3 }, - { 0x0401, 0x040C }, - { 0x040E, 0x044F }, - { 0x0451, 0x045C }, - { 0x045E, 0x0481 }, - { 0x0490, 0x04C4 }, - { 0x04C7, 0x04C8 }, - { 0x04CB, 0x04CC }, - { 0x04D0, 0x04EB }, - { 0x04EE, 0x04F5 }, - { 0x04F8, 0x04F9 }, - { 0x0531, 0x0556 }, - { 0x0559, 0x0559 }, - { 0x0561, 0x0587 }, - { 0x05B0, 0x05B9 }, - { 0x05BB, 0x05BD }, - { 0x05BF, 0x05BF }, - { 0x05C1, 0x05C2 }, - { 0x05D0, 0x05EA }, - { 0x05F0, 0x05F2 }, - { 0x0621, 0x063A }, - { 0x0640, 0x0652 }, - { 0x0660, 0x0669 }, - { 0x0670, 0x06B7 }, - { 0x06BA, 0x06BE }, - { 0x06C0, 0x06CE }, - { 0x06D0, 0x06DC }, - { 0x06E5, 0x06E8 }, - { 0x06EA, 0x06ED }, - { 0x06F0, 0x06F9 }, - { 0x0901, 0x0903 }, - { 0x0905, 0x0939 }, - { 0x093D, 0x093D }, - { 0x093E, 0x094D }, - { 0x0950, 0x0952 }, - { 0x0958, 0x0963 }, - { 0x0966, 0x096F }, - { 0x0981, 0x0983 }, - { 0x0985, 0x098C }, - { 0x098F, 0x0990 }, - { 0x0993, 0x09A8 }, - { 0x09AA, 0x09B0 }, - { 0x09B2, 0x09B2 }, - { 0x09B6, 0x09B9 }, - { 0x09BE, 0x09C4 }, - { 0x09C7, 0x09C8 }, - { 0x09CB, 0x09CD }, - { 0x09DC, 0x09DD }, - { 0x09DF, 0x09E3 }, - { 0x09E6, 0x09EF }, - { 0x09F0, 0x09F1 }, - { 0x0A02, 0x0A02 }, - { 0x0A05, 0x0A0A }, - { 0x0A0F, 0x0A10 }, - { 0x0A13, 0x0A28 }, - { 0x0A2A, 0x0A30 }, - { 0x0A32, 0x0A33 }, - { 0x0A35, 0x0A36 }, - { 0x0A38, 0x0A39 }, - { 0x0A3E, 0x0A42 }, - { 0x0A47, 0x0A48 }, - { 0x0A4B, 0x0A4D }, - { 0x0A59, 0x0A5C }, - { 0x0A5E, 0x0A5E }, - { 0x0A66, 0x0A6F }, - { 0x0A74, 0x0A74 }, - { 0x0A81, 0x0A83 }, - { 0x0A85, 0x0A8B }, - { 0x0A8D, 0x0A8D }, - { 0x0A8F, 0x0A91 }, - { 0x0A93, 0x0AA8 }, - { 0x0AAA, 0x0AB0 }, - { 0x0AB2, 0x0AB3 }, - { 0x0AB5, 0x0AB9 }, - { 0x0ABD, 0x0AC5 }, - { 0x0AC7, 0x0AC9 }, - { 0x0ACB, 0x0ACD }, - { 0x0AD0, 0x0AD0 }, - { 0x0AE0, 0x0AE0 }, - { 0x0AE6, 0x0AEF }, - { 0x0B01, 0x0B03 }, - { 0x0B05, 0x0B0C }, - { 0x0B0F, 0x0B10 }, - { 0x0B13, 0x0B28 }, - { 0x0B2A, 0x0B30 }, - { 0x0B32, 0x0B33 }, - { 0x0B36, 0x0B39 }, - { 0x0B3D, 0x0B3D }, - { 0x0B3E, 0x0B43 }, - { 0x0B47, 0x0B48 }, - { 0x0B4B, 0x0B4D }, - { 0x0B5C, 0x0B5D }, - { 0x0B5F, 0x0B61 }, - { 0x0B66, 0x0B6F }, - { 0x0B82, 0x0B83 }, - { 0x0B85, 0x0B8A }, - { 0x0B8E, 0x0B90 }, - { 0x0B92, 0x0B95 }, - { 0x0B99, 0x0B9A }, - { 0x0B9C, 0x0B9C }, - { 0x0B9E, 0x0B9F }, - { 0x0BA3, 0x0BA4 }, - { 0x0BA8, 0x0BAA }, - { 0x0BAE, 0x0BB5 }, - { 0x0BB7, 0x0BB9 }, - { 0x0BBE, 0x0BC2 }, - { 0x0BC6, 0x0BC8 }, - { 0x0BCA, 0x0BCD }, - { 0x0BE7, 0x0BEF }, - { 0x0C01, 0x0C03 }, - { 0x0C05, 0x0C0C }, - { 0x0C0E, 0x0C10 }, - { 0x0C12, 0x0C28 }, - { 0x0C2A, 0x0C33 }, - { 0x0C35, 0x0C39 }, - { 0x0C3E, 0x0C44 }, - { 0x0C46, 0x0C48 }, - { 0x0C4A, 0x0C4D }, - { 0x0C60, 0x0C61 }, - { 0x0C66, 0x0C6F }, - { 0x0C82, 0x0C83 }, - { 0x0C85, 0x0C8C }, - { 0x0C8E, 0x0C90 }, - { 0x0C92, 0x0CA8 }, - { 0x0CAA, 0x0CB3 }, - { 0x0CB5, 0x0CB9 }, - { 0x0CBE, 0x0CC4 }, - { 0x0CC6, 0x0CC8 }, - { 0x0CCA, 0x0CCD }, - { 0x0CDE, 0x0CDE }, - { 0x0CE0, 0x0CE1 }, - { 0x0CE6, 0x0CEF }, - { 0x0D02, 0x0D03 }, - { 0x0D05, 0x0D0C }, - { 0x0D0E, 0x0D10 }, - { 0x0D12, 0x0D28 }, - { 0x0D2A, 0x0D39 }, - { 0x0D3E, 0x0D43 }, - { 0x0D46, 0x0D48 }, - { 0x0D4A, 0x0D4D }, - { 0x0D60, 0x0D61 }, - { 0x0D66, 0x0D6F }, - { 0x0E01, 0x0E3A }, - { 0x0E40, 0x0E5B }, -// { 0x0E50, 0x0E59 }, - { 0x0E81, 0x0E82 }, - { 0x0E84, 0x0E84 }, - { 0x0E87, 0x0E88 }, - { 0x0E8A, 0x0E8A }, - { 0x0E8D, 0x0E8D }, - { 0x0E94, 0x0E97 }, - { 0x0E99, 0x0E9F }, - { 0x0EA1, 0x0EA3 }, - { 0x0EA5, 0x0EA5 }, - { 0x0EA7, 0x0EA7 }, - { 0x0EAA, 0x0EAB }, - { 0x0EAD, 0x0EAE }, - { 0x0EB0, 0x0EB9 }, - { 0x0EBB, 0x0EBD }, - { 0x0EC0, 0x0EC4 }, - { 0x0EC6, 0x0EC6 }, - { 0x0EC8, 0x0ECD }, - { 0x0ED0, 0x0ED9 }, - { 0x0EDC, 0x0EDD }, - { 0x0F00, 0x0F00 }, - { 0x0F18, 0x0F19 }, - { 0x0F20, 0x0F33 }, - { 0x0F35, 0x0F35 }, - { 0x0F37, 0x0F37 }, - { 0x0F39, 0x0F39 }, - { 0x0F3E, 0x0F47 }, - { 0x0F49, 0x0F69 }, - { 0x0F71, 0x0F84 }, - { 0x0F86, 0x0F8B }, - { 0x0F90, 0x0F95 }, - { 0x0F97, 0x0F97 }, - { 0x0F99, 0x0FAD }, - { 0x0FB1, 0x0FB7 }, - { 0x0FB9, 0x0FB9 }, - { 0x10A0, 0x10C5 }, - { 0x10D0, 0x10F6 }, - { 0x1E00, 0x1E9B }, - { 0x1EA0, 0x1EF9 }, - { 0x1F00, 0x1F15 }, - { 0x1F18, 0x1F1D }, - { 0x1F20, 0x1F45 }, - { 0x1F48, 0x1F4D }, - { 0x1F50, 0x1F57 }, - { 0x1F59, 0x1F59 }, - { 0x1F5B, 0x1F5B }, - { 0x1F5D, 0x1F5D }, - { 0x1F5F, 0x1F7D }, - { 0x1F80, 0x1FB4 }, - { 0x1FB6, 0x1FBC }, - { 0x1FBE, 0x1FBE }, - { 0x1FC2, 0x1FC4 }, - { 0x1FC6, 0x1FCC }, - { 0x1FD0, 0x1FD3 }, - { 0x1FD6, 0x1FDB }, - { 0x1FE0, 0x1FEC }, - { 0x1FF2, 0x1FF4 }, - { 0x1FF6, 0x1FFC }, - { 0x203F, 0x2040 }, - { 0x207F, 0x207F }, - { 0x2102, 0x2102 }, - { 0x2107, 0x2107 }, - { 0x210A, 0x2113 }, - { 0x2115, 0x2115 }, - { 0x2118, 0x211D }, - { 0x2124, 0x2124 }, - { 0x2126, 0x2126 }, - { 0x2128, 0x2128 }, - { 0x212A, 0x2131 }, - { 0x2133, 0x2138 }, - { 0x2160, 0x2182 }, - { 0x3005, 0x3007 }, - { 0x3021, 0x3029 }, - { 0x3041, 0x3093 }, - { 0x309B, 0x309C }, - { 0x30A1, 0x30F6 }, - { 0x30FB, 0x30FC }, - { 0x3105, 0x312C }, - { 0x4E00, 0x9FA5 }, - { 0xAC00, 0xD7A3 }, - }; - -#ifdef DEBUG - for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++) - { - //printf("%x\n", table[i][0]); - assert(table[i][0] <= table[i][1]); - if (i < sizeof(table) / sizeof(table[0]) - 1) - assert(table[i][1] < table[i + 1][0]); - } -#endif - - if (u > 0xD7A3) - goto Lisnot; - - // Binary search - int mid; - int low; - int high; - - low = 0; - high = sizeof(table) / sizeof(table[0]) - 1; - while (low <= high) - { - mid = (low + high) >> 1; - if (u < table[mid][0]) - high = mid - 1; - else if (u > table[mid][1]) - low = mid + 1; - else - goto Lis; - } - -Lisnot: -#ifdef DEBUG - for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++) - { - assert(u < table[i][0] || u > table[i][1]); - } -#endif - return 0; - -Lis: -#ifdef DEBUG - for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++) - { - if (u >= table[i][0] && u <= table[i][1]) - return 1; - } - assert(0); // should have been in table -#endif - return 1; -} - diff --git a/dmd2/unittests.c b/dmd2/unittests.c index 1b3c2770..3cadebe5 100644 --- a/dmd2/unittests.c +++ b/dmd2/unittests.c @@ -1,4 +1,12 @@ +// Copyright (c) 2010-2012 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + #include #include "mars.h" diff --git a/dmd2/utf.c b/dmd2/utf.c index 78f8cd4a..c74f0770 100644 --- a/dmd2/utf.c +++ b/dmd2/utf.c @@ -1,5 +1,5 @@ // utf.c -// Copyright (c) 2003-2009 by Digital Mars +// Copyright (c) 2003-2012 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -7,22 +7,32 @@ // in artistic.txt, or the GNU General Public License in gnu.txt. // See the included readme.txt for details. -// Description of UTF-8 at: -// http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 +/// Description of UTF-8 in [1]. Unicode non-characters and private-use +/// code points described in [2],[4]. +/// +/// References: +/// [1] http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 +/// [2] http://en.wikipedia.org/wiki/Unicode +/// [3] http://unicode.org/faq/utf_bom.html +/// [4] http://www.unicode.org/versions/Unicode6.1.0/ch03.pdf -#include -#include #include #include "utf.h" -int utf_isValidDchar(dchar_t c) +namespace { - return c < 0xD800 || - (c > 0xDFFF && c <= 0x10FFFF && c != 0xFFFE && c != 0xFFFF); -} -static const unsigned char UTF8stride[256] = +/* The following encodings are valid, except for the 5 and 6 byte + * combinations: + * 0xxxxxxx + * 110xxxxx 10xxxxxx + * 1110xxxx 10xxxxxx 10xxxxxx + * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + * 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + * 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + */ +const unsigned UTF8_STRIDE[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, @@ -42,237 +52,73 @@ static const unsigned char UTF8stride[256] = 4,4,4,4,4,4,4,4,5,5,5,5,6,6,0xFF,0xFF, }; -/** - * stride() returns the length of a UTF-8 sequence starting at index i - * in string s. - * Returns: - * The number of bytes in the UTF-8 sequence or - * 0xFF meaning s[i] is not the start of of UTF-8 sequence. - */ +} // namespace -unsigned stride(unsigned char* s, size_t i) +namespace Unicode { - unsigned result = UTF8stride[s[i]]; - return result; + +// UTF-8 decoding errors +char const UTF8_DECODE_OUTSIDE_CODE_SPACE[] = "Outside Unicode code space"; +char const UTF8_DECODE_TRUNCATED_SEQUENCE[] = "Truncated UTF-8 sequence"; +char const UTF8_DECODE_OVERLONG[] = "Overlong UTF-8 sequence"; +char const UTF8_DECODE_INVALID_TRAILER[] = "Invalid trailing code unit"; +char const UTF8_DECODE_INVALID_CODE_POINT[] = "Invalid code point decoded"; + +// UTF-16 decoding errors +char const UTF16_DECODE_TRUNCATED_SEQUENCE[]= "Truncated UTF-16 sequence"; +char const UTF16_DECODE_INVALID_SURROGATE[] = "Invalid low surrogate"; +char const UTF16_DECODE_UNPAIRED_SURROGATE[]= "Unpaired surrogate"; +char const UTF16_DECODE_INVALID_CODE_POINT[]= "Invalid code point decoded"; + +} // namespace Unicode + +using namespace Unicode; + +/// The Unicode code space is the range of code points [0x000000,0x10FFFF] +/// except the UTF-16 surrogate pairs in the range [0xD800,0xDFFF] +/// and non-characters (which end in 0xFFFE or 0xFFFF). +bool utf_isValidDchar(dchar_t c) +{ + // TODO: Whether non-char code points should be rejected is pending review + return c <= 0x10FFFF // largest character code point + && !(0xD800 <= c && c <= 0xDFFF) // surrogate pairs + && (c & 0xFFFFFE) != 0x00FFFE // non-characters +// && (c & 0xFFFE) != 0xFFFE // non-characters +// && !(0x00FDD0 <= c && c <= 0x00FDEF) // non-characters + ; } -/******************************************** - * Decode a single UTF-8 character sequence. - * Returns: - * NULL success - * !=NULL error message string +/******************************* + * Return !=0 if unicode alpha. + * Use table from C99 Appendix D. */ -const char *utf_decodeChar(unsigned char *s, size_t len, size_t *pidx, dchar_t *presult) +bool isUniAlpha(dchar_t c) { - dchar_t V; - size_t i = *pidx; - unsigned char u = s[i]; - - //printf("utf_decodeChar(s = %02x, %02x, %02x len = %d)\n", u, s[1], s[2], len); - - assert(i >= 0 && i < len); - - if (u & 0x80) - { unsigned n; - unsigned char u2; - - /* The following encodings are valid, except for the 5 and 6 byte - * combinations: - * 0xxxxxxx - * 110xxxxx 10xxxxxx - * 1110xxxx 10xxxxxx 10xxxxxx - * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - * 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx - * 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx - */ - for (n = 1; ; n++) - { - if (n > 4) - goto Lerr; // only do the first 4 of 6 encodings - if (((u << n) & 0x80) == 0) - { - if (n == 1) - goto Lerr; - break; - } - } - - // Pick off (7 - n) significant bits of B from first byte of octet - V = (dchar_t)(u & ((1 << (7 - n)) - 1)); - - if (i + (n - 1) >= len) - goto Lerr; // off end of string - - /* The following combinations are overlong, and illegal: - * 1100000x (10xxxxxx) - * 11100000 100xxxxx (10xxxxxx) - * 11110000 1000xxxx (10xxxxxx 10xxxxxx) - * 11111000 10000xxx (10xxxxxx 10xxxxxx 10xxxxxx) - * 11111100 100000xx (10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx) - */ - u2 = s[i + 1]; - if ((u & 0xFE) == 0xC0 || - (u == 0xE0 && (u2 & 0xE0) == 0x80) || - (u == 0xF0 && (u2 & 0xF0) == 0x80) || - (u == 0xF8 && (u2 & 0xF8) == 0x80) || - (u == 0xFC && (u2 & 0xFC) == 0x80)) - goto Lerr; // overlong combination - - for (unsigned j = 1; j != n; j++) - { - u = s[i + j]; - if ((u & 0xC0) != 0x80) - goto Lerr; // trailing bytes are 10xxxxxx - V = (V << 6) | (u & 0x3F); - } - if (!utf_isValidDchar(V)) - goto Lerr; - i += n; - } - else + static size_t const END = sizeof(ALPHA_TABLE) / sizeof(ALPHA_TABLE[0]); + size_t high = END - 1; + // Shortcut search if c is out of range + size_t low + = (c < ALPHA_TABLE[0][0] || ALPHA_TABLE[high][1] < c) ? high + 1 : 0; + // Binary search + while (low <= high) { - V = (dchar_t) u; - i++; - } - - assert(utf_isValidDchar(V)); - *pidx = i; - *presult = V; - return NULL; - - Lerr: - *presult = (dchar_t) s[i]; - *pidx = i + 1; - return "invalid UTF-8 sequence"; -} - -/*************************************************** - * Validate a UTF-8 string. - * Returns: - * NULL success - * !=NULL error message string - */ - -const char *utf_validateString(unsigned char *s, size_t len) -{ - size_t idx; - const char *err = NULL; - dchar_t dc; - - for (idx = 0; idx < len; ) - { - err = utf_decodeChar(s, len, &idx, &dc); - if (err) - break; - } - return err; -} - - -/******************************************** - * Decode a single UTF-16 character sequence. - * Returns: - * NULL success - * !=NULL error message string - */ - - -const char *utf_decodeWchar(unsigned short *s, size_t len, size_t *pidx, dchar_t *presult) -{ - const char *msg; - size_t i = *pidx; - unsigned u = s[i]; - - assert(i >= 0 && i < len); - if (u & ~0x7F) - { if (u >= 0xD800 && u <= 0xDBFF) - { unsigned u2; - - if (i + 1 == len) - { msg = "surrogate UTF-16 high value past end of string"; - goto Lerr; - } - u2 = s[i + 1]; - if (u2 < 0xDC00 || u2 > 0xDFFF) - { msg = "surrogate UTF-16 low value out of range"; - goto Lerr; - } - u = ((u - 0xD7C0) << 10) + (u2 - 0xDC00); - i += 2; - } - else if (u >= 0xDC00 && u <= 0xDFFF) - { msg = "unpaired surrogate UTF-16 value"; - goto Lerr; - } - else if (u == 0xFFFE || u == 0xFFFF) - { msg = "illegal UTF-16 value"; - goto Lerr; - } + size_t mid = (low + high) >> 1; + if (c < ALPHA_TABLE[mid][0]) + high = mid - 1; + else if (ALPHA_TABLE[mid][1] < c) + low = mid + 1; else - i++; + { + assert(ALPHA_TABLE[mid][0] <= c && c <= ALPHA_TABLE[mid][1]); + return true; + } } - else - { - i++; - } - - assert(utf_isValidDchar(u)); - *pidx = i; - *presult = (dchar_t)u; - return NULL; - - Lerr: - *presult = (dchar_t)s[i]; - *pidx = i + 1; - return msg; + return false; } -void utf_encodeChar(unsigned char *s, dchar_t c) -{ - if (c <= 0x7F) - { - s[0] = (char) c; - } - else if (c <= 0x7FF) - { - s[0] = (char)(0xC0 | (c >> 6)); - s[1] = (char)(0x80 | (c & 0x3F)); - } - else if (c <= 0xFFFF) - { - s[0] = (char)(0xE0 | (c >> 12)); - s[1] = (char)(0x80 | ((c >> 6) & 0x3F)); - s[2] = (char)(0x80 | (c & 0x3F)); - } - else if (c <= 0x10FFFF) - { - s[0] = (char)(0xF0 | (c >> 18)); - s[1] = (char)(0x80 | ((c >> 12) & 0x3F)); - s[2] = (char)(0x80 | ((c >> 6) & 0x3F)); - s[3] = (char)(0x80 | (c & 0x3F)); - } - else - assert(0); -} - -void utf_encodeWchar(unsigned short *s, dchar_t c) -{ - if (c <= 0xFFFF) - { - s[0] = (wchar_t) c; - } - else - { - s[0] = (wchar_t) ((((c - 0x10000) >> 10) & 0x3FF) + 0xD800); - s[1] = (wchar_t) (((c - 0x10000) & 0x3FF) + 0xDC00); - } -} - - /** - * Returns the code length of c in the encoding. - * The code is returned in character count, not in bytes. + * Returns the code length of c in code units. */ int utf_codeLengthChar(dchar_t c) @@ -291,10 +137,10 @@ int utf_codeLengthWchar(dchar_t c) } /** - * Returns the code length of c in the encoding. + * Returns the code length of c in code units for the encoding. * sz is the encoding: 1 = utf8, 2 = utf16, 4 = utf32. - * The code is returned in character count, not in bytes. */ + int utf_codeLength(int sz, dchar_t c) { if (sz == 1) @@ -305,16 +151,161 @@ int utf_codeLength(int sz, dchar_t c) return 1; } -void utf_encode(int sz, void *s, dchar_t c) +void utf_encodeChar(utf8_t *s, dchar_t c) { - if (sz == 1) - utf_encodeChar((unsigned char *)s, c); - else if (sz == 2) - utf_encodeWchar((unsigned short *)s, c); + assert(s != NULL); + assert(utf_isValidDchar(c)); + if (c <= 0x7F) + { + s[0] = static_cast(c); + } + else if (c <= 0x07FF) + { + s[0] = static_cast(0xC0 | (c >> 6)); + s[1] = static_cast(0x80 | (c & 0x3F)); + } + else if (c <= 0xFFFF) + { + s[0] = static_cast(0xE0 | (c >> 12)); + s[1] = static_cast(0x80 | ((c >> 6) & 0x3F)); + s[2] = static_cast(0x80 | (c & 0x3F)); + } + else if (c <= 0x10FFFF) + { + s[0] = static_cast(0xF0 | (c >> 18)); + s[1] = static_cast(0x80 | ((c >> 12) & 0x3F)); + s[2] = static_cast(0x80 | ((c >> 6) & 0x3F)); + s[3] = static_cast(0x80 | (c & 0x3F)); + } + else + assert(0); +} + +void utf_encodeWchar(utf16_t *s, dchar_t c) +{ + assert(s != NULL); + assert(utf_isValidDchar(c)); + if (c <= 0xFFFF) + { + s[0] = static_cast(c); + } else { - assert(sz == 4); - memcpy((unsigned char *)s, &c, sz); + s[0] = static_cast((((c - 0x010000) >> 10) & 0x03FF) + 0xD800); + s[1] = static_cast(((c - 0x010000) & 0x03FF) + 0xDC00); } } +void utf_encode(int sz, void *s, dchar_t c) +{ + if (sz == 1) + utf_encodeChar((utf8_t *)s, c); + else if (sz == 2) + utf_encodeWchar((utf16_t *)s, c); + else + { + assert(sz == 4); + *((utf32_t *)s) = c; + } +} + +/******************************************** + * Decode a UTF-8 sequence as a single UTF-32 code point. + * Returns: + * NULL success + * !=NULL error message string + */ + +const char *utf_decodeChar(utf8_t const *s, size_t len, size_t *pidx, dchar_t *presult) +{ + assert(s != NULL); + assert(pidx != NULL); + assert(presult != NULL); + size_t i = (*pidx)++; + assert(i < len); + utf8_t u = s[i]; + // Pre-stage results for ASCII and error cases + *presult = u; + + //printf("utf_decodeChar(s = %02x, %02x, %02x len = %d)\n", u, s[1], s[2], len); + + // Get expected sequence length + unsigned n = UTF8_STRIDE[u]; + switch (n) + { + case 1: // ASCII + return UTF8_DECODE_OK; + case 2: case 3: case 4: // multi-byte UTF-8 + break; + default: // 5- or 6-byte sequence + return UTF8_DECODE_OUTSIDE_CODE_SPACE; + } + if (len < i + n) // source too short + return UTF8_DECODE_TRUNCATED_SEQUENCE; + + // Pick off 7 - n low bits from first code unit + utf32_t c = u & ((1 << (7 - n)) - 1); + /* The following combinations are overlong, and illegal: + * 1100000x (10xxxxxx) + * 11100000 100xxxxx (10xxxxxx) + * 11110000 1000xxxx (10xxxxxx 10xxxxxx) + * 11111000 10000xxx (10xxxxxx 10xxxxxx 10xxxxxx) + * 11111100 100000xx (10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx) + */ + utf8_t u2 = s[++i]; + if ((u & 0xFE) == 0xC0 || // overlong combination + (u == 0xE0 && (u2 & 0xE0) == 0x80) || + (u == 0xF0 && (u2 & 0xF0) == 0x80) || + (u == 0xF8 && (u2 & 0xF8) == 0x80) || + (u == 0xFC && (u2 & 0xFC) == 0x80)) + return UTF8_DECODE_OVERLONG; + // Decode remaining bits + for (n += i - 1; i != n; ++i) + { + u = s[i]; + if ((u & 0xC0) != 0x80) // trailing bytes are 10xxxxxx + return UTF8_DECODE_INVALID_TRAILER; + c = (c << 6) | (u & 0x3F); + } + if (!utf_isValidDchar(c)) + return UTF8_DECODE_INVALID_CODE_POINT; + *pidx = i; + *presult = c; + return UTF8_DECODE_OK; +} + +/******************************************** + * Decode a UTF-16 sequence as a single UTF-32 code point. + * Returns: + * NULL success + * !=NULL error message string + */ + +const char *utf_decodeWchar(utf16_t const *s, size_t len, size_t *pidx, dchar_t *presult) +{ + assert(s != NULL); + assert(pidx != NULL); + assert(presult != NULL); + size_t i = (*pidx)++; + assert(i < len); + // Pre-stage results for ASCII and error cases + utf32_t u = *presult = s[i]; + + if (u < 0x80) // ASCII + return UTF16_DECODE_OK; + if (0xD800 <= u && u <= 0xDBFF) // Surrogate pair + { if (len <= i + 1) + return UTF16_DECODE_TRUNCATED_SEQUENCE; + utf16_t u2 = s[i + 1]; + if (u2 < 0xDC00 || 0xDFFF < u) + return UTF16_DECODE_INVALID_SURROGATE; + u = ((u - 0xD7C0) << 10) + (u2 - 0xDC00); + ++*pidx; + } + else if (0xDC00 <= u && u <= 0xDFFF) + return UTF16_DECODE_UNPAIRED_SURROGATE; + if (!utf_isValidDchar(u)) + return UTF16_DECODE_INVALID_CODE_POINT; + *presult = u; + return UTF16_DECODE_OK; +} diff --git a/dmd2/utf.h b/dmd2/utf.h index 22d8d3eb..e48ffaab 100644 --- a/dmd2/utf.h +++ b/dmd2/utf.h @@ -11,25 +11,114 @@ #ifndef DMD_UTF_H #define DMD_UTF_H +#include -typedef unsigned dchar_t; +/// A UTF-8 code unit +typedef unsigned char utf8_t; +/// A UTF-16 code unit +typedef unsigned short utf16_t; +/// A UTF-32 code unit +typedef unsigned int utf32_t; +typedef utf32_t dchar_t; -int utf_isValidDchar(dchar_t c); +namespace Unicode +{ -const char *utf_decodeChar(unsigned char *s, size_t len, size_t *pidx, dchar_t *presult); -const char *utf_decodeWchar(unsigned short *s, size_t len, size_t *pidx, dchar_t *presult); +static utf16_t const ALPHA_TABLE[][2] = +{ + { 0x00AA, 0x00AA }, { 0x00B5, 0x00B5 }, { 0x00B7, 0x00B7 }, { 0x00BA, 0x00BA }, + { 0x00C0, 0x00D6 }, { 0x00D8, 0x00F6 }, { 0x00F8, 0x01F5 }, { 0x01FA, 0x0217 }, + { 0x0250, 0x02A8 }, { 0x02B0, 0x02B8 }, { 0x02BB, 0x02BB }, { 0x02BD, 0x02C1 }, + { 0x02D0, 0x02D1 }, { 0x02E0, 0x02E4 }, { 0x037A, 0x037A }, { 0x0386, 0x0386 }, + { 0x0388, 0x038A }, { 0x038C, 0x038C }, { 0x038E, 0x03A1 }, { 0x03A3, 0x03CE }, + { 0x03D0, 0x03D6 }, { 0x03DA, 0x03DA }, { 0x03DC, 0x03DC }, { 0x03DE, 0x03DE }, + { 0x03E0, 0x03E0 }, { 0x03E2, 0x03F3 }, { 0x0401, 0x040C }, { 0x040E, 0x044F }, + { 0x0451, 0x045C }, { 0x045E, 0x0481 }, { 0x0490, 0x04C4 }, { 0x04C7, 0x04C8 }, + { 0x04CB, 0x04CC }, { 0x04D0, 0x04EB }, { 0x04EE, 0x04F5 }, { 0x04F8, 0x04F9 }, + { 0x0531, 0x0556 }, { 0x0559, 0x0559 }, { 0x0561, 0x0587 }, { 0x05B0, 0x05B9 }, + { 0x05BB, 0x05BD }, { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 }, { 0x05D0, 0x05EA }, + { 0x05F0, 0x05F2 }, { 0x0621, 0x063A }, { 0x0640, 0x0652 }, { 0x0660, 0x0669 }, + { 0x0670, 0x06B7 }, { 0x06BA, 0x06BE }, { 0x06C0, 0x06CE }, { 0x06D0, 0x06DC }, + { 0x06E5, 0x06E8 }, { 0x06EA, 0x06ED }, { 0x06F0, 0x06F9 }, { 0x0901, 0x0903 }, + { 0x0905, 0x0939 }, { 0x093D, 0x094D }, { 0x0950, 0x0952 }, { 0x0958, 0x0963 }, + { 0x0966, 0x096F }, { 0x0981, 0x0983 }, { 0x0985, 0x098C }, { 0x098F, 0x0990 }, + { 0x0993, 0x09A8 }, { 0x09AA, 0x09B0 }, { 0x09B2, 0x09B2 }, { 0x09B6, 0x09B9 }, + { 0x09BE, 0x09C4 }, { 0x09C7, 0x09C8 }, { 0x09CB, 0x09CD }, { 0x09DC, 0x09DD }, + { 0x09DF, 0x09E3 }, { 0x09E6, 0x09F1 }, { 0x0A02, 0x0A02 }, { 0x0A05, 0x0A0A }, + { 0x0A0F, 0x0A10 }, { 0x0A13, 0x0A28 }, { 0x0A2A, 0x0A30 }, { 0x0A32, 0x0A33 }, + { 0x0A35, 0x0A36 }, { 0x0A38, 0x0A39 }, { 0x0A3E, 0x0A42 }, { 0x0A47, 0x0A48 }, + { 0x0A4B, 0x0A4D }, { 0x0A59, 0x0A5C }, { 0x0A5E, 0x0A5E }, { 0x0A66, 0x0A6F }, + { 0x0A74, 0x0A74 }, { 0x0A81, 0x0A83 }, { 0x0A85, 0x0A8B }, { 0x0A8D, 0x0A8D }, + { 0x0A8F, 0x0A91 }, { 0x0A93, 0x0AA8 }, { 0x0AAA, 0x0AB0 }, { 0x0AB2, 0x0AB3 }, + { 0x0AB5, 0x0AB9 }, { 0x0ABD, 0x0AC5 }, { 0x0AC7, 0x0AC9 }, { 0x0ACB, 0x0ACD }, + { 0x0AD0, 0x0AD0 }, { 0x0AE0, 0x0AE0 }, { 0x0AE6, 0x0AEF }, { 0x0B01, 0x0B03 }, + { 0x0B05, 0x0B0C }, { 0x0B0F, 0x0B10 }, { 0x0B13, 0x0B28 }, { 0x0B2A, 0x0B30 }, + { 0x0B32, 0x0B33 }, { 0x0B36, 0x0B39 }, { 0x0B3D, 0x0B43 }, { 0x0B47, 0x0B48 }, + { 0x0B4B, 0x0B4D }, { 0x0B5C, 0x0B5D }, { 0x0B5F, 0x0B61 }, { 0x0B66, 0x0B6F }, + { 0x0B82, 0x0B83 }, { 0x0B85, 0x0B8A }, { 0x0B8E, 0x0B90 }, { 0x0B92, 0x0B95 }, + { 0x0B99, 0x0B9A }, { 0x0B9C, 0x0B9C }, { 0x0B9E, 0x0B9F }, { 0x0BA3, 0x0BA4 }, + { 0x0BA8, 0x0BAA }, { 0x0BAE, 0x0BB5 }, { 0x0BB7, 0x0BB9 }, { 0x0BBE, 0x0BC2 }, + { 0x0BC6, 0x0BC8 }, { 0x0BCA, 0x0BCD }, { 0x0BE7, 0x0BEF }, { 0x0C01, 0x0C03 }, + { 0x0C05, 0x0C0C }, { 0x0C0E, 0x0C10 }, { 0x0C12, 0x0C28 }, { 0x0C2A, 0x0C33 }, + { 0x0C35, 0x0C39 }, { 0x0C3E, 0x0C44 }, { 0x0C46, 0x0C48 }, { 0x0C4A, 0x0C4D }, + { 0x0C60, 0x0C61 }, { 0x0C66, 0x0C6F }, { 0x0C82, 0x0C83 }, { 0x0C85, 0x0C8C }, + { 0x0C8E, 0x0C90 }, { 0x0C92, 0x0CA8 }, { 0x0CAA, 0x0CB3 }, { 0x0CB5, 0x0CB9 }, + { 0x0CBE, 0x0CC4 }, { 0x0CC6, 0x0CC8 }, { 0x0CCA, 0x0CCD }, { 0x0CDE, 0x0CDE }, + { 0x0CE0, 0x0CE1 }, { 0x0CE6, 0x0CEF }, { 0x0D02, 0x0D03 }, { 0x0D05, 0x0D0C }, + { 0x0D0E, 0x0D10 }, { 0x0D12, 0x0D28 }, { 0x0D2A, 0x0D39 }, { 0x0D3E, 0x0D43 }, + { 0x0D46, 0x0D48 }, { 0x0D4A, 0x0D4D }, { 0x0D60, 0x0D61 }, { 0x0D66, 0x0D6F }, + { 0x0E01, 0x0E3A }, { 0x0E40, 0x0E5B }, /* { 0x0E50, 0x0E59 }, */ { 0x0E81, 0x0E82 }, + { 0x0E84, 0x0E84 }, { 0x0E87, 0x0E88 }, { 0x0E8A, 0x0E8A }, { 0x0E8D, 0x0E8D }, + { 0x0E94, 0x0E97 }, { 0x0E99, 0x0E9F }, { 0x0EA1, 0x0EA3 }, { 0x0EA5, 0x0EA5 }, + { 0x0EA7, 0x0EA7 }, { 0x0EAA, 0x0EAB }, { 0x0EAD, 0x0EAE }, { 0x0EB0, 0x0EB9 }, + { 0x0EBB, 0x0EBD }, { 0x0EC0, 0x0EC4 }, { 0x0EC6, 0x0EC6 }, { 0x0EC8, 0x0ECD }, + { 0x0ED0, 0x0ED9 }, { 0x0EDC, 0x0EDD }, { 0x0F00, 0x0F00 }, { 0x0F18, 0x0F19 }, + { 0x0F20, 0x0F33 }, { 0x0F35, 0x0F35 }, { 0x0F37, 0x0F37 }, { 0x0F39, 0x0F39 }, + { 0x0F3E, 0x0F47 }, { 0x0F49, 0x0F69 }, { 0x0F71, 0x0F84 }, { 0x0F86, 0x0F8B }, + { 0x0F90, 0x0F95 }, { 0x0F97, 0x0F97 }, { 0x0F99, 0x0FAD }, { 0x0FB1, 0x0FB7 }, + { 0x0FB9, 0x0FB9 }, { 0x10A0, 0x10C5 }, { 0x10D0, 0x10F6 }, { 0x1E00, 0x1E9B }, + { 0x1EA0, 0x1EF9 }, { 0x1F00, 0x1F15 }, { 0x1F18, 0x1F1D }, { 0x1F20, 0x1F45 }, + { 0x1F48, 0x1F4D }, { 0x1F50, 0x1F57 }, { 0x1F59, 0x1F59 }, { 0x1F5B, 0x1F5B }, + { 0x1F5D, 0x1F5D }, { 0x1F5F, 0x1F7D }, { 0x1F80, 0x1FB4 }, { 0x1FB6, 0x1FBC }, + { 0x1FBE, 0x1FBE }, { 0x1FC2, 0x1FC4 }, { 0x1FC6, 0x1FCC }, { 0x1FD0, 0x1FD3 }, + { 0x1FD6, 0x1FDB }, { 0x1FE0, 0x1FEC }, { 0x1FF2, 0x1FF4 }, { 0x1FF6, 0x1FFC }, + { 0x203F, 0x2040 }, { 0x207F, 0x207F }, { 0x2102, 0x2102 }, { 0x2107, 0x2107 }, + { 0x210A, 0x2113 }, { 0x2115, 0x2115 }, { 0x2118, 0x211D }, { 0x2124, 0x2124 }, + { 0x2126, 0x2126 }, { 0x2128, 0x2128 }, { 0x212A, 0x2131 }, { 0x2133, 0x2138 }, + { 0x2160, 0x2182 }, { 0x3005, 0x3007 }, { 0x3021, 0x3029 }, { 0x3041, 0x3093 }, + { 0x309B, 0x309C }, { 0x30A1, 0x30F6 }, { 0x30FB, 0x30FC }, { 0x3105, 0x312C }, + { 0x4E00, 0x9FA5 }, { 0xAC00, 0xD7A3 }, +}; -const char *utf_validateString(unsigned char *s, size_t len); +char const *const UTF8_DECODE_OK = NULL; +extern char const UTF8_DECODE_OUTSIDE_CODE_SPACE[]; +extern char const UTF8_DECODE_TRUNCATED_SEQUENCE[]; +extern char const UTF8_DECODE_OVERLONG[]; +extern char const UTF8_DECODE_INVALID_TRAILER[]; +extern char const UTF8_DECODE_INVALID_CODE_POINT[]; -extern int isUniAlpha(dchar_t); +char const *const UTF16_DECODE_OK = NULL; +extern char const UTF16_DECODE_TRUNCATED_SEQUENCE[]; +extern char const UTF16_DECODE_INVALID_SURROGATE[]; +extern char const UTF16_DECODE_UNPAIRED_SURROGATE[]; +extern char const UTF16_DECODE_INVALID_CODE_POINT[]; -void utf_encodeChar(unsigned char *s, dchar_t c); -void utf_encodeWchar(unsigned short *s, dchar_t c); +} // namespace Unicode + +/// \return true if \a c is a valid, non-private UTF-32 code point +bool utf_isValidDchar(dchar_t c); + +bool isUniAlpha(dchar_t c); int utf_codeLengthChar(dchar_t c); int utf_codeLengthWchar(dchar_t c); - int utf_codeLength(int sz, dchar_t c); + +void utf_encodeChar(utf8_t *s, dchar_t c); +void utf_encodeWchar(utf16_t *s, dchar_t c); void utf_encode(int sz, void *s, dchar_t c); -#endif +const char *utf_decodeChar(utf8_t const *s, size_t len, size_t *pidx, dchar_t *presult); +const char *utf_decodeWchar(utf16_t const *s, size_t len, size_t *pidx, dchar_t *presult); + +#endif // DMD_UTF_H diff --git a/driver/ldmd.cpp b/driver/ldmd.cpp index 1a8f6687..e170abca 100644 --- a/driver/ldmd.cpp +++ b/driver/ldmd.cpp @@ -593,7 +593,8 @@ Params parseArgs(int originalArgc, char** originalArgv, ls::Path ldcPath) goto Lerror; result.debugLevel = (int)level; } - result.debugIdentifiers.push_back(p + 7); + else + result.debugIdentifiers.push_back(p + 7); } else if (p[6]) goto Lerror; @@ -616,7 +617,8 @@ Params parseArgs(int originalArgc, char** originalArgv, ls::Path ldcPath) goto Lerror; result.versionLevel = (int)level; } - result.versionIdentifiers.push_back(p + 9); + else + result.versionIdentifiers.push_back(p + 9); } else goto Lerror; @@ -769,11 +771,11 @@ void buildCommandLine(std::vector& r, const Params& p) if (p.debugFlag) r.push_back("-d-debug"); if (p.debugLevel) r.push_back(concat("-d-debug=", p.debugLevel)); pushSwitches("-d-debug=", p.debugIdentifiers, r); - if (p.debugLevel) r.push_back(concat("-d-version=", p.versionLevel)); + if (p.versionLevel) r.push_back(concat("-d-version=", p.versionLevel)); pushSwitches("-d-version=", p.versionIdentifiers, r); pushSwitches("-L=", p.linkerSwitches, r); if (p.defaultLibName) r.push_back(concat("-defaultlib=", p.defaultLibName)); - if (p.debugLibName) r.push_back(concat("-deps=", p.moduleDepsFile)); + if (p.debugLibName) r.push_back(concat("-debuglib=", p.debugLibName)); if (p.hiddenDebugB) r.push_back("-hidden-debug-b"); if (p.hiddenDebugC) r.push_back("-hidden-debug-c"); if (p.hiddenDebugF) r.push_back("-hidden-debug-f"); diff --git a/driver/linker.cpp b/driver/linker.cpp index b5113ef0..067b76d1 100644 --- a/driver/linker.cpp +++ b/driver/linker.cpp @@ -58,167 +58,6 @@ void linkModules(llvm::Module* dst, const Module_vector& MV) static llvm::sys::Path gExePath; -int linkExecutable(const char* argv0) -{ - Logger::println("*** Linking executable ***"); - - // error string - std::string errstr; - - // find the llvm-ld program - llvm::sys::Path ldpath = llvm::sys::Program::FindProgramByName("llvm-ld"); - if (ldpath.isEmpty()) - { - ldpath.set("llvm-ld"); - } - - // build arguments - std::vector args; - - // first the program name ?? - args.push_back("llvm-ld"); - - // output filename - std::string exestr; - if (global.params.exefile) - { // explicit - exestr = global.params.exefile; - } - else - { // inferred - // try root module name - if (Module::rootModule) - exestr = Module::rootModule->toChars(); - else - exestr = "a.out"; - } - if (global.params.os == OSWindows && !(exestr.substr(exestr.length()-4) == ".exe")) - exestr.append(".exe"); - - std::string outopt = "-o=" + exestr; - args.push_back(outopt.c_str()); - - // set the global gExePath - gExePath.set(exestr); - assert(gExePath.isValid()); - - // create path to exe - llvm::sys::Path exedir(llvm::sys::path::parent_path(gExePath.str())); - if (!llvm::sys::fs::exists(exedir.str())) - { - exedir.createDirectoryOnDisk(true, &errstr); - if (!errstr.empty()) - { - error("failed to create path to linking output: %s\n%s", exedir.c_str(), errstr.c_str()); - fatal(); - } - } - - // strip debug info - if (!global.params.symdebug) - args.push_back("-strip-debug"); - - // optimization level - if (!optimize()) - args.push_back("-disable-opt"); - else - { - switch(optLevel()) - { - case 0: - args.push_back("-disable-opt"); - break; - case 1: - args.push_back("-globaldce"); - args.push_back("-disable-opt"); - args.push_back("-globaldce"); - args.push_back("-mem2reg"); - case 2: - case 3: - case 4: - case 5: - // use default optimization - break; - default: - assert(0); - } - } - - // inlining - if (!(global.params.useInline || doInline())) - { - args.push_back("-disable-inlining"); - } - - // additional linker switches - for (unsigned i = 0; i < global.params.linkswitches->dim; i++) - { - char *p = static_cast(global.params.linkswitches->data[i]); - args.push_back(p); - } - - // native please - args.push_back("-native"); - - - // user libs - for (unsigned i = 0; i < global.params.libfiles->dim; i++) - { - char *p = static_cast(global.params.libfiles->data[i]); - args.push_back(p); - } - - // default libs - switch(global.params.os) { - case OSLinux: - case OSMacOSX: - args.push_back("-ldl"); - case OSFreeBSD: - args.push_back("-lpthread"); - args.push_back("-lm"); - break; - case OSHaiku: - args.push_back("-lroot"); - break; - case OSWindows: - // FIXME: I'd assume kernel32 etc - break; - } - - // object files - for (unsigned i = 0; i < global.params.objfiles->dim; i++) - { - char *p = static_cast(global.params.objfiles->data[i]); - args.push_back(p); - } - - // print link command? - if (!quiet || global.params.verbose) - { - // Print it - for (int i = 0; i < args.size(); i++) - printf("%s ", args[i]); - printf("\n"); - fflush(stdout); - } - - // terminate args list - args.push_back(NULL); - - // try to call linker!!! - if (int status = llvm::sys::Program::ExecuteAndWait(ldpath, &args[0], NULL, NULL, 0,0, &errstr)) - { - error("linking failed:\nstatus: %d", status); - if (!errstr.empty()) - error("message: %s", errstr.c_str()); - return status; - } - - return 0; -} - -////////////////////////////////////////////////////////////////////////////// - int linkObjToBinary(bool sharedLib) { Logger::println("*** Linking executable ***"); @@ -244,6 +83,13 @@ int linkObjToBinary(bool sharedLib) args.push_back(p); } + // user libs + for (unsigned i = 0; i < global.params.libfiles->dim; i++) + { + char *p = static_cast(global.params.libfiles->data[i]); + args.push_back(p); + } + // output filename std::string output; if (!sharedLib && global.params.exefile) @@ -308,13 +154,6 @@ int linkObjToBinary(bool sharedLib) args.push_back(p); } - // user libs - for (unsigned i = 0; i < global.params.libfiles->dim; i++) - { - char *p = static_cast(global.params.libfiles->data[i]); - args.push_back(p); - } - // default libs bool addSoname = false; switch(global.params.os) { diff --git a/driver/linker.h b/driver/linker.h index d76c1778..e2844732 100644 --- a/driver/linker.h +++ b/driver/linker.h @@ -18,13 +18,6 @@ namespace llvm */ void linkModules(llvm::Module* dst, const std::vector& MV); -/** - * Link an executable. - * @param argv0 the argv[0] value as passed to main - * @return 0 on success. - */ -int linkExecutable(const char* argv0); - /** * Link an executable only from object files. * @param argv0 the argv[0] value as passed to main @@ -38,12 +31,12 @@ int linkObjToBinary(bool sharedLib); void createStaticLibrary(); /** - * Delete the executable that was previously linked with linkExecutable. + * Delete the executable that was previously linked with linkObjToBinary. */ void deleteExecutable(); /** - * Runs the executable that was previously linked with linkExecutable. + * Runs the executable that was previously linked with linkObjToBinary. * @return the return status of the executable. */ int runExecutable(); diff --git a/driver/main.cpp b/driver/main.cpp index e188cdf1..32052c46 100644 --- a/driver/main.cpp +++ b/driver/main.cpp @@ -23,6 +23,11 @@ #include "rmem.h" #include "root.h" +// stricmp +#if __GNUC__ && !_WIN32 +#include "gnuc.h" +#endif + #include "mars.h" #include "module.h" #include "mtype.h" @@ -835,10 +840,7 @@ int main(int argc, char** argv) #endif if (stricmp(ext, global.mars_ext) == 0 || - stricmp(ext, global.hdr_ext) == 0 || - stricmp(ext, "htm") == 0 || - stricmp(ext, "html") == 0 || - stricmp(ext, "xhtml") == 0) + stricmp(ext, global.hdr_ext) == 0) { ext--; // skip onto '.' assert(*ext == '.'); diff --git a/gen/arrays.cpp b/gen/arrays.cpp index 0130c3a4..a39744c4 100644 --- a/gen/arrays.cpp +++ b/gen/arrays.cpp @@ -208,7 +208,10 @@ void DtoArrayAssign(DValue *array, DValue *value, int op) assert(value && array); assert(op != TOKblit); - Type *t = value->type->toBasetype(); + + // Use array->type instead of value->type so as to not accidentally pick + // up a superfluous const layer (TypeInfo_Const doesn't pass on postblit()). + Type *t = array->type->toBasetype(); assert(t->nextOf()); Type *elemType = t->nextOf()->toBasetype(); diff --git a/gen/asm-x86-32.h b/gen/asm-x86-32.h index 7ae8ccba..127e6704 100644 --- a/gen/asm-x86-32.h +++ b/gen/asm-x86-32.h @@ -2189,7 +2189,7 @@ namespace AsmParserx8632 */ if ( isDollar ( e ) ) { - error ( "dollar labels are not supported", stmt->loc.toChars() ); + stmt->error("dollar labels are not supported"); asmcode->dollarLabel = 1; } else if ( e->op == TOKdsymbol ) diff --git a/gen/asm-x86-64.h b/gen/asm-x86-64.h index 044cba81..f0a5f9a1 100644 --- a/gen/asm-x86-64.h +++ b/gen/asm-x86-64.h @@ -2325,7 +2325,7 @@ namespace AsmParserx8664 */ if ( isDollar ( e ) ) { - error ( "dollar labels are not supported", stmt->loc.toChars() ); + stmt->error("dollar labels are not supported"); asmcode->dollarLabel = 1; } else if ( e->op == TOKdsymbol ) diff --git a/gen/asmstmt.cpp b/gen/asmstmt.cpp index be7da84e..5ae2656c 100644 --- a/gen/asmstmt.cpp +++ b/gen/asmstmt.cpp @@ -187,7 +187,7 @@ int AsmStatement::blockExit(bool mustNotThrow) //printf("AsmStatement::blockExit(%p)\n", this); #if DMDV2 if (mustNotThrow) - error("asm statements are assumed to throw", toChars()); + error("asm statements are assumed to throw"); #endif // Assume the worst return BEfallthru | BEthrow | BEreturn | BEgoto | BEhalt; diff --git a/gen/classes.cpp b/gen/classes.cpp index 1ac63ced..4db73d7f 100644 --- a/gen/classes.cpp +++ b/gen/classes.cpp @@ -676,7 +676,7 @@ LLConstant* DtoDefineClassInfo(ClassDeclaration* cd) // OffsetTypeInfo[] offTi; // void *defaultConstructor; // version(D_Version2) -// const(MemberInfo[]) function(string) xgetMembers; +// immutable(void)* m_RTInfo; // else // TypeInfo typeinfo; // since dmd 1.045 // } @@ -761,10 +761,12 @@ LLConstant* DtoDefineClassInfo(ClassDeclaration* cd) b.push_funcptr(cd->inv, invVar->type); // uint flags + unsigned flags; if (cd->isInterfaceDeclaration()) - b.push_uint(4 | cd->isCOMinterface() | 32); + flags = 4 | cd->isCOMinterface() | 32; else - b.push_uint(build_classinfo_flags(cd)); + flags = build_classinfo_flags(cd); + b.push_uint(flags); // deallocator b.push_funcptr(cd->aggDelete, Type::tvoid->pointerTo()); @@ -790,16 +792,18 @@ LLConstant* DtoDefineClassInfo(ClassDeclaration* cd) b.push_funcptr(cd->defaultCtor, defConstructorVar->type); #if DMDV2 - - // xgetMembers - VarDeclaration* xgetVar = static_cast(cinfo->fields.data[11]); - b.push_funcptr(cd->findGetMembers(), xgetVar->type); - + // immutable(void)* m_RTInfo; + // The cases where getRTInfo is null are not quite here, but the code is + // modelled after what DMD does. + if (cd->getRTInfo) + b.push(cd->getRTInfo->toConstElem(gIR)); + else if (flags & 2) + b.push_size_as_vp(0); // no pointers + else + b.push_size_as_vp(1); // has pointers #else - // typeinfo - since 1.045 b.push_typeinfo(cd->type); - #endif /*size_t n = inits.size(); diff --git a/gen/dvalue.cpp b/gen/dvalue.cpp index cf0a4bdd..e0057654 100644 --- a/gen/dvalue.cpp +++ b/gen/dvalue.cpp @@ -16,6 +16,8 @@ DVarValue::DVarValue(Type* t, VarDeclaration* vd, LLValue* llvmValue) : DValue(t), var(vd), val(llvmValue) { assert(isaPointer(llvmValue)); + assert(!isSpecialRefVar(vd) || + isaPointer(isaPointer(llvmValue)->getElementType())); } DVarValue::DVarValue(Type* t, LLValue* llvmValue) @@ -27,6 +29,8 @@ DVarValue::DVarValue(Type* t, LLValue* llvmValue) LLValue* DVarValue::getLVal() { assert(val); + if (var && isSpecialRefVar(var)) + return DtoLoad(val); return val; } @@ -34,9 +38,14 @@ LLValue* DVarValue::getRVal() { assert(val); Type* bt = type->toBasetype(); + + LLValue* tmp = val; + if (var && isSpecialRefVar(var)) + tmp = DtoLoad(tmp); + if (DtoIsPassedByRef(bt)) - return val; - return DtoLoad(val); + return tmp; + return DtoLoad(tmp); } ///////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/gen/functions.cpp b/gen/functions.cpp index 287464dc..73eb433e 100644 --- a/gen/functions.cpp +++ b/gen/functions.cpp @@ -807,16 +807,15 @@ void DtoDefineFunction(FuncDeclaration* fd) DtoCreateNestedContext(fd); + if (fd->vresult && ! #if DMDV2 - if (fd->vresult && fd->vresult->nestedrefs.dim) // FIXME: not sure here :/ + fd->vresult->nestedrefs.dim // FIXME: not sure here :/ #else - if (fd->vresult && fd->vresult->nestedref) + fd->vresult->nestedref #endif + ) { - DtoNestedInit(fd->vresult); - } else if (fd->vresult) { - fd->vresult->ir.irLocal = new IrLocal(fd->vresult); - fd->vresult->ir.irLocal->value = DtoAlloca(fd->vresult->type, fd->vresult->toChars()); + DtoVarDeclaration(fd->vresult); } // copy _argptr and _arguments to a memory location diff --git a/gen/irstate.cpp b/gen/irstate.cpp index e2ca388d..73837b1f 100644 --- a/gen/irstate.cpp +++ b/gen/irstate.cpp @@ -1,175 +1,175 @@ -/* DMDFE backend stubs - * This file contains the implementations of the backend routines. - * For dmdfe these do nothing but print a message saying the module - * has been parsed. Substitute your own behaviors for these routimes. - */ - -#include - -#include "gen/llvm.h" - -#include "mtype.h" -#include "declaration.h" -#include "statement.h" - -#include "gen/irstate.h" -#include "tollvm.h" - -IRState* gIR = 0; -llvm::TargetMachine* gTargetMachine = 0; -const llvm::TargetData* gTargetData = 0; -TargetABI* gABI = 0; - -////////////////////////////////////////////////////////////////////////////////////////// -IRScope::IRScope() - : builder(gIR->context()) -{ - begin = end = NULL; -} - -IRScope::IRScope(llvm::BasicBlock* b, llvm::BasicBlock* e) - : builder(b) -{ - begin = b; - end = e; -} - -const IRScope& IRScope::operator=(const IRScope& rhs) -{ - begin = rhs.begin; - end = rhs.end; - builder.SetInsertPoint(begin); - return *this; -} - -////////////////////////////////////////////////////////////////////////////////////////// -IRTargetScope::IRTargetScope() -{ -} - -IRTargetScope::IRTargetScope(Statement* s, EnclosingHandler* enclosinghandler, llvm::BasicBlock* continueTarget, llvm::BasicBlock* breakTarget) -{ - this->s = s; - this->enclosinghandler = enclosinghandler; - this->breakTarget = breakTarget; - this->continueTarget = continueTarget; -} - -////////////////////////////////////////////////////////////////////////////////////////// -IRState::IRState(llvm::Module* m) - : module(m), dibuilder(*m) -{ - interfaceInfoType = NULL; - mutexType = NULL; - moduleRefType = NULL; - - dmodule = 0; - emitMain = false; - mainFunc = 0; - ir.state = this; - asmBlock = NULL; -} - -IrFunction* IRState::func() -{ - assert(!functions.empty() && "Function stack is empty!"); - return functions.back(); -} - -llvm::Function* IRState::topfunc() -{ - assert(!functions.empty() && "Function stack is empty!"); - return functions.back()->func; -} - -TypeFunction* IRState::topfunctype() -{ - assert(!functions.empty() && "Function stack is empty!"); - return functions.back()->type; -} - -llvm::Instruction* IRState::topallocapoint() -{ - assert(!functions.empty() && "AllocaPoint stack is empty!"); - return functions.back()->allocapoint; -} - -IrStruct* IRState::topstruct() -{ - assert(!structs.empty() && "Struct vector is empty!"); - return structs.back(); -} - -IRScope& IRState::scope() -{ - assert(!scopes.empty()); - return scopes.back(); -} - -llvm::BasicBlock* IRState::scopebb() -{ - IRScope& s = scope(); - assert(s.begin); - return s.begin; -} -llvm::BasicBlock* IRState::scopeend() -{ - IRScope& s = scope(); - assert(s.end); - return s.end; -} -bool IRState::scopereturned() -{ - //return scope().returned; - return !scopebb()->empty() && scopebb()->back().isTerminator(); -} - -LLCallSite IRState::CreateCallOrInvoke(LLValue* Callee, const char* Name) -{ - LLSmallVector args; - return CreateCallOrInvoke(Callee, args, Name); -} - -LLCallSite IRState::CreateCallOrInvoke(LLValue* Callee, LLValue* Arg1, const char* Name) -{ - LLSmallVector args; - args.push_back(Arg1); - return CreateCallOrInvoke(Callee, args, Name); -} - -LLCallSite IRState::CreateCallOrInvoke2(LLValue* Callee, LLValue* Arg1, LLValue* Arg2, const char* Name) -{ - LLSmallVector args; - args.push_back(Arg1); - args.push_back(Arg2); - return CreateCallOrInvoke(Callee, args, Name); -} - -LLCallSite IRState::CreateCallOrInvoke3(LLValue* Callee, LLValue* Arg1, LLValue* Arg2, LLValue* Arg3, const char* Name) -{ - LLSmallVector args; - args.push_back(Arg1); - args.push_back(Arg2); - args.push_back(Arg3); - return CreateCallOrInvoke(Callee, args, Name); -} - -LLCallSite IRState::CreateCallOrInvoke4(LLValue* Callee, LLValue* Arg1, LLValue* Arg2, LLValue* Arg3, LLValue* Arg4, const char* Name) -{ - LLSmallVector args; - args.push_back(Arg1); - args.push_back(Arg2); - args.push_back(Arg3); - args.push_back(Arg4); - return CreateCallOrInvoke(Callee, args, Name); -} - - -////////////////////////////////////////////////////////////////////////////////////////// - -IRBuilder<>* IRBuilderHelper::operator->() -{ - IRBuilder<>& b = state->scope().builder; - assert(b.GetInsertBlock() != NULL); - return &b; -} +/* DMDFE backend stubs + * This file contains the implementations of the backend routines. + * For dmdfe these do nothing but print a message saying the module + * has been parsed. Substitute your own behaviors for these routimes. + */ + +#include + +#include "gen/llvm.h" + +#include "mtype.h" +#include "declaration.h" +#include "statement.h" + +#include "gen/irstate.h" +#include "tollvm.h" + +IRState* gIR = 0; +llvm::TargetMachine* gTargetMachine = 0; +const llvm::TargetData* gTargetData = 0; +TargetABI* gABI = 0; + +////////////////////////////////////////////////////////////////////////////////////////// +IRScope::IRScope() + : builder(gIR->context()) +{ + begin = end = NULL; +} + +IRScope::IRScope(llvm::BasicBlock* b, llvm::BasicBlock* e) + : builder(b) +{ + begin = b; + end = e; +} + +const IRScope& IRScope::operator=(const IRScope& rhs) +{ + begin = rhs.begin; + end = rhs.end; + builder.SetInsertPoint(begin); + return *this; +} + +////////////////////////////////////////////////////////////////////////////////////////// +IRTargetScope::IRTargetScope() +{ +} + +IRTargetScope::IRTargetScope(Statement* s, EnclosingHandler* enclosinghandler, llvm::BasicBlock* continueTarget, llvm::BasicBlock* breakTarget) +{ + this->s = s; + this->enclosinghandler = enclosinghandler; + this->breakTarget = breakTarget; + this->continueTarget = continueTarget; +} + +////////////////////////////////////////////////////////////////////////////////////////// +IRState::IRState(llvm::Module* m) + : module(m), dibuilder(*m) +{ + interfaceInfoType = NULL; + mutexType = NULL; + moduleRefType = NULL; + + dmodule = 0; + emitMain = false; + mainFunc = 0; + ir.state = this; + asmBlock = NULL; +} + +IrFunction* IRState::func() +{ + assert(!functions.empty() && "Function stack is empty!"); + return functions.back(); +} + +llvm::Function* IRState::topfunc() +{ + assert(!functions.empty() && "Function stack is empty!"); + return functions.back()->func; +} + +TypeFunction* IRState::topfunctype() +{ + assert(!functions.empty() && "Function stack is empty!"); + return functions.back()->type; +} + +llvm::Instruction* IRState::topallocapoint() +{ + assert(!functions.empty() && "AllocaPoint stack is empty!"); + return functions.back()->allocapoint; +} + +IrStruct* IRState::topstruct() +{ + assert(!structs.empty() && "Struct vector is empty!"); + return structs.back(); +} + +IRScope& IRState::scope() +{ + assert(!scopes.empty()); + return scopes.back(); +} + +llvm::BasicBlock* IRState::scopebb() +{ + IRScope& s = scope(); + assert(s.begin); + return s.begin; +} +llvm::BasicBlock* IRState::scopeend() +{ + IRScope& s = scope(); + assert(s.end); + return s.end; +} +bool IRState::scopereturned() +{ + //return scope().returned; + return !scopebb()->empty() && scopebb()->back().isTerminator(); +} + +LLCallSite IRState::CreateCallOrInvoke(LLValue* Callee, const char* Name) +{ + LLSmallVector args; + return CreateCallOrInvoke(Callee, args, Name); +} + +LLCallSite IRState::CreateCallOrInvoke(LLValue* Callee, LLValue* Arg1, const char* Name) +{ + LLSmallVector args; + args.push_back(Arg1); + return CreateCallOrInvoke(Callee, args, Name); +} + +LLCallSite IRState::CreateCallOrInvoke2(LLValue* Callee, LLValue* Arg1, LLValue* Arg2, const char* Name) +{ + LLSmallVector args; + args.push_back(Arg1); + args.push_back(Arg2); + return CreateCallOrInvoke(Callee, args, Name); +} + +LLCallSite IRState::CreateCallOrInvoke3(LLValue* Callee, LLValue* Arg1, LLValue* Arg2, LLValue* Arg3, const char* Name) +{ + LLSmallVector args; + args.push_back(Arg1); + args.push_back(Arg2); + args.push_back(Arg3); + return CreateCallOrInvoke(Callee, args, Name); +} + +LLCallSite IRState::CreateCallOrInvoke4(LLValue* Callee, LLValue* Arg1, LLValue* Arg2, LLValue* Arg3, LLValue* Arg4, const char* Name) +{ + LLSmallVector args; + args.push_back(Arg1); + args.push_back(Arg2); + args.push_back(Arg3); + args.push_back(Arg4); + return CreateCallOrInvoke(Callee, args, Name); +} + + +////////////////////////////////////////////////////////////////////////////////////////// + +IRBuilder<>* IRBuilderHelper::operator->() +{ + IRBuilder<>& b = state->scope().builder; + assert(b.GetInsertBlock() != NULL); + return &b; +} diff --git a/gen/irstate.h b/gen/irstate.h index 3c4c7804..e4aa387c 100644 --- a/gen/irstate.h +++ b/gen/irstate.h @@ -1,234 +1,234 @@ -#ifndef LDC_GEN_IRSTATE_H -#define LDC_GEN_IRSTATE_H - -#include -#include -#include -#include - -#include "root.h" -#include "aggregate.h" - -#include "ir/irfunction.h" -#include "ir/irstruct.h" -#include "ir/irvar.h" - -#if LDC_LLVM_VER >= 302 -#include "llvm/DIBuilder.h" -#else -#include "llvm/Analysis/DIBuilder.h" -#endif -#include "llvm/Support/CallSite.h" - -namespace llvm { - class LLVMContext; - class TargetMachine; -} - -// global ir state for current module -struct IRState; -struct TargetABI; - -extern IRState* gIR; -extern llvm::TargetMachine* gTargetMachine; -extern const llvm::TargetData* gTargetData; -extern TargetABI* gABI; - -struct TypeFunction; -struct TypeStruct; -struct ClassDeclaration; -struct FuncDeclaration; -struct Module; -struct TypeStruct; -struct BaseClass; -struct AnonDeclaration; - -struct IrModule; - -// represents a scope -struct IRScope -{ - llvm::BasicBlock* begin; - llvm::BasicBlock* end; - IRBuilder<> builder; - - IRScope(); - IRScope(llvm::BasicBlock* b, llvm::BasicBlock* e); - - const IRScope& operator=(const IRScope& rhs); - -#if DMDV2 - // list of variables needing destruction - std::vector varsInScope; -#endif -}; - -struct IRBuilderHelper -{ - IRState* state; - IRBuilder<>* operator->(); -}; - -struct IRAsmStmt -{ - IRAsmStmt() - : isBranchToLabel(NULL) {} - - std::string code; - std::string out_c; - std::string in_c; - std::vector out; - std::vector in; - - // if this is nonzero, it contains the target label - Identifier* isBranchToLabel; -}; - -struct IRAsmBlock -{ - std::deque s; - std::set clobs; - size_t outputcount; - - // stores the labels within the asm block - std::vector internalLabels; - - AsmBlockStatement* asmBlock; - LLType* retty; - unsigned retn; - bool retemu; // emulate abi ret with a temporary - LLValue* (*retfixup)(IRBuilderHelper b, LLValue* orig); // Modifies retval - - IRAsmBlock(AsmBlockStatement* b) - : outputcount(0), asmBlock(b), retty(NULL), retn(0), retemu(false), - retfixup(NULL) - {} -}; - -// represents the module -struct IRState -{ - IRState(llvm::Module* m); - - // module - Module* dmodule; - llvm::Module* module; - - // interface info type, used in DtoInterfaceInfoType - LLStructType* interfaceInfoType; - LLStructType* mutexType; - LLStructType* moduleRefType; - - // helper to get the LLVMContext of the module - llvm::LLVMContext& context() const { return module->getContext(); } - - // functions - typedef std::vector FunctionVector; - FunctionVector functions; - IrFunction* func(); - - llvm::Function* topfunc(); - TypeFunction* topfunctype(); - llvm::Instruction* topallocapoint(); - - // structs - typedef std::vector StructVector; - StructVector structs; - IrStruct* topstruct(); - - // D main function - bool emitMain; - llvm::Function* mainFunc; - - // basic block scopes - std::vector scopes; - IRScope& scope(); -#if DMDV2 - std::vector &varsInScope() { return scope().varsInScope; } -#endif - llvm::BasicBlock* scopebb(); - llvm::BasicBlock* scopeend(); - bool scopereturned(); - - // create a call or invoke, depending on the landing pad info - // the template function is defined further down in this file - template - llvm::CallSite CreateCallOrInvoke(LLValue* Callee, const T& args, const char* Name=""); - llvm::CallSite CreateCallOrInvoke(LLValue* Callee, const char* Name=""); - llvm::CallSite CreateCallOrInvoke(LLValue* Callee, LLValue* Arg1, const char* Name=""); - llvm::CallSite CreateCallOrInvoke2(LLValue* Callee, LLValue* Arg1, LLValue* Arg2, const char* Name=""); - llvm::CallSite CreateCallOrInvoke3(LLValue* Callee, LLValue* Arg1, LLValue* Arg2, LLValue* Arg3, const char* Name=""); - llvm::CallSite CreateCallOrInvoke4(LLValue* Callee, LLValue* Arg1, LLValue* Arg2, LLValue* Arg3, LLValue* Arg4, const char* Name=""); - - // this holds the array being indexed or sliced so $ will work - // might be a better way but it works. problem is I only get a - // VarDeclaration for __dollar, but I can't see how to get the - // array pointer from this :( - std::vector arrays; - - // builder helper - IRBuilderHelper ir; - - // debug info helper - llvm::DIBuilder dibuilder; - - // static ctors/dtors/unittests - typedef std::list FuncDeclList; - typedef std::list GatesList; - FuncDeclList ctors; - FuncDeclList dtors; -#if DMDV2 - FuncDeclList sharedCtors; - FuncDeclList sharedDtors; - GatesList gates; - GatesList sharedGates; -#endif - FuncDeclList unitTests; - - // all template instances that had members emitted - // currently only filled for singleobj - // used to make sure the complete template instance gets emitted in the - // first file that touches a member, see #318 - typedef std::set TemplateInstanceSet; - TemplateInstanceSet seenTemplateInstances; - - // for inline asm - IRAsmBlock* asmBlock; - std::ostringstream nakedAsm; - - // 'used' array solely for keeping a reference to globals - std::vector usedArray; -}; - -template -llvm::CallSite IRState::CreateCallOrInvoke(LLValue* Callee, const T &args, const char* Name) -{ - llvm::BasicBlock* pad = func()->gen->landingPad; - if(pad) - { - // intrinsics don't support invoking and 'nounwind' functions don't need it. - LLFunction* funcval = llvm::dyn_cast(Callee); - if (funcval && (funcval->isIntrinsic() || funcval->doesNotThrow())) - { - llvm::CallInst* call = ir->CreateCall(Callee, args, Name); - call->setAttributes(funcval->getAttributes()); - return call; - } - - llvm::BasicBlock* postinvoke = llvm::BasicBlock::Create(gIR->context(), "postinvoke", topfunc(), scopeend()); - llvm::InvokeInst* invoke = ir->CreateInvoke(Callee, postinvoke, pad, args, Name); - if (LLFunction* fn = llvm::dyn_cast(Callee)) - invoke->setAttributes(fn->getAttributes()); - scope() = IRScope(postinvoke, scopeend()); - return invoke; - } - else - { - llvm::CallInst* call = ir->CreateCall(Callee, args, Name); - if (LLFunction* fn = llvm::dyn_cast(Callee)) - call->setAttributes(fn->getAttributes()); - return call; - } -} - -#endif // LDC_GEN_IRSTATE_H +#ifndef LDC_GEN_IRSTATE_H +#define LDC_GEN_IRSTATE_H + +#include +#include +#include +#include + +#include "root.h" +#include "aggregate.h" + +#include "ir/irfunction.h" +#include "ir/irstruct.h" +#include "ir/irvar.h" + +#if LDC_LLVM_VER >= 302 +#include "llvm/DIBuilder.h" +#else +#include "llvm/Analysis/DIBuilder.h" +#endif +#include "llvm/Support/CallSite.h" + +namespace llvm { + class LLVMContext; + class TargetMachine; +} + +// global ir state for current module +struct IRState; +struct TargetABI; + +extern IRState* gIR; +extern llvm::TargetMachine* gTargetMachine; +extern const llvm::TargetData* gTargetData; +extern TargetABI* gABI; + +struct TypeFunction; +struct TypeStruct; +struct ClassDeclaration; +struct FuncDeclaration; +struct Module; +struct TypeStruct; +struct BaseClass; +struct AnonDeclaration; + +struct IrModule; + +// represents a scope +struct IRScope +{ + llvm::BasicBlock* begin; + llvm::BasicBlock* end; + IRBuilder<> builder; + + IRScope(); + IRScope(llvm::BasicBlock* b, llvm::BasicBlock* e); + + const IRScope& operator=(const IRScope& rhs); + +#if DMDV2 + // list of variables needing destruction + std::vector varsInScope; +#endif +}; + +struct IRBuilderHelper +{ + IRState* state; + IRBuilder<>* operator->(); +}; + +struct IRAsmStmt +{ + IRAsmStmt() + : isBranchToLabel(NULL) {} + + std::string code; + std::string out_c; + std::string in_c; + std::vector out; + std::vector in; + + // if this is nonzero, it contains the target label + Identifier* isBranchToLabel; +}; + +struct IRAsmBlock +{ + std::deque s; + std::set clobs; + size_t outputcount; + + // stores the labels within the asm block + std::vector internalLabels; + + AsmBlockStatement* asmBlock; + LLType* retty; + unsigned retn; + bool retemu; // emulate abi ret with a temporary + LLValue* (*retfixup)(IRBuilderHelper b, LLValue* orig); // Modifies retval + + IRAsmBlock(AsmBlockStatement* b) + : outputcount(0), asmBlock(b), retty(NULL), retn(0), retemu(false), + retfixup(NULL) + {} +}; + +// represents the module +struct IRState +{ + IRState(llvm::Module* m); + + // module + Module* dmodule; + llvm::Module* module; + + // interface info type, used in DtoInterfaceInfoType + LLStructType* interfaceInfoType; + LLStructType* mutexType; + LLStructType* moduleRefType; + + // helper to get the LLVMContext of the module + llvm::LLVMContext& context() const { return module->getContext(); } + + // functions + typedef std::vector FunctionVector; + FunctionVector functions; + IrFunction* func(); + + llvm::Function* topfunc(); + TypeFunction* topfunctype(); + llvm::Instruction* topallocapoint(); + + // structs + typedef std::vector StructVector; + StructVector structs; + IrStruct* topstruct(); + + // D main function + bool emitMain; + llvm::Function* mainFunc; + + // basic block scopes + std::vector scopes; + IRScope& scope(); +#if DMDV2 + std::vector &varsInScope() { return scope().varsInScope; } +#endif + llvm::BasicBlock* scopebb(); + llvm::BasicBlock* scopeend(); + bool scopereturned(); + + // create a call or invoke, depending on the landing pad info + // the template function is defined further down in this file + template + llvm::CallSite CreateCallOrInvoke(LLValue* Callee, const T& args, const char* Name=""); + llvm::CallSite CreateCallOrInvoke(LLValue* Callee, const char* Name=""); + llvm::CallSite CreateCallOrInvoke(LLValue* Callee, LLValue* Arg1, const char* Name=""); + llvm::CallSite CreateCallOrInvoke2(LLValue* Callee, LLValue* Arg1, LLValue* Arg2, const char* Name=""); + llvm::CallSite CreateCallOrInvoke3(LLValue* Callee, LLValue* Arg1, LLValue* Arg2, LLValue* Arg3, const char* Name=""); + llvm::CallSite CreateCallOrInvoke4(LLValue* Callee, LLValue* Arg1, LLValue* Arg2, LLValue* Arg3, LLValue* Arg4, const char* Name=""); + + // this holds the array being indexed or sliced so $ will work + // might be a better way but it works. problem is I only get a + // VarDeclaration for __dollar, but I can't see how to get the + // array pointer from this :( + std::vector arrays; + + // builder helper + IRBuilderHelper ir; + + // debug info helper + llvm::DIBuilder dibuilder; + + // static ctors/dtors/unittests + typedef std::list FuncDeclList; + typedef std::list GatesList; + FuncDeclList ctors; + FuncDeclList dtors; +#if DMDV2 + FuncDeclList sharedCtors; + FuncDeclList sharedDtors; + GatesList gates; + GatesList sharedGates; +#endif + FuncDeclList unitTests; + + // all template instances that had members emitted + // currently only filled for singleobj + // used to make sure the complete template instance gets emitted in the + // first file that touches a member, see #318 + typedef std::set TemplateInstanceSet; + TemplateInstanceSet seenTemplateInstances; + + // for inline asm + IRAsmBlock* asmBlock; + std::ostringstream nakedAsm; + + // 'used' array solely for keeping a reference to globals + std::vector usedArray; +}; + +template +llvm::CallSite IRState::CreateCallOrInvoke(LLValue* Callee, const T &args, const char* Name) +{ + llvm::BasicBlock* pad = func()->gen->landingPad; + if(pad) + { + // intrinsics don't support invoking and 'nounwind' functions don't need it. + LLFunction* funcval = llvm::dyn_cast(Callee); + if (funcval && (funcval->isIntrinsic() || funcval->doesNotThrow())) + { + llvm::CallInst* call = ir->CreateCall(Callee, args, Name); + call->setAttributes(funcval->getAttributes()); + return call; + } + + llvm::BasicBlock* postinvoke = llvm::BasicBlock::Create(gIR->context(), "postinvoke", topfunc(), scopeend()); + llvm::InvokeInst* invoke = ir->CreateInvoke(Callee, postinvoke, pad, args, Name); + if (LLFunction* fn = llvm::dyn_cast(Callee)) + invoke->setAttributes(fn->getAttributes()); + scope() = IRScope(postinvoke, scopeend()); + return invoke; + } + else + { + llvm::CallInst* call = ir->CreateCall(Callee, args, Name); + if (LLFunction* fn = llvm::dyn_cast(Callee)) + call->setAttributes(fn->getAttributes()); + return call; + } +} + +#endif // LDC_GEN_IRSTATE_H diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index 625dbb7a..50c47c07 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -393,19 +393,7 @@ void DtoAssign(Loc& loc, DValue* lhs, DValue* rhs, int op) Type* t2 = rhs->getType()->toBasetype(); if (t->ty == Tstruct) { - if (!stripModifiers(t)->equals(stripModifiers(t2))) { - // FIXME: use 'rhs' for something !?! - DtoAggrZeroInit(lhs->getLVal()); -#if DMDV2 - TypeStruct *ts = static_cast(lhs->getType()); - if (ts->sym->isNested() && ts->sym->vthis) - DtoResolveNestedContext(loc, ts->sym, lhs->getLVal()); -#endif - } - else { - DtoAggrCopy(lhs->getLVal(), rhs->getRVal()); - } - + DtoAggrCopy(lhs->getLVal(), rhs->getRVal()); } else if (t->ty == Tarray) { // lhs is slice @@ -1013,6 +1001,110 @@ void DtoConstInitGlobal(VarDeclaration* vd) /*//////////////////////////////////////////////////////////////////////////////////////// // DECLARATION EXP HELPER ////////////////////////////////////////////////////////////////////////////////////////*/ + +// TODO: Merge with DtoRawVarDeclaration! +void DtoVarDeclaration(VarDeclaration* vd) +{ + assert(!vd->isDataseg() && "Statics/globals are handled in DtoDeclarationExp."); + assert(!vd->aliassym && "Aliases are handled in DtoDeclarationExp."); + + Logger::println("vdtype = %s", vd->type->toChars()); + +#if DMDV2 + if (vd->nestedrefs.dim) +#else + if (vd->nestedref) +#endif + { + Logger::println("has nestedref set (referenced by nested function/delegate)"); + assert(vd->ir.irLocal && "irLocal is expected to be already set by DtoCreateNestedContext"); + } + + if(vd->ir.irLocal) + { + // Nothing to do if it has already been allocated. + } +#if DMDV2 + /* Named Return Value Optimization (NRVO): + T f(){ + T ret; // &ret == hidden pointer + ret = ... + return ret; // NRVO. + } + */ + else if (gIR->func()->retArg && gIR->func()->decl->nrvo_can && gIR->func()->decl->nrvo_var == vd) { + assert(!isSpecialRefVar(vd) && "Can this happen?"); + vd->ir.irLocal = new IrLocal(vd); + vd->ir.irLocal->value = gIR->func()->retArg; + } +#endif + // normal stack variable, allocate storage on the stack if it has not already been done + else { + vd->ir.irLocal = new IrLocal(vd); + +#if DMDV2 + /* NRVO again: + T t = f(); // t's memory address is taken hidden pointer + */ + ExpInitializer *ei = 0; + if (vd->type->toBasetype()->ty == Tstruct && vd->init && + !!(ei = vd->init->isExpInitializer())) + { + if (ei->exp->op == TOKconstruct) { + AssignExp *ae = static_cast(ei->exp); + if (ae->e2->op == TOKcall) { + CallExp *ce = static_cast(ae->e2); + TypeFunction *tf = static_cast(ce->e1->type->toBasetype()); + if (tf->ty == Tfunction && tf->fty.arg_sret) { + LLValue* const val = ce->toElem(gIR)->getLVal(); + if (isSpecialRefVar(vd)) + { + vd->ir.irLocal->value = DtoAlloca( + vd->type->pointerTo(), vd->toChars()); + DtoStore(val, vd->ir.irLocal->value); + } + else + { + vd->ir.irLocal->value = val; + } + goto Lexit; + } + } + } + } +#endif + + Type* type = isSpecialRefVar(vd) ? vd->type->pointerTo() : vd->type; + LLType* lltype = DtoType(type); + + llvm::Value* allocainst; + if(gTargetData->getTypeSizeInBits(lltype) == 0) + allocainst = llvm::ConstantPointerNull::get(getPtrToType(lltype)); + else + allocainst = DtoAlloca(type, vd->toChars()); + + vd->ir.irLocal->value = allocainst; + + DtoDwarfLocalVariable(allocainst, vd); + } + + if (Logger::enabled()) + Logger::cout() << "llvm value for decl: " << *vd->ir.irLocal->value << '\n'; + + DtoInitializer(vd->ir.irLocal->value, vd->init); // TODO: Remove altogether? + +#if DMDV2 +Lexit: + /* Mark the point of construction of a variable that needs to be destructed. + */ + if (vd->edtor && !vd->noscope) + { + // Put vd on list of things needing destruction + gIR->varsInScope().push_back(vd); + } +#endif +} + DValue* DtoDeclarationExp(Dsymbol* declaration) { Logger::print("DtoDeclarationExp: %s\n", declaration->toChars()); @@ -1036,123 +1128,8 @@ DValue* DtoDeclarationExp(Dsymbol* declaration) } else { - if (global.params.llvmAnnotate) - DtoAnnotation(declaration->toChars()); - - Logger::println("vdtype = %s", vd->type->toChars()); - - // ref vardecls are generated when DMD lowers foreach to a for statement, - // and this is a hack to support them for this case only - if(vd->isRef()) - { - if (!vd->ir.irLocal) - vd->ir.irLocal = new IrLocal(vd); - - ExpInitializer* ex = vd->init->isExpInitializer(); - assert(ex && "ref vars must have expression initializer"); - assert(ex->exp); - AssignExp* as = ex->exp->isAssignExp(); - assert(as && "ref vars must be initialized by an assign exp"); - DValue *val = as->e2->toElem(gIR); - if (val->isLVal()) - { - vd->ir.irLocal->value = val->getLVal(); - } - else - { - LLValue *newVal = DtoAlloca(val->type); - DtoStore(val->getRVal(), newVal); - vd->ir.irLocal->value = newVal; - } - } - - // referenced by nested delegate? - #if DMDV2 - if (vd->nestedrefs.dim) { - #else - if (vd->nestedref) { - #endif - Logger::println("has nestedref set"); - assert(vd->ir.irLocal); - DtoNestedInit(vd); - // is it already allocated? - } else if(vd->ir.irLocal) { - // nothing to do... - } -#if DMDV2 - /* Named Return Value Optimization (NRVO): - T f(){ - T ret; // &ret == hidden pointer - ret = ... - return ret; // NRVO. - } - */ - else if (gIR->func()->retArg && gIR->func()->decl->nrvo_can && gIR->func()->decl->nrvo_var == vd) { - vd->ir.irLocal = new IrLocal(vd); - vd->ir.irLocal->value = gIR->func()->retArg; - } -#endif - // normal stack variable, allocate storage on the stack if it has not already been done - else if(!vd->isRef()) { - vd->ir.irLocal = new IrLocal(vd); - -#if DMDV2 - /* NRVO again: - T t = f(); // t's memory address is taken hidden pointer - */ - ExpInitializer *ei = 0; - if (vd->type->toBasetype()->ty == Tstruct && vd->init && - !!(ei = vd->init->isExpInitializer())) - { - if (ei->exp->op == TOKconstruct) { - AssignExp *ae = static_cast(ei->exp); - if (ae->e2->op == TOKcall) { - CallExp *ce = static_cast(ae->e2); - TypeFunction *tf = static_cast(ce->e1->type->toBasetype()); - if (tf->ty == Tfunction && tf->fty.arg_sret) { - vd->ir.irLocal->value = ce->toElem(gIR)->getLVal(); - goto Lexit; - } - } - } - } -#endif - - LLType* lltype = DtoType(vd->type); - - llvm::Value* allocainst; - if(gTargetData->getTypeSizeInBits(lltype) == 0) - allocainst = llvm::ConstantPointerNull::get(getPtrToType(lltype)); - else - allocainst = DtoAlloca(vd->type, vd->toChars()); - - //allocainst->setAlignment(vd->type->alignsize()); // TODO - vd->ir.irLocal->value = allocainst; - - DtoDwarfLocalVariable(allocainst, vd); - } - else - { - assert(vd->ir.irLocal->value); - } - - if (Logger::enabled()) - Logger::cout() << "llvm value for decl: " << *vd->ir.irLocal->value << '\n'; - if (!vd->isRef()) - DtoInitializer(vd->ir.irLocal->value, vd->init); // TODO: Remove altogether? - -#if DMDV2 - Lexit: - /* Mark the point of construction of a variable that needs to be destructed. - */ - if (vd->edtor && !vd->noscope) - { - // Put vd on list of things needing destruction - gIR->varsInScope().push_back(vd); - } -#endif + DtoVarDeclaration(vd); } - return new DVarValue(vd->type, vd, vd->ir.getIrValue()); } // struct declaration @@ -1276,8 +1253,6 @@ LLValue* DtoRawVarDeclaration(VarDeclaration* var, LLValue* addr) } else assert(!addr || addr == var->ir.irLocal->value); - - DtoNestedInit(var); } // normal local variable else @@ -1461,7 +1436,7 @@ static LLConstant* expand_to_sarray(Type *base, Expression* exp) TypeSArray* tsa = static_cast(t); dims.push_back(tsa->dim->toInteger()); assert(t->nextOf()); - t = t->nextOf()->toBasetype(); + t = stripModifiers(t->nextOf()->toBasetype()); } size_t i = dims.size(); @@ -1482,8 +1457,8 @@ static LLConstant* expand_to_sarray(Type *base, Expression* exp) LLConstant* DtoConstExpInit(Loc loc, Type* type, Expression* exp) { #if DMDV2 - Type* expbase = exp->type->toBasetype()->mutableOf()->merge(); - Type* base = type->toBasetype()->mutableOf()->merge(); + Type* expbase = stripModifiers(exp->type->toBasetype())->merge(); + Type* base = stripModifiers(type->toBasetype())->merge(); #else Type* expbase = exp->type->toBasetype(); Type* base = type->toBasetype(); @@ -1501,9 +1476,18 @@ LLConstant* DtoConstExpInit(Loc loc, Type* type, Expression* exp) Logger::println("type is a static array, building constant array initializer to single value"); return expand_to_sarray(base, exp); } +#if DMDV2 + else if (base->ty == Tvector) + { + LLConstant* val = exp->toConstElem(gIR); + TypeVector* tv = (TypeVector*)base; + return llvm::ConstantVector::getSplat(tv->size(loc), val); + } +#endif else { - error("cannot yet convert default initializer %s of type %s to %s", exp->toChars(), exp->type->toChars(), type->toChars()); + error(loc, "LDC internal error: cannot yet convert default initializer %s of type %s to %s", + exp->toChars(), exp->type->toChars(), type->toChars()); fatal(); } assert(0); @@ -1769,85 +1753,7 @@ Type * stripModifiers( Type * type ) #if DMDV2 if (type->ty == Tfunction) return type; - Type *t = type; - while (t->mod) - { - switch (t->mod) - { - case MODconst: - t = type->cto; - break; - case MODshared: - t = type->sto; - break; - case MODimmutable: - t = type->ito; - break; - case MODshared | MODconst: - t = type->scto; - break; - case MODwild: - t = type->wto; - break; - case MODshared | MODwild: - t = type->swto; - break; - default: - assert(0 && "Unhandled type modifier"); - } - - if (!t) - { - unsigned sz = type->sizeTy[type->ty]; - t = static_cast(malloc(sz)); - memcpy(t, type, sz); - t->mod = 0; - t->deco = NULL; - t->arrayof = NULL; - t->pto = NULL; - t->rto = NULL; - t->cto = NULL; - t->ito = NULL; - t->sto = NULL; - t->scto = NULL; - t->wto = NULL; - t->swto = NULL; - t->vtinfo = NULL; - t = t->merge(); - - t->fixTo(type); - switch (type->mod) - { - case MODconst: - t->cto = type; - break; - - case MODimmutable: - t->ito = type; - break; - - case MODshared: - t->sto = type; - break; - - case MODshared | MODconst: - t->scto = type; - break; - - case MODwild: - t->wto = type; - break; - - case MODshared | MODwild: - t->swto = type; - break; - - default: - assert(0); - } - } - } - return t; + return type->castMod(0); #else return type; #endif @@ -1895,7 +1801,7 @@ void callPostblit(Loc &loc, Expression *exp, LLValue *val) { Type *tb = exp->type->toBasetype(); - if ((exp->op == TOKvar || exp->op == TOKdotvar || exp->op == TOKstar || exp->op == TOKthis) && + if ((exp->op == TOKvar || exp->op == TOKdotvar || exp->op == TOKstar || exp->op == TOKthis || exp->op == TOKindex) && tb->ty == Tstruct) { StructDeclaration *sd = static_cast(tb)->sym; if (sd->postblit) @@ -1914,6 +1820,13 @@ void callPostblit(Loc &loc, Expression *exp, LLValue *val) ////////////////////////////////////////////////////////////////////////////////////////// +bool isSpecialRefVar(VarDeclaration* vd) +{ + return (vd->storage_class & STCref) && (vd->storage_class & STCforeach); +} + +////////////////////////////////////////////////////////////////////////////////////////// + void printLabelName(std::ostream& target, const char* func_mangle, const char* label_name) { target << gTargetMachine->getMCAsmInfo()->getPrivateGlobalPrefix() << diff --git a/gen/llvmhelpers.h b/gen/llvmhelpers.h index ab80da92..1fd85a07 100644 --- a/gen/llvmhelpers.h +++ b/gen/llvmhelpers.h @@ -98,6 +98,7 @@ void DtoResolveDsymbol(Dsymbol* dsym); void DtoConstInitGlobal(VarDeclaration* vd); // declaration inside a declarationexp +void DtoVarDeclaration(VarDeclaration* var); DValue* DtoDeclarationExp(Dsymbol* declaration); LLValue* DtoRawVarDeclaration(VarDeclaration* var, LLValue* addr = 0); @@ -158,6 +159,14 @@ LLValue* makeLValue(Loc& loc, DValue* value); void callPostblit(Loc &loc, Expression *exp, LLValue *val); #endif +/// Returns whether the given variable is a DMD-internal "ref variable". +/// +/// D doesn't have reference variables (the ref keyword is only usable in +/// function signatures and foreach headers), but the DMD frontend internally +/// creates them in cases like lowering a ref foreach to a for loop or the +/// implicit __result variable for ref-return functions with out contracts. +bool isSpecialRefVar(VarDeclaration* vd); + //////////////////////////////////////////// // gen/tocall.cpp stuff below //////////////////////////////////////////// diff --git a/gen/module.cpp b/gen/module.cpp index e96d83ca..a52a4c1b 100644 --- a/gen/module.cpp +++ b/gen/module.cpp @@ -217,9 +217,16 @@ llvm::Module* Module::genLLVMModule(llvm::LLVMContext& context, Ir* sir) assert(!global.errors); // name the module +#if 1 + // Temporary workaround for http://llvm.org/bugs/show_bug.cgi?id=11479 – + // just use the source file name, as it is unlikely to collide with a + // symbol name used somewhere in the module. + llvm::StringRef mname(srcfile->toChars()); +#else llvm::StringRef mname(toChars()); if (md != 0) mname = md->toChars(); +#endif // create a new ir state // TODO look at making the instance static and moving most functionality into IrModule where it belongs diff --git a/gen/naked.cpp b/gen/naked.cpp index 15bd27e7..b703f758 100644 --- a/gen/naked.cpp +++ b/gen/naked.cpp @@ -18,7 +18,7 @@ void Statement::toNakedIR(IRState *p) { - error("not allowed in naked function"); + error("statement not allowed in naked function"); } ////////////////////////////////////////////////////////////////////////////////////////// @@ -179,6 +179,11 @@ void DtoDefineNakedFunction(FuncDeclaration* fd) // emit body fd->fbody->toNakedIR(gIR); + // We could have generated new errors in toNakedIR(), but we are in codegen + // already so we have to abort here. + if (global.errors) + fatal(); + // emit size after body // llvm does this on linux, but not on osx or Win if (global.params.os != OSMacOSX && global.params.os != OSWindows) diff --git a/gen/nested.cpp b/gen/nested.cpp index 1e4213ab..e84f7446 100644 --- a/gen/nested.cpp +++ b/gen/nested.cpp @@ -12,42 +12,6 @@ #include "llvm/Support/CommandLine.h" namespace cl = llvm::cl; -/// What the context pointer for a nested function looks like -enum NestedCtxType { - /// Context is void*[] of pointers to variables. - /// Variables from higher levels are at the front. - NCArray, - - /// Context is a struct containing variables belonging to the parent function. - /// If the parent function itself has a parent function, one of the members is - /// a pointer to its context. (linked-list style) - // FIXME: implement - // TODO: Functions without any variables accessed by nested functions, but - // with a parent whose variables are accessed, can use the parent's - // context. - // NOTE: This is what DMD seems to do. - NCStruct, - - /// Context is a list of pointers to structs of variables, followed by the - /// variables of the inner-most function with variables accessed by nested - /// functions. The initial pointers point to similar structs for enclosing - /// functions. - /// Only functions whose variables are accessed by nested functions create - /// new frames, others just pass on what got passed in. - NCHybrid -}; - -static cl::opt nestedCtx("nested-ctx", - cl::desc("How to construct a nested function's context:"), - cl::ZeroOrMore, - cl::values( - clEnumValN(NCArray, "array", "Array of pointers to variables (including multi-level)"), - //clEnumValN(NCStruct, "struct", "Struct of variables (with multi-level via linked list)"), - clEnumValN(NCHybrid, "hybrid", "List of pointers to structs of variables, one per level."), - clEnumValEnd), - cl::init(NCHybrid)); - - /****************************************************************************************/ /*//////////////////////////////////////////////////////////////////////////////////////// // NESTED VARIABLE HELPERS @@ -168,114 +132,51 @@ DValue* DtoNestedVariable(Loc loc, Type* astype, VarDeclaration* vd, bool byref) //////////////////////////////////// // Extract variable from nested context - if (nestedCtx == NCArray) { - LLValue* val = DtoBitCast(ctx, getPtrToType(getVoidPtrType())); - val = DtoGEPi1(val, vd->ir.irLocal->nestedIndex); + LLValue* val = DtoBitCast(ctx, LLPointerType::getUnqual(irfunc->frameType)); + Logger::cout() << "Context: " << *val << '\n'; + Logger::cout() << "of type: " << *val->getType() << '\n'; + + unsigned vardepth = vd->ir.irLocal->nestedDepth; + unsigned funcdepth = irfunc->depth; + + Logger::cout() << "Variable: " << vd->toChars() << '\n'; + Logger::cout() << "Variable depth: " << vardepth << '\n'; + Logger::cout() << "Function: " << irfunc->decl->toChars() << '\n'; + Logger::cout() << "Function depth: " << funcdepth << '\n'; + + if (vardepth == funcdepth) { + // This is not always handled above because functions without + // variables accessed by nested functions don't create new frames. + Logger::println("Same depth"); + } else { + // Load frame pointer and index that... + if (dwarfValue && global.params.symdebug) { + dwarfOpOffset(dwarfAddr, val, vd->ir.irLocal->nestedDepth); + dwarfOpDeref(dwarfAddr); + } + Logger::println("Lower depth"); + val = DtoGEPi(val, 0, vd->ir.irLocal->nestedDepth); + Logger::cout() << "Frame index: " << *val << '\n'; + val = DtoAlignedLoad(val, (std::string(".frame.") + vdparent->toChars()).c_str()); + Logger::cout() << "Frame: " << *val << '\n'; + } + + if (dwarfValue && global.params.symdebug) + dwarfOpOffset(dwarfAddr, val, vd->ir.irLocal->nestedIndex); + val = DtoGEPi(val, 0, vd->ir.irLocal->nestedIndex, vd->toChars()); + Logger::cout() << "Addr: " << *val << '\n'; + Logger::cout() << "of type: " << *val->getType() << '\n'; + if (byref || (vd->isParameter() && vd->ir.irParam->arg->byref)) { val = DtoAlignedLoad(val); - assert(vd->ir.irLocal->value); - val = DtoBitCast(val, vd->ir.irLocal->value->getType(), vd->toChars()); - return new DVarValue(astype, vd, val); - } - else if (nestedCtx == NCHybrid) { - LLValue* val = DtoBitCast(ctx, LLPointerType::getUnqual(irfunc->frameType)); - Logger::cout() << "Context: " << *val << '\n'; + //dwarfOpDeref(dwarfAddr); + Logger::cout() << "Was byref, now: " << *val << '\n'; Logger::cout() << "of type: " << *val->getType() << '\n'; - - unsigned vardepth = vd->ir.irLocal->nestedDepth; - unsigned funcdepth = irfunc->depth; - - Logger::cout() << "Variable: " << vd->toChars() << '\n'; - Logger::cout() << "Variable depth: " << vardepth << '\n'; - Logger::cout() << "Function: " << irfunc->decl->toChars() << '\n'; - Logger::cout() << "Function depth: " << funcdepth << '\n'; - - if (vardepth == funcdepth) { - // This is not always handled above because functions without - // variables accessed by nested functions don't create new frames. - Logger::println("Same depth"); - } else { - // Load frame pointer and index that... - if (dwarfValue && global.params.symdebug) { - dwarfOpOffset(dwarfAddr, val, vd->ir.irLocal->nestedDepth); - dwarfOpDeref(dwarfAddr); - } - Logger::println("Lower depth"); - val = DtoGEPi(val, 0, vd->ir.irLocal->nestedDepth); - Logger::cout() << "Frame index: " << *val << '\n'; - val = DtoAlignedLoad(val, (std::string(".frame.") + vdparent->toChars()).c_str()); - Logger::cout() << "Frame: " << *val << '\n'; - } - - if (dwarfValue && global.params.symdebug) - dwarfOpOffset(dwarfAddr, val, vd->ir.irLocal->nestedIndex); - val = DtoGEPi(val, 0, vd->ir.irLocal->nestedIndex, vd->toChars()); - Logger::cout() << "Addr: " << *val << '\n'; - Logger::cout() << "of type: " << *val->getType() << '\n'; - if (vd->ir.irLocal->byref || byref) { - val = DtoAlignedLoad(val); - //dwarfOpDeref(dwarfAddr); - Logger::cout() << "Was byref, now: " << *val << '\n'; - Logger::cout() << "of type: " << *val->getType() << '\n'; - } - - if (dwarfValue && global.params.symdebug) - DtoDwarfLocalVariable(dwarfValue, vd, dwarfAddr); - - return new DVarValue(astype, vd, val); } - else { - assert(0 && "Not implemented yet"); - } -} -void DtoNestedInit(VarDeclaration* vd) -{ - Logger::println("DtoNestedInit for %s", vd->toChars()); - LOG_SCOPE + if (dwarfValue && global.params.symdebug) + DtoDwarfLocalVariable(dwarfValue, vd, dwarfAddr); - IrFunction* irfunc = gIR->func()->decl->ir.irFunc; - LLValue* nestedVar = irfunc->nestedVar; - - if (nestedCtx == NCArray) { - // alloca as usual if no value already - if (!vd->ir.irLocal->value) - vd->ir.irLocal->value = DtoAlloca(vd->type, vd->toChars()); - - // store the address into the nested vars array - assert(vd->ir.irLocal->nestedIndex >= 0); - LLValue* gep = DtoGEPi(nestedVar, 0, vd->ir.irLocal->nestedIndex); - - assert(isaPointer(vd->ir.irLocal->value)); - LLValue* val = DtoBitCast(vd->ir.irLocal->value, getVoidPtrType()); - - DtoAlignedStore(val, gep); - } - else if (nestedCtx == NCHybrid) { - assert(vd->ir.irLocal->value && "Nested variable without storage?"); - - if (!vd->isParameter() && (vd->isRef() || vd->isOut())) { - unsigned vardepth = vd->ir.irLocal->nestedDepth; - - LLValue* val = NULL; - // Retrieve frame pointer - if (vardepth == irfunc->depth) { - val = nestedVar; - } else { - FuncDeclaration *parentfunc = getParentFunc(vd, true); - assert(parentfunc && "No parent function for nested variable?"); - - val = DtoGEPi(nestedVar, 0, vardepth); - val = DtoAlignedLoad(val, (std::string(".frame.") + parentfunc->toChars()).c_str()); - } - val = DtoGEPi(val, 0, vd->ir.irLocal->nestedIndex, vd->toChars()); - storeVariable(vd, val); - } else { - // Already initialized in DtoCreateNestedContext - } - } - else { - assert(0 && "Not implemented yet"); - } + return new DVarValue(astype, vd, val); } #if DMDV2 @@ -336,60 +237,60 @@ LLValue* DtoNestedContext(Loc loc, Dsymbol* sym) { return llvm::UndefValue::get(getVoidPtrType()); } - if (nestedCtx == NCHybrid) { - struct FuncDeclaration* fd = 0; - #if DMDV2 - if (AggregateDeclaration *ad = sym->isAggregateDeclaration()) - // If sym is a nested struct or a nested class, pass the frame - // of the function where sym is declared. - fd = ad->toParent()->isFuncDeclaration(); - else - #endif - if (FuncDeclaration* symfd = sym->isFuncDeclaration()) { - // Make sure we've had a chance to analyze nested context usage - #if DMDV2 - DtoCreateNestedContextType(symfd); - #else - DtoDefineFunction(symfd); - #endif - // if this is for a function that doesn't access variables from - // enclosing scopes, it doesn't matter what we pass. - // Tell LLVM about it by passing an 'undef'. - if (symfd && symfd->ir.irFunc->depth == -1) - return llvm::UndefValue::get(getVoidPtrType()); + struct FuncDeclaration* fd = 0; +#if DMDV2 + if (AggregateDeclaration *ad = sym->isAggregateDeclaration()) + // If sym is a nested struct or a nested class, pass the frame + // of the function where sym is declared. + fd = ad->toParent()->isFuncDeclaration(); + else +#endif + if (FuncDeclaration* symfd = sym->isFuncDeclaration()) { + // Make sure we've had a chance to analyze nested context usage +#if DMDV2 + DtoCreateNestedContextType(symfd); +#else + DtoDefineFunction(symfd); +#endif - // If sym is a nested function, and it's parent context is different than the - // one we got, adjust it. - fd = getParentFunc(symfd, true); + // if this is for a function that doesn't access variables from + // enclosing scopes, it doesn't matter what we pass. + // Tell LLVM about it by passing an 'undef'. + if (symfd && symfd->ir.irFunc->depth == -1) + return llvm::UndefValue::get(getVoidPtrType()); + + // If sym is a nested function, and it's parent context is different than the + // one we got, adjust it. + fd = getParentFunc(symfd, true); + } + if (fd) { + Logger::println("For nested function, parent is %s", fd->toChars()); + FuncDeclaration* ctxfd = irfunc->decl; + Logger::println("Current function is %s", ctxfd->toChars()); + if (fromParent) { + ctxfd = getParentFunc(ctxfd, true); + assert(ctxfd && "Context from outer function, but no outer function?"); } - if (fd) { - Logger::println("For nested function, parent is %s", fd->toChars()); - FuncDeclaration* ctxfd = irfunc->decl; - Logger::println("Current function is %s", ctxfd->toChars()); - if (fromParent) { - ctxfd = getParentFunc(ctxfd, true); - assert(ctxfd && "Context from outer function, but no outer function?"); - } - Logger::println("Context is from %s", ctxfd->toChars()); + Logger::println("Context is from %s", ctxfd->toChars()); - unsigned neededDepth = fd->ir.irFunc->depth; - unsigned ctxDepth = ctxfd->ir.irFunc->depth; + unsigned neededDepth = fd->ir.irFunc->depth; + unsigned ctxDepth = ctxfd->ir.irFunc->depth; - Logger::cout() << "Needed depth: " << neededDepth << '\n'; - Logger::cout() << "Context depth: " << ctxDepth << '\n'; + Logger::cout() << "Needed depth: " << neededDepth << '\n'; + Logger::cout() << "Context depth: " << ctxDepth << '\n'; - if (neededDepth >= ctxDepth) { - // assert(neededDepth <= ctxDepth + 1 && "How are we going more than one nesting level up?"); - // fd needs the same context as we do, so all is well - Logger::println("Calling sibling function or directly nested function"); - } else { - val = DtoBitCast(val, LLPointerType::getUnqual(ctxfd->ir.irFunc->frameType)); - val = DtoGEPi(val, 0, neededDepth); - val = DtoAlignedLoad(val, (std::string(".frame.") + fd->toChars()).c_str()); - } + if (neededDepth >= ctxDepth) { + // assert(neededDepth <= ctxDepth + 1 && "How are we going more than one nesting level up?"); + // fd needs the same context as we do, so all is well + Logger::println("Calling sibling function or directly nested function"); + } else { + val = DtoBitCast(val, LLPointerType::getUnqual(ctxfd->ir.irFunc->frameType)); + val = DtoGEPi(val, 0, neededDepth); + val = DtoAlignedLoad(val, (std::string(".frame.") + fd->toChars()).c_str()); } } + Logger::cout() << "result = " << *val << '\n'; Logger::cout() << "of type " << *val->getType() << '\n'; return val; @@ -417,116 +318,106 @@ static void DtoCreateNestedContextType(FuncDeclaration* fd) { } #endif - if (nestedCtx == NCHybrid) { - // construct nested variables array - if (!fd->nestedVars.empty()) - { - Logger::println("has nested frame"); - // start with adding all enclosing parent frames until a static parent is reached + // construct nested variables array + if (!fd->nestedVars.empty()) + { + Logger::println("has nested frame"); + // start with adding all enclosing parent frames until a static parent is reached - LLStructType* innerFrameType = NULL; - unsigned depth = -1; - if (!fd->isStatic()) { - if (FuncDeclaration* parfd = getParentFunc(fd, true)) { - // Make sure the parent has already been analyzed. - DtoCreateNestedContextType(parfd); + LLStructType* innerFrameType = NULL; + unsigned depth = -1; + if (!fd->isStatic()) { + if (FuncDeclaration* parfd = getParentFunc(fd, true)) { + // Make sure the parent has already been analyzed. + DtoCreateNestedContextType(parfd); - innerFrameType = parfd->ir.irFunc->frameType; - if (innerFrameType) - depth = parfd->ir.irFunc->depth; - } + innerFrameType = parfd->ir.irFunc->frameType; + if (innerFrameType) + depth = parfd->ir.irFunc->depth; } - fd->ir.irFunc->depth = ++depth; - - Logger::cout() << "Function " << fd->toChars() << " has depth " << depth << '\n'; - - typedef std::vector TypeVec; - TypeVec types; - if (depth != 0) { - assert(innerFrameType); - // Add frame pointer types for all but last frame - if (depth > 1) { - for (unsigned i = 0; i < (depth - 1); ++i) { - types.push_back(innerFrameType->getElementType(i)); - } - } - // Add frame pointer type for last frame - types.push_back(LLPointerType::getUnqual(innerFrameType)); - } - - if (Logger::enabled()) { - Logger::println("Frame types: "); - LOG_SCOPE; - for (TypeVec::iterator i = types.begin(); i != types.end(); ++i) - Logger::cout() << **i << '\n'; - } - - // Add the direct nested variables of this function, and update their indices to match. - // TODO: optimize ordering for minimal space usage? - for (std::set::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i) - { - VarDeclaration* vd = *i; - if (!vd->ir.irLocal) - vd->ir.irLocal = new IrLocal(vd); - - vd->ir.irLocal->nestedIndex = types.size(); - vd->ir.irLocal->nestedDepth = depth; - if (vd->isParameter()) { - // Parameters will have storage associated with them (to handle byref etc.), - // so handle those cases specially by storing a pointer instead of a value. - IrParameter * irparam = vd->ir.irParam; - LLValue* value = irparam->value; - assert(value); - LLType* type = value->getType(); - bool refout = vd->storage_class & (STCref | STCout); - bool lazy = vd->storage_class & STClazy; - bool byref = irparam->arg->byref; - #if STRUCTTHISREF - bool isVthisPtr = irparam->isVthis && !byref; - #else - bool isVthisPtr = irparam->isVthis; - #endif - if ((!refout && (!byref || lazy)) || isVthisPtr) { - // This will be copied to the nesting frame. - if (lazy) - type = type->getContainedType(0); - else - type = DtoType(vd->type); - vd->ir.irParam->byref = false; - } else { - vd->ir.irParam->byref = true; - } - types.push_back(type); - } else if (vd->isRef() || vd->isOut()) { - // Foreach variables can also be by reference, for instance. - types.push_back(DtoType(vd->type->pointerTo())); - vd->ir.irLocal->byref = true; - } else { - types.push_back(DtoType(vd->type)); - vd->ir.irLocal->byref = false; - } - if (Logger::enabled()) { - Logger::println("Nested var: %s", vd->toChars()); - Logger::cout() << "of type: " << *types.back() << '\n'; - } - } - - LLStructType* frameType = LLStructType::create(gIR->context(), types, - std::string("nest.") + fd->toChars()); - - Logger::cout() << "frameType = " << *frameType << '\n'; - - // Store type in IrFunction - fd->ir.irFunc->frameType = frameType; - } else if (FuncDeclaration* parFunc = getParentFunc(fd, true)) { - // Propagate context arg properties if the context arg is passed on unmodified. - DtoCreateNestedContextType(parFunc); - fd->ir.irFunc->frameType = parFunc->ir.irFunc->frameType; - fd->ir.irFunc->depth = parFunc->ir.irFunc->depth; } - } - else { - assert(0 && "Not implemented yet"); + fd->ir.irFunc->depth = ++depth; + + Logger::cout() << "Function " << fd->toChars() << " has depth " << depth << '\n'; + + typedef std::vector TypeVec; + TypeVec types; + if (depth != 0) { + assert(innerFrameType); + // Add frame pointer types for all but last frame + if (depth > 1) { + for (unsigned i = 0; i < (depth - 1); ++i) { + types.push_back(innerFrameType->getElementType(i)); + } + } + // Add frame pointer type for last frame + types.push_back(LLPointerType::getUnqual(innerFrameType)); + } + + if (Logger::enabled()) { + Logger::println("Frame types: "); + LOG_SCOPE; + for (TypeVec::iterator i = types.begin(); i != types.end(); ++i) + Logger::cout() << **i << '\n'; + } + + // Add the direct nested variables of this function, and update their indices to match. + // TODO: optimize ordering for minimal space usage? + for (std::set::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i) + { + VarDeclaration* vd = *i; + if (!vd->ir.irLocal) + vd->ir.irLocal = new IrLocal(vd); + + vd->ir.irLocal->nestedIndex = types.size(); + vd->ir.irLocal->nestedDepth = depth; + if (vd->isParameter()) { + // Parameters will have storage associated with them (to handle byref etc.), + // so handle those cases specially by storing a pointer instead of a value. + IrParameter * irparam = vd->ir.irParam; + LLValue* value = irparam->value; + assert(value); + LLType* type = value->getType(); + bool refout = vd->storage_class & (STCref | STCout); + bool lazy = vd->storage_class & STClazy; + bool byref = irparam->arg->byref; +#if STRUCTTHISREF + bool isVthisPtr = irparam->isVthis && !byref; +#else + bool isVthisPtr = irparam->isVthis; +#endif + if ((!refout && (!byref || lazy)) || isVthisPtr) { + // This will be copied to the nesting frame. + if (lazy) + type = type->getContainedType(0); + else + type = DtoType(vd->type); + } else { + } + types.push_back(type); + } else if (isSpecialRefVar(vd)) { + types.push_back(DtoType(vd->type->pointerTo())); + } else { + types.push_back(DtoType(vd->type)); + } + if (Logger::enabled()) { + Logger::println("Nested var: %s", vd->toChars()); + Logger::cout() << "of type: " << *types.back() << '\n'; + } + } + + LLStructType* frameType = LLStructType::create(gIR->context(), types, + std::string("nest.") + fd->toChars()); + + Logger::cout() << "frameType = " << *frameType << '\n'; + + // Store type in IrFunction + fd->ir.irFunc->frameType = frameType; + } else if (FuncDeclaration* parFunc = getParentFunc(fd, true)) { + // Propagate context arg properties if the context arg is passed on unmodified. + DtoCreateNestedContextType(parFunc); + fd->ir.irFunc->frameType = parFunc->ir.irFunc->frameType; + fd->ir.irFunc->depth = parFunc->ir.irFunc->depth; } } @@ -537,207 +428,103 @@ void DtoCreateNestedContext(FuncDeclaration* fd) { DtoCreateNestedContextType(fd); - if (nestedCtx == NCArray) { - // construct nested variables array - if (!fd->nestedVars.empty()) - { - Logger::println("has nested frame"); - // start with adding all enclosing parent frames until a static parent is reached - int nparelems = 0; - if (!fd->isStatic()) - { - Dsymbol* par = fd->toParent2(); - while (par) - { - if (FuncDeclaration* parfd = par->isFuncDeclaration()) - { - nparelems += parfd->nestedVars.size(); - // stop at first static - if (parfd->isStatic()) - break; - } - else if (par->isClassDeclaration()) - { - // nothing needed - } - else - { - break; - } + // construct nested variables array + if (!fd->nestedVars.empty()) + { + IrFunction* irfunction = fd->ir.irFunc; + unsigned depth = irfunction->depth; + LLStructType *frameType = irfunction->frameType; + // Create frame for current function and append to frames list + // FIXME: alignment ? + LLValue* frame = 0; +#if DMDV2 + if (fd->needsClosure()) + frame = DtoGcMalloc(frameType, ".frame"); + else +#endif + frame = DtoRawAlloca(frameType, 0, ".frame"); - par = par->toParent2(); - } + + // copy parent frames into beginning + if (depth != 0) { + LLValue* src = irfunction->nestArg; + if (!src) { + assert(irfunction->thisArg); + assert(fd->isMember2()); + LLValue* thisval = DtoLoad(irfunction->thisArg); +#if DMDV2 + AggregateDeclaration* cd = fd->isMember2(); +#else + ClassDeclaration* cd = fd->isMember2()->isClassDeclaration(); +#endif + assert(cd); + assert(cd->vthis); + Logger::println("Indexing to 'this'"); +#if DMDV2 + if (cd->isStructDeclaration()) + src = DtoExtractValue(thisval, cd->vthis->ir.irField->index, ".vthis"); + else +#endif + src = DtoLoad(DtoGEPi(thisval, 0, cd->vthis->ir.irField->index, ".vthis")); + } else { + src = DtoLoad(src); } - int nelems = fd->nestedVars.size() + nparelems; - - // make array type for nested vars - LLType* nestedVarsTy = LLArrayType::get(getVoidPtrType(), nelems); - - // alloca it - // FIXME align ? - LLValue* nestedVars = DtoRawAlloca(nestedVarsTy, 0, ".nested_vars"); - - IrFunction* irfunction = fd->ir.irFunc; - - // copy parent frame into beginning - if (nparelems) - { - LLValue* src = irfunction->nestArg; - if (!src) - { - assert(irfunction->thisArg); - assert(fd->isMember2()); - LLValue* thisval = DtoLoad(irfunction->thisArg); - ClassDeclaration* cd = fd->isMember2()->isClassDeclaration(); - assert(cd); - assert(cd->vthis); - src = DtoLoad(DtoGEPi(thisval, 0,cd->vthis->ir.irField->index, ".vthis")); - } else { - src = DtoLoad(src); - } - DtoMemCpy(nestedVars, src, DtoConstSize_t(nparelems*PTRSIZE), + if (depth > 1) { + src = DtoBitCast(src, getVoidPtrType()); + LLValue* dst = DtoBitCast(frame, getVoidPtrType()); + DtoMemCpy(dst, src, DtoConstSize_t((depth-1) * PTRSIZE), getABITypeAlign(getVoidPtrType())); } + // Copy nestArg into framelist; the outer frame is not in the list of pointers + src = DtoBitCast(src, frameType->getContainedType(depth-1)); + LLValue* gep = DtoGEPi(frame, 0, depth-1); + DtoAlignedStore(src, gep); + } - // store in IrFunction - irfunction->nestedVar = nestedVars; + // store context in IrFunction + irfunction->nestedVar = frame; - // go through all nested vars and assign indices - int idx = nparelems; - for (std::set::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i) - { - VarDeclaration* vd = *i; - if (!vd->ir.irLocal) - vd->ir.irLocal = new IrLocal(vd); + // go through all nested vars and assign addresses where possible. + for (std::set::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i) + { + VarDeclaration* vd = *i; - if (vd->isParameter()) + LLValue* gep = DtoGEPi(frame, 0, vd->ir.irLocal->nestedIndex, vd->toChars()); + if (vd->isParameter()) { + Logger::println("nested param: %s", vd->toChars()); + LOG_SCOPE + IrParameter* parm = vd->ir.irParam; + + if (parm->arg->byref) { - Logger::println("nested param: %s", vd->toChars()); - LLValue* gep = DtoGEPi(nestedVars, 0, idx); - LLValue* val = DtoBitCast(vd->ir.irLocal->value, getVoidPtrType()); - DtoAlignedStore(val, gep); + storeVariable(vd, gep); } else { - Logger::println("nested var: %s", vd->toChars()); + Logger::println("Copying to nested frame"); + // The parameter value is an alloca'd stack slot. + // Copy to the nesting frame and leave the alloca for + // the optimizers to clean up. + DtoStore(DtoLoad(parm->value), gep); + gep->takeName(parm->value); + parm->value = gep; } + } else { + Logger::println("nested var: %s", vd->toChars()); + assert(!vd->ir.irLocal->value); + vd->ir.irLocal->value = gep; + } - vd->ir.irLocal->nestedIndex = idx++; + if (global.params.symdebug) { + LLSmallVector addr; + dwarfOpOffset(addr, frameType, vd->ir.irLocal->nestedIndex); + DtoDwarfLocalVariable(frame, vd, addr); } } - } - else if (nestedCtx == NCHybrid) { - // construct nested variables array - if (!fd->nestedVars.empty()) - { - IrFunction* irfunction = fd->ir.irFunc; - unsigned depth = irfunction->depth; - LLStructType *frameType = irfunction->frameType; - // Create frame for current function and append to frames list - // FIXME: alignment ? - LLValue* frame = 0; -#if DMDV2 - if (fd->needsClosure()) - frame = DtoGcMalloc(frameType, ".frame"); - else -#endif - frame = DtoRawAlloca(frameType, 0, ".frame"); - - - // copy parent frames into beginning - if (depth != 0) { - LLValue* src = irfunction->nestArg; - if (!src) { - assert(irfunction->thisArg); - assert(fd->isMember2()); - LLValue* thisval = DtoLoad(irfunction->thisArg); -#if DMDV2 - AggregateDeclaration* cd = fd->isMember2(); -#else - ClassDeclaration* cd = fd->isMember2()->isClassDeclaration(); -#endif - assert(cd); - assert(cd->vthis); - Logger::println("Indexing to 'this'"); -#if DMDV2 - if (cd->isStructDeclaration()) - src = DtoExtractValue(thisval, cd->vthis->ir.irField->index, ".vthis"); - else -#endif - src = DtoLoad(DtoGEPi(thisval, 0, cd->vthis->ir.irField->index, ".vthis")); - } else { - src = DtoLoad(src); - } - if (depth > 1) { - src = DtoBitCast(src, getVoidPtrType()); - LLValue* dst = DtoBitCast(frame, getVoidPtrType()); - DtoMemCpy(dst, src, DtoConstSize_t((depth-1) * PTRSIZE), - getABITypeAlign(getVoidPtrType())); - } - // Copy nestArg into framelist; the outer frame is not in the list of pointers - src = DtoBitCast(src, frameType->getContainedType(depth-1)); - LLValue* gep = DtoGEPi(frame, 0, depth-1); - DtoAlignedStore(src, gep); - } - - // store context in IrFunction - irfunction->nestedVar = frame; - - // go through all nested vars and assign addresses where possible. - for (std::set::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i) - { - VarDeclaration* vd = *i; - - LLValue* gep = DtoGEPi(frame, 0, vd->ir.irLocal->nestedIndex, vd->toChars()); - if (vd->isParameter()) { - Logger::println("nested param: %s", vd->toChars()); - LOG_SCOPE - LLValue* value = vd->ir.irLocal->value; - if (llvm::isa(llvm::GetUnderlyingObject(value))) { - Logger::println("Copying to nested frame"); - // The parameter value is an alloca'd stack slot. - // Copy to the nesting frame and leave the alloca for - // the optimizers to clean up. - assert(!vd->ir.irLocal->byref); - DtoStore(DtoLoad(value), gep); - gep->takeName(value); - vd->ir.irLocal->value = gep; - } else { - Logger::println("Adding pointer to nested frame"); - // The parameter value is something else, such as a - // passed-in pointer (for 'ref' or 'out' parameters) or - // a pointer arg with byval attribute. - // Store the address into the frame. - assert(vd->ir.irLocal->byref); - storeVariable(vd, gep); - } - } else if (vd->isRef() || vd->isOut()) { - // This slot is initialized in DtoNestedInit, to handle things like byref foreach variables - // which move around in memory. - assert(vd->ir.irLocal->byref); - } else { - Logger::println("nested var: %s", vd->toChars()); - if (vd->ir.irLocal->value) - Logger::cout() << "Pre-existing value: " << *vd->ir.irLocal->value << '\n'; - assert(!vd->ir.irLocal->value); - vd->ir.irLocal->value = gep; - assert(!vd->ir.irLocal->byref); - } - - if (global.params.symdebug) { - LLSmallVector addr; - dwarfOpOffset(addr, frameType, vd->ir.irLocal->nestedIndex); - DtoDwarfLocalVariable(frame, vd, addr); - } - } - } else if (FuncDeclaration* parFunc = getParentFunc(fd, true)) { - // Propagate context arg properties if the context arg is passed on unmodified. - DtoDeclareFunction(parFunc); - fd->ir.irFunc->frameType = parFunc->ir.irFunc->frameType; - fd->ir.irFunc->depth = parFunc->ir.irFunc->depth; - } - } - else { - assert(0 && "Not implemented yet"); + } else if (FuncDeclaration* parFunc = getParentFunc(fd, true)) { + // Propagate context arg properties if the context arg is passed on unmodified. + DtoDeclareFunction(parFunc); + fd->ir.irFunc->frameType = parFunc->ir.irFunc->frameType; + fd->ir.irFunc->depth = parFunc->ir.irFunc->depth; } } diff --git a/gen/nested.h b/gen/nested.h index 34fff976..91f0a002 100644 --- a/gen/nested.h +++ b/gen/nested.h @@ -13,9 +13,6 @@ /// Creates the context value for a nested function. void DtoCreateNestedContext(FuncDeclaration* fd); -/// Allocate space for variable accessed from nested function. -void DtoNestedInit(VarDeclaration* vd); - /// Resolves the nested context for classes and structs with arbitrary nesting. #if DMDV2 void DtoResolveNestedContext(Loc loc, AggregateDeclaration *decl, LLValue *value); diff --git a/gen/rttibuilder.cpp b/gen/rttibuilder.cpp index 6a8e3eeb..985dcc97 100644 --- a/gen/rttibuilder.cpp +++ b/gen/rttibuilder.cpp @@ -121,6 +121,11 @@ void RTTIBuilder::push_size(uint64_t s) inits.push_back(DtoConstSize_t(s)); } +void RTTIBuilder::push_size_as_vp(uint64_t s) +{ + inits.push_back(llvm::ConstantExpr::getIntToPtr(DtoConstSize_t(s), getVoidPtrType())); +} + void RTTIBuilder::push_funcptr(FuncDeclaration* fd, Type* castto) { if (fd) diff --git a/gen/rttibuilder.h b/gen/rttibuilder.h index d7f54540..98f2598b 100644 --- a/gen/rttibuilder.h +++ b/gen/rttibuilder.h @@ -29,6 +29,7 @@ struct RTTIBuilder void push_null_void_array(); void push_uint(unsigned u); void push_size(uint64_t s); + void push_size_as_vp(uint64_t s); void push_string(const char* str); void push_typeinfo(Type* t); void push_classinfo(ClassDeclaration* cd); diff --git a/gen/tocall.cpp b/gen/tocall.cpp index 0a83c0ec..5b6b4696 100644 --- a/gen/tocall.cpp +++ b/gen/tocall.cpp @@ -652,7 +652,39 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions* break; default: - assert(0 && "unhandled repainting of return value"); + // Unfortunately, DMD has quirks resp. bugs with regard to name + // mangling: For voldemort-type functions which return a nested + // struct, the mangled name of the return type changes during + // semantic analysis. + // + // (When the function deco is first computed as part of + // determining the return type deco, its return type part is + // left off to avoid cycles. If mangle/toDecoBuffer is then + // called again for the type, it will pick up the previous + // result and return the full deco string for the nested struct + // type, consisting of both the full mangled function name, and + // the struct identifier.) + // + // Thus, the type merging in stripModifiers does not work + // reliably, and the equality check above can fail even if the + // types only differ in a qualifier. + // + // Because a proper fix for this in the frontend is hard, we + // just carry on and hope that the frontend didn't mess up, + // i.e. that the LLVM types really match up. + // + // An example situation where this case occurs is: + // --- + // auto iota() { + // static struct Result { + // this(int) {} + // inout(Result) test() inout { return cast(inout)Result(0); } + // } + // return Result.init; + // } + // void main() { auto r = iota(); } + // --- + break; } if (Logger::enabled()) Logger::cout() << "final return value: " << *retllval << '\n'; diff --git a/gen/toir.cpp b/gen/toir.cpp index 77e17f78..d5503094 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -583,10 +583,48 @@ DValue* AssignExp::toElem(IRState* p) return newlen; } - Logger::println("performing normal assignment"); + // Can't just override ConstructExp::toElem because not all TOKconstruct + // operations are actually instances of ConstructExp... Long live the DMD + // coding style! + if (op == TOKconstruct) + { + if (e1->op == TOKvar) + { + VarExp* ve = (VarExp*)e1; + if (ve->var->storage_class & STCref) + { + // Note that the variable value is accessed directly (instead + // of via getLValue(), which would perform a load from the + // uninitialized location), and that rhs is stored as an l-value! + + IrLocal* const local = ve->var->ir.irLocal; + assert(local && "ref var must be local and already initialized"); + + DValue* rhs = e2->toElem(p); + DtoStore(rhs->getLVal(), local->value); + return rhs; + } + } + } DValue* l = e1->toElem(p); DValue* r = e2->toElem(p); + + if (e1->type->toBasetype()->ty == Tstruct && e2->op == TOKint64) + { + Logger::println("performing aggregate zero initialization"); + assert(e2->toInteger() == 0); + DtoAggrZeroInit(l->getLVal()); +#if DMDV2 + TypeStruct *ts = static_cast(e1->type); + if (ts->sym->isNested() && ts->sym->vthis) + DtoResolveNestedContext(loc, ts->sym, l->getLVal()); +#endif + // Return value should be irrelevant. + return r; + } + + Logger::println("performing normal assignment"); DtoAssign(loc, l, r, op); if (l->isSlice()) @@ -1425,25 +1463,32 @@ DValue* DotVarExp::toElem(IRState* p) { DtoResolveDsymbol(fdecl); - LLValue* funcval; - LLValue* vthis2 = 0; - if (e1type->ty == Tclass) { + // This is a bit more convoluted than it would need to be, because it + // has to take templated interface methods into account, for which + // isFinal is not necessarily true. + const bool nonFinal = !fdecl->isFinal() && + (fdecl->isAbstract() || fdecl->isVirtual()); + + // If we are calling a non-final interface function, we need to get + // the pointer to the underlying object instead of passing the + // interface pointer directly. + LLValue* passedThis = 0; + if (e1type->ty == Tclass) + { TypeClass* tc = static_cast(e1type); - if (tc->sym->isInterfaceDeclaration() && !fdecl->isFinal()) - vthis2 = DtoCastInterfaceToObject(l, NULL)->getRVal(); + if (tc->sym->isInterfaceDeclaration() && nonFinal) + passedThis = DtoCastInterfaceToObject(l, NULL)->getRVal(); } LLValue* vthis = l->getRVal(); - if (!vthis2) vthis2 = vthis; + if (!passedThis) passedThis = vthis; - // - // decide whether this function needs to be looked up in the vtable - // - bool vtbllookup = !fdecl->isFinal() && (fdecl->isAbstract() || fdecl->isVirtual()); - - // even virtual functions are looked up directly if super or DotTypeExp - // are used, thus we need to walk through the this expression and check + // Decide whether this function needs to be looked up in the vtable. + // Even virtual functions are looked up directly if super or DotTypeExp + // are used, thus we need to walk through the this expression and check. + bool vtbllookup = nonFinal; Expression* e = e1; - while (e && vtbllookup) { + while (e && vtbllookup) + { if (e->op == TOKsuper || e->op == TOKdottype) vtbllookup = false; else if (e->op == TOKcast) @@ -1452,20 +1497,21 @@ DValue* DotVarExp::toElem(IRState* p) break; } - // - // look up function - // - if (!vtbllookup) { + // Get the actual function value to call. + LLValue* funcval = 0; + if (vtbllookup) + { + DImValue thisVal(e1type, vthis); + funcval = DtoVirtualFunctionPointer(&thisVal, fdecl, toChars()); + } + else + { fdecl->codegen(Type::sir); funcval = fdecl->ir.irFunc->func; - assert(funcval); - } - else { - DImValue vthis3(e1type, vthis); - funcval = DtoVirtualFunctionPointer(&vthis3, fdecl, toChars()); } + assert(funcval); - return new DFuncValue(fdecl, funcval, vthis2); + return new DFuncValue(fdecl, funcval, passedThis); } else { printf("unsupported dotvarexp: %s\n", var->toChars()); @@ -3108,10 +3154,9 @@ LruntimeInit: DValue* GEPExp::toElem(IRState* p) { - // this should be good enough for now! - DValue* val = e1->toElem(p); - assert(val->isLVal()); - LLValue* v = DtoGEPi(val->getLVal(), 0, index); + // (&a.foo).funcptr is a case where e1->toElem is genuinely not an l-value. + LLValue* val = makeLValue(loc, e1->toElem(p)); + LLValue* v = DtoGEPi(val, 0, index); return new DVarValue(type, DtoBitCast(v, getPtrToType(DtoType(type)))); } diff --git a/gen/typinf.cpp b/gen/typinf.cpp index 2dca8aa6..53d12585 100644 --- a/gen/typinf.cpp +++ b/gen/typinf.cpp @@ -1,924 +1,933 @@ - - -// Copyright (c) 1999-2004 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. - -// Modifications for LDC: -// Copyright (c) 2007 by Tomas Lindquist Olsen -// tomas at famolsen dk - -#include -#include - -#include "gen/llvm.h" - -#include "mars.h" -#include "module.h" -#include "mtype.h" -#include "scope.h" -#include "init.h" -#include "expression.h" -#include "attrib.h" -#include "declaration.h" -#include "template.h" -#include "id.h" -#include "enum.h" -#include "import.h" -#include "aggregate.h" - -#include "gen/irstate.h" -#include "gen/logger.h" -#include "gen/runtime.h" -#include "gen/tollvm.h" -#include "gen/llvmhelpers.h" -#include "gen/arrays.h" -#include "gen/structs.h" -#include "gen/classes.h" -#include "gen/linkage.h" -#include "gen/metadata.h" -#include "gen/rttibuilder.h" - -#include "ir/irvar.h" -#include "ir/irtype.h" - -/******************************************* - * Get a canonicalized form of the TypeInfo for use with the internal - * runtime library routines. Canonicalized in that static arrays are - * represented as dynamic arrays, enums are represented by their - * underlying type, etc. This reduces the number of TypeInfo's needed, - * so we can use the custom internal ones more. - */ - -Expression *Type::getInternalTypeInfo(Scope *sc) -{ TypeInfoDeclaration *tid; - Expression *e; - Type *t; - static TypeInfoDeclaration *internalTI[TMAX]; - - //printf("Type::getInternalTypeInfo() %s\n", toChars()); - t = toBasetype(); - switch (t->ty) - { - case Tsarray: -#if 0 - // convert to corresponding dynamic array type - t = t->nextOf()->mutableOf()->arrayOf(); -#endif - break; - - case Tclass: - if (static_cast(t)->sym->isInterfaceDeclaration()) - break; - goto Linternal; - - case Tarray: - #if DMDV2 - // convert to corresponding dynamic array type - t = t->nextOf()->mutableOf()->arrayOf(); - #endif - if (t->nextOf()->ty != Tclass) - break; - goto Linternal; - - case Tfunction: - case Tdelegate: - case Tpointer: - Linternal: - tid = internalTI[t->ty]; - if (!tid) - { tid = new TypeInfoDeclaration(t, 1); - internalTI[t->ty] = tid; - } - e = new VarExp(0, tid); - e = e->addressOf(sc); - e->type = tid->type; // do this so we don't get redundant dereference - return e; - - default: - break; - } - //printf("\tcalling getTypeInfo() %s\n", t->toChars()); - return t->getTypeInfo(sc); -} - -/**************************************************** - * Get the exact TypeInfo. - */ - -Expression *Type::getTypeInfo(Scope *sc) -{ - //printf("Type::getTypeInfo() %p, %s\n", this, toChars()); - if (!Type::typeinfo) - { - error(0, "TypeInfo not found. object.d may be incorrectly installed or corrupt, compile with -v switch"); - fatal(); - } - - Expression *e = 0; - Type *t = merge2(); // do this since not all Type's are merge'd - - if (!t->vtinfo) - { -#if DMDV2 - if (t->isShared()) - t->vtinfo = new TypeInfoSharedDeclaration(t); - else if (t->isConst()) - t->vtinfo = new TypeInfoConstDeclaration(t); - else if (t->isImmutable()) - t->vtinfo = new TypeInfoInvariantDeclaration(t); - else if (t->isWild()) - t->vtinfo = new TypeInfoWildDeclaration(t); - else -#endif - t->vtinfo = t->getTypeInfoDeclaration(); - assert(t->vtinfo); - - /* If this has a custom implementation in std/typeinfo, then - * do not generate a COMDAT for it. - */ - if (!t->builtinTypeInfo()) - { // Generate COMDAT - if (sc) // if in semantic() pass - { // Find module that will go all the way to an object file - Module *m = sc->module->importedFrom; - m->members->push(t->vtinfo); - } - else // if in obj generation pass - { -#if IN_DMD - t->vtinfo->toObjFile(0); // TODO: multiobj -#else - t->vtinfo->codegen(sir); -#endif - } - } - } - e = new VarExp(0, t->vtinfo); - e = e->addressOf(sc); - e->type = t->vtinfo->type; // do this so we don't get redundant dereference - return e; -} - -enum RET TypeFunction::retStyle() -{ - return RETstack; -} - -TypeInfoDeclaration *Type::getTypeInfoDeclaration() -{ - //printf("Type::getTypeInfoDeclaration() %s\n", toChars()); - return new TypeInfoDeclaration(this, 0); -} - -TypeInfoDeclaration *TypeTypedef::getTypeInfoDeclaration() -{ - return new TypeInfoTypedefDeclaration(this); -} - -TypeInfoDeclaration *TypePointer::getTypeInfoDeclaration() -{ - return new TypeInfoPointerDeclaration(this); -} - -TypeInfoDeclaration *TypeDArray::getTypeInfoDeclaration() -{ - return new TypeInfoArrayDeclaration(this); -} - -TypeInfoDeclaration *TypeSArray::getTypeInfoDeclaration() -{ - return new TypeInfoStaticArrayDeclaration(this); -} - -TypeInfoDeclaration *TypeAArray::getTypeInfoDeclaration() -{ - return new TypeInfoAssociativeArrayDeclaration(this); -} - -TypeInfoDeclaration *TypeStruct::getTypeInfoDeclaration() -{ - return new TypeInfoStructDeclaration(this); -} - -TypeInfoDeclaration *TypeClass::getTypeInfoDeclaration() -{ - if (sym->isInterfaceDeclaration()) - return new TypeInfoInterfaceDeclaration(this); - else - return new TypeInfoClassDeclaration(this); -} - -#if DMDV2 -TypeInfoDeclaration *TypeVector::getTypeInfoDeclaration() -{ - return new TypeInfoVectorDeclaration(this); -} -#endif - -TypeInfoDeclaration *TypeEnum::getTypeInfoDeclaration() -{ - return new TypeInfoEnumDeclaration(this); -} - -TypeInfoDeclaration *TypeFunction::getTypeInfoDeclaration() -{ - return new TypeInfoFunctionDeclaration(this); -} - -TypeInfoDeclaration *TypeDelegate::getTypeInfoDeclaration() -{ - return new TypeInfoDelegateDeclaration(this); -} - -TypeInfoDeclaration *TypeTuple::getTypeInfoDeclaration() -{ - return new TypeInfoTupleDeclaration(this); -} - -/* ========================================================================= */ - -/* These decide if there's an instance for them already in std.typeinfo, - * because then the compiler doesn't need to build one. - */ - -int Type::builtinTypeInfo() -{ - return 0; -} - -int TypeBasic::builtinTypeInfo() -{ -#if DMDV2 - return mod ? 0 : 1; -#else - return 1; -#endif -} - -int TypeDArray::builtinTypeInfo() -{ -#if DMDV2 - return !mod && (next->isTypeBasic() != NULL && !next->mod || - // strings are so common, make them builtin - next->ty == Tchar && next->mod == MODimmutable); -#else - return next->isTypeBasic() != NULL; -#endif -} - -int TypeClass::builtinTypeInfo() -{ - /* This is statically put out with the ClassInfo, so - * claim it is built in so it isn't regenerated by each module. - */ -#if IN_DMD - return mod ? 0 : 1; -#elif IN_LLVM - // FIXME if I enable this, the way LDC does typeinfo will cause a bunch - // of linker errors to missing class typeinfo definitions. - return 0; -#endif -} - -/* ========================================================================= */ - -////////////////////////////////////////////////////////////////////////////// -// MAGIC PLACE -// (wut?) -////////////////////////////////////////////////////////////////////////////// - -void DtoResolveTypeInfo(TypeInfoDeclaration* tid); -void DtoDeclareTypeInfo(TypeInfoDeclaration* tid); - -void TypeInfoDeclaration::codegen(Ir*) -{ - DtoResolveTypeInfo(this); -} - -void DtoResolveTypeInfo(TypeInfoDeclaration* tid) -{ - if (tid->ir.resolved) return; - tid->ir.resolved = true; - - Logger::println("DtoResolveTypeInfo(%s)", tid->toChars()); - LOG_SCOPE; - - std::string mangle(tid->mangle()); - - IrGlobal* irg = new IrGlobal(tid); - irg->value = gIR->module->getGlobalVariable(mangle); - - if (!irg->value) { - if (tid->tinfo->builtinTypeInfo()) // this is a declaration of a builtin __initZ var - irg->type = Type::typeinfo->type->irtype->getType(); - else - irg->type = LLStructType::create(gIR->context(), tid->toPrettyChars()); - irg->value = new llvm::GlobalVariable(*gIR->module, irg->type, true, - TYPEINFO_LINKAGE_TYPE, NULL, mangle); - } else { - irg->type = irg->value->getType()->getContainedType(0); - } - - tid->ir.irGlobal = irg; - -#if USE_METADATA - // don't do this for void or llvm will crash - if (tid->tinfo->ty != Tvoid) { - // Add some metadata for use by optimization passes. - std::string metaname = std::string(TD_PREFIX) + mangle; - llvm::NamedMDNode* meta = gIR->module->getNamedMetadata(metaname); - // Don't generate metadata for non-concrete types - // (such as tuple types, slice types, typeof(expr), etc.) - if (!meta && tid->tinfo->toBasetype()->ty < Terror) { - // Construct the fields - MDNodeField* mdVals[TD_NumFields]; - if (TD_Confirm >= 0) - mdVals[TD_Confirm] = llvm::cast(irg->value); - mdVals[TD_Type] = llvm::UndefValue::get(DtoType(tid->tinfo)); - // Construct the metadata - llvm::MetadataBase* metadata = llvm::MDNode::get(gIR->context(), mdVals, TD_NumFields); - // Insert it into the module - llvm::NamedMDNode::Create(gIR->context(), metaname, &metadata, 1, gIR->module); - } - } -#endif // USE_METADATA - - DtoDeclareTypeInfo(tid); -} - -void DtoDeclareTypeInfo(TypeInfoDeclaration* tid) -{ - DtoResolveTypeInfo(tid); - - if (tid->ir.declared) return; - tid->ir.declared = true; - - Logger::println("DtoDeclareTypeInfo(%s)", tid->toChars()); - LOG_SCOPE; - - if (Logger::enabled()) - { - std::string mangled(tid->mangle()); - Logger::println("type = '%s'", tid->tinfo->toChars()); - Logger::println("typeinfo mangle: %s", mangled.c_str()); - } - - IrGlobal* irg = tid->ir.irGlobal; - assert(irg->value != NULL); - - // this is a declaration of a builtin __initZ var - if (tid->tinfo->builtinTypeInfo()) { - LLGlobalVariable* g = isaGlobalVar(irg->value); - g->setLinkage(llvm::GlobalValue::ExternalLinkage); - return; - } - - // define custom typedef - tid->llvmDefine(); -} - -/* ========================================================================= */ - -void TypeInfoDeclaration::llvmDefine() -{ - Logger::println("TypeInfoDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - RTTIBuilder b(Type::typeinfo); - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -void TypeInfoTypedefDeclaration::llvmDefine() -{ - Logger::println("TypeInfoTypedefDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - RTTIBuilder b(Type::typeinfotypedef); - - assert(tinfo->ty == Ttypedef); - TypeTypedef *tc = static_cast(tinfo); - TypedefDeclaration *sd = tc->sym; - - // TypeInfo base - sd->basetype = sd->basetype->merge(); // dmd does it ... why? - b.push_typeinfo(sd->basetype); - - // char[] name - b.push_string(sd->toPrettyChars()); - - // void[] init - // emit null array if we should use the basetype, or if the basetype - // uses default initialization. - if (tinfo->isZeroInit(0) || !sd->init) - { - b.push_null_void_array(); - } - // otherwise emit a void[] with the default initializer - else - { - LLConstant* C = DtoConstInitializer(sd->loc, sd->basetype, sd->init); - b.push_void_array(C, sd->basetype, sd); - } - - // finish - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -void TypeInfoEnumDeclaration::llvmDefine() -{ - Logger::println("TypeInfoEnumDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - RTTIBuilder b(Type::typeinfoenum); - - assert(tinfo->ty == Tenum); - TypeEnum *tc = static_cast(tinfo); - EnumDeclaration *sd = tc->sym; - - // TypeInfo base - b.push_typeinfo(sd->memtype); - - // char[] name - b.push_string(sd->toPrettyChars()); - - // void[] init - // emit void[] with the default initialier, the array is null if the default - // initializer is zero - if (!sd->defaultval || tinfo->isZeroInit(0)) - { - b.push_null_void_array(); - } - // otherwise emit a void[] with the default initializer - else - { - LLType* memty = DtoType(sd->memtype); -#if DMDV2 - LLConstant* C = LLConstantInt::get(memty, sd->defaultval->toInteger(), !sd->memtype->isunsigned()); -#else - LLConstant* C = LLConstantInt::get(memty, sd->defaultval, !sd->memtype->isunsigned()); -#endif - b.push_void_array(C, sd->memtype, sd); - } - - // finish - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -void TypeInfoPointerDeclaration::llvmDefine() -{ - Logger::println("TypeInfoPointerDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - RTTIBuilder b(Type::typeinfopointer); - // TypeInfo base - b.push_typeinfo(tinfo->nextOf()); - // finish - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -void TypeInfoArrayDeclaration::llvmDefine() -{ - Logger::println("TypeInfoArrayDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - RTTIBuilder b(Type::typeinfoarray); - // TypeInfo base - b.push_typeinfo(tinfo->nextOf()); - // finish - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -void TypeInfoStaticArrayDeclaration::llvmDefine() -{ - Logger::println("TypeInfoStaticArrayDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - assert(tinfo->ty == Tsarray); - TypeSArray *tc = static_cast(tinfo); - - RTTIBuilder b(Type::typeinfostaticarray); - - // value typeinfo - b.push_typeinfo(tc->nextOf()); - - // length - b.push(DtoConstSize_t(static_cast(tc->dim->toUInteger()))); - - // finish - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -void TypeInfoAssociativeArrayDeclaration::llvmDefine() -{ - Logger::println("TypeInfoAssociativeArrayDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - assert(tinfo->ty == Taarray); - TypeAArray *tc = static_cast(tinfo); - - RTTIBuilder b(Type::typeinfoassociativearray); - - // value typeinfo - b.push_typeinfo(tc->nextOf()); - - // key typeinfo - b.push_typeinfo(tc->index); - -#if DMDV2 - // impl typeinfo - b.push_typeinfo(tc->getImpl()->type); -#endif - - // finish - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -void TypeInfoFunctionDeclaration::llvmDefine() -{ - Logger::println("TypeInfoFunctionDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - RTTIBuilder b(Type::typeinfofunction); - // TypeInfo base - b.push_typeinfo(tinfo->nextOf()); - // string deco - b.push_string(tinfo->deco); - // finish - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -void TypeInfoDelegateDeclaration::llvmDefine() -{ - Logger::println("TypeInfoDelegateDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - assert(tinfo->ty == Tdelegate); - Type* ret_type = tinfo->nextOf()->nextOf(); - - RTTIBuilder b(Type::typeinfodelegate); - // TypeInfo base - b.push_typeinfo(ret_type); - // string deco - b.push_string(tinfo->deco); - // finish - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -static FuncDeclaration* find_method_overload(AggregateDeclaration* ad, Identifier* id, TypeFunction* tf, Module* mod) -{ - Dsymbol *s = search_function(ad, id); - FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL; - if (fdx) - { - FuncDeclaration *fd = fdx->overloadExactMatch(tf, mod); - if (fd) - { - return fd; - } - } - return NULL; -} - -void TypeInfoStructDeclaration::llvmDefine() -{ - Logger::println("TypeInfoStructDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - // make sure struct is resolved - assert(tinfo->ty == Tstruct); - TypeStruct *tc = static_cast(tinfo); - StructDeclaration *sd = tc->sym; - - // can't emit typeinfo for forward declarations - if (sd->sizeok != 1) - { - sd->error("cannot emit TypeInfo for forward declaration"); - fatal(); - } - - sd->codegen(Type::sir); - IrStruct* irstruct = sd->ir.irStruct; - - RTTIBuilder b(Type::typeinfostruct); - - // char[] name - b.push_string(sd->toPrettyChars()); - - // void[] init - // never emit a null array, even for zero initialized typeinfo - // the size() method uses this array! - size_t init_size = getTypeStoreSize(tc->irtype->getType()); - b.push_void_array(init_size, irstruct->getInitSymbol()); - - // toX functions ground work - static TypeFunction *tftohash; - static TypeFunction *tftostring; - - if (!tftohash) - { - Scope sc; - tftohash = new TypeFunction(NULL, Type::thash_t, 0, LINKd); -#if DMDV2 - tftohash ->mod = MODconst; -#endif - tftohash = static_cast(tftohash->semantic(0, &sc)); - -#if DMDV2 - Type *retType = Type::tchar->invariantOf()->arrayOf(); -#else - Type *retType = Type::tchar->arrayOf(); -#endif - tftostring = new TypeFunction(NULL, retType, 0, LINKd); - tftostring = static_cast(tftostring->semantic(0, &sc)); - } - - // this one takes a parameter, so we need to build a new one each time - // to get the right type. can we avoid this? - TypeFunction *tfcmpptr; - { - Scope sc; - Parameters *arguments = new Parameters; -#if STRUCTTHISREF - // arg type is ref const T - Parameter *arg = new Parameter(STCref, tc->constOf(), NULL, NULL); -#else - // arg type is const T* - Parameter *arg = new Parameter(STCin, tc->pointerTo(), NULL, NULL); -#endif - arguments->push(arg); - tfcmpptr = new TypeFunction(arguments, Type::tint32, 0, LINKd); -#if DMDV2 - tfcmpptr->mod = MODconst; -#endif - tfcmpptr = static_cast(tfcmpptr->semantic(0, &sc)); - } - - // well use this module for all overload lookups - Module *gm = getModule(); - - // toHash - FuncDeclaration* fd = find_method_overload(sd, Id::tohash, tftohash, gm); - b.push_funcptr(fd); - - // opEquals -#if DMDV2 - fd = sd->xeq; -#else - fd = find_method_overload(sd, Id::eq, tfcmpptr, gm); -#endif - b.push_funcptr(fd); - - // opCmp - fd = find_method_overload(sd, Id::cmp, tfcmpptr, gm); - b.push_funcptr(fd); - - // toString - fd = find_method_overload(sd, Id::tostring, tftostring, gm); - b.push_funcptr(fd); - - // uint m_flags; - unsigned hasptrs = tc->hasPointers() ? 1 : 0; - b.push_uint(hasptrs); - -#if DMDV2 - - ClassDeclaration* tscd = Type::typeinfostruct; - - assert((!global.params.is64bit && tscd->fields.dim == 11) || - (global.params.is64bit && tscd->fields.dim == 13)); - - // const(MemberInfo[]) function(in char[]) xgetMembers; - b.push_funcptr(sd->findGetMembers()); - - //void function(void*) xdtor; - b.push_funcptr(sd->dtor); - - //void function(void*) xpostblit; - FuncDeclaration *xpostblit = sd->postblit; - if (xpostblit && sd->postblit->storage_class & STCdisable) - xpostblit = 0; - b.push_funcptr(xpostblit); - - //uint m_align; - b.push_uint(tc->alignsize()); - - if (global.params.is64bit) - { - TypeTuple *tup = tc->toArgTypes(); - assert(tup->arguments->dim <= 2); - for (unsigned i = 0; i < 2; i++) - { - if (i < tup->arguments->dim) - { - Type *targ = static_cast(tup->arguments->data[i])->type; - targ = targ->merge(); - b.push_typeinfo(targ); - } - else - b.push_null(Type::typeinfo->type); - } - } - -#endif - - // finish - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -#if DMDV2 -void TypeInfoClassDeclaration::codegen(Ir*i) -{ - - IrGlobal* irg = new IrGlobal(this); - ir.irGlobal = irg; - assert(tinfo->ty == Tclass); - TypeClass *tc = static_cast(tinfo); - tc->sym->codegen(Type::sir); // make sure class is resolved - irg->value = tc->sym->ir.irStruct->getClassInfoSymbol(); -} -#endif - -void TypeInfoClassDeclaration::llvmDefine() -{ -#if DMDV2 - assert(0); -#endif - Logger::println("TypeInfoClassDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - // make sure class is resolved - assert(tinfo->ty == Tclass); - TypeClass *tc = static_cast(tinfo); - tc->sym->codegen(Type::sir); - - RTTIBuilder b(Type::typeinfoclass); - - // TypeInfo base - b.push_classinfo(tc->sym); - - // finish - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -void TypeInfoInterfaceDeclaration::llvmDefine() -{ - Logger::println("TypeInfoInterfaceDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - // make sure interface is resolved - assert(tinfo->ty == Tclass); - TypeClass *tc = static_cast(tinfo); - tc->sym->codegen(Type::sir); - - RTTIBuilder b(Type::typeinfointerface); - - // TypeInfo base - b.push_classinfo(tc->sym); - - // finish - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -void TypeInfoTupleDeclaration::llvmDefine() -{ - Logger::println("TypeInfoTupleDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - // create elements array - assert(tinfo->ty == Ttuple); - TypeTuple *tu = static_cast(tinfo); - - size_t dim = tu->arguments->dim; - std::vector arrInits; - arrInits.reserve(dim); - - LLType* tiTy = DtoType(Type::typeinfo->type); - - for (size_t i = 0; i < dim; i++) - { - Parameter *arg = static_cast(tu->arguments->data[i]); - arrInits.push_back(DtoTypeInfoOf(arg->type, true)); - } - - // build array - LLArrayType* arrTy = LLArrayType::get(tiTy, dim); - LLConstant* arrC = LLConstantArray::get(arrTy, arrInits); - - RTTIBuilder b(Type::typeinfotypelist); - - // push TypeInfo[] - b.push_array(arrC, dim, Type::typeinfo->type, NULL); - - // finish - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -#if DMDV2 - -void TypeInfoConstDeclaration::llvmDefine() -{ - Logger::println("TypeInfoConstDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - RTTIBuilder b(Type::typeinfoconst); - // TypeInfo base - b.push_typeinfo(tinfo->mutableOf()->merge()); - // finish - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -void TypeInfoInvariantDeclaration::llvmDefine() -{ - Logger::println("TypeInfoInvariantDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - RTTIBuilder b(Type::typeinfoinvariant); - // TypeInfo base - b.push_typeinfo(tinfo->mutableOf()->merge()); - // finish - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -void TypeInfoSharedDeclaration::llvmDefine() -{ - Logger::println("TypeInfoSharedDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - RTTIBuilder b(Type::typeinfoshared); - // TypeInfo base - b.push_typeinfo(tinfo->unSharedOf()->merge()); - // finish - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -void TypeInfoWildDeclaration::llvmDefine() -{ - Logger::println("TypeInfoWildDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - RTTIBuilder b(Type::typeinfowild); - // TypeInfo base - b.push_typeinfo(tinfo->mutableOf()->merge()); - // finish - b.finalize(ir.irGlobal); -} - -/* ========================================================================= */ - -#if DMDV2 - -void TypeInfoVectorDeclaration::llvmDefine() -{ - Logger::println("TypeInfoVectorDeclaration::llvmDefine() %s", toChars()); - LOG_SCOPE; - - assert(tinfo->ty == Tvector); - TypeVector *tv = static_cast(tinfo); - - RTTIBuilder b(Type::typeinfovector); - // TypeInfo base - b.push_typeinfo(tv->basetype); - // finish - b.finalize(ir.irGlobal); -} - -#endif - -#endif + + +// Copyright (c) 1999-2004 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. + +// Modifications for LDC: +// Copyright (c) 2007 by Tomas Lindquist Olsen +// tomas at famolsen dk + +#include +#include + +#include "gen/llvm.h" + +#include "mars.h" +#include "module.h" +#include "mtype.h" +#include "scope.h" +#include "init.h" +#include "expression.h" +#include "attrib.h" +#include "declaration.h" +#include "template.h" +#include "id.h" +#include "enum.h" +#include "import.h" +#include "aggregate.h" + +#include "gen/irstate.h" +#include "gen/logger.h" +#include "gen/runtime.h" +#include "gen/tollvm.h" +#include "gen/llvmhelpers.h" +#include "gen/arrays.h" +#include "gen/structs.h" +#include "gen/classes.h" +#include "gen/linkage.h" +#include "gen/metadata.h" +#include "gen/rttibuilder.h" + +#include "ir/irvar.h" +#include "ir/irtype.h" + +/******************************************* + * Get a canonicalized form of the TypeInfo for use with the internal + * runtime library routines. Canonicalized in that static arrays are + * represented as dynamic arrays, enums are represented by their + * underlying type, etc. This reduces the number of TypeInfo's needed, + * so we can use the custom internal ones more. + */ + +Expression *Type::getInternalTypeInfo(Scope *sc) +{ TypeInfoDeclaration *tid; + Expression *e; + Type *t; + static TypeInfoDeclaration *internalTI[TMAX]; + + //printf("Type::getInternalTypeInfo() %s\n", toChars()); + t = toBasetype(); + switch (t->ty) + { + case Tsarray: +#if 0 + // convert to corresponding dynamic array type + t = t->nextOf()->mutableOf()->arrayOf(); +#endif + break; + + case Tclass: + if (static_cast(t)->sym->isInterfaceDeclaration()) + break; + goto Linternal; + + case Tarray: + #if DMDV2 + // convert to corresponding dynamic array type + t = t->nextOf()->mutableOf()->arrayOf(); + #endif + if (t->nextOf()->ty != Tclass) + break; + goto Linternal; + + case Tfunction: + case Tdelegate: + case Tpointer: + Linternal: + tid = internalTI[t->ty]; + if (!tid) + { tid = new TypeInfoDeclaration(t, 1); + internalTI[t->ty] = tid; + } + e = new VarExp(0, tid); + e = e->addressOf(sc); + e->type = tid->type; // do this so we don't get redundant dereference + return e; + + default: + break; + } + //printf("\tcalling getTypeInfo() %s\n", t->toChars()); + return t->getTypeInfo(sc); +} + +/**************************************************** + * Get the exact TypeInfo. + */ + +Expression *Type::getTypeInfo(Scope *sc) +{ + //printf("Type::getTypeInfo() %p, %s\n", this, toChars()); + if (!Type::typeinfo) + { + error(0, "TypeInfo not found. object.d may be incorrectly installed or corrupt, compile with -v switch"); + fatal(); + } + + Expression *e = 0; + Type *t = merge2(); // do this since not all Type's are merge'd + + if (!t->vtinfo) + { +#if DMDV2 + if (t->isShared()) + t->vtinfo = new TypeInfoSharedDeclaration(t); + else if (t->isConst()) + t->vtinfo = new TypeInfoConstDeclaration(t); + else if (t->isImmutable()) + t->vtinfo = new TypeInfoInvariantDeclaration(t); + else if (t->isWild()) + t->vtinfo = new TypeInfoWildDeclaration(t); + else +#endif + t->vtinfo = t->getTypeInfoDeclaration(); + assert(t->vtinfo); + + /* If this has a custom implementation in std/typeinfo, then + * do not generate a COMDAT for it. + */ + if (!t->builtinTypeInfo()) + { // Generate COMDAT + if (sc) // if in semantic() pass + { // Find module that will go all the way to an object file + Module *m = sc->module->importedFrom; + m->members->push(t->vtinfo); + } + else // if in obj generation pass + { +#if IN_DMD + t->vtinfo->toObjFile(0); // TODO: multiobj +#else + t->vtinfo->codegen(sir); +#endif + } + } + } + e = new VarExp(0, t->vtinfo); + e = e->addressOf(sc); + e->type = t->vtinfo->type; // do this so we don't get redundant dereference + return e; +} + +enum RET TypeFunction::retStyle() +{ + return RETstack; +} + +TypeInfoDeclaration *Type::getTypeInfoDeclaration() +{ + //printf("Type::getTypeInfoDeclaration() %s\n", toChars()); + return new TypeInfoDeclaration(this, 0); +} + +TypeInfoDeclaration *TypeTypedef::getTypeInfoDeclaration() +{ + return new TypeInfoTypedefDeclaration(this); +} + +TypeInfoDeclaration *TypePointer::getTypeInfoDeclaration() +{ + return new TypeInfoPointerDeclaration(this); +} + +TypeInfoDeclaration *TypeDArray::getTypeInfoDeclaration() +{ + return new TypeInfoArrayDeclaration(this); +} + +TypeInfoDeclaration *TypeSArray::getTypeInfoDeclaration() +{ + return new TypeInfoStaticArrayDeclaration(this); +} + +TypeInfoDeclaration *TypeAArray::getTypeInfoDeclaration() +{ + return new TypeInfoAssociativeArrayDeclaration(this); +} + +TypeInfoDeclaration *TypeStruct::getTypeInfoDeclaration() +{ + return new TypeInfoStructDeclaration(this); +} + +TypeInfoDeclaration *TypeClass::getTypeInfoDeclaration() +{ + if (sym->isInterfaceDeclaration()) + return new TypeInfoInterfaceDeclaration(this); + else + return new TypeInfoClassDeclaration(this); +} + +#if DMDV2 +TypeInfoDeclaration *TypeVector::getTypeInfoDeclaration() +{ + return new TypeInfoVectorDeclaration(this); +} +#endif + +TypeInfoDeclaration *TypeEnum::getTypeInfoDeclaration() +{ + return new TypeInfoEnumDeclaration(this); +} + +TypeInfoDeclaration *TypeFunction::getTypeInfoDeclaration() +{ + return new TypeInfoFunctionDeclaration(this); +} + +TypeInfoDeclaration *TypeDelegate::getTypeInfoDeclaration() +{ + return new TypeInfoDelegateDeclaration(this); +} + +TypeInfoDeclaration *TypeTuple::getTypeInfoDeclaration() +{ + return new TypeInfoTupleDeclaration(this); +} + +/* ========================================================================= */ + +/* These decide if there's an instance for them already in std.typeinfo, + * because then the compiler doesn't need to build one. + */ + +int Type::builtinTypeInfo() +{ + return 0; +} + +int TypeBasic::builtinTypeInfo() +{ +#if DMDV2 + return mod ? 0 : 1; +#else + return 1; +#endif +} + +int TypeDArray::builtinTypeInfo() +{ +#if DMDV2 + return !mod && (next->isTypeBasic() != NULL && !next->mod || + // strings are so common, make them builtin + next->ty == Tchar && next->mod == MODimmutable); +#else + return next->isTypeBasic() != NULL; +#endif +} + +int TypeClass::builtinTypeInfo() +{ + /* This is statically put out with the ClassInfo, so + * claim it is built in so it isn't regenerated by each module. + */ +#if IN_DMD + return mod ? 0 : 1; +#elif IN_LLVM + // FIXME if I enable this, the way LDC does typeinfo will cause a bunch + // of linker errors to missing class typeinfo definitions. + return 0; +#endif +} + +/* ========================================================================= */ + +////////////////////////////////////////////////////////////////////////////// +// MAGIC PLACE +// (wut?) +////////////////////////////////////////////////////////////////////////////// + +void DtoResolveTypeInfo(TypeInfoDeclaration* tid); +void DtoDeclareTypeInfo(TypeInfoDeclaration* tid); + +void TypeInfoDeclaration::codegen(Ir*) +{ + DtoResolveTypeInfo(this); +} + +void DtoResolveTypeInfo(TypeInfoDeclaration* tid) +{ + if (tid->ir.resolved) return; + tid->ir.resolved = true; + + Logger::println("DtoResolveTypeInfo(%s)", tid->toChars()); + LOG_SCOPE; + + std::string mangle(tid->mangle()); + + IrGlobal* irg = new IrGlobal(tid); + irg->value = gIR->module->getGlobalVariable(mangle); + + if (!irg->value) { + if (tid->tinfo->builtinTypeInfo()) // this is a declaration of a builtin __initZ var + irg->type = Type::typeinfo->type->irtype->getType(); + else + irg->type = LLStructType::create(gIR->context(), tid->toPrettyChars()); + irg->value = new llvm::GlobalVariable(*gIR->module, irg->type, true, + TYPEINFO_LINKAGE_TYPE, NULL, mangle); + } else { + irg->type = irg->value->getType()->getContainedType(0); + } + + tid->ir.irGlobal = irg; + +#if USE_METADATA + // don't do this for void or llvm will crash + if (tid->tinfo->ty != Tvoid) { + // Add some metadata for use by optimization passes. + std::string metaname = std::string(TD_PREFIX) + mangle; + llvm::NamedMDNode* meta = gIR->module->getNamedMetadata(metaname); + // Don't generate metadata for non-concrete types + // (such as tuple types, slice types, typeof(expr), etc.) + if (!meta && tid->tinfo->toBasetype()->ty < Terror) { + // Construct the fields + MDNodeField* mdVals[TD_NumFields]; + if (TD_Confirm >= 0) + mdVals[TD_Confirm] = llvm::cast(irg->value); + mdVals[TD_Type] = llvm::UndefValue::get(DtoType(tid->tinfo)); + // Construct the metadata + llvm::MetadataBase* metadata = llvm::MDNode::get(gIR->context(), mdVals, TD_NumFields); + // Insert it into the module + llvm::NamedMDNode::Create(gIR->context(), metaname, &metadata, 1, gIR->module); + } + } +#endif // USE_METADATA + + DtoDeclareTypeInfo(tid); +} + +void DtoDeclareTypeInfo(TypeInfoDeclaration* tid) +{ + DtoResolveTypeInfo(tid); + + if (tid->ir.declared) return; + tid->ir.declared = true; + + Logger::println("DtoDeclareTypeInfo(%s)", tid->toChars()); + LOG_SCOPE; + + if (Logger::enabled()) + { + std::string mangled(tid->mangle()); + Logger::println("type = '%s'", tid->tinfo->toChars()); + Logger::println("typeinfo mangle: %s", mangled.c_str()); + } + + IrGlobal* irg = tid->ir.irGlobal; + assert(irg->value != NULL); + + // this is a declaration of a builtin __initZ var + if (tid->tinfo->builtinTypeInfo()) { + LLGlobalVariable* g = isaGlobalVar(irg->value); + g->setLinkage(llvm::GlobalValue::ExternalLinkage); + return; + } + + // define custom typedef + tid->llvmDefine(); +} + +/* ========================================================================= */ + +void TypeInfoDeclaration::llvmDefine() +{ + Logger::println("TypeInfoDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + RTTIBuilder b(Type::typeinfo); + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +void TypeInfoTypedefDeclaration::llvmDefine() +{ + Logger::println("TypeInfoTypedefDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + RTTIBuilder b(Type::typeinfotypedef); + + assert(tinfo->ty == Ttypedef); + TypeTypedef *tc = static_cast(tinfo); + TypedefDeclaration *sd = tc->sym; + + // TypeInfo base + sd->basetype = sd->basetype->merge(); // dmd does it ... why? + b.push_typeinfo(sd->basetype); + + // char[] name + b.push_string(sd->toPrettyChars()); + + // void[] init + // emit null array if we should use the basetype, or if the basetype + // uses default initialization. + if (tinfo->isZeroInit(0) || !sd->init) + { + b.push_null_void_array(); + } + // otherwise emit a void[] with the default initializer + else + { + LLConstant* C = DtoConstInitializer(sd->loc, sd->basetype, sd->init); + b.push_void_array(C, sd->basetype, sd); + } + + // finish + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +void TypeInfoEnumDeclaration::llvmDefine() +{ + Logger::println("TypeInfoEnumDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + RTTIBuilder b(Type::typeinfoenum); + + assert(tinfo->ty == Tenum); + TypeEnum *tc = static_cast(tinfo); + EnumDeclaration *sd = tc->sym; + + // TypeInfo base + b.push_typeinfo(sd->memtype); + + // char[] name + b.push_string(sd->toPrettyChars()); + + // void[] init + // emit void[] with the default initialier, the array is null if the default + // initializer is zero + if (!sd->defaultval || tinfo->isZeroInit(0)) + { + b.push_null_void_array(); + } + // otherwise emit a void[] with the default initializer + else + { + LLType* memty = DtoType(sd->memtype); +#if DMDV2 + LLConstant* C = LLConstantInt::get(memty, sd->defaultval->toInteger(), !sd->memtype->isunsigned()); +#else + LLConstant* C = LLConstantInt::get(memty, sd->defaultval, !sd->memtype->isunsigned()); +#endif + b.push_void_array(C, sd->memtype, sd); + } + + // finish + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +void TypeInfoPointerDeclaration::llvmDefine() +{ + Logger::println("TypeInfoPointerDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + RTTIBuilder b(Type::typeinfopointer); + // TypeInfo base + b.push_typeinfo(tinfo->nextOf()); + // finish + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +void TypeInfoArrayDeclaration::llvmDefine() +{ + Logger::println("TypeInfoArrayDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + RTTIBuilder b(Type::typeinfoarray); + // TypeInfo base + b.push_typeinfo(tinfo->nextOf()); + // finish + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +void TypeInfoStaticArrayDeclaration::llvmDefine() +{ + Logger::println("TypeInfoStaticArrayDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + assert(tinfo->ty == Tsarray); + TypeSArray *tc = static_cast(tinfo); + + RTTIBuilder b(Type::typeinfostaticarray); + + // value typeinfo + b.push_typeinfo(tc->nextOf()); + + // length + b.push(DtoConstSize_t(static_cast(tc->dim->toUInteger()))); + + // finish + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +void TypeInfoAssociativeArrayDeclaration::llvmDefine() +{ + Logger::println("TypeInfoAssociativeArrayDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + assert(tinfo->ty == Taarray); + TypeAArray *tc = static_cast(tinfo); + + RTTIBuilder b(Type::typeinfoassociativearray); + + // value typeinfo + b.push_typeinfo(tc->nextOf()); + + // key typeinfo + b.push_typeinfo(tc->index); + +#if DMDV2 + // impl typeinfo + b.push_typeinfo(tc->getImpl()->type); +#endif + + // finish + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +void TypeInfoFunctionDeclaration::llvmDefine() +{ + Logger::println("TypeInfoFunctionDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + RTTIBuilder b(Type::typeinfofunction); + // TypeInfo base + b.push_typeinfo(tinfo->nextOf()); + // string deco + b.push_string(tinfo->deco); + // finish + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +void TypeInfoDelegateDeclaration::llvmDefine() +{ + Logger::println("TypeInfoDelegateDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + assert(tinfo->ty == Tdelegate); + Type* ret_type = tinfo->nextOf()->nextOf(); + + RTTIBuilder b(Type::typeinfodelegate); + // TypeInfo base + b.push_typeinfo(ret_type); + // string deco + b.push_string(tinfo->deco); + // finish + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +static FuncDeclaration* find_method_overload(AggregateDeclaration* ad, Identifier* id, TypeFunction* tf, Module* mod) +{ + Dsymbol *s = search_function(ad, id); + FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL; + if (fdx) + { + FuncDeclaration *fd = fdx->overloadExactMatch(tf, mod); + if (fd) + { + return fd; + } + } + return NULL; +} + +void TypeInfoStructDeclaration::llvmDefine() +{ + Logger::println("TypeInfoStructDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + // make sure struct is resolved + assert(tinfo->ty == Tstruct); + TypeStruct *tc = static_cast(tinfo); + StructDeclaration *sd = tc->sym; + + // can't emit typeinfo for forward declarations + if (sd->sizeok != 1) + { + sd->error("cannot emit TypeInfo for forward declaration"); + fatal(); + } + + sd->codegen(Type::sir); + IrStruct* irstruct = sd->ir.irStruct; + + RTTIBuilder b(Type::typeinfostruct); + + // char[] name + b.push_string(sd->toPrettyChars()); + + // void[] init + // never emit a null array, even for zero initialized typeinfo + // the size() method uses this array! + size_t init_size = getTypeStoreSize(tc->irtype->getType()); + b.push_void_array(init_size, irstruct->getInitSymbol()); + + // toX functions ground work + static TypeFunction *tftohash; + static TypeFunction *tftostring; + + if (!tftohash) + { + Scope sc; + tftohash = new TypeFunction(NULL, Type::thash_t, 0, LINKd); +#if DMDV2 + tftohash ->mod = MODconst; +#endif + tftohash = static_cast(tftohash->semantic(0, &sc)); + +#if DMDV2 + Type *retType = Type::tchar->invariantOf()->arrayOf(); +#else + Type *retType = Type::tchar->arrayOf(); +#endif + tftostring = new TypeFunction(NULL, retType, 0, LINKd); + tftostring = static_cast(tftostring->semantic(0, &sc)); + } + + // this one takes a parameter, so we need to build a new one each time + // to get the right type. can we avoid this? + TypeFunction *tfcmpptr; + { + Scope sc; + Parameters *arguments = new Parameters; +#if STRUCTTHISREF + // arg type is ref const T + Parameter *arg = new Parameter(STCref, tc->constOf(), NULL, NULL); +#else + // arg type is const T* + Parameter *arg = new Parameter(STCin, tc->pointerTo(), NULL, NULL); +#endif + arguments->push(arg); + tfcmpptr = new TypeFunction(arguments, Type::tint32, 0, LINKd); +#if DMDV2 + tfcmpptr->mod = MODconst; +#endif + tfcmpptr = static_cast(tfcmpptr->semantic(0, &sc)); + } + + // well use this module for all overload lookups + Module *gm = getModule(); + + // toHash + FuncDeclaration* fd = find_method_overload(sd, Id::tohash, tftohash, gm); + b.push_funcptr(fd); + + // opEquals +#if DMDV2 + fd = sd->xeq; +#else + fd = find_method_overload(sd, Id::eq, tfcmpptr, gm); +#endif + b.push_funcptr(fd); + + // opCmp + fd = find_method_overload(sd, Id::cmp, tfcmpptr, gm); + b.push_funcptr(fd); + + // toString + fd = find_method_overload(sd, Id::tostring, tftostring, gm); + b.push_funcptr(fd); + + // uint m_flags; + unsigned hasptrs = tc->hasPointers() ? 1 : 0; + b.push_uint(hasptrs); + +#if DMDV2 + + ClassDeclaration* tscd = Type::typeinfostruct; + + assert((!global.params.is64bit && tscd->fields.dim == 11) || + (global.params.is64bit && tscd->fields.dim == 13)); + + //void function(void*) xdtor; + b.push_funcptr(sd->dtor); + + //void function(void*) xpostblit; + FuncDeclaration *xpostblit = sd->postblit; + if (xpostblit && sd->postblit->storage_class & STCdisable) + xpostblit = 0; + b.push_funcptr(xpostblit); + + //uint m_align; + b.push_uint(tc->alignsize()); + + if (global.params.is64bit) + { + // TypeInfo m_arg1; + // TypeInfo m_arg2; + TypeTuple *tup = tc->toArgTypes(); + assert(tup->arguments->dim <= 2); + for (unsigned i = 0; i < 2; i++) + { + if (i < tup->arguments->dim) + { + Type *targ = static_cast(tup->arguments->data[i])->type; + targ = targ->merge(); + b.push_typeinfo(targ); + } + else + b.push_null(Type::typeinfo->type); + } + } + + // immutable(void)* m_RTInfo; + // The cases where getRTInfo is null are not quite here, but the code is + // modelled after what DMD does. + if (sd->getRTInfo) + b.push(sd->getRTInfo->toConstElem(gIR)); + else if (!tc->hasPointers()) + b.push_size_as_vp(0); // no pointers + else + b.push_size_as_vp(1); // has pointers + +#endif + + // finish + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +#if DMDV2 +void TypeInfoClassDeclaration::codegen(Ir*i) +{ + + IrGlobal* irg = new IrGlobal(this); + ir.irGlobal = irg; + assert(tinfo->ty == Tclass); + TypeClass *tc = static_cast(tinfo); + tc->sym->codegen(Type::sir); // make sure class is resolved + irg->value = tc->sym->ir.irStruct->getClassInfoSymbol(); +} +#endif + +void TypeInfoClassDeclaration::llvmDefine() +{ +#if DMDV2 + assert(0); +#endif + Logger::println("TypeInfoClassDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + // make sure class is resolved + assert(tinfo->ty == Tclass); + TypeClass *tc = static_cast(tinfo); + tc->sym->codegen(Type::sir); + + RTTIBuilder b(Type::typeinfoclass); + + // TypeInfo base + b.push_classinfo(tc->sym); + + // finish + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +void TypeInfoInterfaceDeclaration::llvmDefine() +{ + Logger::println("TypeInfoInterfaceDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + // make sure interface is resolved + assert(tinfo->ty == Tclass); + TypeClass *tc = static_cast(tinfo); + tc->sym->codegen(Type::sir); + + RTTIBuilder b(Type::typeinfointerface); + + // TypeInfo base + b.push_classinfo(tc->sym); + + // finish + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +void TypeInfoTupleDeclaration::llvmDefine() +{ + Logger::println("TypeInfoTupleDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + // create elements array + assert(tinfo->ty == Ttuple); + TypeTuple *tu = static_cast(tinfo); + + size_t dim = tu->arguments->dim; + std::vector arrInits; + arrInits.reserve(dim); + + LLType* tiTy = DtoType(Type::typeinfo->type); + + for (size_t i = 0; i < dim; i++) + { + Parameter *arg = static_cast(tu->arguments->data[i]); + arrInits.push_back(DtoTypeInfoOf(arg->type, true)); + } + + // build array + LLArrayType* arrTy = LLArrayType::get(tiTy, dim); + LLConstant* arrC = LLConstantArray::get(arrTy, arrInits); + + RTTIBuilder b(Type::typeinfotypelist); + + // push TypeInfo[] + b.push_array(arrC, dim, Type::typeinfo->type, NULL); + + // finish + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +#if DMDV2 + +void TypeInfoConstDeclaration::llvmDefine() +{ + Logger::println("TypeInfoConstDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + RTTIBuilder b(Type::typeinfoconst); + // TypeInfo base + b.push_typeinfo(tinfo->mutableOf()->merge()); + // finish + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +void TypeInfoInvariantDeclaration::llvmDefine() +{ + Logger::println("TypeInfoInvariantDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + RTTIBuilder b(Type::typeinfoinvariant); + // TypeInfo base + b.push_typeinfo(tinfo->mutableOf()->merge()); + // finish + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +void TypeInfoSharedDeclaration::llvmDefine() +{ + Logger::println("TypeInfoSharedDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + RTTIBuilder b(Type::typeinfoshared); + // TypeInfo base + b.push_typeinfo(tinfo->unSharedOf()->merge()); + // finish + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +void TypeInfoWildDeclaration::llvmDefine() +{ + Logger::println("TypeInfoWildDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + RTTIBuilder b(Type::typeinfowild); + // TypeInfo base + b.push_typeinfo(tinfo->mutableOf()->merge()); + // finish + b.finalize(ir.irGlobal); +} + +/* ========================================================================= */ + +#if DMDV2 + +void TypeInfoVectorDeclaration::llvmDefine() +{ + Logger::println("TypeInfoVectorDeclaration::llvmDefine() %s", toChars()); + LOG_SCOPE; + + assert(tinfo->ty == Tvector); + TypeVector *tv = static_cast(tinfo); + + RTTIBuilder b(Type::typeinfovector); + // TypeInfo base + b.push_typeinfo(tv->basetype); + // finish + b.finalize(ir.irGlobal); +} + +#endif + +#endif diff --git a/ir/irvar.cpp b/ir/irvar.cpp index f41f6acb..e338f123 100644 --- a/ir/irvar.cpp +++ b/ir/irvar.cpp @@ -31,7 +31,6 @@ IrGlobal::IrGlobal(VarDeclaration* v): IrVar(v) IrLocal::IrLocal(VarDeclaration* v) : IrVar(v) { nestedIndex = -1; - byref = false; } ////////////////////////////////////////////////////////////////////////////// diff --git a/ir/irvar.h b/ir/irvar.h index 3d66cc39..680c112b 100644 --- a/ir/irvar.h +++ b/ir/irvar.h @@ -28,8 +28,8 @@ struct IrLocal : IrVar { IrLocal(VarDeclaration* v); - bool byref; // Not used for -nested-ctx=array - int nestedDepth; // ditto + // Used for hybrid nested context creation. + int nestedDepth; int nestedIndex; }; diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt index 10803e52..51e4a569 100644 --- a/runtime/CMakeLists.txt +++ b/runtime/CMakeLists.txt @@ -15,7 +15,7 @@ else() endif() set(DMDFE_MINOR_VERSION 0) -set(DMDFE_PATCH_VERSION 59) +set(DMDFE_PATCH_VERSION 60) set(DMDFE_VERSION ${D_VERSION}.${DMDFE_MINOR_VERSION}.${DMDFE_PATCH_VERSION}) set(MULTILIB OFF CACHE BOOL "Build both 64-bit and 32-bit libraries") @@ -384,5 +384,5 @@ if(PHOBOS2_DIR) install(DIRECTORY ${PHOBOS2_DIR}/etc DESTINATION ${INCLUDE_INSTALL_DIR} FILES_MATCHING PATTERN "*.d") install(FILES ${PHOBOS2_DIR}/crc32.d DESTINATION ${INCLUDE_INSTALL_DIR}) endif(PHOBOS2_DIR) -install(FILES ${RUNTIME_DIR}/import/object.di DESTINATION ${INCLUDE_INSTALL_DIR}/ldc) +install(FILES ${RUNTIME_DIR}/src/object.di DESTINATION ${INCLUDE_INSTALL_DIR}/ldc) install(DIRECTORY ${RUNTIME_DIR}/import/ldc DESTINATION ${INCLUDE_INSTALL_DIR} FILES_MATCHING PATTERN "*.di") diff --git a/runtime/druntime b/runtime/druntime index 6ac9475a..f611c6ca 160000 --- a/runtime/druntime +++ b/runtime/druntime @@ -1 +1 @@ -Subproject commit 6ac9475aa22924887d5010f41a4dc577836fbbdf +Subproject commit f611c6cacfb158ef82de5c0ff57e89fe469c12ba diff --git a/runtime/phobos b/runtime/phobos index 52b15ed3..e05ad809 160000 --- a/runtime/phobos +++ b/runtime/phobos @@ -1 +1 @@ -Subproject commit 52b15ed3c0abf1d8af58bc5371c90636e01c1073 +Subproject commit e05ad809add2722d4f6492d1a4f43dd26091bdb9 diff --git a/tests/README b/tests/d1/README similarity index 100% rename from tests/README rename to tests/d1/README diff --git a/tests/findregressions.d b/tests/d1/findregressions.d similarity index 100% rename from tests/findregressions.d rename to tests/d1/findregressions.d diff --git a/tests/makewebstatistics.d b/tests/d1/makewebstatistics.d similarity index 100% rename from tests/makewebstatistics.d rename to tests/d1/makewebstatistics.d diff --git a/tests/minicomplex/arrays1.d b/tests/d1/minicomplex/arrays1.d similarity index 100% rename from tests/minicomplex/arrays1.d rename to tests/d1/minicomplex/arrays1.d diff --git a/tests/minicomplex/constructors.d b/tests/d1/minicomplex/constructors.d similarity index 100% rename from tests/minicomplex/constructors.d rename to tests/d1/minicomplex/constructors.d diff --git a/tests/minicomplex/files1.d b/tests/d1/minicomplex/files1.d similarity index 100% rename from tests/minicomplex/files1.d rename to tests/d1/minicomplex/files1.d diff --git a/tests/minicomplex/gc2.d b/tests/d1/minicomplex/gc2.d similarity index 100% rename from tests/minicomplex/gc2.d rename to tests/d1/minicomplex/gc2.d diff --git a/tests/minicomplex/ina1.d b/tests/d1/minicomplex/ina1.d similarity index 100% rename from tests/minicomplex/ina1.d rename to tests/d1/minicomplex/ina1.d diff --git a/tests/minicomplex/l.d b/tests/d1/minicomplex/l.d similarity index 100% rename from tests/minicomplex/l.d rename to tests/d1/minicomplex/l.d diff --git a/tests/minicomplex/mem1.d b/tests/d1/minicomplex/mem1.d similarity index 100% rename from tests/minicomplex/mem1.d rename to tests/d1/minicomplex/mem1.d diff --git a/tests/minicomplex/mem4.d b/tests/d1/minicomplex/mem4.d similarity index 100% rename from tests/minicomplex/mem4.d rename to tests/d1/minicomplex/mem4.d diff --git a/tests/minicomplex/stdout1.d b/tests/d1/minicomplex/stdout1.d similarity index 100% rename from tests/minicomplex/stdout1.d rename to tests/d1/minicomplex/stdout1.d diff --git a/tests/minicomplex/stdout2.d b/tests/d1/minicomplex/stdout2.d similarity index 100% rename from tests/minicomplex/stdout2.d rename to tests/d1/minicomplex/stdout2.d diff --git a/tests/minicomplex/templ1.d b/tests/d1/minicomplex/templ1.d similarity index 100% rename from tests/minicomplex/templ1.d rename to tests/d1/minicomplex/templ1.d diff --git a/tests/minicomplex/u.d b/tests/d1/minicomplex/u.d similarity index 100% rename from tests/minicomplex/u.d rename to tests/d1/minicomplex/u.d diff --git a/tests/minicomplex/vararg1.d b/tests/d1/minicomplex/vararg1.d similarity index 100% rename from tests/minicomplex/vararg1.d rename to tests/d1/minicomplex/vararg1.d diff --git a/tests/minicomplex/vararg2.d b/tests/d1/minicomplex/vararg2.d similarity index 100% rename from tests/minicomplex/vararg2.d rename to tests/d1/minicomplex/vararg2.d diff --git a/tests/minicomplex/volatile1.d b/tests/d1/minicomplex/volatile1.d similarity index 100% rename from tests/minicomplex/volatile1.d rename to tests/d1/minicomplex/volatile1.d diff --git a/tests/runminitest.d b/tests/d1/runminitest.d similarity index 100% rename from tests/runminitest.d rename to tests/d1/runminitest.d diff --git a/tests/runtest b/tests/d1/runtest similarity index 100% rename from tests/runtest rename to tests/d1/runtest diff --git a/tests/testincludes/Makefile b/tests/d1/testincludes/Makefile similarity index 100% rename from tests/testincludes/Makefile rename to tests/d1/testincludes/Makefile diff --git a/tests/testincludes/object.di b/tests/d1/testincludes/object.di similarity index 100% rename from tests/testincludes/object.di rename to tests/d1/testincludes/object.di diff --git a/tests/testincludes/std/IEEE.d b/tests/d1/testincludes/std/IEEE.d similarity index 100% rename from tests/testincludes/std/IEEE.d rename to tests/d1/testincludes/std/IEEE.d diff --git a/tests/testincludes/std/compat.d b/tests/d1/testincludes/std/compat.d similarity index 100% rename from tests/testincludes/std/compat.d rename to tests/d1/testincludes/std/compat.d diff --git a/tests/testincludes/std/gc.d b/tests/d1/testincludes/std/gc.d similarity index 100% rename from tests/testincludes/std/gc.d rename to tests/d1/testincludes/std/gc.d diff --git a/tests/testincludes/std/outofmemory.d b/tests/d1/testincludes/std/outofmemory.d similarity index 100% rename from tests/testincludes/std/outofmemory.d rename to tests/d1/testincludes/std/outofmemory.d diff --git a/tests/testincludes/std/stdarg.d b/tests/d1/testincludes/std/stdarg.d similarity index 100% rename from tests/testincludes/std/stdarg.d rename to tests/d1/testincludes/std/stdarg.d diff --git a/tests/d2/dmd-testsuite b/tests/d2/dmd-testsuite new file mode 160000 index 00000000..b6145220 --- /dev/null +++ b/tests/d2/dmd-testsuite @@ -0,0 +1 @@ +Subproject commit b6145220cd266322519619b0cef8b271a0456240