From e8814d0603889290cc30fbe0b1596dac3f3e62ca Mon Sep 17 00:00:00 2001 From: kai Date: Sun, 3 Mar 2013 17:13:45 +0100 Subject: [PATCH 1/4] Merge of DMD 2.062. --- dmd2/access.c | 3 +- dmd2/aggregate.h | 20 +- dmd2/argtypes.c | 1 - dmd2/attrib.c | 84 ++- dmd2/attrib.h | 5 +- dmd2/cast.c | 45 +- dmd2/class.c | 46 +- dmd2/clone.c | 152 ++++-- dmd2/cppmangle.c | 6 +- dmd2/ctfeexpr.c | 4 +- dmd2/declaration.c | 51 +- dmd2/declaration.h | 41 +- dmd2/delegatize.c | 1 + dmd2/doc.c | 165 +++--- dmd2/dsymbol.c | 46 +- dmd2/dsymbol.h | 17 +- dmd2/enum.c | 10 + dmd2/enum.h | 6 +- dmd2/expression.c | 776 +++++++++------------------ dmd2/expression.h | 17 +- dmd2/func.c | 474 ++++++++++------ dmd2/hdrgen.c | 5 +- dmd2/hdrgen.h | 6 +- dmd2/idgen.c | 1 - dmd2/import.c | 22 +- dmd2/import.h | 1 + dmd2/init.h | 1 - dmd2/inline.c | 14 - dmd2/interpret.c | 59 +- dmd2/json.c | 1132 ++++++++++++++++++++++++++++++--------- dmd2/json.h | 6 +- dmd2/lexer.c | 2 - dmd2/mangle.c | 81 ++- dmd2/mars.c | 101 +++- dmd2/mars.h | 10 +- dmd2/module.c | 196 +++---- dmd2/module.h | 10 +- dmd2/mtype.c | 349 ++++++++---- dmd2/mtype.h | 68 ++- dmd2/opover.c | 9 + dmd2/optimize.c | 3 - dmd2/parse.c | 22 +- dmd2/root/array.c | 46 +- dmd2/root/gnuc.c | 63 --- dmd2/root/gnuc.h | 16 - dmd2/root/port.c | 77 ++- dmd2/root/port.h | 6 +- dmd2/root/response.c | 2 +- dmd2/root/root.c | 176 +++--- dmd2/root/root.h | 41 +- dmd2/root/stringtable.c | 2 +- dmd2/scope.c | 2 +- dmd2/scope.h | 1 - dmd2/statement.c | 125 ++--- dmd2/statement.h | 2 +- dmd2/staticassert.c | 1 - dmd2/struct.c | 6 +- dmd2/template.c | 316 ++++++----- dmd2/template.h | 5 +- dmd2/traits.c | 5 +- dmd2/utf.c | 1 - dmd2/utf.h | 1 - driver/main.cpp | 106 +++- runtime/druntime | 2 +- runtime/phobos | 2 +- 65 files changed, 2964 insertions(+), 2108 deletions(-) delete mode 100644 dmd2/root/gnuc.c delete mode 100644 dmd2/root/gnuc.h diff --git a/dmd2/access.c b/dmd2/access.c index b8b677c6..1d2e5a1c 100644 --- a/dmd2/access.c +++ b/dmd2/access.c @@ -219,7 +219,8 @@ void AggregateDeclaration::accessCheck(Loc loc, Scope *sc, Dsymbol *smember) result = access2 >= PROTpublic || hasPrivateAccess(f) || isFriendOf(cdscope) || - (access2 == PROTpackage && hasPackageAccess(sc, this)); + (access2 == PROTpackage && hasPackageAccess(sc, this)) || + getAccessModule() == sc->module; #if LOG printf("result1 = %d\n", result); #endif diff --git a/dmd2/aggregate.h b/dmd2/aggregate.h index c9f69be1..620f6f00 100644 --- a/dmd2/aggregate.h +++ b/dmd2/aggregate.h @@ -118,9 +118,13 @@ struct AggregateDeclaration : ScopeDsymbol int isExport(); void emitComment(Scope *sc); - void toJsonBuffer(OutBuffer *buf); + void toJson(JsonOut *json); void toDocBuffer(OutBuffer *buf, Scope *sc); + FuncDeclaration *hasIdentityOpAssign(Scope *sc, Dsymbol *assign); + + char *mangle(bool isv = false); + // For access checking virtual PROT getAccess(Dsymbol *smember); // determine access to smember int isFriendOf(AggregateDeclaration *cd); @@ -144,16 +148,6 @@ struct AggregateDeclaration : ScopeDsymbol #endif }; -struct AnonymousAggregateDeclaration : AggregateDeclaration -{ - AnonymousAggregateDeclaration() - : AggregateDeclaration(0, NULL) - { - } - - AnonymousAggregateDeclaration *isAnonymousAggregateDeclaration() { return this; } -}; - struct StructDeclaration : AggregateDeclaration { int zeroInit; // !=0 if initialize with 0 fill @@ -179,7 +173,7 @@ struct StructDeclaration : AggregateDeclaration void semantic(Scope *sc); Dsymbol *search(Loc, Identifier *ident, int flags); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - char *mangle(); + char *mangle(bool isv = false); const char *kind(); void finalizeSize(Scope *sc); bool isPOD(); @@ -320,7 +314,7 @@ struct ClassDeclaration : AggregateDeclaration int isAbstract(); virtual int vtblOffset(); const char *kind(); - char *mangle(); + char *mangle(bool isv = false); void toDocBuffer(OutBuffer *buf, Scope *sc); PROT getAccess(Dsymbol *smember); // determine access to smember diff --git a/dmd2/argtypes.c b/dmd2/argtypes.c index 5f1579ad..a26a1166 100644 --- a/dmd2/argtypes.c +++ b/dmd2/argtypes.c @@ -4,7 +4,6 @@ // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com -// http://www.dsource.org/projects/dmd/browser/branches/dmd-1.x/src/argtypes.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. diff --git a/dmd2/attrib.c b/dmd2/attrib.c index 6783a199..d8defdf1 100644 --- a/dmd2/attrib.c +++ b/dmd2/attrib.c @@ -27,14 +27,10 @@ #include "module.h" #include "parse.h" #include "template.h" -#if TARGET_NET - #include "frontend.net/pragma.h" -#endif #if IN_LLVM #include "../gen/pragma.h" #endif - #if IN_DMD extern bool obj_includelib(const char *name); void obj_startaddress(Symbol *s); @@ -484,7 +480,14 @@ void StorageClassDeclaration::semantic(Scope *sc) } } -void StorageClassDeclaration::stcToCBuffer(OutBuffer *buf, StorageClass stc) + +/************************************************* + * Pick off one of the storage classes from stc, + * and return a pointer to a string representation of it. + * stc is reduced by the one picked. + * tmp[] is a buffer big enough to hold that string. + */ +const char *StorageClassDeclaration::stcToChars(char tmp[], StorageClass& stc) { struct SCstring { @@ -528,21 +531,39 @@ void StorageClassDeclaration::stcToCBuffer(OutBuffer *buf, StorageClass stc) for (int i = 0; i < sizeof(table)/sizeof(table[0]); i++) { - if (stc & table[i].stc) + StorageClass tbl = table[i].stc; + assert(tbl & STCStorageClass); + if (stc & tbl) { + stc &= ~tbl; enum TOK tok = table[i].tok; #if DMDV2 if (tok == TOKat) { - buf->writeByte('@'); - buf->writestring(table[i].id->toChars()); + tmp[0] = '@'; + strcpy(tmp + 1, table[i].id->toChars()); + return tmp; } else #endif - buf->writestring(Token::toChars(tok)); - buf->writeByte(' '); + return Token::toChars(tok); } } + //printf("stc = %llx\n", (unsigned long long)stc); + return NULL; +} + +void StorageClassDeclaration::stcToCBuffer(OutBuffer *buf, StorageClass stc) +{ + while (stc) + { char tmp[20]; + const char *p = stcToChars(tmp, stc); + if (!p) + break; + assert(strlen(p) < sizeof(tmp)); + buf->writestring(p); + buf->writeByte(' '); + } } void StorageClassDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) @@ -916,7 +937,9 @@ void AnonDeclaration::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset void AnonDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->printf(isunion ? "union" : "struct"); - buf->writestring("\n{\n"); + buf->writenl(); + buf->writestring("{"); + buf->writenl(); buf->level++; if (decl) { @@ -927,7 +950,8 @@ void AnonDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) } } buf->level--; - buf->writestring("}\n"); + buf->writestring("}"); + buf->writenl(); } const char *AnonDeclaration::kind() @@ -958,37 +982,6 @@ Dsymbol *PragmaDeclaration::syntaxCopy(Dsymbol *s) void PragmaDeclaration::setScope(Scope *sc) { -#if TARGET_NET - if (ident == Lexer::idPool("assembly")) - { - if (!args || args->dim != 1) - { - error("pragma has invalid number of arguments"); - } - else - { - Expression *e = (*args)[0]; - e = e->semantic(sc); - e = resolveProperties(sc, e); - e = e->ctfeInterpret(); - (*args)[0] = e; - StringExp* se = e->toString(); - if (!se) - { - error("string expected, not '%s'", e->toChars()); - } - PragmaScope* pragma = new PragmaScope(this, sc->parent, se); - - assert(sc); - pragma->setScope(sc); - - //add to module members - assert(sc->module); - assert(sc->module->members); - sc->module->members->push(pragma); - } - } -#endif // TARGET_NET } void PragmaDeclaration::semantic(Scope *sc) @@ -1113,11 +1106,6 @@ void PragmaDeclaration::semantic(Scope *sc) goto Lnodecl; } #endif -#if TARGET_NET - else if (ident == Lexer::idPool("assembly")) - { - } -#endif // TARGET_NET #if IN_LLVM else if ((llvm_internal = DtoGetPragma(sc, this, arg1str)) != LLVMnone) { diff --git a/dmd2/attrib.h b/dmd2/attrib.h index b40f06c7..42ca18ae 100644 --- a/dmd2/attrib.h +++ b/dmd2/attrib.h @@ -55,7 +55,7 @@ struct AttribDeclaration : Dsymbol void checkCtorConstInit(); void addLocalClass(ClassDeclarations *); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toJsonBuffer(OutBuffer *buf); + void toJson(JsonOut *json); AttribDeclaration *isAttribDeclaration() { return this; } #if IN_DMD @@ -78,6 +78,7 @@ struct StorageClassDeclaration : AttribDeclaration int oneMember(Dsymbol **ps, Identifier *ident); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + static const char *stcToChars(char tmp[], StorageClass& stc); static void stcToCBuffer(OutBuffer *buf, StorageClass stc); }; @@ -176,7 +177,7 @@ struct ConditionalDeclaration : AttribDeclaration Dsymbols *include(Scope *sc, ScopeDsymbol *s); void addComment(unsigned char *comment); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toJsonBuffer(OutBuffer *buf); + void toJson(JsonOut *json); void importAll(Scope *sc); void setScope(Scope *sc); }; diff --git a/dmd2/cast.c b/dmd2/cast.c index 4744ea74..f0018dc0 100644 --- a/dmd2/cast.c +++ b/dmd2/cast.c @@ -1992,18 +1992,10 @@ Expression *CondExp::inferType(Type *t, int flag, TemplateParameters *tparams) Expression *BinExp::scaleFactor(Scope *sc) { - if (sc->func && !sc->intypeof) - { - if (sc->func->setUnsafe()) - { - error("pointer arithmetic not allowed in @safe functions"); - return new ErrorExp(); - } - } - d_uns64 stride; Type *t1b = e1->type->toBasetype(); Type *t2b = e2->type->toBasetype(); + Expression *eoff; if (t1b->ty == Tpointer && t2b->isintegral()) { // Need to adjust operator by the stride @@ -2017,6 +2009,7 @@ Expression *BinExp::scaleFactor(Scope *sc) #if !IN_LLVM e2 = new MulExp(loc, e2, new IntegerExp(0, stride, t)); #endif + eoff = e2; e2->type = t; type = e1->type; } @@ -2034,11 +2027,27 @@ Expression *BinExp::scaleFactor(Scope *sc) #if !IN_LLVM e = new MulExp(loc, e, new IntegerExp(0, stride, t)); #endif + eoff = e; e->type = t; type = e2->type; e1 = e2; e2 = e; } + else + assert(0); + + if (sc->func && !sc->intypeof) + { + eoff = eoff->optimize(WANTvalue); + if (eoff->op == TOKint64 && eoff->toInteger() == 0) + ; + else if (sc->func->setUnsafe()) + { + error("pointer arithmetic not allowed in @safe functions"); + return new ErrorExp(); + } + } + return this; } @@ -2088,9 +2097,11 @@ int typeMerge(Scope *sc, Expression *e, Type **pt, Expression **pe1, Expression MATCH m; Expression *e1 = *pe1; Expression *e2 = *pe2; + Type *t1b = e1->type->toBasetype(); + Type *t2b = e2->type->toBasetype(); if (e->op != TOKquestion || - e1->type->toBasetype()->ty != e2->type->toBasetype()->ty) + t1b->ty != t2b->ty && (t1b->isTypeBasic() && t2b->isTypeBasic())) { e1 = e1->integralPromotions(sc); e2 = e2->integralPromotions(sc); @@ -2109,8 +2120,8 @@ int typeMerge(Scope *sc, Expression *e, Type **pt, Expression **pe1, Expression assert(t2); Lagain: - Type *t1b = t1->toBasetype(); - Type *t2b = t2->toBasetype(); + t1b = t1->toBasetype(); + t2b = t2->toBasetype(); TY ty = (TY)Type::impcnvResult[t1b->ty][t2b->ty]; if (ty != Terror) @@ -2199,11 +2210,12 @@ Lagain: if (t1->ty == Tdelegate) { tx = new TypeDelegate(d); - tx = tx->merge(); } else tx = d->pointerTo(); + tx = tx->semantic(e1->loc, sc); + if (t1->implicitConvTo(tx) && t2->implicitConvTo(tx)) { t = tx; @@ -2534,6 +2546,13 @@ Lcc: } else if (t1->isintegral() && t2->isintegral()) { + if (t1->ty != t2->ty) + { + e1 = e1->integralPromotions(sc); + e2 = e2->integralPromotions(sc); + t1 = e1->type; t1b = t1->toBasetype(); + t2 = e2->type; t2b = t2->toBasetype(); + } assert(t1->ty == t2->ty); if (!t1->isImmutable() && !t2->isImmutable() && t1->isShared() != t2->isShared()) goto Lincompatible; diff --git a/dmd2/class.c b/dmd2/class.c index 55cbb050..1621b43c 100644 --- a/dmd2/class.c +++ b/dmd2/class.c @@ -609,14 +609,17 @@ void ClassDeclaration::semantic(Scope *sc) if (isCOMclass()) { -#if _WIN32 - sc->linkage = LINKwindows; +#if IN_LLVM + if (global.params.targetTriple.isOSWindows()) #else - /* This enables us to use COM objects under Linux and - * work with things like XPCOM - */ - sc->linkage = LINKc; + if (global.params.isWindows) #endif + sc->linkage = LINKwindows; + else + /* This enables us to use COM objects under Linux and + * work with things like XPCOM + */ + sc->linkage = LINKc; } sc->protection = PROTpublic; sc->explicitProtection = 0; @@ -794,27 +797,11 @@ void ClassDeclaration::semantic(Scope *sc) dtor = buildDtor(sc); if (Dsymbol *assign = search_function(this, Id::assign)) { - Expression *e = new NullExp(loc, type); // dummy rvalue - Expressions *arguments = new Expressions(); - arguments->push(e); - - // check identity opAssign exists - FuncDeclaration *fd = assign->isFuncDeclaration(); - if (fd) - { fd = fd->overloadResolve(loc, e, arguments, 1); - if (fd && !(fd->storage_class & STCdisable)) - goto Lassignerr; + if (FuncDeclaration *f = hasIdentityOpAssign(sc, assign)) + { + if (!(f->storage_class & STCdisable)) + error("identity assignment operator overload is illegal"); } - - if (TemplateDeclaration *td = assign->isTemplateDeclaration()) - { fd = td->deduceFunctionTemplate(sc, loc, NULL, e, arguments, 1+2); - if (fd && !(fd->storage_class & STCdisable)) - goto Lassignerr; - } - -Lassignerr: - if (fd && !(fd->storage_class & STCdisable)) - error("identity assignment operator overload is illegal"); } sc->pop(); @@ -1664,6 +1651,7 @@ int BaseClass::fillVtbl(ClassDeclaration *cd, FuncDeclarations *vtbl, int newins assert(ifd); // Find corresponding function in this class tf = (ifd->type->ty == Tfunction) ? (TypeFunction *)(ifd->type) : NULL; + assert(tf); // should always be non-null fd = cd->findFunc(ifd->ident, tf); if (fd && !fd->isAbstract()) { @@ -1687,8 +1675,10 @@ int BaseClass::fillVtbl(ClassDeclaration *cd, FuncDeclarations *vtbl, int newins //printf(" not found\n"); // BUG: should mark this class as abstract? if (!cd->isAbstract()) - cd->error("interface function %s.%s isn't implemented", - id->toChars(), ifd->ident->toChars()); + cd->error("interface function %s.%s%s isn't implemented", + id->toChars(), ifd->ident->toChars(), + Parameter::argsTypesToChars(tf->parameters, tf->varargs)); + fd = NULL; } if (vtbl) diff --git a/dmd2/clone.c b/dmd2/clone.c index 37fa2a13..c0a0b97a 100644 --- a/dmd2/clone.c +++ b/dmd2/clone.c @@ -24,6 +24,62 @@ #include "template.h" +/******************************************* + * Check given opAssign symbol is really identity opAssign or not. + */ + +FuncDeclaration *AggregateDeclaration::hasIdentityOpAssign(Scope *sc, Dsymbol *assign) +{ + if (assign) + { + assert(assign->ident == Id::assign); + + /* check identity opAssign exists + */ + Expression *er = new NullExp(loc, type); // dummy rvalue + Expression *el = new IdentifierExp(loc, Id::p); // dummy lvalue + el->type = type; + Expressions ar; ar.push(er); + Expressions al; al.push(el); + FuncDeclaration *f = NULL; + if (FuncDeclaration *fd = assign->isFuncDeclaration()) + { + f = fd->overloadResolve(loc, er, &ar, 1); + if (!f) f = fd->overloadResolve(loc, er, &al, 1); + } + if (TemplateDeclaration *td = assign->isTemplateDeclaration()) + { + unsigned errors = global.startGagging(); // Do not report errors, even if the + unsigned oldspec = global.speculativeGag; // template opAssign fbody makes it. + global.speculativeGag = global.gag; + Scope *sc2 = sc->push(); + sc2->speculative = true; + + f = td->deduceFunctionTemplate(sc2, loc, NULL, er, &ar, 1); + if (!f) f = td->deduceFunctionTemplate(sc2, loc, NULL, er, &al, 1); + + sc2->pop(); + global.speculativeGag = oldspec; + global.endGagging(errors); + } + if (f) + { + int varargs; + Parameters *fparams = f->getParameters(&varargs); + if (fparams->dim >= 1) + { + Parameter *arg0 = Parameter::getNth(fparams, 0); + if (arg0->type->toDsymbol(NULL) != this) + f = NULL; + } + } + // BUGS: This detection mechanism cannot find some opAssign-s like follows: + // struct S { void opAssign(ref immutable S) const; } + return f; + } + return NULL; +} + /******************************************* * We need an opAssign for the struct if * it has a destructor or a postblit. @@ -90,27 +146,8 @@ FuncDeclaration *StructDeclaration::buildOpAssign(Scope *sc) Dsymbol *assign = search_function(this, Id::assign); if (assign) { - /* check identity opAssign exists - */ - Expression *er = new NullExp(loc, type); // dummy rvalue - Expression *el = new IdentifierExp(loc, Id::p); // dummy lvalue - el->type = type; - Expressions ar; ar.push(er); - Expressions al; al.push(el); - if (FuncDeclaration *fd = assign->isFuncDeclaration()) - { - FuncDeclaration *f = fd->overloadResolve(loc, er, &ar, 1); - if (f == NULL) f = fd->overloadResolve(loc, er, &al, 1); - if (f) - return (f->storage_class & STCdisable) ? NULL : f; - } - if (TemplateDeclaration *td = assign->isTemplateDeclaration()) - { - FuncDeclaration *f = td->deduceFunctionTemplate(sc, loc, NULL, er, &ar, 1); - if (f == NULL) f = td->deduceFunctionTemplate(sc, loc, NULL, er, &al, 1); - if (f) - return (f->storage_class & STCdisable) ? NULL : f; - } + if (FuncDeclaration *f = hasIdentityOpAssign(sc, assign)) + return f; // Even if non-identity opAssign is defined, built-in identity opAssign // will be defined. (Is this an exception of operator overloading rule?) } @@ -123,9 +160,7 @@ FuncDeclaration *StructDeclaration::buildOpAssign(Scope *sc) Parameters *fparams = new Parameters; fparams->push(new Parameter(STCnodtor, type, Id::p, NULL)); Type *ftype = new TypeFunction(fparams, handle, FALSE, LINKd); -#if STRUCTTHISREF ((TypeFunction *)ftype)->isref = 1; -#endif FuncDeclaration *fop = new FuncDeclaration(loc, 0, Id::assign, STCundefined, ftype); @@ -146,21 +181,13 @@ FuncDeclaration *StructDeclaration::buildOpAssign(Scope *sc) e = new DeclarationExp(0, tmp); ec = new AssignExp(0, new VarExp(0, tmp), -#if STRUCTTHISREF new ThisExp(0) -#else - new PtrExp(0, new ThisExp(0)) -#endif ); ec->op = TOKblit; e = Expression::combine(e, ec); } ec = new AssignExp(0, -#if STRUCTTHISREF new ThisExp(0), -#else - new PtrExp(0, new ThisExp(0)), -#endif new IdentifierExp(0, Id::p)); ec->op = TOKblit; e = Expression::combine(e, ec); @@ -213,14 +240,29 @@ FuncDeclaration *StructDeclaration::buildOpAssign(Scope *sc) } members->push(s); s->addMember(sc, this, 1); + this->hasIdentityAssign = 1; // temporary mark identity assignable - sc = sc->push(); - sc->stc = 0; - sc->linkage = LINKd; - s->semantic(sc); - sc->pop(); + unsigned errors = global.startGagging(); // Do not report errors, even if the + unsigned oldspec = global.speculativeGag; // template opAssign fbody makes it. + global.speculativeGag = global.gag; + Scope *sc2 = sc->push(); + sc2->stc = 0; + sc2->linkage = LINKd; + sc2->speculative = true; - //printf("-StructDeclaration::buildOpAssign() %s\n", toChars()); + s->semantic(sc2); + s->semantic2(sc2); + s->semantic3(sc2); + + sc2->pop(); + global.speculativeGag = oldspec; + if (global.endGagging(errors)) // if errors happened + { // Disable generated opAssign, because some members forbid identity assignment. + fop->storage_class |= STCdisable; + fop->fbody = NULL; // remove fbody which contains the error + } + + //printf("-StructDeclaration::buildOpAssign() %s %s, errors = %d\n", toChars(), s->kind(), (fop->storage_class & STCdisable) != 0); return fop; } @@ -410,20 +452,20 @@ FuncDeclaration *StructDeclaration::buildXopEquals(Scope *sc) size_t index = members->dim; members->push(fop); - sc = sc->push(); - sc->stc = 0; - sc->linkage = LINKd; + unsigned errors = global.startGagging(); // Do not report errors, even if the + unsigned oldspec = global.speculativeGag; // template opAssign fbody makes it. + global.speculativeGag = global.gag; + Scope *sc2 = sc->push(); + sc2->stc = 0; + sc2->linkage = LINKd; + sc2->speculative = true; - unsigned errors = global.startGagging(); - fop->semantic(sc); - if (errors == global.gaggedErrors) - { fop->semantic2(sc); - if (errors == global.gaggedErrors) - { fop->semantic3(sc); - if (errors == global.gaggedErrors) - fop->addMember(sc, this, 1); - } - } + fop->semantic(sc2); + fop->semantic2(sc2); + fop->semantic3(sc2); + + sc2->pop(); + global.speculativeGag = oldspec; if (global.endGagging(errors)) // if errors happened { members->remove(index); @@ -441,8 +483,8 @@ FuncDeclaration *StructDeclaration::buildXopEquals(Scope *sc) } fop = xerreq; } - - sc->pop(); + else + fop->addMember(sc, this, 1); return fop; } @@ -492,9 +534,6 @@ FuncDeclaration *StructDeclaration::buildCpCtor(Scope *sc) { // Build *this = p; Expression *e = new ThisExp(0); -#if !STRUCTTHISREF - e = new PtrExp(0, e); -#endif AssignExp *ea = new AssignExp(0, new PtrExp(0, new CastExp(0, new AddrExp(0, e), type->mutableOf()->pointerTo())), new PtrExp(0, new CastExp(0, new AddrExp(0, new IdentifierExp(0, Id::p)), type->mutableOf()->pointerTo())) @@ -504,9 +543,6 @@ FuncDeclaration *StructDeclaration::buildCpCtor(Scope *sc) // Build postBlit(); e = new ThisExp(0); -#if !STRUCTTHISREF - e = new PtrExp(0, e); -#endif e = new PtrExp(0, new CastExp(0, new AddrExp(0, e), type->mutableOf()->pointerTo())); e = new DotVarExp(0, e, postblit, 0); e = new CallExp(0, e); diff --git a/dmd2/cppmangle.c b/dmd2/cppmangle.c index 48e37094..78750549 100644 --- a/dmd2/cppmangle.c +++ b/dmd2/cppmangle.c @@ -160,10 +160,10 @@ char *cpp_mangle(Dsymbol *s) cms.components.setDim(0); OutBuffer buf; -#if TARGET_OSX - buf.writestring("__Z"); +#if IN_LLVM + buf.writestring("__Z" + !(global.params.targetTriple.isMacOSX())); // "_Z" for OSX #else - buf.writestring("_Z"); + buf.writestring("__Z" + !global.params.isOSX); // "_Z" for OSX #endif cpp_mangle_name(&buf, &cms, s); diff --git a/dmd2/ctfeexpr.c b/dmd2/ctfeexpr.c index b9f95356..e56a35da 100644 --- a/dmd2/ctfeexpr.c +++ b/dmd2/ctfeexpr.c @@ -1575,7 +1575,7 @@ Expression *ctfeIndex(Loc loc, Type *type, Expression *e1, uinteger_t indx) { StringExp *es1 = (StringExp *)e1; if (indx >= es1->len) { - error(loc, "string index %ju is out of bounds [0 .. %zu]", indx, es1->len); + error(loc, "string index %llu is out of bounds [0 .. %llu]", indx, (ulonglong)es1->len); return EXP_CANT_INTERPRET; } else @@ -1585,7 +1585,7 @@ Expression *ctfeIndex(Loc loc, Type *type, Expression *e1, uinteger_t indx) ArrayLiteralExp *ale = (ArrayLiteralExp *)e1; if (indx >= ale->elements->dim) { - error(loc, "array index %ju is out of bounds %s[0 .. %u]", indx, e1->toChars(), ale->elements->dim); + error(loc, "array index %llu is out of bounds %s[0 .. %llu]", indx, e1->toChars(), (ulonglong)ale->elements->dim); return EXP_CANT_INTERPRET; } Expression *e = ale->elements->tdata()[indx]; diff --git a/dmd2/declaration.c b/dmd2/declaration.c index ac7f65fa..b44307b2 100644 --- a/dmd2/declaration.c +++ b/dmd2/declaration.c @@ -19,6 +19,7 @@ #include "scope.h" #include "aggregate.h" #include "module.h" +#include "import.h" #include "id.h" #include "expression.h" #include "statement.h" @@ -130,26 +131,30 @@ enum PROT Declaration::prot() #if DMDV2 -int Declaration::checkModify(Loc loc, Scope *sc, Type *t) +int Declaration::checkModify(Loc loc, Scope *sc, Type *t, Expression *e1, int flag) { + VarDeclaration *v = isVarDeclaration(); + if (v && v->canassign) + return 2; + if ((sc->flags & SCOPEcontract) && isParameter()) - error(loc, "cannot modify parameter '%s' in contract", toChars()); - - if ((sc->flags & SCOPEcontract) && isResult()) - error(loc, "cannot modify result '%s' in contract", toChars()); - - if (isCtorinit() && !t->isMutable() || - (storage_class & STCnodefaultctor)) - { // It's only modifiable if inside the right constructor - return modifyFieldVar(loc, sc, isVarDeclaration(), NULL); - } - else { - VarDeclaration *v = isVarDeclaration(); - if (v && v->canassign) - return TRUE; + if (!flag) error(loc, "cannot modify parameter '%s' in contract", toChars()); + return 0; } - return FALSE; + if ((sc->flags & SCOPEcontract) && isResult()) + { + if (!flag) error(loc, "cannot modify result '%s' in contract", toChars()); + return 0; + } + + if (v && isCtorinit()) + { // It's only modifiable if inside the right constructor + if ((storage_class & (STCforeach | STCref)) == (STCforeach | STCref)) + return 2; + return modifyFieldVar(loc, sc, v, e1) ? 2 : 1; + } + return 1; } #endif @@ -431,6 +436,7 @@ AliasDeclaration::AliasDeclaration(Loc loc, Identifier *id, Type *type) this->loc = loc; this->type = type; this->aliassym = NULL; + this->import = NULL; this->htype = NULL; this->haliassym = NULL; this->overnext = NULL; @@ -447,6 +453,7 @@ AliasDeclaration::AliasDeclaration(Loc loc, Identifier *id, Dsymbol *s) this->loc = loc; this->type = NULL; this->aliassym = s; + this->import = NULL; this->htype = NULL; this->haliassym = NULL; this->overnext = NULL; @@ -694,6 +701,13 @@ Dsymbol *AliasDeclaration::toAlias() } else if (aliassym || type->deco) ; // semantic is already done. + else if (import) + { + /* If this is an internal alias for selective import, + * resolve it under the correct scope. + */ + import->semantic(NULL); + } else if (scope) semantic(scope); Dsymbol *s = aliassym ? aliassym->toAlias() : this; @@ -1126,6 +1140,7 @@ Lnomatch: (*exps)[i] = e; } TupleDeclaration *v2 = new TupleDeclaration(loc, ident, exps); + v2->parent = this->parent; v2->isexp = 1; aliassym = v2; return; @@ -2065,6 +2080,10 @@ Expression *VarDeclaration::getConstInitializer() ExpInitializer *ei = getExpInitializer(); if (ei) return ei->exp; + else if (init) + { + return init->toExpression(); + } } return NULL; diff --git a/dmd2/declaration.h b/dmd2/declaration.h index ee488b2d..3e0d21dd 100644 --- a/dmd2/declaration.h +++ b/dmd2/declaration.h @@ -104,6 +104,12 @@ enum PURE; #define STCtemp 0x10000000000LL // temporary variable introduced by inlining // and used only in backend process, so it's rvalue +#define STCStorageClass (STCauto | STCscope | STCstatic | STCextern | STCconst | STCfinal | \ + STCabstract | STCsynchronized | STCdeprecated | STCoverride | STClazy | STCalias | \ + STCout | STCin | \ + STCmanifest | STCimmutable | STCshared | STCnothrow | STCpure | STCref | STCtls | \ + STCgshared | STCproperty | STCsafe | STCtrusted | STCsystem | STCdisable) + #ifdef BUG6652 #define STCbug6652 0x800000000000LL // #endif @@ -152,15 +158,16 @@ struct Declaration : Dsymbol void semantic(Scope *sc); const char *kind(); unsigned size(Loc loc); - int checkModify(Loc loc, Scope *sc, Type *t); + int checkModify(Loc loc, Scope *sc, Type *t, Expression *e1, int flag); Dsymbol *search(Loc loc, Identifier *ident, int flags); void emitComment(Scope *sc); - void toJsonBuffer(OutBuffer *buf); + void toJson(JsonOut *json); + void jsonProperties(JsonOut *json); void toDocBuffer(OutBuffer *buf, Scope *sc); - char *mangle(); + char *mangle(bool isv = false); int isStatic() { return storage_class & STCstatic; } virtual int isDelete(); virtual int isDataseg(); @@ -229,10 +236,11 @@ struct TypedefDeclaration : Declaration Dsymbol *syntaxCopy(Dsymbol *); void semantic(Scope *sc); void semantic2(Scope *sc); - char *mangle(); + char *mangle(bool isv = false); const char *kind(); Type *getType(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void toJson(JsonOut *json); Type *htype; Type *hbasetype; @@ -263,6 +271,7 @@ struct AliasDeclaration : Declaration { Dsymbol *aliassym; Dsymbol *overnext; // next in overload list + Dsymbol *import; // !=NULL if unresolved internal alias for selective import int inSemantic; PROT importprot; // if generated by import, store its protection @@ -327,6 +336,7 @@ struct VarDeclaration : Declaration void semantic2(Scope *sc); const char *kind(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void toJson(JsonOut *json); Type *htype; Initializer *hinit; AggregateDeclaration *isThis(); @@ -405,7 +415,7 @@ struct ClassInfoDeclaration : VarDeclaration void semantic(Scope *sc); void emitComment(Scope *sc); - void toJsonBuffer(OutBuffer *buf); + void toJson(JsonOut *json); #if IN_DMD Symbol *toSymbol(); @@ -423,7 +433,7 @@ struct ModuleInfoDeclaration : VarDeclaration void semantic(Scope *sc); void emitComment(Scope *sc); - void toJsonBuffer(OutBuffer *buf); + void toJson(JsonOut *json); #if IN_DMD Symbol *toSymbol(); @@ -439,7 +449,7 @@ struct TypeInfoDeclaration : VarDeclaration void semantic(Scope *sc); void emitComment(Scope *sc); - void toJsonBuffer(OutBuffer *buf); + void toJson(JsonOut *json); #if IN_DMD void toObjFile(int multiobj); // compile to .obj file @@ -812,6 +822,8 @@ struct FuncDeclaration : Declaration VarDeclarations closureVars; // local variables in this function // which are referenced by nested // functions + FuncDeclarations siblingCallers; // Sibling nested functions which + // called this one FuncDeclarations deferred; // toObjFile() these functions after this one unsigned flags; @@ -827,13 +839,15 @@ struct FuncDeclaration : Declaration void semantic(Scope *sc); void semantic2(Scope *sc); void semantic3(Scope *sc); + bool functionSemantic(); + bool functionSemantic3(); // called from semantic3 - void varArgs(Scope *sc, TypeFunction*, VarDeclaration *&, VarDeclaration *&); VarDeclaration *declareThis(Scope *sc, AggregateDeclaration *ad); int equals(Object *o); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); void bodyToCBuffer(OutBuffer *buf, HdrGenState *hgs); + void toJson(JsonOut *json); int overrides(FuncDeclaration *fd); int findVtblIndex(Dsymbols *vtbl, int dim); int overloadInsert(Dsymbol *s); @@ -846,7 +860,7 @@ struct FuncDeclaration : Declaration int getLevel(Loc loc, Scope *sc, FuncDeclaration *fd); // lexical nesting level difference void appendExp(Expression *e); void appendState(Statement *s); - char *mangle(); + char *mangle(bool isv = false); const char *toPrettyChars(); int isMain(); int isWinMain(); @@ -956,7 +970,7 @@ struct FuncAliasDeclaration : FuncDeclaration #if IN_DMD Symbol *toSymbol(); #endif - char *mangle() { return toAliasFunc()->mangle(); } + char *mangle(bool isv = false) { return toAliasFunc()->mangle(isv); } FuncDeclaration *toAliasFunc(); }; @@ -1009,12 +1023,12 @@ struct PostBlitDeclaration : FuncDeclaration Dsymbol *syntaxCopy(Dsymbol *); void semantic(Scope *sc); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void toJson(JsonOut *json); int isVirtual(); int addPreInvariant(); int addPostInvariant(); int overloadInsert(Dsymbol *s); void emitComment(Scope *sc); - void toJsonBuffer(OutBuffer *buf); PostBlitDeclaration *isPostBlitDeclaration() { return this; } }; @@ -1034,7 +1048,6 @@ struct DtorDeclaration : FuncDeclaration int addPostInvariant(); int overloadInsert(Dsymbol *s); void emitComment(Scope *sc); - void toJsonBuffer(OutBuffer *buf); DtorDeclaration *isDtorDeclaration() { return this; } }; @@ -1051,7 +1064,6 @@ struct StaticCtorDeclaration : FuncDeclaration int addPostInvariant(); bool hasStaticCtorOrDtor(); void emitComment(Scope *sc); - void toJsonBuffer(OutBuffer *buf); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); StaticCtorDeclaration *isStaticCtorDeclaration() { return this; } @@ -1081,7 +1093,6 @@ struct StaticDtorDeclaration : FuncDeclaration int addPreInvariant(); int addPostInvariant(); void emitComment(Scope *sc); - void toJsonBuffer(OutBuffer *buf); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); StaticDtorDeclaration *isStaticDtorDeclaration() { return this; } @@ -1107,7 +1118,6 @@ struct InvariantDeclaration : FuncDeclaration int addPreInvariant(); int addPostInvariant(); void emitComment(Scope *sc); - void toJsonBuffer(OutBuffer *buf); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); InvariantDeclaration *isInvariantDeclaration() { return this; } @@ -1123,7 +1133,6 @@ struct UnitTestDeclaration : FuncDeclaration int addPreInvariant(); int addPostInvariant(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toJsonBuffer(OutBuffer *buf); UnitTestDeclaration *isUnitTestDeclaration() { return this; } }; diff --git a/dmd2/delegatize.c b/dmd2/delegatize.c index b6014892..3c9670f5 100644 --- a/dmd2/delegatize.c +++ b/dmd2/delegatize.c @@ -41,6 +41,7 @@ Expression *Expression::toDelegate(Scope *sc, Type *t) Type *tw = t->semantic(loc, sc); Type *tc = t->substWildTo(MODconst)->semantic(loc, sc); TypeFunction *tf = new TypeFunction(NULL, tc, 0, LINKd); + if (tw != tc) tf->mod = MODwild; // hack for bug7757 (tf = (TypeFunction *)tf->semantic(loc, sc))->next = tw; // hack for bug7757 FuncLiteralDeclaration *fld = new FuncLiteralDeclaration(loc, loc, tf, TOKdelegate, NULL); diff --git a/dmd2/doc.c b/dmd2/doc.c index 4b566155..4ac4bc85 100644 --- a/dmd2/doc.c +++ b/dmd2/doc.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars +// Copyright (c) 1999-2013 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -18,10 +18,7 @@ #include "rmem.h" #include "root.h" - -#if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun -#include "gnuc.h" -#endif +#include "port.h" #include "mars.h" #include "dsymbol.h" @@ -30,6 +27,7 @@ #include "lexer.h" #include "aggregate.h" #include "declaration.h" +#include "statement.h" #include "enum.h" #include "id.h" #include "module.h" @@ -43,7 +41,7 @@ struct Escape { const char *strings[256]; - static const char *escapeChar(unsigned c); + const char *escapeChar(unsigned c); }; struct Section @@ -117,7 +115,7 @@ DDOC = \n\ \n\

$(TITLE)

\n\ $(BODY)\n\ -
$(SMALL Page generated by $(LINK2 http://www.digitalmars.com/d/2.0/ddoc.html, Ddoc). $(COPYRIGHT))\n\ +
$(SMALL Page generated by $(LINK2 http://dlang.org/ddoc.html, Ddoc). $(COPYRIGHT))\n\ \n\ \n\ B = $0\n\ @@ -290,7 +288,7 @@ void Module::gendocfile() dc->macros->write(dc, sc, this, sc->docbuf); } sc->docbuf->write(comment, commentlen); - highlightText(NULL, this, sc->docbuf, 0); + highlightText(sc, this, sc->docbuf, 0); } else { @@ -341,10 +339,7 @@ void Module::gendocfile() 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); + FileName::ensurePathToNameExists(docfile->toChars()); docfile->writev(); #else /* Remove all the escape sequences from buf2 @@ -367,10 +362,7 @@ void Module::gendocfile() // 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); + FileName::ensurePathToNameExists(docfile->toChars()); docfile->writev(); #endif } @@ -515,6 +507,34 @@ void Dsymbol::emitDitto(Scope *sc) sc->lastoffset += b.offset; } +void emitUnittestComment(Scope *sc, Dsymbol *s, UnitTestDeclaration *test) +{ + static char pre[] = "$(D_CODE \n"; + OutBuffer *buf = sc->docbuf; + + buf->writestring("$(DDOC_SECTION "); + buf->writestring("$(B Example:)"); + for (UnitTestDeclaration *utd = test; utd; utd = utd->unittest) + { + if (utd->protection == PROTprivate || !utd->comment || !utd->fbody) + continue; + + OutBuffer codebuf; + const char *body = utd->fbody->toChars(); + if (strlen(body)) + { + codebuf.writestring(pre); + codebuf.writestring(body); + codebuf.writestring(")"); + codebuf.writeByte(0); + highlightCode2(sc, s, &codebuf, 0); + buf->writestring(codebuf.toChars()); + } + } + + buf->writestring(")"); +} + void ScopeDsymbol::emitMemberComments(Scope *sc) { //printf("ScopeDsymbol::emitMemberComments() %s\n", toChars()); @@ -989,7 +1009,7 @@ void FuncDeclaration::toDocBuffer(OutBuffer *buf, Scope *sc) declarationToDocBuffer(this, buf, td); - highlightCode(NULL, this, buf, o); + highlightCode(sc, this, buf, o); } else { @@ -1037,7 +1057,7 @@ void StructDeclaration::toDocBuffer(OutBuffer *buf, Scope *sc) td->onemember == this) { size_t o = buf->offset; td->toDocBuffer(buf, sc); - highlightCode(NULL, this, buf, o); + highlightCode(sc, this, buf, o); } else { @@ -1063,7 +1083,7 @@ void ClassDeclaration::toDocBuffer(OutBuffer *buf, Scope *sc) td->onemember == this) { size_t o = buf->offset; td->toDocBuffer(buf, sc); - highlightCode(NULL, this, buf, o); + highlightCode(sc, this, buf, o); } else { @@ -1299,6 +1319,8 @@ void DocComment::writeSections(Scope *sc, Dsymbol *s, OutBuffer *buf) buf->writestring(")\n"); } } + if (s->unittest) + emitUnittestComment(sc, s, s->unittest); buf->writestring(")\n"); } else @@ -1618,8 +1640,10 @@ void DocComment::parseEscapes(Escape **pescapetable, unsigned char *textstart, s if (!escapetable) { escapetable = new Escape; + memset(escapetable, 0, sizeof(Escape)); *pescapetable = escapetable; } + //printf("parseEscapes('%.*s') pescapetable = %p\n", textlen, textstart, pescapetable); unsigned char *p = textstart; unsigned char *pend = p + textlen; @@ -1650,7 +1674,7 @@ void DocComment::parseEscapes(Escape **pescapetable, unsigned char *textstart, s char *s = (char *)memcpy(mem.malloc(len + 1), start, len); s[len] = 0; escapetable->strings[c] = s; - //printf("%c = '%s'\n", c, s); + //printf("\t%c = '%s'\n", c, s); p++; } } @@ -1676,7 +1700,7 @@ int icmp(const char *stringz, void *s, size_t slen) if (len1 != slen) return len1 - slen; - return memicmp(stringz, (char *)s, slen); + return Port::memicmp(stringz, (char *)s, slen); } /***************************************** @@ -1689,7 +1713,7 @@ int isDitto(unsigned char *comment) { unsigned char *p = skipwhitespace(comment); - if (memicmp((char *)p, "ditto", 5) == 0 && *skipwhitespace(p + 5) == 0) + if (Port::memicmp((char *)p, "ditto", 5) == 0 && *skipwhitespace(p + 5) == 0) return 1; } return 0; @@ -1787,11 +1811,11 @@ size_t skippastURL(OutBuffer *buf, size_t i) size_t j; unsigned sawdot = 0; - if (length > 7 && memicmp((char *)p, "http://", 7) == 0) + if (length > 7 && Port::memicmp((char *)p, "http://", 7) == 0) { j = 7; } - else if (length > 8 && memicmp((char *)p, "https://", 8) == 0) + else if (length > 8 && Port::memicmp((char *)p, "https://", 8) == 0) { j = 8; } @@ -1901,7 +1925,8 @@ void highlightText(Scope *sc, Dsymbol *s, OutBuffer *buf, size_t offset) break; case '\n': - if (sc && !inCode && i == iLineStart && i + 1 < buf->offset) // if "\n\n" + if (!sc->module->isDocFile && + !inCode && i == iLineStart && i + 1 < buf->offset) // if "\n\n" { static char blankline[] = "$(DDOC_BLANKLINE)\n"; @@ -1916,48 +1941,53 @@ void highlightText(Scope *sc, Dsymbol *s, OutBuffer *buf, size_t offset) if (inCode) break; p = &buf->data[i]; + se = sc->module->escapetable->escapeChar('<'); - // Skip over comments - if (p[1] == '!' && p[2] == '-' && p[3] == '-') - { size_t j = i + 4; - p += 4; - while (1) + if (se && strcmp(se, "<") == 0) + { + // Generating HTML + // Skip over comments + if (p[1] == '!' && p[2] == '-' && p[3] == '-') { - if (j == buf->offset) - goto L1; - if (p[0] == '-' && p[1] == '-' && p[2] == '>') + size_t j = i + 4; + p += 4; + while (1) { - i = j + 2; // place on closing '>' - break; + if (j == buf->offset) + goto L1; + if (p[0] == '-' && p[1] == '-' && p[2] == '>') + { + i = j + 2; // place on closing '>' + break; + } + j++; + p++; } - j++; - p++; + break; } - break; - } - // Skip over HTML tag - if (isalpha(p[1]) || (p[1] == '/' && isalpha(p[2]))) - { size_t j = i + 2; - p += 2; - while (1) + // Skip over HTML tag + if (isalpha(p[1]) || (p[1] == '/' && isalpha(p[2]))) { - if (j == buf->offset) - goto L1; - if (p[0] == '>') + size_t j = i + 2; + p += 2; + while (1) { - i = j; // place on closing '>' - break; + if (j == buf->offset) + break; + if (p[0] == '>') + { + i = j; // place on closing '>' + break; + } + j++; + p++; } - j++; - p++; + break; } - break; } - L1: // Replace '<' with '<' character entity - se = Escape::escapeChar('<'); if (se) { size_t len = strlen(se); buf->remove(i, 1); @@ -1971,7 +2001,7 @@ void highlightText(Scope *sc, Dsymbol *s, OutBuffer *buf, size_t offset) if (inCode) break; // Replace '>' with '>' character entity - se = Escape::escapeChar('>'); + se = sc->module->escapetable->escapeChar('>'); if (se) { size_t len = strlen(se); buf->remove(i, 1); @@ -1988,7 +2018,7 @@ void highlightText(Scope *sc, Dsymbol *s, OutBuffer *buf, size_t offset) if (p[1] == '#' || isalpha(p[1])) break; // already a character entity // Replace '&' with '&' character entity - se = Escape::escapeChar('&'); + se = sc->module->escapetable->escapeChar('&'); if (se) { size_t len = strlen(se); buf->remove(i, 1); @@ -2073,7 +2103,8 @@ void highlightText(Scope *sc, Dsymbol *s, OutBuffer *buf, size_t offset) default: leadingBlank = 0; - if (sc && !inCode && isIdStart(&buf->data[i])) + if (!sc->module->isDocFile && + !inCode && isIdStart(&buf->data[i])) { size_t j = skippastident(buf, i); if (j > i) @@ -2144,7 +2175,7 @@ void highlightCode(Scope *sc, Dsymbol *s, OutBuffer *buf, size_t offset, bool an { unsigned char c = buf->data[i]; const char *se; - se = Escape::escapeChar(c); + se = sc->module->escapetable->escapeChar(c); if (se) { size_t len = strlen(se); @@ -2180,10 +2211,10 @@ void highlightCode(Scope *sc, Dsymbol *s, OutBuffer *buf, size_t offset, bool an /**************************************** */ -void highlightCode3(OutBuffer *buf, unsigned char *p, unsigned char *pend) +void highlightCode3(Scope *sc, OutBuffer *buf, unsigned char *p, unsigned char *pend) { for (; p < pend; p++) - { const char *s = Escape::escapeChar(*p); + { const char *s = sc->module->escapetable->escapeChar(*p); if (s) buf->writestring(s); else @@ -2212,7 +2243,7 @@ void highlightCode2(Scope *sc, Dsymbol *s, OutBuffer *buf, size_t offset) while (1) { lex.scan(&tok); - highlightCode3(&res, lastp, tok.ptr); + highlightCode3(sc, &res, lastp, tok.ptr); highlight = NULL; switch (tok.value) { @@ -2250,7 +2281,7 @@ void highlightCode2(Scope *sc, Dsymbol *s, OutBuffer *buf, size_t offset) } if (highlight) res.writestring(highlight); - highlightCode3(&res, tok.ptr, lex.p); + highlightCode3(sc, &res, tok.ptr, lex.p); if (highlight) res.writeByte(')'); if (tok.value == TOKeof) @@ -2267,8 +2298,13 @@ void highlightCode2(Scope *sc, Dsymbol *s, OutBuffer *buf, size_t offset) */ const char *Escape::escapeChar(unsigned c) -{ const char *s; - +{ +#if 1 + assert(c < 256); + //printf("escapeChar('%c') => %p, %p\n", c, strings, strings[c]); + return strings[c]; +#else + const char *s; switch (c) { case '<': @@ -2285,6 +2321,7 @@ const char *Escape::escapeChar(unsigned c) break; } return s; +#endif } /**************************************** diff --git a/dmd2/dsymbol.c b/dmd2/dsymbol.c index 87dd10a6..6be7b208 100644 --- a/dmd2/dsymbol.c +++ b/dmd2/dsymbol.c @@ -54,7 +54,7 @@ Dsymbol::Dsymbol() this->scope = NULL; this->errors = false; this->userAttributes = NULL; - + this->unittest = NULL; #if IN_LLVM this->llvmInternal = LLVMnone; #endif @@ -76,7 +76,7 @@ Dsymbol::Dsymbol(Identifier *ident) this->errors = false; this->depmsg = NULL; this->userAttributes = NULL; - + this->unittest = NULL; #if IN_LLVM this->llvmInternal = LLVMnone; #endif @@ -220,16 +220,6 @@ const char *Dsymbol::toPrettyChars() 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; @@ -285,6 +275,7 @@ Dsymbol *Dsymbol::pastMixin() /********************************** * Use this instead of toParent() when looking for the * 'this' pointer of the enclosing function/class. + * This skips over both TemplateInstance's and TemplateMixin's. */ Dsymbol *Dsymbol::toParent2() @@ -1353,6 +1344,9 @@ Dsymbol *ArrayScopeSymbol::search(Loc loc, Identifier *ident, int flags) */ return NULL; + while (ce->op == TOKcomma) + ce = ((CommaExp *)ce)->e2; + /* 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. @@ -1403,6 +1397,29 @@ Dsymbol *ArrayScopeSymbol::search(Loc loc, Identifier *ident, int flags) return NULL; s = s->toAlias(); + if (ce->hasSideEffect()) + { + /* Even if opDollar is needed, 'ce' should be evaluate only once. So + * Rewrite: + * ce.opIndex( ... use of $ ... ) + * ce.opSlice( ... use of $ ... ) + * as: + * (ref __dop = ce, __dop).opIndex( ... __dop.opDollar ...) + * (ref __dop = ce, __dop).opSlice( ... __dop.opDollar ...) + */ + Identifier *id = Lexer::uniqueId("__dop"); + ExpInitializer *ei = new ExpInitializer(loc, ce); + VarDeclaration *v = new VarDeclaration(loc, NULL, id, ei); + v->storage_class |= STCctfe | STCforeach | STCref; + DeclarationExp *de = new DeclarationExp(loc, v); + VarExp *ve = new VarExp(loc, v); + v->semantic(sc); + de->type = ce->type; + ve->type = ce->type; + ((UnaExp *)exp)->e1 = new CommaExp(loc, de, ve); + ce = ve; + } + Expression *e = NULL; // Check for multi-dimensional opDollar(dim) template. if (TemplateDeclaration *td = s->isTemplateDeclaration()) @@ -1411,14 +1428,11 @@ Dsymbol *ArrayScopeSymbol::search(Loc loc, Identifier *ident, int flags) if (exp->op == TOKarray) { dim = ((ArrayExp *)exp)->currentDimension; - e = ((ArrayExp *)exp)->e1; } else if (exp->op == TOKslice) { dim = 0; // slices are currently always one-dimensional - e = ((SliceExp *)exp)->e1; } - assert(e); Objects *tdargs = new Objects(); Expression *edim = new IntegerExp(0, dim, Type::tsize_t); @@ -1428,7 +1442,7 @@ Dsymbol *ArrayScopeSymbol::search(Loc loc, Identifier *ident, int flags) //TemplateInstance *ti = new TemplateInstance(loc, td, tdargs); //ti->semantic(sc); - e = new DotTemplateInstanceExp(loc, e, td->ident, tdargs); + e = new DotTemplateInstanceExp(loc, ce, td->ident, tdargs); } else { /* opDollar exists, but it's not a template. diff --git a/dmd2/dsymbol.h b/dmd2/dsymbol.h index 07506121..c9f28003 100644 --- a/dmd2/dsymbol.h +++ b/dmd2/dsymbol.h @@ -82,14 +82,11 @@ struct DeleteDeclaration; struct HdrGenState; struct OverloadSet; struct AA; -#if TARGET_NET -struct PragmaScope; -#endif +struct JsonOut; #if IN_LLVM struct TypeInfoDeclaration; struct ClassInfoDeclaration; #endif - #ifdef IN_GCC union tree_node; typedef union tree_node TYPE; @@ -153,6 +150,7 @@ struct Dsymbol : Object bool errors; // this symbol failed to pass semantic() char *depmsg; // customized deprecation message Expressions *userAttributes; // user defined attributes from UserAttributeDeclaration + UnitTestDeclaration *unittest; // !=NULL means there's a unittest associated with this symbol Dsymbol(); Dsymbol(Identifier *); @@ -198,7 +196,8 @@ struct Dsymbol : Object virtual void toHBuffer(OutBuffer *buf, HdrGenState *hgs); virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs); virtual void toDocBuffer(OutBuffer *buf, Scope *sc); - virtual void toJsonBuffer(OutBuffer *buf); + virtual void toJson(JsonOut *json); + virtual void jsonProperties(JsonOut *json); virtual unsigned size(Loc loc); virtual int isforwardRef(); virtual void defineRef(Dsymbol *s); @@ -216,7 +215,7 @@ struct Dsymbol : Object 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 char *mangle(bool isv = false); virtual int needThis(); // need a 'this' pointer? virtual enum PROT prot(); virtual Dsymbol *syntaxCopy(Dsymbol *s); // copy only syntax trees @@ -285,12 +284,10 @@ struct Dsymbol : Object virtual StaticStructInitDeclaration *isStaticStructInitDeclaration() { return NULL; } virtual AttribDeclaration *isAttribDeclaration() { return NULL; } virtual OverloadSet *isOverloadSet() { return NULL; } +#if IN_LLVM 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); diff --git a/dmd2/enum.c b/dmd2/enum.c index ecc32504..df01847e 100644 --- a/dmd2/enum.c +++ b/dmd2/enum.c @@ -35,6 +35,9 @@ EnumDeclaration::EnumDeclaration(Loc loc, Identifier *id, Type *memtype) #endif isdeprecated = 0; isdone = 0; +#if IN_DMD + objFileDone = 0; +#endif } Dsymbol *EnumDeclaration::syntaxCopy(Dsymbol *s) @@ -54,6 +57,13 @@ Dsymbol *EnumDeclaration::syntaxCopy(Dsymbol *s) return ed; } +void EnumDeclaration::setScope(Scope *sc) +{ + if (isdone) + return; + ScopeDsymbol::setScope(sc); +} + void EnumDeclaration::semantic0(Scope *sc) { /* This function is a hack to get around a significant problem. diff --git a/dmd2/enum.h b/dmd2/enum.h index 5059317f..165f5356 100644 --- a/dmd2/enum.h +++ b/dmd2/enum.h @@ -49,6 +49,7 @@ struct EnumDeclaration : ScopeDsymbol EnumDeclaration(Loc loc, Identifier *id, Type *memtype); Dsymbol *syntaxCopy(Dsymbol *s); + void setScope(Scope *sc); void semantic0(Scope *sc); void semantic(Scope *sc); int oneMember(Dsymbol **ps, Identifier *ident = NULL); @@ -61,12 +62,13 @@ struct EnumDeclaration : ScopeDsymbol int isDeprecated(); // is Dsymbol deprecated? void emitComment(Scope *sc); - void toJsonBuffer(OutBuffer *buf); + void toJson(JsonOut *json); void toDocBuffer(OutBuffer *buf, Scope *sc); EnumDeclaration *isEnumDeclaration() { return this; } #if IN_DMD + bool objFileDone; // if toObjFile was already called void toObjFile(int multiobj); // compile to .obj file void toDebug(); int cvMember(unsigned char *p); @@ -92,7 +94,7 @@ struct EnumMember : Dsymbol const char *kind(); void emitComment(Scope *sc); - void toJsonBuffer(OutBuffer *buf); + void toJson(JsonOut *json); void toDocBuffer(OutBuffer *buf, Scope *sc); EnumMember *isEnumMember() { return this; } diff --git a/dmd2/expression.c b/dmd2/expression.c index a410a390..827b916b 100644 --- a/dmd2/expression.c +++ b/dmd2/expression.c @@ -1,5 +1,5 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars +// Copyright (c) 1999-2013 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -786,23 +786,9 @@ 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(); -#if 0 - if (arg->type->ty == Tfunction) - { - arg = new AddrExp(arg->loc, arg); - arg = arg->semantic(sc); - (*exps)[i] = arg; - } -#endif } } } @@ -933,25 +919,22 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, size_t nparams = Parameter::dim(tf->parameters); if (nargs > nparams && tf->varargs == 0) - { error(loc, "expected %zu arguments, not %llu for non-variadic function type %s", nparams, (ulonglong)nargs, tf->toChars()); + { error(loc, "expected %llu arguments, not %llu for non-variadic function type %s", (ulonglong)nparams, (ulonglong)nargs, tf->toChars()); return Type::terror; } // If inferring return type, and semantic3() needs to be run if not already run if (!tf->next && fd->inferRetType) { - TemplateInstance *spec = fd->isSpeculative(); - int olderrs = global.errors; - // If it isn't speculative, we need to show errors - unsigned oldgag = global.gag; - if (global.gag && !spec) - global.gag = 0; - fd->semantic3(fd->scope); - global.gag = oldgag; - // Update the template instantiation with the number - // of errors which occured. - if (spec && global.errors != olderrs) - spec->errors = global.errors - olderrs; + fd->functionSemantic(); + } + else if (fd && fd->parent) + { + TemplateInstance *ti = fd->parent->isTemplateInstance(); + if (ti && ti->tempdecl) + { + fd->functionSemantic3(); + } } size_t n = (nargs > nparams) ? nargs : nparams; // n = max(nargs, nparams) @@ -1149,7 +1132,7 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, if (p->type->hasWild()) { arg = arg->implicitCastTo(sc, p->type->substWildTo(wildmatch)); - arg = arg->optimize(WANTvalue); + arg = arg->optimize(WANTvalue, p->storageClass & STCref); } else if (p->type != arg->type) { @@ -1161,7 +1144,7 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, } else arg = arg->implicitCastTo(sc, p->type); - arg = arg->optimize(WANTvalue); + arg = arg->optimize(WANTvalue, p->storageClass & STCref); } } if (p->storageClass & STCref) @@ -1171,7 +1154,7 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, else if (p->storageClass & STCout) { Type *t = arg->type; - if (!t->isMutable() || !t->isAssignable(1)) // check blit assignable + if (!t->isMutable() || !t->isAssignable()) // check blit assignable arg->error("cannot modify struct %s with immutable members", arg->toChars()); arg = arg->toLvalue(sc, arg); } @@ -1184,13 +1167,8 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, Type *tb = arg->type->toBasetype(); 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) @@ -1648,7 +1626,6 @@ int Expression::isLvalue() return 0; } - /******************************* * Give error if we're not an lvalue. * If we can, convert expression to be an lvalue. @@ -1664,17 +1641,53 @@ Expression *Expression::toLvalue(Scope *sc, Expression *e) return new ErrorExp(); } +/*************************************** + * Parameters: + * sc: scope + * flag: 1: do not issue error message for invalid modification + * Returns: + * 0: is not modifiable + * 1: is modifiable in default == being related to type->isMutable() + * 2: is modifiable, because this is a part of initializing. + */ + +int Expression::checkModifiable(Scope *sc, int flag) +{ + return type ? 1 : 0; // default modifiable +} + Expression *Expression::modifiableLvalue(Scope *sc, Expression *e) { //printf("Expression::modifiableLvalue() %s, type = %s\n", toChars(), type->toChars()); // See if this expression is a modifiable lvalue (i.e. not const) -#if DMDV2 - if (type && !type->isMutable()) - { e->error("%s is not mutable", e->toChars()); - return new ErrorExp(); + if (checkModifiable(sc) == 1) + { + assert(type); + if (type->isMutable()) + { + if (!type->isAssignable()) + error("cannot modify struct %s %s with immutable members", toChars(), type->toChars()); + } + else + { + Declaration *var = NULL; + if (op == TOKvar) + var = ((VarExp *)this)->var; + else if (op == TOKdotvar) + var = ((DotVarExp *)this)->var; + if (var && var->storage_class & STCctorinit) + { + const char *p = var->isStatic() ? "static " : ""; + error("can only initialize %sconst member %s inside %sconstructor", + p, var->toChars(), p); + } + else + { + error("cannot modify %s expression %s", MODtoChars(type->mod), toChars()); + } + } } -#endif return toLvalue(sc, e); } @@ -1926,54 +1939,6 @@ void Expression::checkSafety(Scope *sc, FuncDeclaration *f) } #endif -void Expression::checkModifiable(Scope *sc) -{ - assert(type); - - /* We should call checkCtorInit() first, because this rejects - the modifying parameter and result inside contract. - */ - if (!checkCtorInit(sc)) - { - if (type->isMutable()) - { - if (!type->isAssignable()) - { - error("cannot modify struct %s %s with immutable members", toChars(), type->toChars()); - } - } - else - { - Declaration *var = NULL; - if (op == TOKvar) - var = ((VarExp *)this)->var; - else if (op == TOKdotvar) - var = ((DotVarExp *)this)->var; - if (var && var->storage_class & STCctorinit) - { - const char *p = var->isStatic() ? "static " : ""; - error("can only initialize %sconst member %s inside %sconstructor", - p, var->toChars(), p); - } - else - { - OutBuffer buf; - MODtoBuffer(&buf, type->mod); - error("cannot modify %s expression %s", buf.toChars(), toChars()); - } - } - } -} - -/*************************************** - * Return !=0 if expression is a part of initializing. - */ - -int Expression::checkCtorInit(Scope *sc) -{ - return FALSE; -} - /***************************** * Check that expression can be tested for true or false. */ @@ -2028,18 +1993,6 @@ Expression *Expression::checkToPointer() //printf("Expression::checkToPointer()\n"); Expression *e = this; -#if !SARRAYVALUE - // If C static array, convert to pointer - Type *tb = type->toBasetype(); - if (tb->ty == Tsarray) - { TypeSArray *ts = (TypeSArray *)tb; - if (ts->size(loc) == 0) - e = new NullExp(loc); - else - e = new AddrExp(loc, this); - e->type = ts->next->pointerTo(); - } -#endif return e; } @@ -2207,14 +2160,7 @@ int IntegerExp::equals(Object *o) char *IntegerExp::toChars() { -#if 1 return Expression::toChars(); -#else - static char buffer[sizeof(value) * 3 + 1]; - - sprintf(buffer, "%lld", value); - return buffer; -#endif } dinteger_t IntegerExp::toInteger() @@ -2620,8 +2566,6 @@ void floatToBuffer(OutBuffer *buf, Type *type, real_t value) __locale_decpoint = "."; real_t r = strtold(buffer, NULL); __locale_decpoint = save; -#elif IN_LLVM - real_t r = Port::strtold(buffer, NULL); #else real_t r = strtold(buffer, NULL); #endif @@ -2995,16 +2939,8 @@ int IdentifierExp::isLvalue() return 1; } - Expression *IdentifierExp::toLvalue(Scope *sc, Expression *e) { -#if 0 - tym = tybasic(e1->ET->Tty); - if (!(tyscalar(tym) || - tym == TYstruct || - tym == TYarray && e->Eoper == TOKaddr)) - synerr(EM_lvalue); // lvalue expected -#endif return this; } @@ -3122,34 +3058,10 @@ Lagain: } f = s->isFuncDeclaration(); if (f) - { f = f->toAliasFunc(); - - if (!f->originalType && f->scope) // semantic not yet run - { - unsigned oldgag = global.gag; - if (global.isSpeculativeGagging() && !f->isSpeculative()) - global.gag = 0; - f->semantic(f->scope); - global.gag = oldgag; - } - - // if inferring return type, sematic3 needs to be run - if (f->scope && (f->inferRetType && f->type && !f->type->nextOf() || - getFuncTemplateDecl(f))) - { - TemplateInstance *spec = f->isSpeculative(); - int olderrs = global.errors; - // If it isn't speculative, we need to show errors - unsigned oldgag = global.gag; - if (global.gag && !spec) - global.gag = 0; - f->semantic3(f->scope); - global.gag = oldgag; - // Update the template instantiation with the number - // of errors which occured. - if (spec && global.errors != olderrs) - spec->errors = global.errors - olderrs; - } + { + f = f->toAliasFunc(); + if (!f->functionSemantic()) + return new ErrorExp(); if (f->isUnitTestDeclaration()) { @@ -3280,16 +3192,8 @@ int DsymbolExp::isLvalue() return 1; } - Expression *DsymbolExp::toLvalue(Scope *sc, Expression *e) { -#if 0 - tym = tybasic(e1->ET->Tty); - if (!(tyscalar(tym) || - tym == TYstruct || - tym == TYarray && e->Eoper == TOKaddr)) - synerr(EM_lvalue); // lvalue expected -#endif return this; } @@ -3339,11 +3243,7 @@ Expression *ThisExp::semantic(Scope *sc) StructDeclaration *sd = s->isStructDeclaration(); if (sd) { -#if STRUCTTHISREF type = sd->type; -#else - type = sd->type->pointerTo(); -#endif return this; } } @@ -3382,7 +3282,6 @@ int ThisExp::isLvalue() return 1; } - Expression *ThisExp::toLvalue(Scope *sc, Expression *e) { return this; @@ -3391,7 +3290,10 @@ Expression *ThisExp::toLvalue(Scope *sc, Expression *e) Expression *ThisExp::modifiableLvalue(Scope *sc, Expression *e) { if (type->toBasetype()->ty == Tclass) + { error("Cannot modify '%s'", toChars()); + return toLvalue(sc, e); + } return Expression::modifiableLvalue(sc, e); } @@ -3452,6 +3354,8 @@ Expression *SuperExp::semantic(Scope *sc) s = fd->toParent(); while (s && s->isTemplateInstance()) s = s->toParent(); + if (s->isTemplateDeclaration()) // allow inside template constraint + s = s->toParent(); assert(s); cd = s->isClassDeclaration(); //printf("parent is %s %s\n", fd->toParent()->kind(), fd->toParent()->toChars()); @@ -3816,7 +3720,6 @@ int StringExp::isLvalue() return 0; } - Expression *StringExp::toLvalue(Scope *sc, Expression *e) { //printf("StringExp::toLvalue(%s)\n", toChars()); @@ -4221,6 +4124,7 @@ Expression *StructLiteralExp::semantic(Scope *sc) Type *telem = v->type; if (stype) telem = telem->addMod(stype->mod); + Type *origType = telem; while (!e->implicitConvTo(telem) && telem->toBasetype()->ty == Tsarray) { /* Static array initialization, as in: * T[3][5] = e; @@ -4228,6 +4132,9 @@ Expression *StructLiteralExp::semantic(Scope *sc) telem = telem->toBasetype()->nextOf(); } + if (!e->implicitConvTo(telem)) + telem = origType; // restore type for better diagnostic + e = e->implicitCastTo(sc, telem); if (e->op == TOKerror) return e; @@ -4309,13 +4216,16 @@ Expression *StructLiteralExp::semantic(Scope *sc) Expression *StructLiteralExp::getField(Type *type, unsigned offset) { //printf("StructLiteralExp::getField(this = %s, type = %s, offset = %u)\n", -// /*toChars()*/"", type->toChars(), offset); + // /*toChars()*/"", type->toChars(), offset); Expression *e = NULL; int i = getFieldIndex(type, offset); if (i != -1) { //printf("\ti = %d\n", i); + if (i == sd->fields.dim - 1 && sd->isNested()) + return NULL; + assert(i < elements->dim); e = (*elements)[i]; if (e) @@ -4372,7 +4282,11 @@ int StructLiteralExp::getFieldIndex(Type *type, unsigned offset) if (offset == v->offset && type->size() == v->type->size()) - { Expression *e = (*elements)[i]; + { + /* context field might not be filled. */ + if (i == sd->fields.dim - 1 && sd->isNested()) + return (int)i; + Expression *e = (*elements)[i]; if (e) { return (int)i; @@ -4747,25 +4661,7 @@ Lagain: goto Lerr; } } -#if 0 - else - { - for (Dsymbol *sf = sc->func; 1; sf= sf->toParent2()->isFuncDeclaration()) - { - if (!sf) - { - error("outer class %s 'this' needed to 'new' nested class %s", cdn->toChars(), cd->toChars()); - goto Lerr; } - printf("sf = %s\n", sf->toChars()); - AggregateDeclaration *ad = sf->isThis(); - if (ad && (ad == cdn || cdn->isBaseOf(ad->isClassDeclaration(), NULL))) - break; - } - } -#endif - } -#if 1 else if (thisexp) { error("e.new is only for allocating nested classes"); goto Lerr; @@ -4785,19 +4681,6 @@ Lagain: } } } -#else - else if (fdn) - { /* The nested class cd is nested inside a function, - * we'll let getEthis() look for errors. - */ - //printf("nested class %s is nested inside function %s, we're in %s\n", cd->toChars(), fdn->toChars(), sc->func->toChars()); - if (thisexp) - { // Because thisexp cannot be a function frame pointer - error("e.new is only for allocating nested classes"); - goto Lerr; - } - } -#endif else assert(0); } @@ -5182,20 +5065,16 @@ Expression *VarExp::semantic(Scope *sc) #if LOGSEMANTIC printf("VarExp::semantic(%s)\n", toChars()); #endif -// if (var->sem == SemanticStart && var->scope) // if forward referenced -// var->semantic(sc); - if (!type) - { type = var->type; -#if 0 - if (var->storage_class & STClazy) - { - TypeFunction *tf = new TypeFunction(NULL, type, 0, LINKd); - type = new TypeDelegate(tf); - type = type->semantic(loc, sc); - } -#endif + if (FuncDeclaration *f = var->isFuncDeclaration()) + { + //printf("L%d fd = %s\n", __LINE__, f->toChars()); + if (!f->functionSemantic()) + return new ErrorExp(); } + if (!type) + type = var->type; + if (type && !type->deco) type = type->semantic(loc, sc); @@ -5216,14 +5095,6 @@ Expression *VarExp::semantic(Scope *sc) FuncDeclaration *f = var->isFuncDeclaration(); if (f) f->checkNestedReference(sc, loc); -#if 0 - else if ((fd = var->isFuncLiteralDeclaration()) != NULL) - { Expression *e; - e = new FuncExp(loc, fd); - e->type = type; - return e; - } -#endif return this; } @@ -5264,12 +5135,6 @@ void VarExp::checkEscapeRef() } } -int VarExp::checkCtorInit(Scope *sc) -{ - return var->checkModify(loc, sc, type); -} - - int VarExp::isLvalue() { if (var->storage_class & (STClazy | STCtemp)) @@ -5277,16 +5142,8 @@ int VarExp::isLvalue() return 1; } - Expression *VarExp::toLvalue(Scope *sc, Expression *e) { -#if 0 - tym = tybasic(e1->ET->Tty); - if (!(tyscalar(tym) || - tym == TYstruct || - tym == TYarray && e->Eoper == TOKaddr)) - synerr(EM_lvalue); // lvalue expected -#endif if (var->storage_class & STClazy) { error("lazy variables cannot be lvalues"); return new ErrorExp(); @@ -5299,6 +5156,13 @@ Expression *VarExp::toLvalue(Scope *sc, Expression *e) return this; } +int VarExp::checkModifiable(Scope *sc, int flag) +{ + //printf("VarExp::checkModifiable %s", toChars()); + assert(type); + return var->checkModify(loc, sc, type, NULL, flag); +} + Expression *VarExp::modifiableLvalue(Scope *sc, Expression *e) { //printf("VarExp::modifiableLvalue('%s')\n", var->toChars()); @@ -5315,10 +5179,8 @@ Expression *VarExp::modifiableLvalue(Scope *sc, Expression *e) deprecation("variable modified in foreach body requires ref storage class"); #endif - checkModifiable(sc); - // See if this expression is a modifiable lvalue (i.e. not const) - return toLvalue(sc, e); + return Expression::modifiableLvalue(sc, e); } @@ -5793,6 +5655,9 @@ Expression *TypeidExp::semantic(Scope *sc) if (ea) { + Dsymbol *sym = getDsymbol(ea); + if (sym) + ea = new DsymbolExp(loc, sym); ea = ea->semantic(sc); ea = resolveProperties(sc, ea); ta = ea->type; @@ -6063,6 +5928,12 @@ Expression *IsExp::semantic(Scope *sc) for (size_t i = 0; i < dim; i++) { Parameter *arg = Parameter::getNth(params, i); assert(arg && arg->type); + /* If one of the default arguments was an error, + don't return an invalid tuple + */ + if (tok2 == TOKparameters && arg->defaultArg && + arg->defaultArg->op == TOKerror) + return new ErrorExp(); args->push(new Parameter(arg->storageClass, arg->type, (tok2 == TOKparameters) ? arg->ident : NULL, (tok2 == TOKparameters) ? arg->defaultArg : NULL)); @@ -6457,15 +6328,17 @@ Expression *BinExp::incompatibleTypes() e2->type->toBasetype() != Type::terror ) { + // CondExp uses 'a ? b : c' but we're comparing 'b : c' + TOK thisOp = (op == TOKquestion) ? TOKcolon : op; if (e1->op == TOKtype || e2->op == TOKtype) { error("incompatible types for ((%s) %s (%s)): cannot use '%s' with types", - e1->toChars(), Token::toChars(op), e2->toChars(), Token::toChars(op)); + e1->toChars(), Token::toChars(thisOp), e2->toChars(), Token::toChars(op)); } else { error("incompatible types for ((%s) %s (%s)): '%s' and '%s'", - e1->toChars(), Token::toChars(op), e2->toChars(), + e1->toChars(), Token::toChars(thisOp), e2->toChars(), e1->type->toChars(), e2->type->toChars()); } return new ErrorExp(); @@ -6612,6 +6485,7 @@ Expression *BinAssignExp::toLvalue(Scope *sc, Expression *ex) Expression *BinAssignExp::modifiableLvalue(Scope *sc, Expression *e) { + // should check e1->checkModifiable() ? return toLvalue(sc, this); } @@ -6672,7 +6546,8 @@ FileExp::FileExp(Loc loc, Expression *e) } Expression *FileExp::semantic(Scope *sc) -{ char *name; +{ + const char *name; StringExp *se; #if LOGSEMANTIC @@ -6819,18 +6694,6 @@ Expression *DotIdExp::semantic(Scope *sc, int flag) //{ static int z; fflush(stdout); if (++z == 10) *(char*)0=0; } -#if 0 - /* Don't do semantic analysis if we'll be converting - * it to a string. - */ - if (ident == Id::stringof) - { char *s = e1->toChars(); - e = new StringExp(loc, s, strlen(s), 'c'); - e = e->semantic(sc); - return e; - } -#endif - /* Special case: rewrite this.id and super.id * to be classtype.id and baseclasstype.id * if we have no this pointer. @@ -6876,26 +6739,6 @@ Expression *DotIdExp::semantic(Scope *sc, int flag) 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; @@ -7289,16 +7132,27 @@ Expression *DotVarExp::semantic(Scope *sc) e1 = e1->semantic(sc); e1 = e1->addDtorHook(sc); - type = var->type; - if (!type && global.errors) - { // var is goofed up, just return 0 - return new ErrorExp(); - } - assert(type); Type *t1 = e1->type; - if (!var->isFuncDeclaration()) // for functions, do checks after overload resolution + FuncDeclaration *f = var->isFuncDeclaration(); + if (f) // for functions, do checks after overload resolution { + //printf("L%d fd = %s\n", __LINE__, f->toChars()); + if (!f->functionSemantic()) + return new ErrorExp(); + + type = f->type; + assert(type); + } + else + { + type = var->type; + if (!type && global.errors) + { // var is goofed up, just return 0 + goto Lerr; + } + assert(type); + if (t1->ty == Tpointer) t1 = t1->nextOf(); @@ -7337,21 +7191,11 @@ Lerr: return new ErrorExp(); } -int DotVarExp::checkCtorInit(Scope *sc) -{ - if (e1->op == TOKthis) - return modifyFieldVar(loc, sc, var->isVarDeclaration(), e1); - else - return e1->checkCtorInit(sc); -} - - int DotVarExp::isLvalue() { return 1; } - Expression *DotVarExp::toLvalue(Scope *sc, Expression *e) { //printf("DotVarExp::toLvalue(%s)\n", toChars()); @@ -7394,6 +7238,16 @@ int modifyFieldVar(Loc loc, Scope *sc, VarDeclaration *var, Expression *e1) return FALSE; } +int DotVarExp::checkModifiable(Scope *sc, int flag) +{ + //printf("DotVarExp::checkModifiable %s %s\n", toChars(), type->toChars()); + if (e1->op == TOKthis) + return var->checkModify(loc, sc, type, e1, flag); + + //printf("\te1 = %s\n", e1->toChars()); + return e1->checkModifiable(sc, flag); +} + Expression *DotVarExp::modifiableLvalue(Scope *sc, Expression *e) { #if 0 @@ -7402,8 +7256,7 @@ Expression *DotVarExp::modifiableLvalue(Scope *sc, Expression *e) printf("var->type = %s\n", var->type->toChars()); #endif - checkModifiable(sc); - return this; + return Expression::modifiableLvalue(sc, e); } void DotVarExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) @@ -7780,9 +7633,7 @@ Expression *CallExp::resolveUFCS(Scope *sc) return new ErrorExp(); } if (!e->type->isMutable()) - { OutBuffer buf; - MODtoBuffer(&buf, e->type->mod); - error("cannot remove key from %s associative array %s", buf.toChars(), e->toChars()); + { error("cannot remove key from %s associative array %s", MODtoChars(e->type->mod), e->toChars()); return new ErrorExp(); } Expression *key = (*arguments)[0]; @@ -7909,7 +7760,6 @@ Expression *CallExp::semantic(Scope *sc) if (e) return e; -#if 1 /* This recognizes: * foo!(tiargs)(funcargs) */ @@ -7953,17 +7803,6 @@ Ldotti: * If not, go with partial explicit specialization. */ ti->semanticTiargs(sc); -#if 0 - Expression *etmp = e1->trySemantic(sc); - if (etmp) - e1 = etmp; // it worked - else // didn't work - { - targsi = ti->tiargs; - tierror = ti; // for error reporting - e1 = new DotIdExp(loc, se->e1, ti->name); - } -#else if (!ti->tempdecl) { se->getTempdecl(sc); @@ -7980,10 +7819,8 @@ Ldotti: { e1 = e1->semantic(sc); } -#endif } } -#endif istemp = 0; Lagain: @@ -8055,8 +7892,6 @@ Lagain: e1 = ve; } } - - } #else else if (e1->op == TOKsymoff && ((SymOffExp *)e1)->hasOverloads) @@ -8066,7 +7901,6 @@ Lagain: e1 = e1->semantic(sc); } #endif -#if 1 // patch for #540 by Oskar Linde else if (e1->op == TOKdotexp) { DotExp *de = (DotExp *) e1; @@ -8089,7 +7923,6 @@ Lagain: e1 = new DotTemplateExp(loc,de->e1,te->td); } } -#endif } t1 = NULL; @@ -8104,6 +7937,17 @@ Lagain: { ad = ((TypeStruct *)t1)->sym; #if DMDV2 + + if (ad->sizeok == SIZEOKnone && !ad->ctor && + ad->search(0, Id::ctor, 0)) + { + // The constructor hasn't been found yet, see bug 8741 + // This can happen if we are inferring type from + // from VarDeclaration::semantic() in declaration.c + error("cannot create a struct until its size is determined"); + return new ErrorExp(); + } + // First look for constructor if (e1->op == TOKtype && ad->ctor && (ad->noDefaultCtor || arguments && arguments->dim)) { @@ -8134,11 +7978,6 @@ Lagain: e = new DotTemplateExp(loc, av, td); } e = new CallExp(loc, e, arguments); -#if !STRUCTTHISREF - /* Constructors return a pointer to the instance - */ - e = new PtrExp(loc, e); -#endif e = e->semantic(sc); return e; } @@ -8247,6 +8086,8 @@ Lagain: if (f->needThis()) { ue->e1 = getRightThis(loc, sc, ad, ue->e1, f); + if (ue->e1->op == TOKerror) + return ue->e1; ethis = ue->e1; } @@ -8297,43 +8138,6 @@ Lagain: printf("e1 = %s\n", e1->toChars()); printf("e1->type = %s\n", e1->type->toChars()); #endif - // Const member function can take const/immutable/mutable/inout this - if (!(f->type->isConst())) - { - // Check for const/immutable compatibility - Type *tthis = ue->e1->type->toBasetype(); - if (tthis->ty == Tpointer) - tthis = tthis->nextOf()->toBasetype(); -#if 0 // this checking should have been already done - if (f->type->isImmutable()) - { - if (tthis->mod != MODimmutable) - error("%s can only be called with an immutable object", e1->toChars()); - } - else if (f->type->isShared()) - { - if (tthis->mod != MODimmutable && - tthis->mod != MODshared && - tthis->mod != (MODshared | MODconst)) - error("shared %s can only be called with a shared or immutable object", e1->toChars()); - } - else - { - if (tthis->mod != 0) - { //printf("mod = %x\n", tthis->mod); - error("%s can only be called with a mutable object, not %s", e1->toChars(), tthis->toChars()); - } - } -#endif - /* Cannot call mutable method on a final struct - */ - if (tthis->ty == Tstruct && - ue->e1->op == TOKvar) - { VarExp *v = (VarExp *)ue->e1; - if (v->var->storage_class & STCfinal) - error("cannot call mutable method on final struct"); - } - } // See if we need to adjust the 'this' pointer AggregateDeclaration *ad = f->isThis(); @@ -8369,10 +8173,6 @@ Lagain: { if (!sc->intypeof) { -#if 0 - if (sc->callSuper & (CSXthis | CSXsuper)) - error("reference to this before super()"); -#endif if (sc->noctor || sc->callSuper & CSXlabel) error("constructor calls not allowed in loops or after labels"); if (sc->callSuper & (CSXsuper_ctor | CSXthis_ctor)) @@ -8383,6 +8183,8 @@ Lagain: } f = resolveFuncCall(sc, loc, cd->baseClass->ctor, NULL, NULL, arguments, 0); + if (!f) + return new ErrorExp(); accessCheck(loc, sc, NULL, f); checkDeprecated(sc, f); #if DMDV2 @@ -8411,10 +8213,6 @@ Lagain: { if (!sc->intypeof) { -#if 0 - if (sc->callSuper & (CSXthis | CSXsuper)) - error("reference to this before super()"); -#endif if (sc->noctor || sc->callSuper & CSXlabel) error("constructor calls not allowed in loops or after labels"); if (sc->callSuper & (CSXsuper_ctor | CSXthis_ctor)) @@ -8425,6 +8223,8 @@ Lagain: } f = resolveFuncCall(sc, loc, cd->ctor, NULL, NULL, arguments, 0); + if (!f) + return new ErrorExp(); checkDeprecated(sc, f); #if DMDV2 checkPurity(sc, f); @@ -8705,7 +8505,6 @@ int CallExp::isLvalue() return 0; } - Expression *CallExp::toLvalue(Scope *sc, Expression *e) { if (isLvalue()) @@ -8997,16 +8796,6 @@ void PtrExp::checkEscapeRef() e1->checkEscape(); } -int PtrExp::checkCtorInit(Scope *sc) -{ - if (e1->op == TOKsymoff) - { SymOffExp *se = (SymOffExp *)e1; - return se->var->checkModify(loc, sc, type); - } - return FALSE; -} - - int PtrExp::isLvalue() { return 1; @@ -9014,23 +8803,28 @@ int PtrExp::isLvalue() Expression *PtrExp::toLvalue(Scope *sc, Expression *e) { -#if 0 - tym = tybasic(e1->ET->Tty); - if (!(tyscalar(tym) || - tym == TYstruct || - tym == TYarray && e->Eoper == TOKaddr)) - synerr(EM_lvalue); // lvalue expected -#endif return this; } +int PtrExp::checkModifiable(Scope *sc, int flag) +{ + if (e1->op == TOKsymoff) + { SymOffExp *se = (SymOffExp *)e1; + return se->var->checkModify(loc, sc, type, NULL, flag); + } + else if (e1->op == TOKaddress) + { + AddrExp *ae = (AddrExp *)e1; + return ae->e1->checkModifiable(sc, flag); + } + return 1; +} + #if DMDV2 Expression *PtrExp::modifiableLvalue(Scope *sc, Expression *e) { //printf("PtrExp::modifiableLvalue() %s, type %s\n", toChars(), type->toChars()); - - checkModifiable(sc); - return toLvalue(sc, e); + return Expression::modifiableLvalue(sc, e); } #endif @@ -9356,13 +9150,6 @@ Expression *CastExp::semantic(Scope *sc) if (!to->equals(e1->type)) { -#if 0 // attempt at fixing 6720 - if (e1->type->ty == Tvoid) - { - error("cannot cast from void to %s", to->toChars()); - return new ErrorExp(); - } -#endif Expression *e = op_overload(sc); if (e) { @@ -9626,6 +9413,16 @@ Expression *SliceExp::semantic(Scope *sc) Lagain: UnaExp::semantic(sc); e1 = resolveProperties(sc, e1); + if (e1->op == TOKtype && e1->type->ty != Ttuple) + { + if (lwr || upr) + { + error("cannot slice type '%s'", e1->toChars()); + return new ErrorExp(); + } + e = new TypeExp(loc, e1->type->arrayOf()); + return e->semantic(sc); + } e = this; @@ -9809,29 +9606,28 @@ void SliceExp::checkEscapeRef() e1->checkEscapeRef(); } -int SliceExp::checkCtorInit(Scope *sc) -{ - if (e1->type->ty == Tsarray || - (e1->op == TOKindex && e1->type->ty != Tarray) || - e1->op == TOKslice) - { - return e1->checkCtorInit(sc); - } - return FALSE; -} - - int SliceExp::isLvalue() { return 1; } - Expression *SliceExp::toLvalue(Scope *sc, Expression *e) { return this; } +int SliceExp::checkModifiable(Scope *sc, int flag) +{ + //printf("SliceExp::checkModifiable %s\n", toChars()); + if (e1->type->ty == Tsarray || + (e1->op == TOKindex && e1->type->ty != Tarray) || + e1->op == TOKslice) + { + return e1->checkModifiable(sc, flag); + } + return 1; +} + Expression *SliceExp::modifiableLvalue(Scope *sc, Expression *e) { error("slice expression %s is not a modifiable lvalue", toChars()); @@ -10009,7 +9805,6 @@ int ArrayExp::isLvalue() return 1; } - Expression *ArrayExp::toLvalue(Scope *sc, Expression *e) { if (type && type->toBasetype()->ty == Tvoid) @@ -10090,24 +9885,22 @@ void CommaExp::checkEscapeRef() e2->checkEscapeRef(); } -int CommaExp::checkCtorInit(Scope *sc) -{ - return e2->checkCtorInit(sc); -} - - int CommaExp::isLvalue() { return e2->isLvalue(); } - Expression *CommaExp::toLvalue(Scope *sc, Expression *e) { e2 = e2->toLvalue(sc, NULL); return this; } +int CommaExp::checkModifiable(Scope *sc, int flag) +{ + return e2->checkModifiable(sc, flag); +} + Expression *CommaExp::modifiableLvalue(Scope *sc, Expression *e) { e2 = e2->modifiableLvalue(sc, e); @@ -10158,6 +9951,18 @@ Expression *IndexExp::semantic(Scope *sc) if (!e1->type) e1 = e1->semantic(sc); assert(e1->type); // semantic() should already be run on it + if (e1->op == TOKtype && e1->type->ty != Ttuple) + { + e2 = e2->semantic(sc); + e2 = resolveProperties(sc, e2); + Type *nt; + if (e2->op == TOKtype) + nt = new TypeAArray(e1->type, e2->type); + else + nt = new TypeSArray(e1->type, e2); + e = new TypeExp(loc, nt); + return e->semantic(sc); + } if (e1->op == TOKerror) goto Lerr; e = this; @@ -10187,6 +9992,19 @@ Expression *IndexExp::semantic(Scope *sc) switch (t1->ty) { case Tpointer: + e2 = e2->implicitCastTo(sc, Type::tsize_t); + e2 = e2->optimize(WANTvalue); + if (e2->op == TOKint64 && e2->toInteger() == 0) + ; + else if (sc->func->setUnsafe()) + { + error("safe function '%s' cannot index pointer '%s'", + sc->func->toPrettyChars(), e1->toChars()); + return new ErrorExp(); + } + e->type = ((TypeNext *)t1)->next; + break; + case Tarray: e2 = e2->implicitCastTo(sc, Type::tsize_t); e->type = ((TypeNext *)t1)->next; @@ -10195,21 +10013,7 @@ Expression *IndexExp::semantic(Scope *sc) case Tsarray: { e2 = e2->implicitCastTo(sc, Type::tsize_t); - TypeSArray *tsa = (TypeSArray *)t1; - -#if 0 // Don't do now, because it might be short-circuit evaluated - // Do compile time array bounds checking if possible - e2 = e2->optimize(WANTvalue); - if (e2->op == TOKint64) - { - dinteger_t index = e2->toInteger(); - dinteger_t length = tsa->dim->toInteger(); - if (index < 0 || index >= length) - error("array index [%lld] is outside array bounds [0 .. %lld]", - index, length); - } -#endif e->type = t1->nextOf(); break; } @@ -10287,24 +10091,11 @@ Lerr: return new ErrorExp(); } -int IndexExp::checkCtorInit(Scope *sc) -{ - if (e1->type->ty == Tsarray || - (e1->op == TOKindex && e1->type->ty != Tarray) || - e1->op == TOKslice) - { - return e1->checkCtorInit(sc); - } - return FALSE; -} - - int IndexExp::isLvalue() { return 1; } - Expression *IndexExp::toLvalue(Scope *sc, Expression *e) { // if (type && type->toBasetype()->ty == Tvoid) @@ -10312,6 +10103,17 @@ Expression *IndexExp::toLvalue(Scope *sc, Expression *e) return this; } +int IndexExp::checkModifiable(Scope *sc, int flag) +{ + if (e1->type->ty == Tsarray || + (e1->op == TOKindex && e1->type->ty != Tarray) || + e1->op == TOKslice) + { + return e1->checkModifiable(sc, flag); + } + return 1; +} + Expression *IndexExp::modifiableLvalue(Scope *sc, Expression *e) { //printf("IndexExp::modifiableLvalue(%s)\n", toChars()); @@ -10323,12 +10125,10 @@ Expression *IndexExp::modifiableLvalue(Scope *sc, Expression *e) if (t2b->ty == Tarray && t2b->nextOf()->isMutable()) error("associative arrays can only be assigned values with immutable keys, not %s", e2->type->toChars()); e1 = e1->modifiableLvalue(sc, e1); + return toLvalue(sc, e); } - else - { - checkModifiable(sc); - } - return toLvalue(sc, e); + + return Expression::modifiableLvalue(sc, e); } void IndexExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) @@ -10751,13 +10551,13 @@ Expression *AssignExp::semantic(Scope *sc) Type *t1 = e1->type->toBasetype(); e2 = e2->inferType(t1); - if (!e2->rvalue()) - return new ErrorExp(); e2 = e2->semantic(sc); if (e2->op == TOKerror) return new ErrorExp(); e2 = resolveProperties(sc, e2); + if (!e2->rvalue()) + return new ErrorExp(); /* Rewrite tuple assignment as a tuple of assignments. */ @@ -10832,8 +10632,6 @@ Ltupleassign: } } - int ctorinit = e1->checkCtorInit(sc); - // Determine if this is an initialization of a reference int refinit = 0; if (op == TOKconstruct && e1->op == TOKvar) @@ -10851,17 +10649,6 @@ Ltupleassign: StructDeclaration *sd = ((TypeStruct *)t1)->sym; if (op == TOKassign) { - /* See if we need to set ctorinit, i.e. track - * assignments to fields. An assignment to a field counts even - * if done through an opAssign overload. - */ - if (e1->op == TOKdotvar) - { DotVarExp *dve = (DotVarExp *)e1; - VarDeclaration *v = dve->var->isVarDeclaration(); - if (v && v->storage_class & STCnodefaultctor) - modifyFieldVar(loc, sc, v, dve->e1); - } - Expression *e = op_overload(sc); if (e && e1->op == TOKindex && ((IndexExp *)e1)->e1->type->toBasetype()->ty == Taarray) @@ -10893,7 +10680,14 @@ Ltupleassign: e = this; } if (e) + { + /* See if we need to set ctorinit, i.e. track + * assignments to fields. An assignment to a field counts even + * if done through an opAssign overload. + */ + e1->checkModifiable(sc); return e; + } } else if (op == TOKconstruct && !refinit) { Type *t2 = e2->type->toBasetype(); @@ -10984,7 +10778,7 @@ Ltupleassign: else if (e1->op == TOKslice) { Type *tn = e1->type->nextOf(); - if (op == TOKassign && !ctorinit && !tn->isMutable()) + if (op == TOKassign && e1->checkModifiable(sc) == 1 && !tn->isMutable()) { error("slice %s is not mutable", e1->toChars()); return new ErrorExp(); } @@ -11000,16 +10794,7 @@ Ltupleassign: } Type *t2 = e2->type->toBasetype(); -#if 0 - if (t1->ty == Tvector && t2->ty != Tvector && - e2->implicitConvTo(((TypeVector *)t1)->basetype->nextOf()) - ) - { // memset - ismemset = 1; // make it easy for back end to tell what this is - e2 = e2->implicitCastTo(sc, ((TypeVector *)t1)->basetype->nextOf()); - } - else -#endif + // If it is a array, get the element type. Note that it may be // multi-dimensional. Type *telem = t1; @@ -11588,7 +11373,8 @@ Expression *CatExp::semantic(Scope *sc) */ } else if ((tb1->ty == Tsarray || tb1->ty == Tarray) && - e2->implicitConvTo(tb1next) >= MATCHconvert) + e2->implicitConvTo(tb1next) >= MATCHconvert && + tb2->ty != Tvoid) { checkPostblit(e2->loc, tb2); e2 = e2->implicitCastTo(sc, tb1next); @@ -11601,7 +11387,8 @@ Expression *CatExp::semantic(Scope *sc) return this; } else if ((tb2->ty == Tsarray || tb2->ty == Tarray) && - e1->implicitConvTo(tb2next) >= MATCHconvert) + e1->implicitConvTo(tb2next) >= MATCHconvert && + tb1->ty != Tvoid) { checkPostblit(e1->loc, tb1); e1 = e1->implicitCastTo(sc, tb2next); @@ -12431,28 +12218,6 @@ Expression *CmpExp::semantic(Scope *sc) if (e->op == TOKerror) return e; -#if 0 - // For integer comparisons, ensure the combined type can hold both arguments. - if (type && type->isintegral() && (op == TOKlt || op == TOKle || - op == TOKgt || op == TOKge)) - { - IntRange trange = IntRange::fromType(type); - - Expression *errorexp = 0; - if (!trange.contains(eb1->getIntRange())) - errorexp = eb1; - if (!trange.contains(eb2->getIntRange())) - errorexp = eb2; - - if (errorexp) - { - error("implicit conversion of '%s' to '%s' is unsafe in '(%s) %s (%s)'", - errorexp->toChars(), type->toChars(), eb1->toChars(), Token::toChars(op), eb2->toChars()); - return new ErrorExp(); - } - } -#endif - type = Type::tboolean; // Special handling for array comparisons @@ -12478,13 +12243,11 @@ Expression *CmpExp::semantic(Scope *sc) error("need member function opCmp() for %s %s to compare", t1->toDsymbol(sc)->kind(), t1->toChars()); e = new ErrorExp(); } -#if 1 else if (t1->iscomplex() || t2->iscomplex()) { error("compare not defined for complex operands"); e = new ErrorExp(); } -#endif else if (t1->ty == Tvector) return incompatibleTypes(); else @@ -12723,30 +12486,6 @@ Expression *CondExp::semantic(Scope *sc) econd = econd->checkToPointer(); econd = econd->checkToBoolean(sc); -#if 0 /* this cannot work right because the types of e1 and e2 - * both contribute to the type of the result. - */ - if (sc->flags & SCOPEstaticif) - { - /* If in static if, don't evaluate what we don't have to. - */ - econd = econd->optimize(WANTflags); - if (econd->isBool(TRUE)) - { - e1 = e1->semantic(sc); - e1 = resolveProperties(sc, e1); - return e1; - } - else if (econd->isBool(FALSE)) - { - e2 = e2->semantic(sc); - e2 = resolveProperties(sc, e2); - return e2; - } - } -#endif - - cs0 = sc->callSuper; e1 = e1->semantic(sc); e1 = resolveProperties(sc, e1); @@ -12797,12 +12536,6 @@ Expression *CondExp::semantic(Scope *sc) return this; } -int CondExp::checkCtorInit(Scope *sc) -{ - return e1->checkCtorInit(sc) && e2->checkCtorInit(sc); -} - - int CondExp::isLvalue() { return e1->isLvalue() && e2->isLvalue(); @@ -12825,6 +12558,11 @@ Expression *CondExp::toLvalue(Scope *sc, Expression *ex) return e; } +int CondExp::checkModifiable(Scope *sc, int flag) +{ + return e1->checkModifiable(sc, flag) && e2->checkModifiable(sc, flag); +} + Expression *CondExp::modifiableLvalue(Scope *sc, Expression *e) { //error("conditional expression %s is not a modifiable lvalue", toChars()); diff --git a/dmd2/expression.h b/dmd2/expression.h index 40028dbb..1d28a95d 100644 --- a/dmd2/expression.h +++ b/dmd2/expression.h @@ -173,8 +173,7 @@ struct Expression : Object void checkPurity(Scope *sc, FuncDeclaration *f); void checkPurity(Scope *sc, VarDeclaration *v, Expression *e1); void checkSafety(Scope *sc, FuncDeclaration *f); - void checkModifiable(Scope *sc); - virtual int checkCtorInit(Scope *sc); + virtual int checkModifiable(Scope *sc, int flag = 0); virtual Expression *checkToBoolean(Scope *sc); virtual Expression *addDtorHook(Scope *sc); Expression *checkToPointer(); @@ -778,7 +777,7 @@ struct VarExp : SymbolExp void toCBuffer(OutBuffer *buf, HdrGenState *hgs); void checkEscape(); void checkEscapeRef(); - int checkCtorInit(Scope *sc); + int checkModifiable(Scope *sc, int flag); int isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); Expression *modifiableLvalue(Scope *sc, Expression *e); @@ -1069,7 +1068,7 @@ struct DotVarExp : UnaExp DotVarExp(Loc loc, Expression *e, Declaration *var, int hasOverloads = 0); Expression *semantic(Scope *sc); - int checkCtorInit(Scope *sc); + int checkModifiable(Scope *sc, int flag); int isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); Expression *modifiableLvalue(Scope *sc, Expression *e); @@ -1202,7 +1201,7 @@ struct PtrExp : UnaExp PtrExp(Loc loc, Expression *e, Type *t); Expression *semantic(Scope *sc); void checkEscapeRef(); - int checkCtorInit(Scope *sc); + int checkModifiable(Scope *sc, int flag); int isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); Expression *modifiableLvalue(Scope *sc, Expression *e); @@ -1385,7 +1384,7 @@ struct SliceExp : UnaExp Expression *semantic(Scope *sc); void checkEscape(); void checkEscapeRef(); - int checkCtorInit(Scope *sc); + int checkModifiable(Scope *sc, int flag); int isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); Expression *modifiableLvalue(Scope *sc, Expression *e); @@ -1466,7 +1465,7 @@ struct CommaExp : BinExp Expression *semantic(Scope *sc); void checkEscape(); void checkEscapeRef(); - int checkCtorInit(Scope *sc); + int checkModifiable(Scope *sc, int flag); IntRange getIntRange(); int isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); @@ -1495,7 +1494,7 @@ struct IndexExp : BinExp IndexExp(Loc loc, Expression *e1, Expression *e2); Expression *syntaxCopy(); Expression *semantic(Scope *sc); - int checkCtorInit(Scope *sc); + int checkModifiable(Scope *sc, int flag); int isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); Expression *modifiableLvalue(Scope *sc, Expression *e); @@ -2070,7 +2069,7 @@ struct CondExp : BinExp Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); void checkEscape(); void checkEscapeRef(); - int checkCtorInit(Scope *sc); + int checkModifiable(Scope *sc, int flag); int isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); Expression *modifiableLvalue(Scope *sc, Expression *e); diff --git a/dmd2/func.c b/dmd2/func.c index 7a7b55bc..776252f3 100644 --- a/dmd2/func.c +++ b/dmd2/func.c @@ -25,10 +25,6 @@ #include "template.h" #include "hdrgen.h" -#ifdef IN_GCC -#include "d-dmd-gcc.h" -#endif - /********************************* FuncDeclaration ****************************/ FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, StorageClass storage_class, Type *type) @@ -429,7 +425,7 @@ void FuncDeclaration::semantic(Scope *sc) isNewDeclaration() || isDelete()) error("constructors, destructors, postblits, invariants, new and delete functions are not allowed in interface %s", id->toChars()); if (fbody && isVirtual()) - error("function body is not abstract in interface %s", id->toChars()); + error("function body only allowed in final functions in interface %s", id->toChars()); } /* Contracts can only appear without a body when they are virtual interface functions @@ -546,8 +542,23 @@ void FuncDeclaration::semantic(Scope *sc) return; default: - { FuncDeclaration *fdv = (FuncDeclaration *)cd->baseClass->vtbl[vi]; + { FuncDeclaration *fdv = cd->baseClass->vtbl[vi]->isFuncDeclaration(); + FuncDeclaration *fdc = cd->vtbl[vi]->isFuncDeclaration(); // This function is covariant with fdv + + if (fdc->toParent() == parent) + { + //printf("vi = %d,\tthis = %p %s %s @ [%s]\n\tfdc = %p %s %s @ [%s]\n\tfdv = %p %s %s @ [%s]\n", + // vi, this, this->toChars(), this->type->toChars(), this->loc.toChars(), + // fdc, fdc ->toChars(), fdc ->type->toChars(), fdc ->loc.toChars(), + // fdv, fdv ->toChars(), fdv ->type->toChars(), fdv ->loc.toChars()); + + // fdc overrides fdv exactly, then this introduces new function. + if (fdc->type->mod == fdv->type->mod && this->type->mod != fdv->type->mod) + goto Lintro; + } + + // This function overrides fdv if (fdv->isFinal()) error("cannot override final function %s", fdv->toPrettyChars()); @@ -557,28 +568,20 @@ void FuncDeclaration::semantic(Scope *sc) ::deprecation(loc, "overriding base class function without using override attribute is deprecated (%s overrides %s)", toPrettyChars(), fdv->toPrettyChars()); #endif - FuncDeclaration *fdc = ((Dsymbol *)cd->vtbl.data[vi])->isFuncDeclaration(); if (fdc->toParent() == parent) { - // fdc overrides fdv exactly, then this introduces new function. - if (fdc->type->mod == fdv->type->mod && this->type->mod != fdv->type->mod) - goto Lintro; - - // If both are mixins, then error. + // If both are mixins, or both are not, then error. // If either is not, the one that is not overrides the other. - if (this->parent->isClassDeclaration() && fdc->parent->isClassDeclaration()) + bool thismixin = this->parent->isClassDeclaration() != NULL; + bool fdcmixin = fdc->parent->isClassDeclaration() != NULL; + if (thismixin == fdcmixin) + { error("multiple overrides of same function"); - - // if (this is mixin) && (fdc is not mixin) then fdc overrides - else if (!this->parent->isClassDeclaration() && fdc->parent->isClassDeclaration()) + } + else if (!thismixin) // fdc overrides fdv + { // this doesn't override any function break; - - else if (!this->parent->isClassDeclaration() // if both are mixins then error -#if DMDV2 - && !isPostBlitDeclaration() -#endif - ) - error("multiple overrides of same function"); + } } cd->vtbl[vi] = this; vtblIndex = vi; @@ -691,9 +694,15 @@ void FuncDeclaration::semantic(Scope *sc) if (!doesoverride && isOverride()) { - Dsymbol *s = cd->search_correct(ident); + Dsymbol *s = NULL; + for (size_t i = 0; i < cd->baseclasses->dim; i++) + { + s = (*cd->baseclasses)[i]->base->search_correct(ident); + if (s) break; + } + if (s) - error("does not override any function, did you mean '%s'", s->toPrettyChars()); + error("does not override any function, did you mean to override '%s'?", s->toPrettyChars()); else error("does not override any function"); } @@ -1030,9 +1039,6 @@ void FuncDeclaration::semantic3(Scope *sc) // Declare hidden variable _arguments[] and _argptr if (f->varargs == 1) { -#if TARGET_NET - varArgs(sc2, f, argptr, _arguments); -#else Type *t; #if !IN_GCC && !IN_LLVM @@ -1072,17 +1078,12 @@ void FuncDeclaration::semantic3(Scope *sc) } if (f->linkage == LINKd || (f->parameters && Parameter::dim(f->parameters))) { // Declare _argptr -#ifdef IN_GCC - t = d_gcc_builtin_va_list_d_type; -#else - t = Type::tvoid->pointerTo(); -#endif + t = Type::tvalist; argptr = new VarDeclaration(0, t, Id::_argptr, NULL); argptr->semantic(sc2); sc2->insert(argptr); argptr->parent = this; } -#endif } #if IN_LLVM @@ -1244,10 +1245,8 @@ void FuncDeclaration::semantic3(Scope *sc) 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(); @@ -1293,10 +1292,8 @@ void FuncDeclaration::semantic3(Scope *sc) 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) @@ -1345,7 +1342,7 @@ void FuncDeclaration::semantic3(Scope *sc) { // If no return type inferred yet, then infer a void if (!type->nextOf()) { - ((TypeFunction *)type)->next = Type::tvoid; + f->next = Type::tvoid; //type = type->semantic(loc, sc); // Removed with 6902 } else if (returns && f->next->ty != Tvoid) @@ -1414,11 +1411,7 @@ void FuncDeclaration::semantic3(Scope *sc) * as delegating calls to other constructors */ if (v->isCtorinit() && !v->type->isMutable() && cd) - { - OutBuffer buf; - MODtoBuffer(&buf, v->type->mod); - error("missing initializer for %s field %s", buf.toChars(), v->toChars()); - } + error("missing initializer for %s field %s", MODtoChars(v->type->mod), v->toChars()); else if (v->storage_class & STCnodefaultctor) error("field %s must be initialized in constructor", v->toChars()); else if (v->type->needsNested()) @@ -1449,6 +1442,20 @@ void FuncDeclaration::semantic3(Scope *sc) fbody = new CompoundStatement(0, s, fbody); } } + + /* Append: + * return this; + * to function body + */ + if (blockexit & BEfallthru) + { + Expression *e = new ThisExp(loc); + if (cd) + e->type = cd->type; + Statement *s = new ReturnStatement(loc, e); + s = s->semantic(sc2); + fbody = new CompoundStatement(loc, fbody, s); + } } else if (fes) { // For foreach(){} body, append a return 0; @@ -1472,7 +1479,10 @@ void FuncDeclaration::semantic3(Scope *sc) if (f->isnothrow && (global.errors != nothrowErrors) ) error("'%s' is nothrow yet may throw", toChars()); if (flags & FUNCFLAGnothrowInprocess) + { + if (type == f) f = f->copy(); f->isnothrow = !(blockexit & BEthrow); + } int offend = blockexit & BEfallthru; #endif @@ -1748,15 +1758,6 @@ void FuncDeclaration::semantic3(Scope *sc) 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; @@ -1782,7 +1783,6 @@ void FuncDeclaration::semantic3(Scope *sc) flags &= ~FUNCFLAGnothrowInprocess; #endif -#if 1 if (isSynchronized()) { /* Wrap the entire function body in a synchronized statement */ @@ -1791,8 +1791,12 @@ void FuncDeclaration::semantic3(Scope *sc) if (cd) { -#if TARGET_WINDOS if (!global.params.is64bit && +#if IN_LLVM + global.params.targetTriple.isOSWindows() && +#else + global.params.isWindows && +#endif !isStatic() && !fbody->usesEH()) { /* The back end uses the "jmonitor" hack for syncing; @@ -1800,7 +1804,6 @@ void FuncDeclaration::semantic3(Scope *sc) */ } else -#endif { Expression *vsync; if (isStatic()) @@ -1821,7 +1824,6 @@ void FuncDeclaration::semantic3(Scope *sc) error("synchronized function %s must be a member of a class", toChars()); } } -#endif } sc2->callSuper = 0; @@ -1833,19 +1835,28 @@ void FuncDeclaration::semantic3(Scope *sc) if (flags & FUNCFLAGpurityInprocess) { flags &= ~FUNCFLAGpurityInprocess; + if (type == f) f = f->copy(); f->purity = PUREfwdref; } if (flags & FUNCFLAGsafetyInprocess) { flags &= ~FUNCFLAGsafetyInprocess; + if (type == f) f = f->copy(); f->trust = TRUSTsafe; } + // reset deco to apply inference result to mangled name + if (f != type) + f->deco = NULL; + // Do semantic type AFTER pure/nothrow inference. - if (inferRetType) + if (!f->deco) { - type = type->semantic(loc, sc); + sc = sc->push(); + sc->linkage = linkage; // Bugzilla 8496 + type = f->semantic(loc, sc); + sc = sc->pop(); } if (global.gag && global.errors != nerrors) @@ -1868,13 +1879,82 @@ void FuncDeclaration::semantic3(Scope *sc) //fflush(stdout); } +bool FuncDeclaration::functionSemantic() +{ + if (scope && !originalType) // semantic not yet run + { + TemplateInstance *spec = isSpeculative(); + unsigned olderrs = global.errors; + unsigned oldgag = global.gag; + if (global.gag && !spec) + global.gag = 0; + semantic(scope); + global.gag = oldgag; + if (spec && global.errors != olderrs) + spec->errors = global.errors - olderrs; + if (olderrs != global.errors) // if errors compiling this function + return false; + } + + // if inferring return type, sematic3 needs to be run + if (scope && (inferRetType && type && !type->nextOf() || + getFuncTemplateDecl(this))) + { + return functionSemantic3(); + } + + return true; +} + +bool FuncDeclaration::functionSemantic3() +{ + if (semanticRun < PASSsemantic3 && scope) + { + /* Forward reference - we need to run semantic3 on this function. + * If errors are gagged, and it's not part of a speculative + * template instance, we need to temporarily ungag errors. + */ + TemplateInstance *spec = isSpeculative(); + unsigned olderrs = global.errors; + unsigned oldgag = global.gag; + if (global.gag && !spec) + global.gag = 0; + semantic3(scope); + global.gag = oldgag; + + // If it is a speculatively-instantiated template, and errors occur, + // we need to mark the template as having errors. + if (spec && global.errors != olderrs) + spec->errors = global.errors - olderrs; + if (olderrs != global.errors) // if errors compiling this function + return false; + } + + return true; +} + void FuncDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { //printf("FuncDeclaration::toCBuffer() '%s'\n", toChars()); StorageClassDeclaration::stcToCBuffer(buf, storage_class); type->toCBuffer(buf, ident, hgs); - bodyToCBuffer(buf, hgs); + if(hgs->hdrgen == 1) + { + if(storage_class & STCauto) + { + hgs->autoMember++; + bodyToCBuffer(buf, hgs); + hgs->autoMember--; + } + else if(hgs->tpltMember == 0 && global.params.useInline == 0) + buf->writestring(";"); + else + bodyToCBuffer(buf, hgs); + } + else + bodyToCBuffer(buf, hgs); + buf->writenl(); } VarDeclaration *FuncDeclaration::declareThis(Scope *sc, AggregateDeclaration *ad) @@ -1885,43 +1965,15 @@ VarDeclaration *FuncDeclaration::declareThis(Scope *sc, AggregateDeclaration *ad { assert(ad->handle); Type *thandle = ad->handle; -#if STRUCTTHISREF thandle = thandle->addMod(type->mod); thandle = thandle->addStorageClass(storage_class); //if (isPure()) //thandle = thandle->addMod(MODconst); -#else - if (storage_class & STCconst || type->isConst()) - { - assert(0); // BUG: shared not handled - if (thandle->ty == Tclass) - thandle = thandle->constOf(); - else - { assert(thandle->ty == Tpointer); - thandle = thandle->nextOf()->constOf()->pointerTo(); - } - } - else if (storage_class & STCimmutable || type->isImmutable()) - { - if (thandle->ty == Tclass) - thandle = thandle->invariantOf(); - else - { assert(thandle->ty == Tpointer); - thandle = thandle->nextOf()->invariantOf()->pointerTo(); - } - } - else if (storage_class & STCshared || type->isShared()) - { - assert(0); // not implemented - } -#endif v = new ThisDeclaration(loc, thandle); //v = new ThisDeclaration(loc, isCtorDeclaration() ? ad->handle : thandle); v->storage_class |= STCparameter; -#if STRUCTTHISREF if (thandle->ty == Tstruct) v->storage_class |= STCref; -#endif v->semantic(sc); if (!sc->insert(v)) assert(0); @@ -1969,21 +2021,27 @@ int FuncDeclaration::equals(Object *o) void FuncDeclaration::bodyToCBuffer(OutBuffer *buf, HdrGenState *hgs) { - if (fbody && - (!hgs->hdrgen || hgs->tpltMember || canInline(1,1,1)) - ) - { buf->writenl(); + if (fbody && (!hgs->hdrgen || global.params.useInline || hgs->autoMember || hgs->tpltMember)) + { + int savetlpt = hgs->tpltMember; + int saveauto = hgs->autoMember; + hgs->tpltMember = 0; + hgs->autoMember = 0; + + buf->writenl(); // in{} if (frequire) - { buf->writestring("in"); + { + buf->writestring("in"); buf->writenl(); frequire->toCBuffer(buf, hgs); } // out{} if (fensure) - { buf->writestring("out"); + { + buf->writestring("out"); if (outId) { buf->writebyte('('); buf->writestring(outId->toChars()); @@ -1994,7 +2052,8 @@ void FuncDeclaration::bodyToCBuffer(OutBuffer *buf, HdrGenState *hgs) } if (frequire || fensure) - { buf->writestring("body"); + { + buf->writestring("body"); buf->writenl(); } @@ -2005,6 +2064,9 @@ void FuncDeclaration::bodyToCBuffer(OutBuffer *buf, HdrGenState *hgs) buf->level--; buf->writebyte('}'); buf->writenl(); + + hgs->tpltMember = savetlpt; + hgs->autoMember = saveauto; } else { buf->writeByte(';'); @@ -2654,6 +2716,28 @@ void overloadResolveX(Match *m, FuncDeclaration *fstart, overloadApply(fstart, &fp2, &p); } +static void MODMatchToBuffer(OutBuffer *buf, unsigned char lhsMod, unsigned char rhsMod) +{ + bool bothMutable = ((lhsMod & rhsMod) == 0); + bool sharedMismatch = ((lhsMod ^ rhsMod) & MODshared); + bool sharedMismatchOnly = ((lhsMod ^ rhsMod) == MODshared); + + if (lhsMod & MODshared) + buf->writestring("shared "); + else if (sharedMismatch && !(lhsMod & MODimmutable)) + buf->writestring("non-shared "); + + if (bothMutable && sharedMismatchOnly) + { } + else if (lhsMod & MODimmutable) + buf->writestring("immutable "); + else if (lhsMod & MODconst) + buf->writestring("const "); + else if (lhsMod & MODwild) + buf->writestring("inout "); + else + buf->writestring("mutable "); +} FuncDeclaration *FuncDeclaration::overloadResolve(Loc loc, Expression *ethis, Expressions *arguments, int flags, Module* from) { @@ -2704,15 +2788,23 @@ if (arguments) return NULL; // no match tf = (TypeFunction *)type; + if (ethis && !MODimplicitConv(ethis->type->mod, tf->mod)) // modifier mismatch + { + OutBuffer thisBuf, funcBuf; + MODMatchToBuffer(&thisBuf, ethis->type->mod, tf->mod); + MODMatchToBuffer(&funcBuf, tf->mod, ethis->type->mod); + ::error(loc, "%smethod %s is not callable using a %sobject", + funcBuf.toChars(), this->toPrettyChars(), thisBuf.toChars()); + } + else + { + //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), + tf->modToChars(), + buf.toChars()); + } - OutBuffer buf2; - tf->modToBuffer(&buf2); - - //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(), - buf.toChars()); return m.anyf; // as long as it's not a FuncAliasDeclaration } else @@ -3144,6 +3236,8 @@ enum PURE FuncDeclaration::isPure() if (tf->purity == PUREfwdref) tf->purityLevel(); enum PURE purity = tf->purity; + if (purity > PUREweak && isNested()) + purity = PUREweak; if (purity > PUREweak && needThis()) { // The attribute of the 'this' reference affects purity strength if (type->mod & (MODimmutable | MODwild)) @@ -3317,14 +3411,24 @@ const char *FuncDeclaration::kind() return "function"; } +/********************************************* + * In the current function, we are calling 'this' function. + * 1. Check to see if the current function can call 'this' function, issue error if not. + * 2. If the current function is not the parent of 'this' function, then add + * the current function to the list of siblings of 'this' function. + * 3. If the current function is a literal, and it's accessing an uplevel scope, + * then mark it as a delegate. + */ + void FuncDeclaration::checkNestedReference(Scope *sc, Loc loc) { - //printf("FuncDeclaration::checkNestedReference() %s\n", toChars()); + //printf("FuncDeclaration::checkNestedReference() %s\n", toPrettyChars()); if (parent && parent != sc->parent && this->isNested() && this->ident != Id::require && this->ident != Id::ensure) { // The function that this function is in - FuncDeclaration *fdv = toParent()->isFuncDeclaration(); + FuncDeclaration *fdv2 = toParent2()->isFuncDeclaration(); + // The current function FuncDeclaration *fdthis = sc->parent->isFuncDeclaration(); @@ -3332,13 +3436,35 @@ void FuncDeclaration::checkNestedReference(Scope *sc, Loc loc) //printf("fdv = %s in [%s]\n", fdv->toChars(), fdv->loc.toChars()); //printf("fdthis = %s in [%s]\n", fdthis->toChars(), fdthis->loc.toChars()); + if (fdv2 && fdthis && fdv2 != fdthis) + { + // Add this function to the list of those which called us + if (fdthis != this) + { + bool found = false; + for (int i = 0; i < siblingCallers.dim; ++i) + { if (siblingCallers[i] == fdthis) + found = true; + } + if (!found) + { + //printf("\tadding sibling %s\n", fdthis->toPrettyChars()); + siblingCallers.push(fdthis); + } + } + } + + FuncDeclaration *fdv = toParent()->isFuncDeclaration(); + fdv = toParent()->isFuncDeclaration(); if (fdv && fdthis && fdv != fdthis) { int lv = fdthis->getLevel(loc, sc, fdv); if (lv == -1) - return; // OK + return; // downlevel call if (lv == 0) - return; // OK + return; // same level call + + // Uplevel call // BUG: may need to walk up outer scopes like Declaration::checkNestedReference() does @@ -3349,6 +3475,52 @@ void FuncDeclaration::checkNestedReference(Scope *sc, Loc loc) } } +/* For all functions between outerFunc and f, mark them as needing + * a closure. + */ +void markAsNeedingClosure(Dsymbol *f, FuncDeclaration *outerFunc) +{ + for (Dsymbol *sx = f; sx != outerFunc; sx = sx->parent) + { + FuncDeclaration *fy = sx->isFuncDeclaration(); + if (fy && fy->closureVars.dim) + { + /* fy needs a closure if it has closureVars[], + * because the frame pointer in the closure will be accessed. + */ + fy->requiresClosure = true; + } + } +} + + +/* Given a nested function f inside a function outerFunc, check + * if any sibling callers of f have escaped. If so, mark + * all the enclosing functions as needing closures. + * Return true if any closures were detected. + * This is recursive: we need to check the callers of our siblings. + * Note that nested functions can only call lexically earlier nested + * functions, so loops are impossible. + */ +bool checkEscapingSiblings(FuncDeclaration *f, FuncDeclaration *outerFunc) +{ + //printf("checkEscapingSiblings(f = %s, outerfunc = %s)\n", f->toChars(), outerFunc->toChars()); + bool bAnyClosures = false; + for (int i = 0; i < f->siblingCallers.dim; ++i) + { + FuncDeclaration *g = f->siblingCallers[i]; + if (g->isThis() || g->tookAddressOf) + { + markAsNeedingClosure(g, outerFunc); + bAnyClosures = true; + } + bAnyClosures |= checkEscapingSiblings(g, outerFunc); + } + //printf("\t%d\n", bAnyClosures); + return bAnyClosures; +} + + /******************************* * Look at all the variables in this function that are referenced * by nested functions, and determine if a closure needs to be @@ -3361,12 +3533,14 @@ int FuncDeclaration::needsClosure() /* Need a closure for all the closureVars[] if any of the * closureVars[] are accessed by a * function that escapes the scope of this function. - * We take the conservative approach and decide that any function that: + * We take the conservative approach and decide that a function needs + * a closure if it: * 1) is a virtual function * 2) has its address taken * 3) has a parent that escapes + * 4) calls another nested function that needs a closure * -or- - * 4) this function returns a local struct/class + * 5) this function returns a local struct/class * * Note that since a non-virtual function can be called by * a virtual one, if that non-virtual function accesses a closure @@ -3390,7 +3564,11 @@ int FuncDeclaration::needsClosure() //printf("\t\tf = %s, isVirtual=%d, isThis=%p, tookAddressOf=%d\n", f->toChars(), f->isVirtual(), f->isThis(), f->tookAddressOf); - // Look to see if f or any parents of f that are below this escape + /* Look to see if f escapes. We consider all parents of f within + * this, and also all siblings which call f; if any of them escape, + * so does f. + * Mark all affected functions as requiring closures. + */ for (Dsymbol *s = f; s && s != this; s = s->parent) { FuncDeclaration *fx = s->isFuncDeclaration(); @@ -3400,26 +3578,22 @@ int FuncDeclaration::needsClosure() /* Mark as needing closure any functions between this and f */ - for (Dsymbol *sx = fx; sx != this; sx = sx->parent) - { - if (sx != f) - { FuncDeclaration *fy = sx->isFuncDeclaration(); - if (fy && fy->closureVars.dim) - { - /* fy needs a closure if it has closureVars[], - * because the frame pointer in the closure will be accessed. - */ - fy->requiresClosure = true; - } - } - } + markAsNeedingClosure( (fx == f) ? fx->parent : fx, this); + goto Lyes; } + + /* We also need to check if any sibling functions that + * called us, have escaped. This is recursive: we need + * to check the callers of our siblings. + */ + if (fx && checkEscapingSiblings(fx, this)) + goto Lyes; } } } - /* Look for case (4) + /* Look for case (5) */ if (closureVars.dim) { @@ -3610,10 +3784,31 @@ const char *FuncLiteralDeclaration::kind() void FuncLiteralDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { - buf->writestring(kind()); - buf->writeByte(' '); - type->toCBuffer(buf, NULL, hgs); - bodyToCBuffer(buf, hgs); + if (tok != TOKreserved) + { + buf->writestring(kind()); + buf->writeByte(' '); + } + + TypeFunction *tf = (TypeFunction *)type; + // Don't print tf->mod, tf->trust, and tf->linkage + if (tf->next) + tf->next->toCBuffer2(buf, hgs, 0); + Parameter::argsToCBuffer(buf, hgs, tf->parameters, tf->varargs); + + ReturnStatement *ret = !fbody->isCompoundStatement() ? + fbody->isReturnStatement() : NULL; + if (ret && ret->exp) + { + buf->writestring(" => "); + ret->exp->toCBuffer(buf, hgs); + } + else + { + hgs->tpltMember++; + bodyToCBuffer(buf, hgs); + hgs->tpltMember--; + } } @@ -3676,22 +3871,8 @@ void CtorDeclaration::semantic(Scope *sc) originalType = type->syntaxCopy(); type = type->semantic(loc, sc); -#if STRUCTTHISREF if (ad && ad->isStructDeclaration()) ((TypeFunction *)type)->isref = 1; -#endif - - // Append: - // return this; - // to the function body - if (fbody && semanticRun < PASSsemantic) - { - ThisExp *e = new ThisExp(loc); - if (parent->isClassDeclaration()) - e->type = tret; - Statement *s = new ReturnStatement(loc, e); - fbody = new CompoundStatement(loc, fbody, s); - } FuncDeclaration::semantic(sc); @@ -3979,9 +4160,6 @@ void StaticCtorDeclaration::semantic(Scope *sc) if (m) { m->needmoduleinfo = 1; //printf("module1 %s needs moduleinfo\n", m->toChars()); -#ifdef IN_GCC - m->strictlyneedmoduleinfo = 1; -#endif } } @@ -4013,7 +4191,8 @@ int StaticCtorDeclaration::addPostInvariant() void StaticCtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { if (hgs->hdrgen && !hgs->tpltMember) - { buf->writestring("static this();"); + { + buf->writestring("static this();"); buf->writenl(); return; } @@ -4116,9 +4295,6 @@ void StaticDtorDeclaration::semantic(Scope *sc) if (m) { m->needmoduleinfo = 1; //printf("module2 %s needs moduleinfo\n", m->toChars()); -#ifdef IN_GCC - m->strictlyneedmoduleinfo = 1; -#endif } } diff --git a/dmd2/hdrgen.c b/dmd2/hdrgen.c index 6ba45e2d..a1e288e8 100644 --- a/dmd2/hdrgen.c +++ b/dmd2/hdrgen.c @@ -66,10 +66,7 @@ void Module::genhdrfile() hdrfile->setbuffer(hdrbufr.data, hdrbufr.offset); hdrbufr.data = NULL; - char *pt = FileName::path(hdrfile->toChars()); - if (*pt) - FileName::ensurePathExists(pt); - mem.free(pt); + FileName::ensurePathToNameExists(hdrfile->toChars()); hdrfile->writev(); } diff --git a/dmd2/hdrgen.h b/dmd2/hdrgen.h index 19900fed..cce63383 100644 --- a/dmd2/hdrgen.h +++ b/dmd2/hdrgen.h @@ -23,6 +23,8 @@ struct HdrGenState int inBinExp; int inArrExp; int emitInst; + int autoMember; + struct { int init; @@ -31,6 +33,4 @@ struct HdrGenState Scope* scope; // Scope when generating ddoc HdrGenState() { memset(this, 0, sizeof(HdrGenState)); } -}; - - +}; \ No newline at end of file diff --git a/dmd2/idgen.c b/dmd2/idgen.c index edd66bf9..eb156eb5 100644 --- a/dmd2/idgen.c +++ b/dmd2/idgen.c @@ -4,7 +4,6 @@ // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com -// http://www.dsource.org/projects/dmd/browser/trunk/src/idgen.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. diff --git a/dmd2/import.c b/dmd2/import.c index 0d8a7b80..a9fecd1e 100644 --- a/dmd2/import.c +++ b/dmd2/import.c @@ -93,8 +93,6 @@ void Import::load(Scope *sc) // See if existing module DsymbolTable *dst = Package::resolve(packages, NULL, &pkg); -#if TARGET_NET //dot net needs modules and packages with same name -#else if (pkg && pkg->isModule()) { ::error(loc, "can only import from a module, not from a member of module %s. Did you mean `import %s : %s`?", @@ -102,13 +100,9 @@ void Import::load(Scope *sc) mod = pkg->isModule(); // Error recovery - treat as import of that module return; } -#endif Dsymbol *s = dst->lookup(id); if (s) { -#if TARGET_NET - mod = (Module *)s; -#else if (s->isModule()) mod = (Module *)s; else @@ -124,7 +118,6 @@ void Import::load(Scope *sc) id->toChars()); } } -#endif } if (!mod) @@ -187,6 +180,11 @@ void Import::semantic(Scope *sc) { //printf("Import::semantic('%s')\n", toChars()); + if (scope) + { sc = scope; + scope = NULL; + } + // Load if not already done so if (!mod) { load(sc); @@ -241,14 +239,17 @@ void Import::semantic(Scope *sc) sc->protection = PROTpublic; #endif for (size_t i = 0; i < aliasdecls.dim; i++) - { Dsymbol *s = aliasdecls[i]; + { AliasDeclaration *ad = aliasdecls[i]; //printf("\tImport alias semantic('%s')\n", s->toChars()); if (mod->search(loc, names[i], 0)) - s->semantic(sc); + { + ad->semantic(sc); + ad->import = NULL; // forward reference resolved + } else { - s = mod->search_correct(names[i]); + Dsymbol *s = mod->search_correct(names[i]); if (s) mod->error(loc, "import '%s' not found, did you mean '%s %s'?", names[i]->toChars(), s->kind(), s->toChars()); else @@ -381,6 +382,7 @@ int Import::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) TypeIdentifier *tname = new TypeIdentifier(loc, name); AliasDeclaration *ad = new AliasDeclaration(loc, alias, tname); + ad->import = this; result |= ad->addMember(sc, sd, memnum); aliasdecls.push(ad); diff --git a/dmd2/import.h b/dmd2/import.h index a3ef1a55..5549a82b 100644 --- a/dmd2/import.h +++ b/dmd2/import.h @@ -59,6 +59,7 @@ struct Import : Dsymbol Dsymbol *search(Loc loc, Identifier *ident, int flags); int overloadInsert(Dsymbol *s); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void toJson(JsonOut *json); Import *isImport() { return this; } }; diff --git a/dmd2/init.h b/dmd2/init.h index ecc4c151..88db7487 100644 --- a/dmd2/init.h +++ b/dmd2/init.h @@ -123,7 +123,6 @@ struct ArrayInitializer : Initializer #if IN_DMD dt_t *toDt(); - dt_t *toDtBit(); // for bit arrays #endif ArrayInitializer *isArrayInitializer() { return this; } diff --git a/dmd2/inline.c b/dmd2/inline.c index 6198eb78..3b3313d6 100644 --- a/dmd2/inline.c +++ b/dmd2/inline.c @@ -1647,7 +1647,6 @@ Expression *FuncDeclaration::expandInline(InlineScanState *iss, Expression *ethi ExpInitializer *ei; VarExp *ve; -#if STRUCTTHISREF if (ethis->type->ty == Tpointer) { Type *t = ethis->type->nextOf(); ethis = new PtrExp(ethis->loc, ethis); @@ -1660,17 +1659,6 @@ Expression *FuncDeclaration::expandInline(InlineScanState *iss, Expression *ethi vthis->storage_class = STCref; else vthis->storage_class = STCin; -#else - if (ethis->type->ty != Tclass && ethis->type->ty != Tpointer) - { - ethis = ethis->addressOf(NULL); - } - - ei = new ExpInitializer(ethis->loc, ethis); - - vthis = new VarDeclaration(ethis->loc, ethis->type, Id::This, ei); - vthis->storage_class = STCin; -#endif vthis->linkage = LINKd; vthis->parent = iss->fd; @@ -1679,13 +1667,11 @@ Expression *FuncDeclaration::expandInline(InlineScanState *iss, Expression *ethi ei->exp = new AssignExp(vthis->loc, ve, ethis); ei->exp->type = ve->type; -#if STRUCTTHISREF if (ethis->type->ty != Tclass) { /* This is a reference initialization, not a simple assignment. */ ei->exp->op = TOKconstruct; } -#endif ids.vthis = vthis; } diff --git a/dmd2/interpret.c b/dmd2/interpret.c index 49e456e7..d9284786 100644 --- a/dmd2/interpret.c +++ b/dmd2/interpret.c @@ -278,29 +278,8 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument error("circular dependency. Functions cannot be interpreted while being compiled"); return EXP_CANT_INTERPRET; } - if (semanticRun < PASSsemantic3 && scope) - { - /* Forward reference - we need to run semantic3 on this function. - * If errors are gagged, and it's not part of a speculative - * template instance, we need to temporarily ungag errors. - */ - int olderrors = global.errors; - int oldgag = global.gag; - TemplateInstance *spec = isSpeculative(); - if (global.gag && !spec) - global.gag = 0; - ++scope->ignoreTemplates; - semantic3(scope); - --scope->ignoreTemplates; - global.gag = oldgag; // regag errors - - // If it is a speculatively-instantiated template, and errors occur, - // we need to mark the template as having errors. - if (spec && global.errors != olderrors) - spec->errors = global.errors - olderrors; - if (olderrors != global.errors) // if errors compiling this function - return EXP_CANT_INTERPRET; - } + if (!functionSemantic3()) + return EXP_CANT_INTERPRET; if (semanticRun < PASSsemantic3done) return EXP_CANT_INTERPRET; @@ -1325,6 +1304,11 @@ Expression *WithStatement::interpret(InterState *istate) #if LOG printf("%s WithStatement::interpret()\n", loc.toChars()); #endif + + // If it is with(Enum) {...}, just execute the body. + if (exp->op == TOKimport || exp->op == TOKtype) + return body ? body->interpret(istate) : EXP_VOID_INTERPRET; + START() Expression *e = exp->interpret(istate); if (exceptionOrCantInterpret(e)) @@ -4051,25 +4035,16 @@ Expression *CallExp::interpret(InterState *istate, CtfeGoal goal) } if (pthis) { // Member function call - Expression *oldpthis; - if (pthis->op == TOKthis) - { - pthis = istate ? istate->localThis : NULL; - oldpthis = pthis; - } - else - { - if (pthis->op == TOKcomma) - pthis = pthis->interpret(istate); - if (exceptionOrCantInterpret(pthis)) - return pthis; - // Evaluate 'this' - oldpthis = pthis; - if (pthis->op != TOKvar) - pthis = pthis->interpret(istate, ctfeNeedLvalue); - if (exceptionOrCantInterpret(pthis)) - return pthis; - } + if (pthis->op == TOKcomma) + pthis = pthis->interpret(istate); + if (exceptionOrCantInterpret(pthis)) + return pthis; + // Evaluate 'this' + Expression *oldpthis = pthis; + if (pthis->op != TOKvar) + pthis = pthis->interpret(istate, ctfeNeedLvalue); + if (exceptionOrCantInterpret(pthis)) + return pthis; if (fd->isVirtual()) { // Make a virtual function call. Expression *thisval = pthis; diff --git a/dmd2/json.c b/dmd2/json.c index fc4ca016..24503b07 100644 --- a/dmd2/json.c +++ b/dmd2/json.c @@ -1,6 +1,5 @@ - // Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars +// Copyright (c) 1999-2013 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -12,92 +11,122 @@ #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 "json.h" #include "mtype.h" #include "attrib.h" #include "cond.h" +#include "init.h" +#include "import.h" +#include "id.h" -const char Pname[] = "name"; -const char Pkind[] = "kind"; -const char Pfile[] = "file"; -const char Pline[] = "line"; -const char Ptype[] = "type"; -const char Pcomment[] = "comment"; -const char Pmembers[] = "members"; -const char Pprotection[] = "protection"; +struct JsonOut +{ + OutBuffer *buf; + int indentLevel; + const char *filename; -void JsonRemoveComma(OutBuffer *buf); + JsonOut(OutBuffer *buf) {this->buf = buf; indentLevel = 0; filename = NULL;} -void json_generate(Modules *modules) -{ OutBuffer buf; + void indent(); + void removeComma(); + void comma(); + void stringStart(); + void stringEnd(); + void stringPart(const char* part); - buf.writestring("[\n"); + void value(const char* s); + void value(int value); + void valueBool(bool value); + + void item(const char*); + void item(int); + void itemBool(bool); + + + void arrayStart(); + void arrayEnd(); + void objectStart(); + void objectEnd(); + + void propertyStart(const char* name); + + void property(const char *name, const char* s); + void property(const char *name, int value); + void propertyBool(const char *name, bool value); + void propertyStorageClass(const char *name, StorageClass stc); + void property(const char *name, Loc* loc); + void property(const char *name, Type* type); + void property(const char *name, const char *deconame, Type* type); + void property(const char *name, Parameters* parameters); + void property(const char *name, Expressions* expressions); + void property(const char *name, enum TRUST trust); + void property(const char *name, enum PURE purity); + void property(const char *name, enum LINK linkage); +}; + + +void json_generate(OutBuffer *buf, Modules *modules) +{ + JsonOut json(buf); + + json.arrayStart(); for (size_t i = 0; i < modules->dim; i++) { Module *m = (*modules)[i]; if (global.params.verbose) printf("json gen %s\n", m->toChars()); - m->toJsonBuffer(&buf); - buf.writestring(",\n"); + m->toJson(&json); } - JsonRemoveComma(&buf); - buf.writestring("]\n"); - - // Write buf to file - char *arg = global.params.xfilename; - if (!arg || !*arg) - { // Generate lib file name from first obj name - char *n = (*global.params.objfiles)[0]; - - n = FileName::name(n); - FileName *fn = FileName::forceExt(n, global.json_ext); - arg = fn->toChars(); - } - else if (arg[0] == '-' && arg[1] == 0) - { // Write to stdout; assume it succeeds - size_t n = fwrite(buf.data, 1, buf.offset, stdout); - assert(n == buf.offset); // keep gcc happy about return values - return; - } -// if (!FileName::absolute(arg)) -// arg = FileName::combine(dir, arg); - FileName *jsonfilename = FileName::defaultExt(arg, global.json_ext); - File *jsonfile = new File(jsonfilename); - assert(jsonfile); - jsonfile->setbuffer(buf.data, buf.offset); - jsonfile->ref = 1; - char *pt = FileName::path(jsonfile->toChars()); - if (*pt) - FileName::ensurePathExists(pt); - mem.free(pt); - jsonfile->writev(); + json.arrayEnd(); + json.removeComma(); } -/********************************* - * Encode string into buf, and wrap it in double quotes. - */ -void JsonString(OutBuffer *buf, const char *s) + + +void JsonOut::indent() +{ + if (buf->offset >= 1 && + buf->data[buf->offset - 1] == '\n') + for (int i = 0; i < indentLevel; i++) + buf->writeByte(' '); +} + +void JsonOut::removeComma() +{ + if (buf->offset >= 2 && + buf->data[buf->offset - 2] == ',' && + (buf->data[buf->offset - 1] == '\n' || buf->data[buf->offset - 1] == ' ')) + buf->offset -= 2; +} + +void JsonOut::comma() +{ + if (indentLevel > 0) + buf->writestring(",\n"); +} + +void JsonOut::stringStart() { buf->writeByte('\"'); +} + +void JsonOut::stringEnd() +{ + buf->writeByte('\"'); +} + +void JsonOut::stringPart(const char *s) +{ for (; *s; s++) { unsigned char c = (unsigned char) *s; @@ -123,10 +152,6 @@ void JsonString(OutBuffer *buf, const char *s) buf->writestring("\\\\"); break; - case '/': - buf->writestring("\\/"); - break; - case '\b': buf->writestring("\\b"); break; @@ -144,318 +169,923 @@ void JsonString(OutBuffer *buf, const char *s) break; } } - buf->writeByte('\"'); } -void JsonProperty(OutBuffer *buf, const char *name, const char *value) + +// Json value functions + +/********************************* + * Encode string into buf, and wrap it in double quotes. + */ +void JsonOut::value(const char *s) { - JsonString(buf, name); - buf->writestring(" : "); - JsonString(buf, value); - buf->writestring(",\n"); + stringStart(); + stringPart(s); + stringEnd(); } -void JsonProperty(OutBuffer *buf, const char *name, int value) +void JsonOut::value(int value) { - JsonString(buf, name); - buf->writestring(" : "); buf->printf("%d", value); - buf->writestring(",\n"); } -void JsonRemoveComma(OutBuffer *buf) +void JsonOut::valueBool(bool value) { + buf->writestring(value? "true" : "false"); +} + +/********************************* + * Item is an intented value and a comma, for use in arrays + */ +void JsonOut::item(const char *s) +{ + indent(); + value(s); + comma(); +} + +void JsonOut::item(int i) +{ + indent(); + value(i); + comma(); +} + +void JsonOut::itemBool(bool b) +{ + indent(); + valueBool(b); + comma(); +} + + +// Json array functions + +void JsonOut::arrayStart() +{ + indent(); + buf->writestring("[\n"); + indentLevel++; +} + +void JsonOut::arrayEnd() +{ + indentLevel--; + removeComma(); if (buf->offset >= 2 && - buf->data[buf->offset - 2] == ',' && + buf->data[buf->offset - 2] == '[' && buf->data[buf->offset - 1] == '\n') - buf->offset -= 2; + buf->offset -= 1; + else if (!(buf->offset >= 1 && + buf->data[buf->offset - 1] == '[')) + { + buf->writestring("\n"); + indent(); + } + buf->writestring("]"); + comma(); } -void Dsymbol::toJsonBuffer(OutBuffer *buf) -{ -} -void Module::toJsonBuffer(OutBuffer *buf) +// Json object functions + +void JsonOut::objectStart() { + indent(); buf->writestring("{\n"); + indentLevel++; +} - if (md) - JsonProperty(buf, Pname, md->toChars()); +void JsonOut::objectEnd() +{ + indentLevel--; + removeComma(); + if (buf->offset >= 2 && + buf->data[buf->offset - 2] == '{' && + buf->data[buf->offset - 1] == '\n') + buf->offset -= 1; + else + { + buf->writestring("\n"); + indent(); + } + buf->writestring("}"); + comma(); +} - JsonProperty(buf, Pkind, kind()); - JsonProperty(buf, Pfile, srcfile->toChars()); - if (comment) - JsonProperty(buf, Pcomment, (const char *)comment); +// Json object property functions - JsonString(buf, Pmembers); - buf->writestring(" : [\n"); +void JsonOut::propertyStart(const char *name) +{ + indent(); + value(name); + buf->writestring(" : "); +} - size_t offset = buf->offset; - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = (*members)[i]; - if (offset != buf->offset) - { buf->writestring(",\n"); - offset = buf->offset; +void JsonOut::property(const char *name, const char *s) +{ + if (s == NULL) return; + + propertyStart(name); + value(s); + comma(); +} + +void JsonOut::property(const char *name, int i) +{ + propertyStart(name); + value(i); + comma(); +} + +void JsonOut::propertyBool(const char *name, bool b) +{ + propertyStart(name); + valueBool(b); + comma(); +} + + +void JsonOut::property(const char *name, enum TRUST trust) +{ + switch (trust) + { + case TRUSTdefault: + // Should not be printed + //property(name, "default"); + break; + case TRUSTsystem: + property(name, "system"); + break; + case TRUSTtrusted: + property(name, "trusted"); + break; + case TRUSTsafe: + property(name, "safe"); + break; + default: + assert(false); + } +} + +void JsonOut::property(const char *name, enum PURE purity) +{ + switch (purity) + { + case PUREimpure: + // Should not be printed + //property(name, "impure"); + break; + case PUREweak: + property(name, "weak"); + break; + case PUREconst: + property(name, "const"); + break; + case PUREstrong: + property(name, "strong"); + break; + case PUREfwdref: + property(name, "fwdref"); + break; + default: + assert(false); + } +} + +void JsonOut::property(const char *name, enum LINK linkage) +{ + switch (linkage) + { + case LINKdefault: + // Should not be printed + //property(name, "default"); + break; + case LINKd: + // Should not be printed + //property(name, "d"); + break; + case LINKc: + property(name, "c"); + break; + case LINKcpp: + property(name, "cpp"); + break; + case LINKwindows: + property(name, "windows"); + break; + case LINKpascal: + property(name, "pascal"); + break; + default: + assert(false); + } +} + +void JsonOut::propertyStorageClass(const char *name, StorageClass stc) +{ + stc &= STCStorageClass; + if (stc) + { + propertyStart(name); + arrayStart(); + + while (stc) + { char tmp[20]; + const char *p = StorageClassDeclaration::stcToChars(tmp, stc); + assert(p); + assert(strlen(p) < sizeof(tmp)); + if (p[0] == '@') + { + indent(); + stringStart(); + buf->writestring(p); + stringEnd(); + comma(); + } + else + item(p); } - s->toJsonBuffer(buf); + + arrayEnd(); + } +} + +void JsonOut::property(const char *name, Loc *loc) +{ + if (loc) + { + const char *filename = loc->filename; + if (filename) + { + if (!this->filename || strcmp(filename, this->filename)) + { this->filename = filename; + property("file", filename); + } + } + + if (loc->linnum) + property(name, loc->linnum); + } +} + +void JsonOut::property(const char *name, Type *type) +{ + if (type) + { + property(name, type->toChars()); + } +} + +void JsonOut::property(const char *name, const char *deconame, Type *type) +{ + if (type) + { + if (type->deco) + property(deconame, type->deco); + else + property(name, type->toChars()); + } +} + +void JsonOut::property(const char *name, Parameters *parameters) +{ + if (parameters == NULL || parameters->dim == 0) + return; + + propertyStart(name); + arrayStart(); + + if (parameters) + for (size_t i = 0; i < parameters->dim; i++) + { Parameter *p = (*parameters)[i]; + objectStart(); + + if (p->ident) + property("name", p->ident->toChars()); + + property("type", "deco", p->type); + + propertyStorageClass("storageClass", p->storageClass); + + if (p->defaultArg) + property("default", p->defaultArg->toChars()); + + + objectEnd(); + } + + arrayEnd(); +} + +/* ========================================================================== */ + +void Type::toJson(JsonOut *json) +{ +} + +void TypeSArray::toJson(JsonOut *json) +{ + json->property("elementType", next); + json->property("dim", dim->toChars()); +} + +void TypeDArray::toJson(JsonOut *json) +{ + json->property("elementType", next); +} + +void TypeAArray::toJson(JsonOut *json) +{ + json->property("elementType", next); + json->property("index", index); +} + +void TypePointer::toJson(JsonOut *json) +{ + json->property("targetType", next); +} + +void TypeReference::toJson(JsonOut *json) +{ + json->property("targetType", next); +} + +void TypeFunction::toJson(JsonOut *json) +{ + if (purity || isnothrow || isproperty || isref) + { + json->propertyStart("attributes"); + json->arrayStart(); + if (purity) json->item("pure"); + if (isnothrow) json->item("nothrow"); + if (isproperty) json->item("@property"); + if (isref) json->item("ref"); + json->arrayEnd(); } - JsonRemoveComma(buf); - buf->writestring("]\n"); + json->property("trust", trust); + json->property("purity", purity); + json->property("linkage", linkage); - buf->writestring("}\n"); + json->property("returnType", next); + json->property("parameters", parameters); } -void AttribDeclaration::toJsonBuffer(OutBuffer *buf) +void TypeDelegate::toJson(JsonOut *json) { - //printf("AttribDeclaration::toJsonBuffer()\n"); + next->toJson(json); // next is TypeFunction +} +void TypeQualified::toJson(JsonOut *json) // ident.ident.ident.etc +{ + json->propertyStart("idents"); + json->arrayStart(); + + for (size_t i = 0; i < idents.dim; i++) + { Identifier *ident = idents[i]; + json->item(ident->toChars()); + } + + json->arrayEnd(); +} + +void TypeIdentifier::toJson(JsonOut *json) +{ + TypeQualified::toJson(json); + json->property("rawIdentifier", ident->toChars()); + json->property("identifier", ident->toHChars2()); +} + +void TypeInstance::toJson(JsonOut *json) +{ + TypeQualified::toJson(json); + json->property("tempinst", tempinst->toChars()); +} + +void TypeTypeof::toJson(JsonOut *json) +{ + TypeQualified::toJson(json); + json->property("exp", exp->toChars()); + json->property("type", exp->type); +} + +void TypeReturn::toJson(JsonOut *json) +{ + TypeQualified::toJson(json); +} + +void TypeStruct::toJson(JsonOut *json) +{ + json->propertyStorageClass("storageClass", sym->storage_class); +} + +void TypeEnum::toJson(JsonOut *json) +{ + sym->jsonProperties(json); +} + +void TypeTypedef::toJson(JsonOut *json) +{ + sym->jsonProperties(json); +} + +void TypeClass::toJson(JsonOut *json) +{ + json->propertyStorageClass("storageClass", sym->storage_class); +} + +void TypeTuple::toJson(JsonOut *json) +{ + json->property("arguments", arguments); +} + +void TypeSlice::toJson(JsonOut *json) +{ + json->property("lower", lwr->toChars()); + json->property("upper", upr->toChars()); +} + +void TypeNull::toJson(JsonOut *json) { } + +void TypeVector::toJson(JsonOut *json) +{ + json->property("basetype", basetype); +} + + +/* ========================================================================== */ + +void Dsymbol::toJson(JsonOut *json) +{ +#if 0 + json->objectStart(); + jsonProperties(json); + json->objectEnd(); +#endif +} + +void Dsymbol::jsonProperties(JsonOut *json) +{ + json->property("name", toChars()); + if (!isTemplateDeclaration()) // TemplateDeclaration::kind() acts weird sometimes + json->property("kind", kind()); + + if (prot() != PROTpublic) + json->property("protection", Pprotectionnames[prot()]); + + json->property("comment", (const char *)comment); + + json->property("line", &loc); + +#if 0 + if (!isModule()) + { + Module *module = getModule(); + if (module) + { + json->propertyStart("module"); + json->objectStart(); + module->jsonProperties(json); + json->objectEnd(); + } + + Module *accessModule = getAccessModule(); + if (accessModule && accessModule != module) + { + json->propertyStart("accessModule"); + json->objectStart(); + accessModule->jsonProperties(json); + json->objectEnd(); + } + } +#endif +} + +void Module::toJson(JsonOut *json) +{ + json->objectStart(); + + if (md) + json->property("name", md->toChars()); + + json->property("kind", kind()); + + json->filename = srcfile->toChars(); + json->property("file", json->filename); + + json->property("comment", (const char *)comment); + + json->propertyStart("members"); + json->arrayStart(); + for (size_t i = 0; i < members->dim; i++) + { Dsymbol *s = (*members)[i]; + s->toJson(json); + } + json->arrayEnd(); + + json->objectEnd(); +} + +void Module::jsonProperties(JsonOut *json) +{ +#if 0 + Dsymbol::jsonProperties(json); + + if (md && md->packages) + { + json->propertyStart("package"); + json->arrayStart(); + for (size_t i = 0; i < md->packages->dim; i++) + { Identifier *pid = (*md->packages)[i]; + json->item(pid->toChars()); + } + json->arrayEnd(); + } + + json->property("prettyName", toPrettyChars()); +#endif +} + +void Import::toJson(JsonOut *json) +{ + if (id == Id::object) + return; + + json->objectStart(); + + json->propertyStart("name"); + json->stringStart(); + if (packages && packages->dim) + { + for (size_t i = 0; i < packages->dim; i++) + { Identifier *pid = (*packages)[i]; + + json->stringPart(pid->toChars()); + json->buf->writeByte('.'); + } + } + json->stringPart(id->toChars()); + json->stringEnd(); + json->comma(); + + json->property("kind", kind()); + json->property("comment", (const char *)comment); + json->property("line", &loc); + if (prot() != PROTpublic) + json->property("protection", Pprotectionnames[prot()]); + if (aliasId) + json->property("alias", aliasId->toChars()); + + bool hasRenamed = false; + bool hasSelective = false; + for (size_t i = 0; i < aliases.dim; i++) + { // avoid empty "renamed" and "selective" sections + if (hasRenamed && hasSelective) + break; + else if (aliases[i]) + hasRenamed = true; + else + hasSelective = true; + } + + if (hasRenamed) + { + // import foo : alias1 = target1; + json->propertyStart("renamed"); + json->objectStart(); + for (size_t i = 0; i < aliases.dim; i++) + { + Identifier *name = names[i]; + Identifier *alias = aliases[i]; + if (alias) json->property(alias->toChars(), name->toChars()); + } + json->objectEnd(); + } + + if (hasSelective) + { + // import foo : target1; + json->propertyStart("selective"); + json->arrayStart(); + for (size_t i = 0; i < names.dim; i++) + { + Identifier *name = names[i]; + if (!aliases[i]) json->item(name->toChars()); + } + json->arrayEnd(); + } + + json->objectEnd(); +} + +void AttribDeclaration::toJson(JsonOut *json) +{ Dsymbols *d = include(NULL, NULL); if (d) { - size_t offset = buf->offset; - for (unsigned i = 0; i < d->dim; i++) + for (size_t i = 0; i < d->dim; i++) { Dsymbol *s = (*d)[i]; - //printf("AttribDeclaration::toJsonBuffer %s\n", s->toChars()); - if (offset != buf->offset) - { buf->writestring(",\n"); - offset = buf->offset; - } - s->toJsonBuffer(buf); + s->toJson(json); } - JsonRemoveComma(buf); } } -void ConditionalDeclaration::toJsonBuffer(OutBuffer *buf) +void ConditionalDeclaration::toJson(JsonOut *json) { - //printf("ConditionalDeclaration::toJsonBuffer()\n"); if (condition->inc) { - AttribDeclaration::toJsonBuffer(buf); + AttribDeclaration::toJson(json); } } -void InvariantDeclaration::toJsonBuffer(OutBuffer *buf) { } -void DtorDeclaration::toJsonBuffer(OutBuffer *buf) { } -void StaticCtorDeclaration::toJsonBuffer(OutBuffer *buf) { } -void StaticDtorDeclaration::toJsonBuffer(OutBuffer *buf) { } -void ClassInfoDeclaration::toJsonBuffer(OutBuffer *buf) { } -void ModuleInfoDeclaration::toJsonBuffer(OutBuffer *buf) { } -void TypeInfoDeclaration::toJsonBuffer(OutBuffer *buf) { } -void UnitTestDeclaration::toJsonBuffer(OutBuffer *buf) { } +void ClassInfoDeclaration::toJson(JsonOut *json) { } +void ModuleInfoDeclaration::toJson(JsonOut *json) { } +void TypeInfoDeclaration::toJson(JsonOut *json) { } #if DMDV2 -void PostBlitDeclaration::toJsonBuffer(OutBuffer *buf) { } +void PostBlitDeclaration::toJson(JsonOut *json) { } #endif -void Declaration::toJsonBuffer(OutBuffer *buf) + +void Declaration::toJson(JsonOut *json) { - //printf("Declaration::toJsonBuffer()\n"); - buf->writestring("{\n"); + json->objectStart(); - JsonProperty(buf, Pname, toChars()); - JsonProperty(buf, Pkind, kind()); + //json->property("unknown", "declaration"); - if (prot()) - JsonProperty(buf, Pprotection, Pprotectionnames[prot()]); + jsonProperties(json); - if (type) - JsonProperty(buf, Ptype, type->toChars()); - - if (comment) - JsonProperty(buf, Pcomment, (const char *)comment); - - if (loc.linnum) - JsonProperty(buf, Pline, loc.linnum); - - TypedefDeclaration *td = isTypedefDeclaration(); - if (td) - { - JsonProperty(buf, "base", td->basetype->toChars()); - } - - JsonRemoveComma(buf); - buf->writestring("}\n"); + json->objectEnd(); } -void AggregateDeclaration::toJsonBuffer(OutBuffer *buf) +void Declaration::jsonProperties(JsonOut *json) { - //printf("AggregateDeclaration::toJsonBuffer()\n"); - buf->writestring("{\n"); + Dsymbol::jsonProperties(json); - JsonProperty(buf, Pname, toChars()); - JsonProperty(buf, Pkind, kind()); + json->propertyStorageClass("storageClass", storage_class); - if (prot()) - JsonProperty(buf, Pprotection, Pprotectionnames[prot()]); + json->property("type", "deco", type); - if (comment) - JsonProperty(buf, Pcomment, (const char *)comment); + // Emit originalType if it differs from type + if (type != originalType && originalType) + { + const char *ostr = originalType->toChars(); + if (type) + { const char *tstr = type->toChars(); + if (strcmp(tstr, ostr)) + { + //printf("tstr = %s, ostr = %s\n", tstr, ostr); + json->property("originalType", ostr); + } + } + else + json->property("originalType", ostr); + } +} - if (loc.linnum) - JsonProperty(buf, Pline, loc.linnum); +void TypedefDeclaration::toJson(JsonOut *json) +{ + json->objectStart(); + + jsonProperties(json); + + json->property("base", "baseDeco", basetype); + + json->objectEnd(); +} + +void AggregateDeclaration::toJson(JsonOut *json) +{ + json->objectStart(); + + jsonProperties(json); ClassDeclaration *cd = isClassDeclaration(); if (cd) { - if (cd->baseClass) + if (cd->baseClass && cd->baseClass->ident != Id::Object) { - JsonProperty(buf, "base", cd->baseClass->toChars()); + json->property("base", cd->baseClass->toChars()); } if (cd->interfaces_dim) { - JsonString(buf, "interfaces"); - buf->writestring(" : [\n"); - size_t offset = buf->offset; + json->propertyStart("interfaces"); + json->arrayStart(); for (size_t i = 0; i < cd->interfaces_dim; i++) { BaseClass *b = cd->interfaces[i]; - if (offset != buf->offset) - { buf->writestring(",\n"); - offset = buf->offset; - } - JsonString(buf, b->base->toChars()); + json->item(b->base->toChars()); } - JsonRemoveComma(buf); - buf->writestring("],\n"); + json->arrayEnd(); } } if (members) { - JsonString(buf, Pmembers); - buf->writestring(" : [\n"); - size_t offset = buf->offset; + json->propertyStart("members"); + json->arrayStart(); for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (*members)[i]; - if (offset != buf->offset) - { buf->writestring(",\n"); - offset = buf->offset; - } - s->toJsonBuffer(buf); + s->toJson(json); } - JsonRemoveComma(buf); - buf->writestring("]\n"); + json->arrayEnd(); } - JsonRemoveComma(buf); - buf->writestring("}\n"); + json->objectEnd(); } -void TemplateDeclaration::toJsonBuffer(OutBuffer *buf) +void FuncDeclaration::toJson(JsonOut *json) { - //printf("TemplateDeclaration::toJsonBuffer()\n"); + json->objectStart(); - buf->writestring("{\n"); + jsonProperties(json); - JsonProperty(buf, Pname, toChars()); - JsonProperty(buf, Pkind, kind()); + TypeFunction *tf = (TypeFunction *)type; + if (tf && tf->ty == Tfunction) + json->property("parameters", tf->parameters); - if (prot()) - JsonProperty(buf, Pprotection, Pprotectionnames[prot()]); + json->property("endline", &endloc); - if (comment) - JsonProperty(buf, Pcomment, (const char *)comment); + if (foverrides.dim) + { + json->propertyStart("overrides"); + json->arrayStart(); + for (size_t i = 0; i < foverrides.dim; i++) + { FuncDeclaration *fd = foverrides[i]; + json->item(fd->toPrettyChars()); + } + json->arrayEnd(); + } - if (loc.linnum) - JsonProperty(buf, Pline, loc.linnum); + if (fdrequire) + { + json->propertyStart("in"); + fdrequire->toJson(json); + } - JsonString(buf, Pmembers); - buf->writestring(" : [\n"); - size_t offset = buf->offset; + if (fdensure) + { + json->propertyStart("out"); + fdensure->toJson(json); + } + + json->objectEnd(); +} + +void TemplateDeclaration::toJson(JsonOut *json) +{ + json->objectStart(); + + // TemplateDeclaration::kind returns the kind of its Aggregate onemember, if it is one + json->property("kind", "template"); + + jsonProperties(json); + + json->propertyStart("parameters"); + json->arrayStart(); + for (size_t i = 0; i < parameters->dim; i++) + { TemplateParameter *s = (*parameters)[i]; + json->objectStart(); + + json->property("name", s->ident->toChars()); + + TemplateTypeParameter *type = s->isTemplateTypeParameter(); + if (type) + { +#if DMDV2 + if (s->isTemplateThisParameter()) + json->property("kind", "this"); + else +#endif + json->property("kind", "type"); + + json->property("type", "deco", type->specType); + + json->property("default", "defaultDeco", type->defaultType); + } + + TemplateValueParameter *value = s->isTemplateValueParameter(); + if (value) + { + json->property("kind", "value"); + + json->property("type", "deco", value->valType); + + if (value->specValue) + json->property("specValue", value->specValue->toChars()); + + if (value->defaultValue) + json->property("defaultValue", value->defaultValue->toChars()); + } + + TemplateAliasParameter *alias = s->isTemplateAliasParameter(); + if (alias) + { + json->property("kind", "alias"); + + json->property("type", "deco", alias->specType); + + if (alias->specAlias) + json->property("specAlias", alias->specAlias->toChars()); + + if (alias->defaultAlias) + json->property("defaultAlias", alias->defaultAlias->toChars()); + } + + TemplateTupleParameter *tuple = s->isTemplateTupleParameter(); + if (tuple) + { + json->property("kind", "tuple"); + } + + json->objectEnd(); + } + json->arrayEnd(); + + json->propertyStart("members"); + json->arrayStart(); for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (*members)[i]; - if (offset != buf->offset) - { buf->writestring(",\n"); - offset = buf->offset; - } - s->toJsonBuffer(buf); + s->toJson(json); } - JsonRemoveComma(buf); - buf->writestring("]\n"); + json->arrayEnd(); - buf->writestring("}\n"); + json->objectEnd(); } -void EnumDeclaration::toJsonBuffer(OutBuffer *buf) +void EnumDeclaration::toJson(JsonOut *json) { - //printf("EnumDeclaration::toJsonBuffer()\n"); if (isAnonymous()) { if (members) { for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = (*members)[i]; - s->toJsonBuffer(buf); - buf->writestring(",\n"); + { Dsymbol *s = (*members)[i]; + s->toJson(json); } - JsonRemoveComma(buf); } return; } - buf->writestring("{\n"); + json->objectStart(); - JsonProperty(buf, Pname, toChars()); - JsonProperty(buf, Pkind, kind()); + jsonProperties(json); - if (prot()) - JsonProperty(buf, Pprotection, Pprotectionnames[prot()]); - - if (comment) - JsonProperty(buf, Pcomment, (const char *)comment); - - if (loc.linnum) - JsonProperty(buf, Pline, loc.linnum); - - if (memtype) - JsonProperty(buf, "base", memtype->toChars()); + json->property("base", "baseDeco", memtype); if (members) { - JsonString(buf, Pmembers); - buf->writestring(" : [\n"); - size_t offset = buf->offset; + json->propertyStart("members"); + json->arrayStart(); for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (*members)[i]; - if (offset != buf->offset) - { buf->writestring(",\n"); - offset = buf->offset; - } - s->toJsonBuffer(buf); + s->toJson(json); } - JsonRemoveComma(buf); - buf->writestring("]\n"); + json->arrayEnd(); } - JsonRemoveComma(buf); - buf->writestring("}\n"); + json->objectEnd(); } -void EnumMember::toJsonBuffer(OutBuffer *buf) +void EnumMember::toJson(JsonOut *json) { - //printf("EnumMember::toJsonBuffer()\n"); - buf->writestring("{\n"); + json->objectStart(); - JsonProperty(buf, Pname, toChars()); - JsonProperty(buf, Pkind, kind()); + jsonProperties(json); - if (prot()) - JsonProperty(buf, Pprotection, Pprotectionnames[prot()]); + json->property("type", "deco", type); - if (comment) - JsonProperty(buf, Pcomment, (const char *)comment); - - if (loc.linnum) - JsonProperty(buf, Pline, loc.linnum); - - JsonRemoveComma(buf); - buf->writestring("}\n"); + json->objectEnd(); } +void VarDeclaration::toJson(JsonOut *json) +{ + json->objectStart(); + + jsonProperties(json); + + if (init) + json->property("init", init->toChars()); + + if (storage_class & STCfield) + json->property("offset", offset); + + if (alignment && alignment != STRUCTALIGN_DEFAULT) + json->property("align", alignment); + + json->objectEnd(); +} + +void TemplateMixin::toJson(JsonOut *json) +{ + json->objectStart(); + + jsonProperties(json); + + json->objectEnd(); +} diff --git a/dmd2/json.h b/dmd2/json.h index 2c7e2e60..4e80300d 100644 --- a/dmd2/json.h +++ b/dmd2/json.h @@ -1,7 +1,7 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2008 by Digital Mars +// Copyright (c) 1999-2013 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -18,7 +18,9 @@ #include "arraytypes.h" -void json_generate(Modules *); +struct OutBuffer; + +void json_generate(OutBuffer *, Modules *); #endif /* DMD_JSON_H */ diff --git a/dmd2/lexer.c b/dmd2/lexer.c index a142ad78..2e53a992 100644 --- a/dmd2/lexer.c +++ b/dmd2/lexer.c @@ -2364,8 +2364,6 @@ done: #endif #ifdef IN_GCC t->float80value = real_t::parse((char *)stringbuffer.data, real_t::LongDouble); -#elif IN_LLVM - t->float80value = Port::strtold((char *)stringbuffer.data, NULL); #else t->float80value = strtold((char *)stringbuffer.data, NULL); #endif diff --git a/dmd2/mangle.c b/dmd2/mangle.c index 629a9315..3e627104 100644 --- a/dmd2/mangle.c +++ b/dmd2/mangle.c @@ -24,11 +24,18 @@ #include "id.h" #include "module.h" -#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS || IN_LLVM +#if CPP_MANGLE || IN_LLVM char *cpp_mangle(Dsymbol *s); #endif -char *mangle(Declaration *sthis) +/****************************************************************************** + * isv : for the enclosing auto functions of an inner class/struct type. + * An aggregate type which defined inside auto function, it might + * become Voldemort Type so its object might be returned. + * This flag is necessary due to avoid mutual mangling + * between return type and enclosing scope. See bugzilla 8847. + */ +char *mangle(Declaration *sthis, bool isv) { OutBuffer buf; char *id; @@ -44,7 +51,7 @@ char *mangle(Declaration *sthis) FuncDeclaration *fd = s->isFuncDeclaration(); if (s != sthis && fd) { - id = mangle(fd); + id = mangle(fd, isv); buf.prependstring(id); goto L1; } @@ -70,7 +77,23 @@ L1: FuncDeclaration *fd = sthis->isFuncDeclaration(); if (fd && (fd->needThis() || fd->isNested())) buf.writeByte(Type::needThisPrefix()); - if (sthis->type->deco) + if (isv && fd && (fd->inferRetType || getFuncTemplateDecl(fd))) + { + TypeFunction tfn = *(TypeFunction *)sthis->type; + TypeFunction *tfo = (TypeFunction *)sthis->originalType; + tfn.purity = tfo->purity; + tfn.isnothrow = tfo->isnothrow; + tfn.isproperty = tfo->isproperty; + tfn.isref = fd->storage_class & STCauto ? false : tfo->isref; + tfn.trust = tfo->trust; + tfn.next = NULL; // do not mangle return type +#if IN_LLVM + tfn.toDecoBuffer(&buf, 0, true); +#else + tfn.toDecoBuffer(&buf, 0); +#endif + } + else if (sthis->type->deco) buf.writestring(sthis->type->deco); else { @@ -86,7 +109,7 @@ L1: return id; } -char *Declaration::mangle() +char *Declaration::mangle(bool isv) #if __DMC__ __out(result) { @@ -138,7 +161,7 @@ char *Declaration::mangle() assert(0); } } - char *p = ::mangle(this); + char *p = ::mangle(this, isv); OutBuffer buf; buf.writestring("_D"); buf.writestring(p); @@ -148,7 +171,7 @@ char *Declaration::mangle() return p; } -char *FuncDeclaration::mangle() +char *FuncDeclaration::mangle(bool isv) #if __DMC__ __out(result) { @@ -164,24 +187,40 @@ char *FuncDeclaration::mangle() return ident->toChars(); assert(this); - return Declaration::mangle(); + return Declaration::mangle(isv); } -char *StructDeclaration::mangle() -{ - //printf("StructDeclaration::mangle() '%s'\n", toChars()); - return Dsymbol::mangle(); -} - -char *TypedefDeclaration::mangle() +char *TypedefDeclaration::mangle(bool isv) { //printf("TypedefDeclaration::mangle() '%s'\n", toChars()); - return Dsymbol::mangle(); + return Dsymbol::mangle(isv); } -char *ClassDeclaration::mangle() +char *AggregateDeclaration::mangle(bool isv) +{ +#if 1 + //printf("AggregateDeclaration::mangle() '%s'\n", toChars()); + if (Dsymbol *p = toParent2()) + { if (FuncDeclaration *fd = p->isFuncDeclaration()) + { // This might be the Voldemort Type + char *id = Dsymbol::mangle(fd->inferRetType || getFuncTemplateDecl(fd)); + //printf("isv ad %s, %s\n", toChars(), id); + return id; + } + } +#endif + return Dsymbol::mangle(isv); +} + +char *StructDeclaration::mangle(bool isv) +{ + //printf("StructDeclaration::mangle() '%s'\n", toChars()); + return AggregateDeclaration::mangle(isv); +} + +char *ClassDeclaration::mangle(bool isv) { Dsymbol *parentsave = parent; @@ -209,13 +248,13 @@ char *ClassDeclaration::mangle() ) parent = NULL; - char *id = Dsymbol::mangle(); + char *id = AggregateDeclaration::mangle(isv); parent = parentsave; return id; } -char *TemplateInstance::mangle() +char *TemplateInstance::mangle(bool isv) { OutBuffer buf; @@ -274,7 +313,7 @@ char *TemplateMixin::mangle() } #endif -char *Dsymbol::mangle() +char *Dsymbol::mangle(bool isv) { OutBuffer buf; char *id; @@ -288,7 +327,7 @@ char *Dsymbol::mangle() id = ident ? ident->toChars() : toChars(); if (parent) { - char *p = parent->mangle(); + char *p = parent->mangle(isv); if (p[0] == '_' && p[1] == 'D') p += 2; buf.writestring(p); diff --git a/dmd2/mars.c b/dmd2/mars.c index 146b8bb4..cd06970f 100644 --- a/dmd2/mars.c +++ b/dmd2/mars.c @@ -80,7 +80,6 @@ Global::Global() 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 @@ -89,23 +88,24 @@ Global::Global() 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 + written = "written by Walter Bright"; +#if IN_DMD + version = "v" +#include "verstr.h" ; - version = "v2.061"; +#endif #if IN_LLVM + version = "v2.062"; ldc_version = "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 @@ -321,7 +321,7 @@ void usage() sizeof(size_t) * 8, global.version, global.copyright, global.written); printf("\ -Documentation: http://www.dlang.org/index.html\n\ +Documentation: http://dlang.org/\n\ Usage:\n\ dmd files.d ... { -switch }\n\ \n\ @@ -344,6 +344,7 @@ Usage:\n\ " -g add symbolic debug info\n\ -gc add symbolic debug info, pretend to be C\n\ -gs always emit stack frame\n\ + -gx add stack stomp code\n\ -H generate 'header' file\n\ -Hddirectory write 'header' file to directory\n\ -Hffilename write 'header' file to filename\n\ @@ -466,7 +467,6 @@ int tryMain(size_t argc, char *argv[]) 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 @@ -477,10 +477,6 @@ int tryMain(size_t argc, char *argv[]) #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"); @@ -579,6 +575,8 @@ int tryMain(size_t argc, char *argv[]) global.params.symdebug = 2; else if (strcmp(p + 1, "gs") == 0) global.params.alwaysframe = 1; + else if (strcmp(p + 1, "gx") == 0) + global.params.stackstomp = true; else if (strcmp(p + 1, "gt") == 0) { error(0, "use -profile instead of -gt"); global.params.trace = 1; @@ -834,35 +832,35 @@ int tryMain(size_t argc, char *argv[]) #if DMDV1 browse("http://www.digitalmars.com/d/1.0/dmd-windows.html"); #else - browse("http://www.dlang.org/dmd-windows.html"); + browse("http://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"); + browse("http://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"); + browse("http://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"); + browse("http://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"); + browse("http://dlang.org/dmd-openbsd.html"); #endif #endif exit(EXIT_SUCCESS); @@ -872,6 +870,14 @@ int tryMain(size_t argc, char *argv[]) global.params.runargs_length = ((i >= argcstart) ? argc : argcstart) - i - 1; if (global.params.runargs_length) { + const char *ext = FileName::ext(argv[i + 1]); + if (ext && FileName::equals(ext, "d") == 0 + && FileName::equals(ext, "di") == 0) + { + error(0, "-run must be followed by a source file, not '%s'", argv[i + 1]); + break; + } + files.push(argv[i + 1]); global.params.runargs = &argv[i + 2]; i += global.params.runargs_length; @@ -896,7 +902,7 @@ int tryMain(size_t argc, char *argv[]) else { #if TARGET_WINDOS - char *ext = FileName::ext(p); + const char *ext = FileName::ext(p); if (ext && FileName::compare(ext, "exe") == 0) { global.params.objname = p; @@ -961,14 +967,14 @@ int tryMain(size_t argc, char *argv[]) /* 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(); + global.params.objname = const_cast(FileName::forceExt(global.params.objname, global.obj_ext)); /* 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); + { const char *name = FileName::name(global.params.objname); + global.params.objname = (char *)FileName::combine(global.params.objdir, name); } } } @@ -1101,7 +1107,7 @@ int tryMain(size_t argc, char *argv[]) int firstmodule = 1; for (size_t i = 0; i < files.dim; i++) { - char *ext; + const char *ext; char *name; p = files[i]; @@ -1115,7 +1121,7 @@ int tryMain(size_t argc, char *argv[]) } #endif - p = FileName::name(p); // strip path + p = (char *)FileName::name(p); // strip path ext = FileName::ext(p); if (ext) { /* Deduce what to do with a file based on its extension @@ -1214,7 +1220,7 @@ int tryMain(size_t argc, char *argv[]) modules.push(m); if (firstmodule) - { global.params.objfiles->push(m->objfile->name->str); + { global.params.objfiles->push((char *)m->objfile->name->str); firstmodule = 0; } } @@ -1431,7 +1437,50 @@ int tryMain(size_t argc, char *argv[]) // Generate output files if (global.params.doXGeneration) - json_generate(&modules); + { + OutBuffer buf; + json_generate(&buf, &modules); + + // Write buf to file + const char *name = global.params.xfilename; + + if (name && name[0] == '-' && name[1] == 0) + { // Write to stdout; assume it succeeds + int n = fwrite(buf.data, 1, buf.offset, stdout); + assert(n == buf.offset); // keep gcc happy about return values + } + else + { + /* The filename generation code here should be harmonized with Module::setOutfile() + */ + + const char *jsonfilename; + + if (name && *name) + { + jsonfilename = FileName::defaultExt(name, global.json_ext); + } + else + { + // Generate json file name from first obj name + const char *n = (*global.params.objfiles)[0]; + n = FileName::name(n); + + //if (!FileName::absolute(name)) + //name = FileName::combine(dir, name); + + jsonfilename = FileName::forceExt(n, global.json_ext); + } + + FileName::ensurePathToNameExists(jsonfilename); + + File *jsonfile = new File(jsonfilename); + + jsonfile->setbuffer(buf.data, buf.offset); + jsonfile->ref = 1; + jsonfile->writev(); + } + } if (global.params.oneobj) { diff --git a/dmd2/mars.h b/dmd2/mars.h index 62b2f52e..59e1f7f6 100644 --- a/dmd2/mars.h +++ b/dmd2/mars.h @@ -51,7 +51,6 @@ the target object file format: TARGET_FREEBSD Covers 32 and 64 bit FreeBSD TARGET_OPENBSD Covers 32 and 64 bit OpenBSD TARGET_SOLARIS Covers 32 and 64 bit Solaris - TARGET_NET Covers .Net It is expected that the compiler for each platform will be able to generate 32 and 64 bit code from the same compiler binary. @@ -101,11 +100,9 @@ void unittests(); #define DMDV1 0 #define DMDV2 1 // Version 2.0 features -#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 +#define BUG6652 2 // 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 @@ -167,7 +164,7 @@ struct Param char lib; // write library file instead of object file(s) char multiobj; // break one object file into multiple ones char oneobj; // write one object file instead of multiple ones - char trace; // insert profiling hooks + bool trace; // insert profiling hooks char quiet; // suppress non-error messages #endif bool verbose; // verbose compile @@ -184,7 +181,7 @@ struct Param char isOSX; // generate code for Mac OSX char isWindows; // generate code for Windows char isFreeBSD; // generate code for FreeBSD - char isOPenBSD; // generate code for OpenBSD + char isOpenBSD; // generate code for OpenBSD char isSolaris; // generate code for Solaris char scheduler; // which scheduler to use #endif @@ -203,6 +200,7 @@ struct Param // 2: array bounds checks for all functions #endif bool noboundscheck; // no array bounds checking at all + bool stackstomp; // add stack stomping code bool useSwitchError; // check for switches without a default bool useUnitTests; // generate unittest code bool useInline; // inline expand functions diff --git a/dmd2/module.c b/dmd2/module.c index a3068dce..2cf024af 100644 --- a/dmd2/module.c +++ b/dmd2/module.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars +// Copyright (c) 1999-2013 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -12,20 +12,6 @@ #include #include -#if defined (__sun) -#include -#endif - -#if defined(_MSC_VER) || defined(__MINGW32__) -#include -#endif - -#ifdef IN_GCC -#include "gdc_alloca.h" -#endif - -#include "rmem.h" - #include "mars.h" #include "module.h" #include "parse.h" @@ -37,11 +23,6 @@ #include "hdrgen.h" #include "lexer.h" -// stricmp -#if __GNUC__ && !_WIN32 -#include "gnuc.h" -#endif - #ifdef IN_GCC #include "d-dmd-gcc.h" #endif @@ -59,6 +40,12 @@ #include "llvm/Support/CommandLine.h" #include +#if _WIN32 +#define strcasecmp(s1, s2) _stricmp(s1, s2) +#else +#define strcasecmp(s1, s2) strcmp(s1, s2) +#endif + static llvm::cl::opt preservePaths("op", llvm::cl::desc("Do not strip paths from source file"), llvm::cl::ZeroOrMore); @@ -85,10 +72,9 @@ void Module::init() Module::Module(char *filename, Identifier *ident, int doDocComment, int doHdrGen) : Package(ident) { - FileName *srcfilename; + const char *srcfilename; #if IN_DMD - FileName *objfilename; - FileName *symfilename; + const char *symfilename; #endif // printf("Module::Module(filename = '%s', ident = '%s')\n", filename, ident->toChars()); @@ -99,9 +85,6 @@ Module::Module(char *filename, Identifier *ident, int doDocComment, int doHdrGen members = NULL; isDocFile = 0; needmoduleinfo = 0; -#ifdef IN_GCC - strictlyneedmoduleinfo = 0; -#endif selfimports = 0; insearch = 0; searchCacheIdent = NULL; @@ -150,61 +133,27 @@ Module::Module(char *filename, Identifier *ident, int doDocComment, int doHdrGen namelen = 0; srcfilename = FileName::defaultExt(filename, global.mars_ext); - if (!srcfilename->equalsExt(global.mars_ext) && - !srcfilename->equalsExt(global.hdr_ext) && - !srcfilename->equalsExt("dd")) + if (!FileName::equalsExt(srcfilename, global.mars_ext) && + !FileName::equalsExt(srcfilename, global.hdr_ext) && + !FileName::equalsExt(srcfilename, "dd")) { - error("source file name '%s' must have .%s extension", srcfilename->toChars(), global.mars_ext); + error("source file name '%s' must have .%s extension", srcfilename, global.mars_ext); fatal(); } -#if !IN_LLVM - char *argobj; - if (global.params.objname) - argobj = global.params.objname; -#if 0 - else if (global.params.preservePaths) - argobj = filename; - else - argobj = FileName::name(filename); - if (!FileName::absolute(argobj)) - { - argobj = FileName::combine(global.params.objdir, argobj); - } -#else // Bugzilla 3547 - else - { - if (global.params.preservePaths) - argobj = filename; - else - argobj = FileName::name(filename); - if (!FileName::absolute(argobj)) - { - argobj = FileName::combine(global.params.objdir, argobj); - } - } -#endif + srcfile = new File(srcfilename); - if (global.params.objname) - objfilename = new FileName(argobj); - else - objfilename = FileName::forceExt(argobj, global.obj_ext); +#if IN_DMD + objfile = setOutfile(global.params.objname, global.params.objdir, filename, global.obj_ext); symfilename = FileName::forceExt(filename, global.sym_ext); -#endif - srcfile = new File(srcfilename); -#if IN_DMD if (doDocComment) - { setDocfile(); - } if (doHdrGen) - { - setHdrfile(); - } + hdrfile = setOutfile(global.params.hdrname, global.params.hdrdir, arg, global.hdr_ext); - objfile = new File(objfilename); + //objfile = new File(objfilename); symfile = new File(symfilename); #endif #if IN_LLVM @@ -263,8 +212,8 @@ File* Module::buildFilePath(const char* forcename, const char* path, const char* // else // allow for .o and .obj on windows #if _WIN32 - if (ext == global.params.objdir && FileName::ext(argobj) - && stricmp(FileName::ext(argobj), global.obj_ext_alt) == 0) + if (ext == global.params.objdir && FileName::ext(argobj) + && strcasecmp(FileName::ext(argobj), global.obj_ext_alt) == 0) return new File((char*)argobj); #endif return new File(FileName::forceExt(argobj, ext)); @@ -273,58 +222,50 @@ File* Module::buildFilePath(const char* forcename, const char* path, const char* #if IN_DMD void Module::setDocfile() { - FileName *docfilename; - char *argdoc; - - if (global.params.docname) - argdoc = global.params.docname; - else if (global.params.preservePaths) - argdoc = (char *)arg; - else - argdoc = FileName::name((char *)arg); - if (!FileName::absolute(argdoc)) - { //FileName::ensurePathExists(global.params.docdir); - argdoc = FileName::combine(global.params.docdir, argdoc); - } - if (global.params.docname) - docfilename = new FileName(argdoc); - else - docfilename = FileName::forceExt(argdoc, global.doc_ext); - - if (docfilename->equals(srcfile->name)) - { error("Source file and documentation file have same name '%s'", srcfile->name->str); - fatal(); - } - - docfile = new File(docfilename); + docfile = setOutfile(global.params.docname, global.params.docdir, arg, global.doc_ext); } -void Module::setHdrfile() +/********************************************* + * Combines things into output file name for .html and .di files. + * Input: + * name Command line name given for the file, NULL if none + * dir Command line directory given for the file, NULL if none + * arg Name of the source file + * ext File name extension to use if 'name' is NULL + * global.params.preservePaths get output path from arg + * srcfile Input file - output file name must not match input file + */ + +File *Module::setOutfile(const char *name, const char *dir, const char *arg, const char *ext) { - FileName *hdrfilename; - char *arghdr; + const char *docfilename; - if (global.params.hdrname) - arghdr = global.params.hdrname; - else if (global.params.preservePaths) - arghdr = (char *)arg; - else - arghdr = FileName::name((char *)arg); - if (!FileName::absolute(arghdr)) - { //FileName::ensurePathExists(global.params.hdrdir); - arghdr = FileName::combine(global.params.hdrdir, arghdr); + if (name) + { + docfilename = name; } - if (global.params.hdrname) - hdrfilename = new FileName(arghdr); else - hdrfilename = FileName::forceExt(arghdr, global.hdr_ext); + { + const char *argdoc; + if (global.params.preservePaths) + argdoc = arg; + else + argdoc = FileName::name(arg); - if (hdrfilename->equals(srcfile->name)) - { error("Source file and 'header' file have same name '%s'", srcfile->name->str); + // If argdoc doesn't have an absolute path, make it relative to dir + if (!FileName::absolute(argdoc)) + { //FileName::ensurePathExists(dir); + argdoc = FileName::combine(dir, argdoc); + } + docfilename = FileName::forceExt(argdoc, ext); + } + + if (FileName::equals(docfilename, srcfile->name->str)) + { error("Source file and output file have same name '%s'", srcfile->name->str); fatal(); } - hdrfile = new File(hdrfilename); + return new File(docfilename); } #endif @@ -361,7 +302,7 @@ void Module::buildTargetFiles(bool singleObj) global.params.targetTriple.isOSWindows() ? global.obj_ext_alt : global.obj_ext); else if (global.params.output_bc) objfile = Module::buildFilePath(global.params.objname, global.params.objdir, global.bc_ext); - else if (global.params.output_ll) + else if (global.params.output_ll) objfile = Module::buildFilePath(global.params.objname, global.params.objdir, global.ll_ext); else if (global.params.output_s) objfile = Module::buildFilePath(global.params.objname, global.params.objdir, global.s_ext); @@ -372,17 +313,17 @@ void Module::buildTargetFiles(bool singleObj) hdrfile = Module::buildFilePath(global.params.hdrname, global.params.hdrdir, global.hdr_ext); // safety check: never allow obj, doc or hdr file to have the source file's name - if(stricmp(FileName::name(objfile->name->str), FileName::name((char*)this->arg)) == 0) + if(strcasecmp(FileName::name(objfile->name->str), FileName::name((char*)this->arg)) == 0) { error("Output object files with the same name as the source file are forbidden"); fatal(); } - if(docfile && stricmp(FileName::name(docfile->name->str), FileName::name((char*)this->arg)) == 0) + if(docfile && strcasecmp(FileName::name(docfile->name->str), FileName::name((char*)this->arg)) == 0) { error("Output doc files with the same name as the source file are forbidden"); fatal(); } - if(hdrfile && stricmp(FileName::name(hdrfile->name->str), FileName::name((char*)this->arg)) == 0) + if(hdrfile && strcasecmp(FileName::name(hdrfile->name->str), FileName::name((char*)this->arg)) == 0) { error("Output header files with the same name as the source file are forbidden"); fatal(); @@ -457,11 +398,11 @@ Module *Module::load(Loc loc, Identifiers *packages, Identifier *ident) /* Search along global.path for .di file, then .d file. */ - char *result = NULL; - FileName *fdi = FileName::forceExt(filename, global.hdr_ext); - FileName *fd = FileName::forceExt(filename, global.mars_ext); - char *sdi = fdi->toChars(); - char *sd = fd->toChars(); + const char *result = NULL; + const char *fdi = FileName::forceExt(filename, global.hdr_ext); + const char *fd = FileName::forceExt(filename, global.mars_ext); + const char *sdi = fdi; + const char *sd = fd; if (FileName::exists(sdi)) result = sdi; @@ -475,19 +416,19 @@ Module *Module::load(Loc loc, Identifiers *packages, Identifier *ident) { for (size_t i = 0; i < global.path->dim; i++) { - char *p = (*global.path)[i]; - char *n = FileName::combine(p, sdi); + const char *p = (*global.path)[i]; + const char *n = FileName::combine(p, sdi); if (FileName::exists(n)) { result = n; break; } - mem.free(n); + FileName::free(n); n = FileName::combine(p, sd); if (FileName::exists(n)) { result = n; break; } - mem.free(n); + FileName::free(n); } } if (result) @@ -1395,15 +1336,12 @@ DsymbolTable *Package::resolve(Identifiers *packages, Dsymbol **pparent, Package dst = ((Package *)p)->symtab; if (ppkg && !*ppkg) *ppkg = (Package *)p; -#if TARGET_NET -#else if (p->isModule()) { // Return the module so that a nice error message can be generated if (ppkg) *ppkg = (Package *)p; break; } -#endif } if (pparent) { diff --git a/dmd2/module.h b/dmd2/module.h index dabd3a83..b80a756f 100644 --- a/dmd2/module.h +++ b/dmd2/module.h @@ -81,9 +81,6 @@ struct Module : Package unsigned numlines; // number of lines in source file int isDocFile; // if it is a documentation input file, not D source int needmoduleinfo; -#ifdef IN_GCC - int strictlyneedmoduleinfo; -#endif int selfimports; // 0: don't know, 1: does not, 2: does int selfImports(); // returns !=0 if module imports itself @@ -132,9 +129,11 @@ struct Module : Package static Module *load(Loc loc, Identifiers *packages, Identifier *ident); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toJsonBuffer(OutBuffer *buf); + void toJson(JsonOut *json); + void jsonProperties(JsonOut *json); const char *kind(); #if !IN_LLVM + File *setOutfile(const char *name, const char *dir, const char *arg, const char *ext); void setDocfile(); // set docfile member #endif bool read(Loc loc); // read file, returns 'true' if succeed, 'false' otherwise. @@ -148,9 +147,6 @@ struct Module : Package void semantic2(Scope* unused_sc = NULL); // pass 2 semantic analysis void semantic3(Scope* unused_sc = NULL); // pass 3 semantic analysis void inlineScan(); // scan for functions to inline -#if !IN_LLVM - void setHdrfile(); // set hdrfile member -#endif void genhdrfile(); // generate D import file // void gensymfile(); void gendocfile(); diff --git a/dmd2/mtype.c b/dmd2/mtype.c index 6b8786f1..1cd6c2ba 100644 --- a/dmd2/mtype.c +++ b/dmd2/mtype.c @@ -4,7 +4,6 @@ // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com -// http://www.dsource.org/projects/dmd/browser/trunk/src/mtype.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. @@ -12,16 +11,11 @@ #define __C99FEATURES__ 1 // Needed on Solaris for NaN and more #define __USE_ISOC99 1 // so signbit() gets defined -#if defined (__sun) -#include -#endif - #ifdef __DMC__ #include #else #include #endif - #include #include #include @@ -136,6 +130,7 @@ TemplateDeclaration *Type::rtinfo; Type *Type::tvoidptr; Type *Type::tstring; +Type *Type::tvalist; Type *Type::basic[TMAX]; unsigned char Type::mangleChar[TMAX]; unsigned short Type::sizeTy[TMAX]; @@ -172,6 +167,12 @@ Type::Type(TY ty) #endif } +const char *Type::kind() +{ + assert(false); // should be overridden + return NULL; +} + Type *Type::syntaxCopy() { print(); @@ -315,6 +316,7 @@ void Type::init() tvoidptr = tvoid->pointerTo(); tstring = tchar->invariantOf()->arrayOf(); + tvalist = tvoid->pointerTo(); #if IN_DMD if (global.params.is64bit) @@ -1370,28 +1372,13 @@ Type *Type::aliasthisOf() FuncDeclaration *fd = (FuncDeclaration *)d; Expression *ethis = this->defaultInit(0); fd = fd->overloadResolve(0, ethis, NULL, 1); - if (fd) - { TypeFunction *tf = (TypeFunction *)fd->type; - if (!tf->next && fd->inferRetType) - { - TemplateInstance *spec = fd->isSpeculative(); - int olderrs = global.errors; - // If it isn't speculative, we need to show errors - unsigned oldgag = global.gag; - if (global.gag && !spec) - global.gag = 0; - fd->semantic3(fd->scope); - global.gag = oldgag; - // Update the template instantiation with the number - // of errors which occured. - if (spec && global.errors != olderrs) - spec->errors = global.errors - olderrs; - tf = (TypeFunction *)fd->type; - } - t = tf->next; - if (tf->isWild()) - t = t->substWildTo(mod == 0 ? MODmutable : mod); + if (fd && fd->functionSemantic()) + { + t = fd->type->nextOf(); + t = t->substWildTo(mod == 0 ? MODmutable : mod); } + else + return Type::terror; } return t; } @@ -1406,26 +1393,14 @@ Type *Type::aliasthisOf() { assert(td->scope); Expression *ethis = defaultInit(0); FuncDeclaration *fd = td->deduceFunctionTemplate(td->scope, 0, NULL, ethis, NULL, 1); - if (fd) + if (fd && fd->functionSemantic()) { - //if (!fd->type->nextOf() && fd->inferRetType) - { - TemplateInstance *spec = fd->isSpeculative(); - int olderrs = global.errors; - fd->semantic3(fd->scope); - // Update the template instantiation with the number - // of errors which occured. - if (spec && global.errors != olderrs) - spec->errors = global.errors - olderrs; - } - if (!fd->errors) - { - Type *t = fd->type->nextOf(); - t = t->substWildTo(mod == 0 ? MODmutable : mod); - return t; - } + Type *t = fd->type->nextOf(); + t = t->substWildTo(mod == 0 ? MODmutable : mod); + return t; } - return Type::terror; + else + return Type::terror; } //printf("%s\n", ad->aliasthis->kind()); } @@ -1592,7 +1567,7 @@ void MODtoDecoBuffer(OutBuffer *buf, unsigned char mod) } /********************************* - * Name for mod. + * Store modifier name into buf. */ void MODtoBuffer(OutBuffer *buf, unsigned char mod) { @@ -1626,6 +1601,18 @@ void MODtoBuffer(OutBuffer *buf, unsigned char mod) } } + +/********************************* + * Return modifier name. + */ +char *MODtoChars(unsigned char mod) +{ + OutBuffer buf; + MODtoBuffer(&buf, mod); + buf.writebyte(0); + return buf.extractData(); +} + /******************************** * Name mangling. * Input: @@ -1699,6 +1686,9 @@ void Type::toCBuffer3(OutBuffer *buf, HdrGenState *hgs, int mod) } } +/********************************* + * Store this type's modifier name into buf. + */ void Type::modToBuffer(OutBuffer *buf) { if (mod) @@ -1708,6 +1698,17 @@ void Type::modToBuffer(OutBuffer *buf) } } +/********************************* + * Return this type's modifier name. + */ +char *Type::modToChars() +{ + OutBuffer buf; + modToBuffer(&buf); + buf.writebyte(0); + return buf.extractData(); +} + /************************************ */ @@ -1719,7 +1720,7 @@ Type *Type::merge() if (ty == Tinstance) return this; if (ty == Taarray && !((TypeAArray *)this)->index->merge()->deco) return this; - if (nextOf() && !nextOf()->merge()->deco) + if (nextOf() && !nextOf()->deco) return this; //printf("merge(%s)\n", toChars()); @@ -1847,13 +1848,14 @@ int Type::isString() } /************************** + * When T is mutable, * Given: * T a, b; - * Can we assign: + * Can we bitwise assign: * a = b; * ? */ -int Type::isAssignable(int blit) +int Type::isAssignable() { return TRUE; } @@ -2289,9 +2291,6 @@ Identifier *Type::getTypeInfoIdent(int internal) { // _init_10TypeInfo_%s OutBuffer buf; - Identifier *id; - char *name; - size_t len; if (internal) { buf.writeByte(mangleChar[ty]); @@ -2300,21 +2299,29 @@ Identifier *Type::getTypeInfoIdent(int internal) } else toDecoBuffer(&buf, 0, true); - len = buf.offset; - name = (char *)alloca(19 + sizeof(len) * 3 + len + 1); + + size_t len = buf.offset; buf.writeByte(0); -#if TARGET_OSX - // The LINKc will prepend the _ - sprintf(name, "D%dTypeInfo_%s6__initZ", 9 + len, buf.data); -#else + + // Allocate buffer on stack, fail over to using malloc() + char namebuf[40]; + size_t namelen = 19 + sizeof(len) * 3 + len + 1; + char *name = namelen <= sizeof(namebuf) ? namebuf : (char *)malloc(namelen); + assert(name); + sprintf(name, "_D%dTypeInfo_%s6__initZ", 9 + len, buf.data); -#endif -#if !IN_LLVM - if (global.params.isWindows && !global.params.is64bit) - name++; // C mangling will add it back in -#endif //printf("name = %s\n", name); - id = Lexer::idPool(name); + assert(strlen(name) < namelen); // don't overflow the buffer + + size_t off = 0; +#if !IN_LLVM + if (global.params.isOSX || global.params.isWindows && !global.params.is64bit) + ++off; // C mangling will add '_' back in +#endif + Identifier *id = Lexer::idPool(name + off); + + if (name != namebuf) + free(name); return id; } @@ -2815,6 +2822,11 @@ TypeBasic::TypeBasic(TY ty) merge(); } +const char *TypeBasic::kind() +{ + return dstring; +} + Type *TypeBasic::syntaxCopy() { // No semantic analysis done on basic types, no need to copy @@ -3496,6 +3508,11 @@ TypeVector::TypeVector(Loc loc, Type *basetype) this->basetype = basetype; } +const char *TypeVector::kind() +{ + return "vector"; +} + Type *TypeVector::syntaxCopy() { return new TypeVector(0, basetype->syntaxCopy()); @@ -3842,6 +3859,11 @@ TypeSArray::TypeSArray(Type *t, Expression *dim) this->dim = dim; } +const char *TypeSArray::kind() +{ + return "sarray"; +} + Type *TypeSArray::syntaxCopy() { Type *t = next->syntaxCopy(); @@ -4163,11 +4185,19 @@ Expression *TypeSArray::dotExp(Scope *sc, Expression *e, Identifier *ident) #endif if (ident == Id::length) { - e = dim; + Loc oldLoc = e->loc; + e = dim->copy(); + e->loc = oldLoc; } else if (ident == Id::ptr) { - e = e->castTo(sc, next->pointerTo()); + if (size(e->loc) == 0) + e = new NullExp(e->loc, next->pointerTo()); + else + { + e = new IndexExp(e->loc, e, new IntegerExp(0)); + e = new AddrExp(e->loc, e); + } } else { @@ -4343,6 +4373,11 @@ TypeDArray::TypeDArray(Type *t) //printf("TypeDArray(t = %p)\n", t); } +const char *TypeDArray::kind() +{ + return "darray"; +} + Type *TypeDArray::syntaxCopy() { Type *t = next->syntaxCopy(); @@ -4497,7 +4532,7 @@ MATCH TypeDArray::implicitConvTo(Type *to) return MATCHconvert; } - return next->constConv(to); + return next->constConv(to) ? MATCHconvert : MATCHnomatch; } if (to->ty == Tarray) @@ -4567,6 +4602,11 @@ TypeAArray::TypeAArray(Type *t, Type *index) this->sc = NULL; } +const char *TypeAArray::kind() +{ + return "aarray"; +} + Type *TypeAArray::syntaxCopy() { Type *t = next->syntaxCopy(); @@ -5002,6 +5042,11 @@ TypePointer::TypePointer(Type *t) { } +const char *TypePointer::kind() +{ + return "pointer"; +} + Type *TypePointer::syntaxCopy() { Type *t = next->syntaxCopy(); @@ -5170,6 +5215,11 @@ TypeReference::TypeReference(Type *t) // BUG: what about references to static arrays? } +const char *TypeReference::kind() +{ + return "reference"; +} + Type *TypeReference::syntaxCopy() { Type *t = next->syntaxCopy(); @@ -5274,6 +5324,18 @@ TypeFunction::TypeFunction(Parameters *parameters, Type *treturn, int varargs, e this->trust = TRUSTtrusted; } +const char *TypeFunction::kind() +{ + return "function"; +} + +TypeFunction *TypeFunction::copy() +{ + TypeFunction *tf = (TypeFunction *)mem.malloc(sizeof(TypeFunction)); + memcpy(tf, this, sizeof(TypeFunction)); + return tf; +} + Type *TypeFunction::syntaxCopy() { Type *treturn = next ? next->syntaxCopy() : NULL; @@ -5558,8 +5620,8 @@ void TypeFunction::toDecoBuffer(OutBuffer *buf, int flag, bool mangle) Parameter::argsToDecoBuffer(buf, parameters, mangle); //if (buf->data[buf->offset - 1] == '@') halt(); buf->writeByte('Z' - varargs); // mark end of arg list - assert(next); - next->toDecoBuffer(buf, 0, mangle); + if(next != NULL) + next->toDecoBuffer(buf, 0, mangle); inuse--; } @@ -5763,8 +5825,7 @@ Type *TypeFunction::semantic(Loc loc, Scope *sc) * This can produce redundant copies if inferring return type, * as semantic() will get called again on this. */ - TypeFunction *tf = (TypeFunction *)mem.malloc(sizeof(TypeFunction)); - memcpy(tf, this, sizeof(TypeFunction)); + TypeFunction *tf = copy(); if (parameters) { tf->parameters = (Parameters *)parameters->copy(); for (size_t i = 0; i < parameters->dim; i++) @@ -5817,12 +5878,6 @@ Type *TypeFunction::semantic(Loc loc, Scope *sc) sc->stc &= ~(STC_TYPECTOR | STC_FUNCATTR); tf->next = tf->next->semantic(loc,sc); sc = sc->pop(); -#if !SARRAYVALUE - if (tf->next->toBasetype()->ty == Tsarray) - { error(loc, "functions cannot return static array %s", tf->next->toChars()); - tf->next = Type::terror; - } -#endif if (tf->next->toBasetype()->ty == Tfunction) { error(loc, "functions cannot return a function"); tf->next = Type::terror; @@ -5888,9 +5943,9 @@ Type *TypeFunction::semantic(Loc loc, Scope *sc) if (fparam->defaultArg) { Expression *e = fparam->defaultArg; - e = e->inferType(fparam->type); - e = e->semantic(argsc); - e = resolveProperties(argsc, e); + Initializer *init = new ExpInitializer(e->loc, e); + init = init->semantic(argsc, fparam->type, INITnointerpret); + e = init->toExpression(); if (e->op == TOKfunction) // see Bugzilla 4820 { FuncExp *fe = (FuncExp *)e; // Replace function literal with a function symbol, @@ -6302,25 +6357,6 @@ MATCH TypeFunction::callMatch(Expression *ethis, Expressions *args, int flag) 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; - if (ce->e1->op == TOKdotvar && - ((DotVarExp *)ce->e1)->var->isCtorDeclaration()) - { - match = MATCHconvert; - } - else - goto Nomatch; - } else goto Nomatch; } @@ -6557,6 +6593,11 @@ TypeDelegate::TypeDelegate(Type *t) ty = Tdelegate; } +const char *TypeDelegate::kind() +{ + return "delegate"; +} + Type *TypeDelegate::syntaxCopy() { Type *t = next->syntaxCopy(); @@ -6750,6 +6791,7 @@ void TypeQualified::resolveHelper(Loc loc, Scope *sc, VarDeclaration *v; EnumMember *em; Expression *e; + TemplateInstance *ti; #if 0 printf("TypeQualified::resolveHelper(sc = %p, idents = '%s')\n", sc, toChars()); @@ -6775,6 +6817,7 @@ void TypeQualified::resolveHelper(Loc loc, Scope *sc, { Type *t; v = s->isVarDeclaration(); + ti = s->isTemplateInstance(); if (v && id == Id::length) { e = new VarExp(loc, v); @@ -6783,7 +6826,8 @@ void TypeQualified::resolveHelper(Loc loc, Scope *sc, goto Lerror; goto L3; } - else if (v && (id == Id::stringof || id == Id::offsetof)) + else if ((v && (id == Id::stringof || id == Id::offsetof)) + || (ti && (id == Id::stringof || id == Id::mangleof))) { e = new DsymbolExp(loc, s, 0); do @@ -6959,6 +7003,11 @@ TypeIdentifier::TypeIdentifier(Loc loc, Identifier *ident) this->ident = ident; } +const char *TypeIdentifier::kind() +{ + return "identifier"; +} + Type *TypeIdentifier::syntaxCopy() { @@ -7133,6 +7182,11 @@ TypeInstance::TypeInstance(Loc loc, TemplateInstance *tempinst) this->tempinst = tempinst; } +const char *TypeInstance::kind() +{ + return "instance"; +} + Type *TypeInstance::syntaxCopy() { //printf("TypeInstance::syntaxCopy() %s, %d\n", toChars(), idents.dim); @@ -7274,6 +7328,11 @@ TypeTypeof::TypeTypeof(Loc loc, Expression *exp) inuse = 0; } +const char *TypeTypeof::kind() +{ + return "typeof"; +} + Type *TypeTypeof::syntaxCopy() { //printf("TypeTypeof::syntaxCopy() %s\n", toChars()); @@ -7458,6 +7517,11 @@ TypeReturn::TypeReturn(Loc loc) { } +const char *TypeReturn::kind() +{ + return "return"; +} + Type *TypeReturn::syntaxCopy() { TypeReturn *t = new TypeReturn(loc); @@ -7541,6 +7605,11 @@ TypeEnum::TypeEnum(EnumDeclaration *sym) this->sym = sym; } +const char *TypeEnum::kind() +{ + return "enum"; +} + char *TypeEnum::toChars() { if (mod) @@ -7722,9 +7791,9 @@ int TypeEnum::isscalar() return sym->memtype->isscalar(); } -int TypeEnum::isAssignable(int blit) +int TypeEnum::isAssignable() { - return sym->memtype->isAssignable(blit); + return sym->memtype->isAssignable(); } int TypeEnum::checkBoolean() @@ -7811,6 +7880,11 @@ TypeTypedef::TypeTypedef(TypedefDeclaration *sym) this->sym = sym; } +const char *TypeTypedef::kind() +{ + return "typedef"; +} + Type *TypeTypedef::syntaxCopy() { return this; @@ -7939,9 +8013,9 @@ int TypeTypedef::isscalar() return sym->basetype->isscalar(); } -int TypeTypedef::isAssignable(int blit) +int TypeTypedef::isAssignable() { - return sym->basetype->isAssignable(blit); + return sym->basetype->isAssignable(); } int TypeTypedef::checkBoolean() @@ -8094,6 +8168,11 @@ TypeStruct::TypeStruct(StructDeclaration *sym) this->unaligned = 0; } +const char *TypeStruct::kind() +{ + return "struct"; +} + char *TypeStruct::toChars() { //printf("sym.parent: %s, deco = %s\n", sym->parent->toChars(), deco); @@ -8423,6 +8502,7 @@ Expression *TypeStruct::defaultInitLiteral(Loc loc) for (size_t j = 0; j < structelems->dim; j++) { VarDeclaration *vd = sym->fields[j]; + Type *telem = vd->type->addMod(this->mod); Expression *e; if (vd->init) { if (vd->init->isVoidInitializer()) @@ -8433,7 +8513,10 @@ Expression *TypeStruct::defaultInitLiteral(Loc loc) else e = vd->type->defaultInitLiteral(loc); if (e && vd->scope) - e = e->semantic(vd->scope); + { + e = e->semantic(vd->scope); + e = e->implicitCastTo(vd->scope, telem); + } (*structelems)[j] = e; } StructLiteralExp *structinit = new StructLiteralExp(loc, (StructDeclaration *)sym, structelems); @@ -8481,18 +8564,8 @@ bool TypeStruct::needsNested() return false; } -int TypeStruct::isAssignable(int blit) +int TypeStruct::isAssignable() { - if (!blit) - { - if (sym->hasIdentityAssign) - return TRUE; - - // has non-identity opAssign - if (search_function(sym, Id::assign)) - return FALSE; - } - int assignable = TRUE; unsigned offset; @@ -8518,7 +8591,7 @@ int TypeStruct::isAssignable(int blit) if (!assignable) return FALSE; } - assignable = v->type->isMutable() && v->type->isAssignable(blit); + assignable = v->type->isMutable() && v->type->isAssignable(); offset = v->offset; //printf(" -> assignable = %d\n", assignable); } @@ -8638,6 +8711,11 @@ TypeClass::TypeClass(ClassDeclaration *sym) this->sym = sym; } +const char *TypeClass::kind() +{ + return "class"; +} + char *TypeClass::toChars() { if (mod) @@ -9122,7 +9200,7 @@ int TypeClass::isscope() int TypeClass::isBaseOf(Type *t, int *poffset) { - if (t->ty == Tclass) + if (t && t->ty == Tclass) { ClassDeclaration *cd; cd = ((TypeClass *)t)->sym; @@ -9294,6 +9372,11 @@ TypeTuple::TypeTuple(Type *t1, Type *t2) arguments->push(new Parameter(0, t2, NULL, NULL)); } +const char *TypeTuple::kind() +{ + return "tuple"; +} + Type *TypeTuple::syntaxCopy() { Parameters *args = Parameter::arraySyntaxCopy(arguments); @@ -9440,6 +9523,11 @@ TypeSlice::TypeSlice(Type *next, Expression *lwr, Expression *upr) this->upr = upr; } +const char *TypeSlice::kind() +{ + return "slice"; +} + Type *TypeSlice::syntaxCopy() { Type *t = new TypeSlice(next->syntaxCopy(), lwr->syntaxCopy(), upr->syntaxCopy()); @@ -9568,6 +9656,11 @@ TypeNull::TypeNull() { } +const char *TypeNull::kind() +{ + return "null"; +} + Type *TypeNull::syntaxCopy() { // No semantic analysis done, no need to copy @@ -9596,10 +9689,23 @@ MATCH TypeNull::implicitConvTo(Type *to) return MATCHnomatch; } +int TypeNull::checkBoolean() +{ + return TRUE; +} + +#if IN_LLVM void TypeNull::toDecoBuffer(OutBuffer *buf, int flag, bool mangle) +#else +void TypeNull::toDecoBuffer(OutBuffer *buf, int flag) +#endif { //tvoidptr->toDecoBuffer(buf, flag); +#if IN_LLVM Type::toDecoBuffer(buf, flag, mangle); +#else + Type::toDecoBuffer(buf, flag); +#endif } void TypeNull::toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs) @@ -9700,6 +9806,13 @@ void Parameter::argsToCBuffer(OutBuffer *buf, HdrGenState *hgs, Parameters *argu { if (arg->ident) argbuf.writestring(arg->ident->toChars()); } + else if (arg->type->ty == Tident && + ((TypeIdentifier *)arg->type)->ident->len > 3 && + strncmp(((TypeIdentifier *)arg->type)->ident->string, "__T", 3) == 0) + { + // print parameter name, instead of undetermined type parameter + argbuf.writestring(arg->ident->toChars()); + } else arg->type->toCBuffer(&argbuf, arg->ident, hgs); if (arg->defaultArg) diff --git a/dmd2/mtype.h b/dmd2/mtype.h index 50142416..6dbda261 100644 --- a/dmd2/mtype.h +++ b/dmd2/mtype.h @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars +// Copyright (c) 1999-2013 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -41,6 +41,7 @@ struct Dsymbol; struct TemplateInstance; struct CppMangleState; struct TemplateDeclaration; +struct JsonOut; enum LINK; struct TypeBasic; @@ -191,6 +192,7 @@ struct Type : Object #define tindex tsize_t // array/ptr index static Type *tvoidptr; // void* static Type *tstring; // immutable(char)[] + static Type *tvalist; // va_list alias #define terror basic[Terror] // for error recovery #define tnull basic[Tnull] // for null type @@ -239,6 +241,7 @@ struct Type : Object static unsigned char impcnvWarn[TMAX][TMAX]; Type(TY ty); + virtual const char *kind(); virtual Type *syntaxCopy(); int equals(Object *o); int dyncast() { return DYNCAST_TYPE; } // kludge for template.isType() @@ -263,6 +266,9 @@ struct Type : Object virtual void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); void toCBuffer3(OutBuffer *buf, HdrGenState *hgs, int mod); void modToBuffer(OutBuffer *buf); + char *modToChars(); + void toJsonProperty(JsonOut *json, const char *); + virtual void toJson(JsonOut *json); #if CPP_MANGLE virtual void toCppMangle(OutBuffer *buf, CppMangleState *cms); #endif @@ -275,7 +281,7 @@ struct Type : Object virtual int isunsigned(); virtual int isscope(); virtual int isString(); - virtual int isAssignable(int blit = 0); + virtual int isAssignable(); virtual int checkBoolean(); // if can be converted to boolean value virtual void checkDeprecated(Loc loc, Scope *sc); int isConst() { return mod & MODconst; } @@ -412,6 +418,7 @@ struct TypeBasic : Type unsigned flags; TypeBasic(TY ty); + const char *kind(); Type *syntaxCopy(); d_uns64 size(Loc loc); unsigned alignsize(); @@ -447,6 +454,7 @@ struct TypeVector : Type Type *basetype; TypeVector(Loc loc, Type *basetype); + const char *kind(); Type *syntaxCopy(); Type *semantic(Loc loc, Scope *sc); d_uns64 size(Loc loc); @@ -455,7 +463,12 @@ struct TypeVector : Type Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); char *toChars(); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); +#if IN_LLVM void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); +#else + void toDecoBuffer(OutBuffer *buf, int flag); +#endif + void toJson(JsonOut *json); MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch = NULL); #if CPP_MANGLE void toCppMangle(OutBuffer *buf, CppMangleState *cms); @@ -489,6 +502,7 @@ struct TypeSArray : TypeArray Expression *dim; TypeSArray(Type *t, Expression *dim); + const char *kind(); Type *syntaxCopy(); d_uns64 size(Loc loc); unsigned alignsize(); @@ -496,6 +510,7 @@ struct TypeSArray : TypeArray void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); + void toJson(JsonOut *json); Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); int isString(); int isZeroInit(Loc loc); @@ -530,6 +545,7 @@ struct TypeSArray : TypeArray struct TypeDArray : TypeArray { TypeDArray(Type *t); + const char *kind(); Type *syntaxCopy(); d_uns64 size(Loc loc); unsigned alignsize(); @@ -537,6 +553,7 @@ struct TypeDArray : TypeArray void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); + void toJson(JsonOut *json); Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); int isString(); int isZeroInit(Loc loc); @@ -566,6 +583,7 @@ struct TypeAArray : TypeArray StructDeclaration *impl; // implementation TypeAArray(Type *t, Type *index); + const char *kind(); Type *syntaxCopy(); d_uns64 size(Loc loc); Type *semantic(Loc loc, Scope *sc); @@ -573,6 +591,7 @@ struct TypeAArray : TypeArray void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); + void toJson(JsonOut *json); Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); Expression *defaultInit(Loc loc); MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch = NULL); @@ -600,10 +619,12 @@ struct TypeAArray : TypeArray struct TypePointer : TypeNext { TypePointer(Type *t); + const char *kind(); Type *syntaxCopy(); Type *semantic(Loc loc, Scope *sc); d_uns64 size(Loc loc); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); + void toJson(JsonOut *json); MATCH implicitConvTo(Type *to); MATCH constConv(Type *to); int isscalar(); @@ -624,10 +645,12 @@ struct TypePointer : TypeNext struct TypeReference : TypeNext { TypeReference(Type *t); + const char *kind(); Type *syntaxCopy(); Type *semantic(Loc loc, Scope *sc); d_uns64 size(Loc loc); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); + void toJson(JsonOut *json); Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); Expression *defaultInit(Loc loc); int isZeroInit(Loc loc); @@ -678,6 +701,8 @@ struct TypeFunction : TypeNext int inuse; TypeFunction(Parameters *parameters, Type *treturn, int varargs, enum LINK linkage, StorageClass stc = 0); + const char *kind(); + TypeFunction *copy(); Type *syntaxCopy(); Type *semantic(Loc loc, Scope *sc); void purityLevel(); @@ -686,6 +711,7 @@ struct TypeFunction : TypeNext void toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs); void toCBufferWithAttributes(OutBuffer *buf, Identifier *ident, HdrGenState* hgs, TypeFunction *attrs, TemplateDeclaration *td); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); + void toJson(JsonOut *json); void attributesToCBuffer(OutBuffer *buf, int mod); MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch = NULL); TypeInfoDeclaration *getTypeInfoDeclaration(); @@ -723,12 +749,14 @@ struct TypeDelegate : TypeNext // .next is a TypeFunction TypeDelegate(Type *t); + const char *kind(); Type *syntaxCopy(); Type *semantic(Loc loc, Scope *sc); d_uns64 size(Loc loc); unsigned alignsize(); MATCH implicitConvTo(Type *to); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); + void toJson(JsonOut *json); Expression *defaultInit(Loc loc); int isZeroInit(Loc loc); int checkBoolean(); @@ -754,6 +782,7 @@ struct TypeQualified : Type void syntaxCopyHelper(TypeQualified *t); void addIdent(Identifier *ident); void toCBuffer2Helper(OutBuffer *buf, HdrGenState *hgs); + void toJson(JsonOut *json); d_uns64 size(Loc loc); void resolveHelper(Loc loc, Scope *sc, Dsymbol *s, Dsymbol *scopesym, Expression **pe, Type **pt, Dsymbol **ps); @@ -765,10 +794,12 @@ struct TypeIdentifier : TypeQualified Dsymbol *originalSymbol; // The symbol representing this identifier, before alias resolution TypeIdentifier(Loc loc, Identifier *ident); + const char *kind(); Type *syntaxCopy(); //char *toChars(); void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); + void toJson(JsonOut *json); void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); Dsymbol *toDsymbol(Scope *sc); Type *semantic(Loc loc, Scope *sc); @@ -784,10 +815,12 @@ struct TypeInstance : TypeQualified TemplateInstance *tempinst; TypeInstance(Loc loc, TemplateInstance *tempinst); + const char *kind(); Type *syntaxCopy(); //char *toChars(); //void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); + void toJson(JsonOut *json); void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); Type *semantic(Loc loc, Scope *sc); Dsymbol *toDsymbol(Scope *sc); @@ -801,9 +834,11 @@ struct TypeTypeof : TypeQualified int inuse; TypeTypeof(Loc loc, Expression *exp); + const char *kind(); Type *syntaxCopy(); Dsymbol *toDsymbol(Scope *sc); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); + void toJson(JsonOut *json); Type *semantic(Loc loc, Scope *sc); d_uns64 size(Loc loc); }; @@ -811,10 +846,12 @@ struct TypeTypeof : TypeQualified struct TypeReturn : TypeQualified { TypeReturn(Loc loc); + const char *kind(); Type *syntaxCopy(); Dsymbol *toDsymbol(Scope *sc); Type *semantic(Loc loc, Scope *sc); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); + void toJson(JsonOut *json); }; struct TypeStruct : Type @@ -822,6 +859,7 @@ struct TypeStruct : Type StructDeclaration *sym; TypeStruct(StructDeclaration *sym); + const char *kind(); d_uns64 size(Loc loc); unsigned alignsize(); char *toChars(); @@ -830,13 +868,14 @@ struct TypeStruct : Type Dsymbol *toDsymbol(Scope *sc); void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); + void toJson(JsonOut *json); Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); structalign_t alignment(); Expression *defaultInit(Loc loc); Expression *defaultInitLiteral(Loc loc); Expression *voidInitLiteral(VarDeclaration *var); int isZeroInit(Loc loc); - int isAssignable(int blit = 0); + int isAssignable(); int checkBoolean(); int needsDestruction(); bool needsNested(); @@ -870,6 +909,7 @@ struct TypeEnum : Type EnumDeclaration *sym; TypeEnum(EnumDeclaration *sym); + const char *kind(); Type *syntaxCopy(); d_uns64 size(Loc loc); unsigned alignsize(); @@ -878,6 +918,7 @@ struct TypeEnum : Type Dsymbol *toDsymbol(Scope *sc); void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); + void toJson(JsonOut *json); Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); Expression *getProperty(Loc loc, Identifier *ident); int isintegral(); @@ -888,7 +929,7 @@ struct TypeEnum : Type int isscalar(); int isunsigned(); int checkBoolean(); - int isAssignable(int blit = 0); + int isAssignable(); int needsDestruction(); bool needsNested(); MATCH implicitConvTo(Type *to); @@ -914,6 +955,7 @@ struct TypeTypedef : Type TypedefDeclaration *sym; TypeTypedef(TypedefDeclaration *sym); + const char *kind(); Type *syntaxCopy(); d_uns64 size(Loc loc); unsigned alignsize(); @@ -922,6 +964,7 @@ struct TypeTypedef : Type Dsymbol *toDsymbol(Scope *sc); void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); + void toJson(JsonOut *json); Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); structalign_t alignment(); Expression *getProperty(Loc loc, Identifier *ident); @@ -933,7 +976,7 @@ struct TypeTypedef : Type int isscalar(); int isunsigned(); int checkBoolean(); - int isAssignable(int blit = 0); + int isAssignable(); int needsDestruction(); bool needsNested(); Type *toBasetype(); @@ -966,6 +1009,7 @@ struct TypeClass : Type ClassDeclaration *sym; TypeClass(ClassDeclaration *sym); + const char *kind(); d_uns64 size(Loc loc); char *toChars(); Type *syntaxCopy(); @@ -973,6 +1017,7 @@ struct TypeClass : Type Dsymbol *toDsymbol(Scope *sc); void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); + void toJson(JsonOut *json); Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); ClassDeclaration *isClassHandle(); int isBaseOf(Type *t, int *poffset); @@ -1009,12 +1054,18 @@ struct TypeTuple : Type TypeTuple(); TypeTuple(Type *t1); TypeTuple(Type *t1, Type *t2); + const char *kind(); Type *syntaxCopy(); Type *semantic(Loc loc, Scope *sc); int equals(Object *o); Type *reliesOnTident(TemplateParameters *tparams = NULL); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); +#if IN_LLVM void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); +#else + void toDecoBuffer(OutBuffer *buf, int flag); +#endif + void toJson(JsonOut *json); Expression *getProperty(Loc loc, Identifier *ident); Expression *defaultInit(Loc loc); TypeInfoDeclaration *getTypeInfoDeclaration(); @@ -1026,21 +1077,26 @@ struct TypeSlice : TypeNext Expression *upr; TypeSlice(Type *next, Expression *lwr, Expression *upr); + const char *kind(); Type *syntaxCopy(); Type *semantic(Loc loc, Scope *sc); void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); + void toJson(JsonOut *json); }; struct TypeNull : Type { TypeNull(); + const char *kind(); Type *syntaxCopy(); void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); MATCH implicitConvTo(Type *to); + int checkBoolean(); void toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs); + void toJson(JsonOut *json); d_uns64 size(Loc loc); //Expression *getProperty(Loc loc, Identifier *ident); @@ -1066,6 +1122,7 @@ struct Parameter : Object Type *isLazyArray(); void toDecoBuffer(OutBuffer *buf, bool mangle); int dyncast() { return DYNCAST_PARAMETER; } // kludge for template.isType() + void toJson(JsonOut *json); static Parameters *arraySyntaxCopy(Parameters *args); static char *argsTypesToChars(Parameters *args, int varargs); static void argsCppMangle(OutBuffer *buf, CppMangleState *cms, Parameters *arguments, int varargs); @@ -1089,6 +1146,7 @@ extern int Tptrdiff_t; int arrayTypeCompatible(Loc loc, Type *t1, Type *t2); int arrayTypeCompatibleWithoutCasting(Loc loc, Type *t1, Type *t2); void MODtoBuffer(OutBuffer *buf, unsigned char mod); +char *MODtoChars(unsigned char mod); int MODimplicitConv(unsigned char modfrom, unsigned char modto); int MODmethodConv(unsigned char modfrom, unsigned char modto); int MODmerge(unsigned char mod1, unsigned char mod2); diff --git a/dmd2/opover.c b/dmd2/opover.c index 5d731df2..16cea8a2 100644 --- a/dmd2/opover.c +++ b/dmd2/opover.c @@ -465,6 +465,15 @@ Expression *BinExp::op_overload(Scope *sc) AggregateDeclaration *ad1 = isAggregate(e1->type); AggregateDeclaration *ad2 = isAggregate(e2->type); + if (op == TOKassign && ad1 == ad2) + { + StructDeclaration *sd = ad1->isStructDeclaration(); + if (sd && !sd->hasIdentityAssign) + { /* This is bitwise struct assignment. */ + return NULL; + } + } + Dsymbol *s = NULL; Dsymbol *s_r = NULL; diff --git a/dmd2/optimize.c b/dmd2/optimize.c index 0b0530b3..a6f8453a 100644 --- a/dmd2/optimize.c +++ b/dmd2/optimize.c @@ -27,9 +27,6 @@ #ifdef IN_GCC #include "d-gcc-real.h" - -/* %% fix? */ -extern "C" bool real_isnan (const real_t *); #endif static real_t zero; // work around DMC bug for now diff --git a/dmd2/parse.c b/dmd2/parse.c index ef36b455..603e0c4f 100644 --- a/dmd2/parse.c +++ b/dmd2/parse.c @@ -269,6 +269,20 @@ Dsymbols *Parser::parseDeclDefs(int once) case TOKunittest: s = parseUnitTest(); + if (decldefs && decldefs->dim) + { + Dsymbol *ds = (*decldefs)[decldefs->dim-1]; + AttribDeclaration *ad; + while ((ad = ds->isAttribDeclaration()) != NULL) + { + if (ad->decl && ad->decl->dim) + ds = (*ad->decl)[ad->decl->dim-1]; + else + break; + } + + ds->unittest = (UnitTestDeclaration *)s; + } break; case TOKnew: @@ -2238,7 +2252,11 @@ Objects *Parser::parseTemplateArgument() break; } if (token.value == TOKnot) - error("multiple ! arguments are not allowed"); + { + enum TOK tok = peekNext(); + if (tok != TOKis && tok != TOKin) + error("multiple ! arguments are not allowed"); + } return tiargs; } @@ -2843,6 +2861,7 @@ Dsymbols *Parser::parseDeclarations(StorageClass storage_class, unsigned char *c addComment(s, comment); return a; } +#if 0 /* Look for: * alias this = identifier; */ @@ -2858,6 +2877,7 @@ Dsymbols *Parser::parseDeclarations(StorageClass storage_class, unsigned char *c addComment(s, comment); return a; } +#endif /* Look for: * alias identifier = type; */ diff --git a/dmd2/root/array.c b/dmd2/root/array.c index 94c2cebb..6f949755 100644 --- a/dmd2/root/array.c +++ b/dmd2/root/array.c @@ -1,5 +1,5 @@ -// Copyright (c) 1999-2010 by Digital Mars +// Copyright (c) 1999-2013 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -9,35 +9,9 @@ #include #include -#include #include #include -#if defined (__sun) -#include -#endif - -#if _MSC_VER || __MINGW32__ -#include -#endif - -#if IN_GCC -#include "gdc_alloca.h" -#endif - -#if _WIN32 -#include -#endif - -#ifndef _WIN32 -#include -#include -#include -#include -#include -#include -#endif - #include "port.h" #include "root.h" #include "rmem.h" @@ -181,25 +155,19 @@ void Array::remove(size_t i) char *Array::toChars() { - size_t len; - size_t u; - char **buf; - char *str; - char *p; - - buf = (char **)malloc(dim * sizeof(char *)); + char **buf = (char **)malloc(dim * sizeof(char *)); assert(buf); - len = 2; - for (u = 0; u < dim; u++) + size_t len = 2; + for (size_t u = 0; u < dim; u++) { buf[u] = ((Object *)data[u])->toChars(); len += strlen(buf[u]) + 1; } - str = (char *)mem.malloc(len); + char *str = (char *)mem.malloc(len); str[0] = '['; - p = str + 1; - for (u = 0; u < dim; u++) + char *p = str + 1; + for (size_t u = 0; u < dim; u++) { if (u) *p++ = ','; diff --git a/dmd2/root/gnuc.c b/dmd2/root/gnuc.c deleted file mode 100644 index 90358da1..00000000 --- a/dmd2/root/gnuc.c +++ /dev/null @@ -1,63 +0,0 @@ - -// 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" - -int memicmp(const char *s1, const char *s2, int n) -{ - int result = 0; - - for (int i = 0; i < n; i++) - { char c1 = s1[i]; - char c2 = s2[i]; - - result = c1 - c2; - if (result) - { - if ('A' <= c1 && c1 <= 'Z') - c1 += 'a' - 'A'; - if ('A' <= c2 && c2 <= 'Z') - c2 += 'a' - 'A'; - result = c1 - c2; - if (result) - break; - } - } - return result; -} - -int stricmp(const char *s1, const char *s2) -{ - int result = 0; - - for (;;) - { char c1 = *s1; - char c2 = *s2; - - result = c1 - c2; - if (result) - { - if ('A' <= c1 && c1 <= 'Z') - c1 += 'a' - 'A'; - if ('A' <= c2 && c2 <= 'Z') - c2 += 'a' - 'A'; - result = c1 - c2; - if (result) - break; - } - if (!c1) - break; - s1++; - s2++; - } - return result; -} - diff --git a/dmd2/root/gnuc.h b/dmd2/root/gnuc.h deleted file mode 100644 index 6b25fbf2..00000000 --- a/dmd2/root/gnuc.h +++ /dev/null @@ -1,16 +0,0 @@ - -// 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 - -int memicmp(const char *s1, const char *s2, int n); -int stricmp(const char *s1, const char *s2); - -#endif diff --git a/dmd2/root/port.c b/dmd2/root/port.c index 238059a6..820a36e8 100644 --- a/dmd2/root/port.c +++ b/dmd2/root/port.c @@ -116,6 +116,16 @@ char *Port::strupr(char *s) return ::strupr(s); } +int Port::memicmp(const char *s1, const char *s2, int n) +{ + return ::memicmp(s1, s2, n); +} + +int Port::stricmp(const char *s1, const char *s2) +{ + return ::stricmp(s1, s2); +} + #endif #if _MSC_VER @@ -328,6 +338,16 @@ char *Port::strupr(char *s) return ::strupr(s); } +int Port::memicmp(const char *s1, const char *s2, int n) +{ + return ::memicmp(s1, s2, n); +} + +int Port::stricmp(const char *s1, const char *s2) +{ + return ::stricmp(s1, s2); +} + #endif #if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __HAIKU__ || __MINGW32__ @@ -524,6 +544,48 @@ char *Port::strupr(char *s) return t; } +int Port::memicmp(const char *s1, const char *s2, int n) +{ + int result = 0; + + for (int i = 0; i < n; i++) + { char c1 = s1[i]; + char c2 = s2[i]; + + result = c1 - c2; + if (result) + { + result = toupper(c1) - toupper(c2); + if (result) + break; + } + } + return result; +} + +int Port::stricmp(const char *s1, const char *s2) +{ + int result = 0; + + for (;;) + { char c1 = *s1; + char c2 = *s2; + + result = c1 - c2; + if (result) + { + result = toupper(c1) - toupper(c2); + if (result) + break; + } + if (!c1) + break; + s1++; + s2++; + } + return result; +} + #endif #if __sun @@ -670,18 +732,3 @@ char *Port::strupr(char *s) } #endif - - -#if IN_LLVM -#if __MINGW32__ -longdouble Port::strtold(const char *str, char **pend) -{ - return __mingw_strtold(str, pend); -} -#else -longdouble Port::strtold(const char *str, char **pend) -{ - return ::strtold(str, pend); -} -#endif -#endif diff --git a/dmd2/root/port.h b/dmd2/root/port.h index 8d4136aa..6714cd71 100644 --- a/dmd2/root/port.h +++ b/dmd2/root/port.h @@ -61,9 +61,6 @@ struct Port static longdouble fmodl(longdouble x, longdouble y); static ulonglong strtoull(const char *p, char **pend, int base); -#if IN_LLVM - static longdouble strtold(const char *str, char **pend); -#endif static char *ull_to_string(char *buffer, ulonglong ull); static wchar_t *ull_to_string(wchar_t *buffer, ulonglong ull); @@ -76,6 +73,9 @@ struct Port static const wchar_t *wlist_separator(); static char *strupr(char *); + + static int memicmp(const char *s1, const char *s2, int n); + static int stricmp(const char *s1, const char *s2); }; #endif diff --git a/dmd2/root/response.c b/dmd2/root/response.c index e2e91b92..31b41b7d 100644 --- a/dmd2/root/response.c +++ b/dmd2/root/response.c @@ -5,7 +5,7 @@ // Written by Walter Bright /* * This source file is made available for personal use - * only. The license is in /dmd/src/dmd/backendlicense.txt + * only. The license is in backendlicense.txt * For any other uses, please contact Digital Mars. */ diff --git a/dmd2/root/root.c b/dmd2/root/root.c index 01fe0d89..8a16e83f 100644 --- a/dmd2/root/root.c +++ b/dmd2/root/root.c @@ -139,19 +139,19 @@ void Object::mark() /****************************** String ********************************/ -String::String(char *str) +String::String(const char *str) : str(mem.strdup(str)) { } String::~String() { - mem.free(str); + mem.free((void *)str); } void String::mark() { - mem.mark(str); + mem.mark((void *)str); } hash_t String::calcHash(const char *str, size_t len) @@ -218,7 +218,7 @@ int String::compare(Object *obj) char *String::toChars() { - return str; + return (char *)str; // toChars() should really be const } void String::print() @@ -229,12 +229,12 @@ void String::print() /****************************** FileName ********************************/ -FileName::FileName(char *str) +FileName::FileName(const char *str) : String(str) { } -char *FileName::combine(const char *path, const char *name) +const char *FileName::combine(const char *path, const char *name) { char *f; size_t pathlen; size_t namelen; @@ -431,12 +431,11 @@ int FileName::absolute(const char *name) * If there isn't one, return NULL. */ -char *FileName::ext(const char *str) +const char *FileName::ext(const char *str) { - char *e; size_t len = strlen(str); - e = (char *)str + len; + const char *e = str + len; for (;;) { switch (*e) @@ -462,7 +461,7 @@ char *FileName::ext(const char *str) } } -char *FileName::ext() +const char *FileName::ext() { return ext(str); } @@ -471,7 +470,7 @@ char *FileName::ext() * Return mem.malloc'd filename with extension removed. */ -char *FileName::removeExt(const char *str) +const char *FileName::removeExt(const char *str) { const char *e = ext(str); if (e) @@ -488,12 +487,11 @@ char *FileName::removeExt(const char *str) * Return filename name excluding path (read-only). */ -char *FileName::name(const char *str) +const char *FileName::name(const char *str) { - char *e; size_t len = strlen(str); - e = (char *)str + len; + const char *e = str + len; for (;;) { switch (*e) @@ -525,7 +523,7 @@ char *FileName::name(const char *str) } } -char *FileName::name() +const char *FileName::name() { return name(str); } @@ -535,10 +533,9 @@ char *FileName::name() * Path will does not include trailing path separator. */ -char *FileName::path(const char *str) +const char *FileName::path(const char *str) { - char *n = name(str); - char *path; + const char *n = name(str); size_t pathlen; if (n > str) @@ -554,7 +551,7 @@ char *FileName::path(const char *str) #endif } pathlen = n - str; - path = (char *)mem.malloc(pathlen + 1); + char *path = (char *)mem.malloc(pathlen + 1); memcpy(path, str, pathlen); path[pathlen] = 0; return path; @@ -565,20 +562,19 @@ char *FileName::path(const char *str) */ const char *FileName::replaceName(const char *path, const char *name) -{ char *f; - char *n; +{ size_t pathlen; size_t namelen; if (absolute(name)) return name; - n = FileName::name(path); + const char *n = FileName::name(path); if (n == path) return name; pathlen = n - path; namelen = strlen(name); - f = (char *)mem.malloc(pathlen + 1 + namelen + 1); + char *f = (char *)mem.malloc(pathlen + 1 + namelen + 1); memcpy(f, path, pathlen); #if POSIX if (path[pathlen - 1] != '/') @@ -600,48 +596,40 @@ const char *FileName::replaceName(const char *path, const char *name) } /*************************** + * Free returned value with FileName::free() */ -FileName *FileName::defaultExt(const char *name, const char *ext) +const char *FileName::defaultExt(const char *name, const char *ext) { - char *e; - char *s; - size_t len; - size_t extlen; - - e = FileName::ext(name); + const char *e = FileName::ext(name); if (e) // if already has an extension - return new FileName((char *)name); + return mem.strdup(name); - len = strlen(name); - extlen = strlen(ext); - s = (char *)alloca(len + 1 + extlen + 1); + size_t len = strlen(name); + size_t extlen = strlen(ext); + char *s = (char *)mem.malloc(len + 1 + extlen + 1); memcpy(s,name,len); s[len] = '.'; memcpy(s + len + 1, ext, extlen + 1); - return new FileName(s); + return s; } /*************************** + * Free returned value with FileName::free() */ -FileName *FileName::forceExt(const char *name, const char *ext) +const char *FileName::forceExt(const char *name, const char *ext) { - char *e; - char *s; - size_t len; - size_t extlen; - - e = FileName::ext(name); + const char *e = FileName::ext(name); if (e) // if already has an extension { - len = e - name; - extlen = strlen(ext); + size_t len = e - name; + size_t extlen = strlen(ext); - s = (char *)alloca(len + extlen + 1); + char *s = (char *)mem.malloc(len + extlen + 1); memcpy(s,name,len); memcpy(s + len, ext, extlen + 1); - return new FileName(s); + return s; } else return defaultExt(name, ext); // doesn't have one @@ -652,20 +640,18 @@ FileName *FileName::forceExt(const char *name, const char *ext) */ int FileName::equalsExt(const char *ext) -{ const char *e; +{ + return equalsExt(str, ext); +} - e = FileName::ext(); +int FileName::equalsExt(const char *name, const char *ext) +{ + const char *e = FileName::ext(name); if (!e && !ext) return 1; if (!e || !ext) return 0; -#if POSIX - return strcmp(e,ext) == 0; -#elif _WIN32 - return stricmp(e,ext) == 0; -#else - assert(0); -#endif + return FileName::compare(e, ext) == 0; } /************************************* @@ -694,24 +680,24 @@ void FileName::CopyTo(FileName *to) * cwd if !=0, search current directory before searching path */ -char *FileName::searchPath(Strings *path, const char *name, int cwd) +const char *FileName::searchPath(Strings *path, const char *name, int cwd) { if (absolute(name)) { - return exists(name) ? (char *)name : NULL; + return exists(name) ? name : NULL; } if (cwd) { if (exists(name)) - return (char *)name; + return name; } if (path) - { unsigned i; + { - for (i = 0; i < path->dim; i++) + for (size_t i = 0; i < path->dim; i++) { - char *p = path->tdata()[i]; - char *n = combine(p, name); + const char *p = path->tdata()[i]; + const char *n = combine(p, name); if (exists(n)) return n; @@ -734,7 +720,7 @@ char *FileName::searchPath(Strings *path, const char *name, int cwd) * !=NULL mem.malloc'd file name */ -char *FileName::safeSearchPath(Strings *path, const char *name) +const char *FileName::safeSearchPath(Strings *path, const char *name) { #if _WIN32 /* Disallow % / \ : and .. in name characters @@ -763,15 +749,14 @@ char *FileName::safeSearchPath(Strings *path, const char *name) } if (path) - { unsigned i; - + { /* Each path is converted to a cannonical name and then a check is done to see * that the searched name is really a child one of the the paths searched. */ - for (i = 0; i < path->dim; i++) + for (size_t i = 0; i < path->dim; i++) { - char *cname = NULL; - char *cpath = canonicalName(path->tdata()[i]); + const char *cname = NULL; + const char *cpath = canonicalName(path->tdata()[i]); //printf("FileName::safeSearchPath(): name=%s; path=%s; cpath=%s\n", // name, (char *)path->data[i], cpath); if (cpath == NULL) @@ -786,16 +771,16 @@ char *FileName::safeSearchPath(Strings *path, const char *name) // exists and name is *really* a "child" of path if (exists(cname) && strncmp(cpath, cname, strlen(cpath)) == 0) { - free(cpath); - char *p = mem.strdup(cname); - free(cname); + ::free((void *)cpath); + const char *p = mem.strdup(cname); + ::free((void *)cname); return p; } cont: if (cpath) - free(cpath); + ::free((void *)cpath); if (cname) - free(cname); + ::free((void *)cname); } } return NULL; @@ -839,18 +824,18 @@ void FileName::ensurePathExists(const char *path) { if (!exists(path)) { - char *p = FileName::path(path); + const char *p = FileName::path(path); if (*p) { #if _WIN32 size_t len = strlen(path); if (len > 2 && p[-1] == ':' && path + 2 == p) - { mem.free(p); + { mem.free((void *)p); return; } #endif ensurePathExists(p); - mem.free(p); + mem.free((void *)p); } #if _WIN32 if (path[strlen(path) - 1] != '\\') @@ -878,12 +863,20 @@ void FileName::ensurePathExists(const char *path) } } +void FileName::ensurePathToNameExists(const char *name) +{ + const char *pt = path(name); + if (*pt) + ensurePathExists(pt); + free(pt); +} + /****************************************** * Return canonical version of name in a malloc'd buffer. * This code is high risk. */ -char *FileName::canonicalName(const char *name) +const char *FileName::canonicalName(const char *name) { #if linux // Lovely glibc extension to do it for us @@ -922,7 +915,7 @@ char *FileName::canonicalName(const char *name) result = GetFullPathName(name, result, buf, NULL); if (result == 0) { - free(buf); + ::free(buf); return NULL; } return buf; @@ -934,19 +927,31 @@ char *FileName::canonicalName(const char *name) #endif } +/******************************** + * Free memory allocated by FileName routines + */ +void FileName::free(const char *str) +{ + if (str) + { assert(str[0] != 0xAB); + memset((void *)str, 0xAB, strlen(str) + 1); // stomp + } + mem.free((void *)str); +} + /****************************** File ********************************/ -File::File(FileName *n) +File::File(const FileName *n) { ref = 0; buffer = NULL; len = 0; touchtime = NULL; - name = n; + name = (FileName *)n; } -File::File(char *n) +File::File(const char *n) { ref = 0; buffer = NULL; @@ -1372,13 +1377,10 @@ Files *File::match(FileName *n) #elif _WIN32 HANDLE h; WIN32_FIND_DATAA fileinfo; - Files *a; - char *c; - char *name; - a = new Files(); - c = n->toChars(); - name = n->name(); + Files *a = new Files(); + const char *c = n->toChars(); + const char *name = n->name(); h = FindFirstFileA(c,&fileinfo); if (h != INVALID_HANDLE_VALUE) { diff --git a/dmd2/root/root.h b/dmd2/root/root.h index 6b7ba246..6cb36d69 100644 --- a/dmd2/root/root.h +++ b/dmd2/root/root.h @@ -76,9 +76,9 @@ struct Object struct String : Object { - char *str; // the string itself + const char *str; // the string itself - String(char *str); + String(const char *str); ~String(); static hash_t calcHash(const char *str, size_t len); @@ -94,33 +94,38 @@ struct String : Object struct FileName : String { - FileName(char *str); + FileName(const char *str); hash_t hashCode(); int equals(Object *obj); static int equals(const char *name1, const char *name2); int compare(Object *obj); static int compare(const char *name1, const char *name2); static int absolute(const char *name); - static char *ext(const char *); - char *ext(); - static char *removeExt(const char *str); - static char *name(const char *); - char *name(); - static char *path(const char *); + static const char *ext(const char *); + const char *ext(); + static const char *removeExt(const char *str); + static const char *name(const char *); + const char *name(); + static const char *path(const char *); static const char *replaceName(const char *path, const char *name); - static char *combine(const char *path, const char *name); + static const char *combine(const char *path, const char *name); static Strings *splitPath(const char *path); - static FileName *defaultExt(const char *name, const char *ext); - static FileName *forceExt(const char *name, const char *ext); + static const char *defaultExt(const char *name, const char *ext); + static const char *forceExt(const char *name, const char *ext); + static int equalsExt(const char *name, const char *ext); + int equalsExt(const char *ext); void CopyTo(FileName *to); - static char *searchPath(Strings *path, const char *name, int cwd); - static char *safeSearchPath(Strings *path, const char *name); + static const char *searchPath(Strings *path, const char *name, int cwd); + static const char *safeSearchPath(Strings *path, const char *name); static int exists(const char *name); static void ensurePathExists(const char *path); - static char *canonicalName(const char *name); + static void ensurePathToNameExists(const char *name); + static const char *canonicalName(const char *name); + + static void free(const char *str); }; struct File : Object @@ -132,8 +137,8 @@ struct File : Object FileName *name; // name of our file - File(char *); - File(FileName *); + File(const char *); + File(const FileName *); ~File(); void mark(); @@ -271,7 +276,7 @@ struct OutBuffer : Object char *extractString(); }; -struct Array : Object +struct Array { size_t dim; void **data; diff --git a/dmd2/root/stringtable.c b/dmd2/root/stringtable.c index 5464f7f0..f1ea45d3 100644 --- a/dmd2/root/stringtable.c +++ b/dmd2/root/stringtable.c @@ -1,5 +1,5 @@ -// Copyright (c) 1999-2011 by Digital Mars +// Copyright (c) 1999-2013 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com diff --git a/dmd2/scope.c b/dmd2/scope.c index a58ed613..09da8d9c 100644 --- a/dmd2/scope.c +++ b/dmd2/scope.c @@ -131,7 +131,7 @@ Scope::Scope(Scope *enclosing) this->parameterSpecialization = enclosing->parameterSpecialization; this->ignoreTemplates = enclosing->ignoreTemplates; this->callSuper = enclosing->callSuper; - this->flags = (enclosing->flags & SCOPEcontract); + this->flags = (enclosing->flags & (SCOPEcontract | SCOPEdebug)); this->lastdc = NULL; this->lastoffset = 0; this->docbuf = enclosing->docbuf; diff --git a/dmd2/scope.h b/dmd2/scope.h index 09f60b03..a3b7725b 100644 --- a/dmd2/scope.h +++ b/dmd2/scope.h @@ -25,7 +25,6 @@ struct LabelStatement; struct ForeachStatement; struct ClassDeclaration; struct AggregateDeclaration; -struct AnonymousAggregateDeclaration; struct FuncDeclaration; struct DocComment; struct TemplateInstance; diff --git a/dmd2/statement.c b/dmd2/statement.c index 15da3909..ecabefdd 100644 --- a/dmd2/statement.c +++ b/dmd2/statement.c @@ -31,8 +31,6 @@ #include "import.h" #if IN_LLVM -// From pragma.cpp -bool matchPragma(Identifier* needle, Identifier* ident, Identifier* oldIdent); #if defined(_MSC_VER) #include #else @@ -923,7 +921,8 @@ void UnrolledLoopStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) buf->level++; for (size_t i = 0; i < statements->dim; i++) - { Statement *s; + { + Statement *s; s = (*statements)[i]; if (s) @@ -1131,46 +1130,20 @@ bool WhileStatement::hasContinue() bool WhileStatement::usesEH() { - assert(0); - return body ? body->usesEH() : 0; + assert(global.errors); + return 0; } int WhileStatement::blockExit(bool mustNotThrow) { - assert(0); - //printf("WhileStatement::blockExit(%p)\n", this); - - int result = BEnone; - if (condition->canThrow(mustNotThrow)) - result |= BEthrow; - if (condition->isBool(TRUE)) - { - if (body) - { result |= body->blockExit(mustNotThrow); - if (result & BEbreak) - result |= BEfallthru; - } - } - else if (condition->isBool(FALSE)) - { - result |= BEfallthru; - } - else - { - if (body) - result |= body->blockExit(mustNotThrow); - result |= BEfallthru; - } - result &= ~(BEbreak | BEcontinue); - return result; + assert(global.errors); + return BEfallthru; } int WhileStatement::comeFrom() { - assert(0); - if (body) - return body->comeFrom(); + assert(global.errors); return FALSE; } @@ -1847,7 +1820,9 @@ Lagain: { /* Reference to immutable data should be marked as const */ - if (!tn->isMutable()) + if (aggr->checkModifiable(sc, 1) == 2) + var->storage_class |= STCctorinit; + else if (!tn->isMutable()) var->storage_class |= STCconst; Type *t = tab->nextOf(); @@ -1982,18 +1957,12 @@ Lagain: error("only one or two arguments for associative array foreach"); break; } -#if SARRAYVALUE + /* This only works if Key or Value is a static array. */ tab = taa->getImpl()->type; goto Lagain; -#else - if (op == TOKforeach_reverse) - { - error("no reverse iteration on associative arrays"); - } - goto Lapply; -#endif + case Tclass: case Tstruct: #if DMDV2 @@ -2757,33 +2726,20 @@ bool ForeachRangeStatement::hasContinue() bool ForeachRangeStatement::usesEH() { - assert(0); + assert(global.errors); return body->usesEH(); } int ForeachRangeStatement::blockExit(bool mustNotThrow) { - assert(0); - int result = BEfallthru; - - if (lwr && lwr->canThrow(mustNotThrow)) - result |= BEthrow; - else if (upr && upr->canThrow(mustNotThrow)) - result |= BEthrow; - - if (body) - { - result |= body->blockExit(mustNotThrow) & ~(BEbreak | BEcontinue); - } - return result; + assert(global.errors); + return BEfallthru; } int ForeachRangeStatement::comeFrom() { - assert(0); - if (body) - return body->comeFrom(); + assert(global.errors); return FALSE; } @@ -2952,7 +2908,8 @@ void IfStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) if (arg->type) arg->type->toCBuffer(buf, arg->ident, hgs); else - { buf->writestring("auto "); + { + buf->writestring("auto "); buf->writestring(arg->ident->toChars()); } buf->writestring(" = "); @@ -2966,7 +2923,8 @@ void IfStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) if (!ifbody->isScopeStatement()) buf->level--; if (elsebody) - { buf->writestring("else"); + { + buf->writestring("else"); buf->writenl(); if (!elsebody->isScopeStatement()) buf->level++; @@ -3170,8 +3128,8 @@ Statement *PragmaStatement::semantic(Scope *sc) #endif } #if IN_LLVM - // FIXME Move to pragma.cpp - else if (matchPragma(ident, Id::LDC_allow_inline, Id::allow_inline)) + // LDC + else if (ident == Id::allow_inline) { sc->func->allowInlining = true; } @@ -3343,7 +3301,8 @@ Statement *SwitchStatement::semantic(Scope *sc) } else { condition = condition->integralPromotions(sc); - condition->checkIntegral(); + if (!condition->type->isintegral()) + error("'%s' must be of integral or string type, it is a %s", condition->toChars(), condition->type->toChars()); } condition = condition->optimize(WANTvalue); @@ -3392,14 +3351,18 @@ Statement *SwitchStatement::semantic(Scope *sc) #if DMDV2 if (isFinal) { Type *t = condition->type; - while (t->ty == Ttypedef) + while (t && t->ty == Ttypedef) { // Don't use toBasetype() because that will skip past enums t = ((TypeTypedef *)t)->sym->basetype; } - if (te) + Dsymbol *ds; + EnumDeclaration *ed = NULL; + if (t && ((ds = t->toDsymbol(sc)) != NULL)) + ed = ds->isEnumDeclaration(); // typedef'ed enum + if (!ed && te && ((ds = te->toDsymbol(sc)) != NULL)) + ed = ds->isEnumDeclaration(); + if (ed) { - EnumDeclaration *ed = te->toDsymbol(sc)->isEnumDeclaration(); - assert(ed); size_t dim = ed->members->dim; for (size_t i = 0; i < dim; i++) { @@ -3442,8 +3405,10 @@ Statement *SwitchStatement::semantic(Scope *sc) a->reserve(2); sc->sw->sdefault = new DefaultStatement(loc, s); - a->push(sc->sw->sdefault); a->push(body); + if (body->blockExit(FALSE) & BEfallthru) + a->push(new BreakStatement(0, NULL)); + a->push(sc->sw->sdefault); cs = new CompoundStatement(loc, a); body = cs; } @@ -3490,7 +3455,8 @@ void SwitchStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) if (body) { if (!body->isScopeStatement()) - { buf->writebyte('{'); + { + buf->writebyte('{'); buf->writenl(); buf->level++; body->toCBuffer(buf, hgs); @@ -3567,7 +3533,7 @@ Statement *CaseStatement::semantic(Scope *sc) if (exp->op != TOKstring && exp->op != TOKint64 && exp->op != TOKerror) { error("case must be a string or an integral constant, not %s", exp->toChars()); - exp = new IntegerExp(0); + exp = new ErrorExp(); } L1: @@ -4073,7 +4039,7 @@ Statement *ReturnStatement::semantic(Scope *sc) } else { - if (tf->isref) + if (tf->isref && (fd->storage_class & STCauto)) { /* Determine "refness" of function return: * if it's an lvalue, return by ref, else return by value */ @@ -4086,11 +4052,11 @@ Statement *ReturnStatement::semantic(Scope *sc) unsigned errors = global.startGagging(); exp->checkEscapeRef(); if (global.endGagging(errors)) - { tf->isref = FALSE; // return by value - } + tf->isref = FALSE; // return by value } else tf->isref = FALSE; // return by value + fd->storage_class &= ~STCauto; } tf->next = exp->type; //fd->type = tf->semantic(loc, sc); // Removed with 6902 @@ -4786,7 +4752,7 @@ Statement *WithStatement::semantic(Scope *sc) sym->parent = sc->scopesym; } else - { error("with expressions must be class objects, not '%s'", exp->type->toChars()); + { error("with expressions must be aggregate types, not '%s'", exp->type->toChars()); return NULL; } } @@ -5269,9 +5235,10 @@ Statement *ThrowStatement::semantic(Scope *sc) int ThrowStatement::blockExit(bool mustNotThrow) { - if (mustNotThrow) + Type *t = exp->type->toBasetype(); + if (mustNotThrow && t->ty != Terror) { - ClassDeclaration *cd = exp->type->toBasetype()->isClassHandle(); + ClassDeclaration *cd = t->isClassHandle(); assert(cd); // Bugzilla 8675 @@ -5649,6 +5616,7 @@ void AsmStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writestring("asm { "); Token *t = tokens; + buf->level++; while (t) { buf->writestring(t->toChars()); @@ -5669,6 +5637,7 @@ void AsmStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) } t = t->next; } + buf->level--; buf->writestring("; }"); buf->writenl(); } diff --git a/dmd2/statement.h b/dmd2/statement.h index e085a409..4ff0ddee 100644 --- a/dmd2/statement.h +++ b/dmd2/statement.h @@ -673,7 +673,7 @@ struct SwitchErrorStatement : Statement struct ReturnStatement : Statement { Expression *exp; - int implicit0; + bool implicit0; // this is an implicit "return 0;" ReturnStatement(Loc loc, Expression *exp); Statement *syntaxCopy(); diff --git a/dmd2/staticassert.c b/dmd2/staticassert.c index 662b74a1..3ce09b1d 100644 --- a/dmd2/staticassert.c +++ b/dmd2/staticassert.c @@ -3,7 +3,6 @@ // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com -// http://www.dsource.org/projects/dmd/browser/trunk/src/staticassert.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. diff --git a/dmd2/struct.c b/dmd2/struct.c index 3bef2d59..6c7135d2 100644 --- a/dmd2/struct.c +++ b/dmd2/struct.c @@ -441,11 +441,7 @@ void StructDeclaration::semantic(Scope *sc) parent = sc->parent; type = type->semantic(loc, sc); -#if STRUCTTHISREF handle = type; -#else - handle = type->pointerTo(); -#endif protection = sc->protection; alignment = sc->structalign; storage_class |= sc->stc; @@ -743,7 +739,7 @@ void StructDeclaration::finalizeSize(Scope *sc) void StructDeclaration::makeNested() { - if (!isnested && sizeok != SIZEOKdone) + if (!isnested && sizeok != SIZEOKdone && !isUnionDeclaration()) { // If nested struct, add in hidden 'this' pointer to outer scope if (!(storage_class & STCstatic)) diff --git a/dmd2/template.c b/dmd2/template.c index bafbf7ae..5aabcd0f 100644 --- a/dmd2/template.c +++ b/dmd2/template.c @@ -699,7 +699,7 @@ void TemplateDeclaration::makeParamNamesVisibleInConstraint(Scope *paramscope, E if (!paramscope->insert(v)) error("parameter %s.%s is already defined", toChars(), v->toChars()); else - v->parent = this; + v->parent = fd; } } } @@ -1350,6 +1350,15 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Scope *sc, Loc loc, Objec if (m < match) match = m; + /* Remove top const for dynamic array types and pointer types + */ + if ((tt->ty == Tarray || tt->ty == Tpointer) && + !tt->isMutable() && + (!(fparam->storageClass & STCref) || + (fparam->storageClass & STCauto) && !farg->isLvalue())) + { + tt = tt->mutableOf(); + } t->objects[i] = tt; } declareParameter(paramscope, tp, t); @@ -1585,21 +1594,7 @@ 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; + goto Lnomatch; } } if (m && (fparam->storageClass & STCout)) @@ -2253,22 +2248,19 @@ FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Scope *sc, Loc loc, /* As Bugzilla 3682 shows, a template instance can be matched while instantiating * that same template. Thus, the function type can be incomplete. Complete it. + * + * Bugzilla 9208: For auto function, completion should be deferred to the end of + * its semantic3. Should not complete it in here. */ { TypeFunction *tf = (TypeFunction *)fd_best->type; assert(tf->ty == Tfunction); - if (tf->next) + if (tf->next && !fd_best->inferRetType) + { fd_best->type = tf->semantic(loc, sc); + } } - if (fd_best->scope) - { - TemplateInstance *spec = fd_best->isSpeculative(); - int olderrs = global.errors; - fd_best->semantic3(fd_best->scope); - // Update the template instantiation with the number - // of errors which occured. - if (spec && global.errors != olderrs) - spec->errors = global.errors - olderrs; - } + + fd_best->functionSemantic(); return fd_best; @@ -2448,9 +2440,11 @@ char *TemplateDeclaration::toChars() } buf.writeByte(')'); - if (onemember && onemember->toAlias()) - { - FuncDeclaration *fd = onemember->toAlias()->isFuncDeclaration(); + if (onemember) + { /* Bugzilla 9406: + * onemember->toAlias() might run semantic, so should not call it in stringizing + */ + FuncDeclaration *fd = onemember->isFuncDeclaration(); if (fd && fd->type) { TypeFunction *tf = (TypeFunction *)fd->type; @@ -3983,6 +3977,45 @@ Lnomatch: return 0; } +/* Bugzilla 6538: In template constraint, each function parameters, 'this', + * and 'super' is *pseudo* symbol. If it is passed to other template through + * alias/tuple parameter, it will cause an error. Because such symbol + * does not have the actual entity yet. + * + * Example: + * template Sym(alias A) { enum Sym = true; } + * struct S { + * void foo() if (Sym!(this)) {} // Sym!(this) always make an error, + * } // because Sym template cannot + * void main() { S s; s.foo(); } // access to the valid 'this' symbol. + */ +bool isPseudoDsymbol(Object *o) +{ + Dsymbol *s = isDsymbol(o); + Expression *e = isExpression(o); + if (e && e->op == TOKvar) s = ((VarExp *)e)->var->isVarDeclaration(); + if (e && e->op == TOKthis) s = ((ThisExp *)e)->var->isThisDeclaration(); + if (e && e->op == TOKsuper) s = ((SuperExp *)e)->var->isThisDeclaration(); + + if (s && s->parent) + { + s = s->toAlias(); + VarDeclaration *v = s->isVarDeclaration(); + TupleDeclaration *t = s->isTupleDeclaration(); + if (v || t) + { + FuncDeclaration *fd = s->parent->isFuncDeclaration(); + if (fd && fd->parent && fd->parent->isTemplateDeclaration()) + { + const char *str = (e && e->op == TOKsuper) ? "super" : s->toChars(); + ::error(s->loc, "cannot take a not yet instantiated symbol '%s' inside template constraint", str); + return true; + } + } + } + return false; +} + MATCH TemplateAliasParameter::matchArg(Scope *sc, Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam) @@ -4678,7 +4711,10 @@ Dsymbol *TemplateInstance::syntaxCopy(Dsymbol *s) ti->tiargs = arraySyntaxCopy(tiargs); - ScopeDsymbol::syntaxCopy(ti); + if (inst) + tempdecl->ScopeDsymbol::syntaxCopy(ti); + else + ScopeDsymbol::syntaxCopy(ti); return ti; } @@ -5020,8 +5056,8 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs) a = scx->scopesym->members; } else - { //Module *m = sc->module->importedFrom; - Module *m = tempdecl->scope->module->importedFrom; + { + Module *m = (isnested ? sc : tempdecl->scope)->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) @@ -5278,70 +5314,50 @@ void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f //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); - //printf("-> ea = %s %s\n", Token::toChars(ea->op), ea->toChars()); - /* 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]; - if (flags & 2 && arg->ident) - tiargs->insert(j + i, arg); - else - tiargs->insert(j + i, arg->type); - } - } - j--; - } - else - (*tiargs)[j] = ta; - } - else + if (ea) goto Lexpr; + if (sa) goto Ldsym; + if (ta == NULL) { assert(global.errors); - (*tiargs)[j] = Type::terror; + ta = Type::terror; } + + 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]; + if (flags & 2 && arg->ident) + tiargs->insert(j + i, arg); + else + tiargs->insert(j + i, arg->type); + } + } + j--; + continue; + } + (*tiargs)[j] = ta; } else if (ea) { + Lexpr: //printf("+[%d] ea = %s %s\n", j, Token::toChars(ea->op), ea->toChars()); 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 && + else if (ea->op == TOKvar) + { /* 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(). + */ + } + else if (ea->op != TOKtuple && ea->op != TOKimport && ea->op != TOKtype && ea->op != TOKfunction && ea->op != TOKerror && ea->op != TOKthis && ea->op != TOKsuper) @@ -5352,7 +5368,25 @@ void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f ea = new ErrorExp(); } //printf("-[%d] ea = %s %s\n", j, Token::toChars(ea->op), ea->toChars()); + if (!flags && isPseudoDsymbol(ea)) + { (*tiargs)[j] = new ErrorExp(); + continue; + } + 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--; + continue; + } (*tiargs)[j] = ea; + if (ea->op == TOKtype) { ta = ea->type; goto Ltype; @@ -5375,9 +5409,8 @@ void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f else if (fe->td) { /* If template argument is a template lambda, * get template declaration itself. */ - ea = NULL; - (*tiargs)[j] = sa = fe->td; - goto Lsa; + sa = fe->td; + goto Ldsym; } } if (ea->op == TOKdotvar) @@ -5394,25 +5427,31 @@ void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f sa = ((DotTemplateExp *)ea)->td; 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)[i]); - } - j--; - } } else if (sa) { - Lsa: + Ldsym: + //printf("dsym %s %s\n", sa->kind(), sa->toChars()); + if (!flags && isPseudoDsymbol(sa)) + { (*tiargs)[j] = new ErrorExp(); + continue; + } + TupleDeclaration *d = sa->toAlias()->isTupleDeclaration(); + if (d) + { // Expand tuple + size_t dim = d->objects->dim; + tiargs->remove(j); + tiargs->insert(j, d->objects); + j--; + continue; + } + (*tiargs)[j] = sa; + TemplateDeclaration *td = sa->isTemplateDeclaration(); if (td && !td->semanticRun && td->literal) + { td->semantic(sc); + } } else if (isParameter(o)) { @@ -6002,7 +6041,7 @@ int TemplateInstance::needsTypeInference(Scope *sc) */ FuncDeclaration *fd; if (!td->onemember || - (fd = td->onemember->toAlias()->isFuncDeclaration()) == NULL || + (fd = td->onemember/*->toAlias()*/->isFuncDeclaration()) == NULL || fd->type->ty != Tfunction) { /* Not a template function, therefore type inference is not possible. @@ -6516,30 +6555,25 @@ void TemplateMixin::semantic(Scope *sc) { if (!td->semanticRun) { - if (td->scope) - td->semantic(td->scope); + /* 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 { - /* 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; + // Forward reference + //printf("forward reference - deferring\n"); + scope = scx ? scx : new Scope(*sc); + scope->setNoFree(); + scope->module->addDeferredSemantic(this); } + return; } } @@ -6658,6 +6692,8 @@ void TemplateMixin::semantic(Scope *sc) sc2 = argscope->push(this); sc2->offset = sc->offset; + size_t deferred_dim = Module::deferred.dim; + static int nest; //printf("%d\n", nest); if (++nest > 500) @@ -6677,6 +6713,36 @@ void TemplateMixin::semantic(Scope *sc) sc->offset = sc2->offset; + if (!sc->func && Module::deferred.dim > deferred_dim) + { + sc2->pop(); + argscope->pop(); + scy->pop(); + //printf("deferring mixin %s, deferred.dim += %d\n", toChars(), Module::deferred.dim - deferred_dim); + //printf("\t["); + //for (size_t u = 0; u < Module::deferred.dim; u++) printf("%s%s", Module::deferred[u]->toChars(), u == Module::deferred.dim-1?"":", "); + //printf("]\n"); + + semanticRun = PASSinit; + AggregateDeclaration *ad = toParent()->isAggregateDeclaration(); + if (ad) + { + /* Forward reference of base class should not make derived class SIZEfwd. + */ + //printf("\tad = %s, sizeok = %d\n", ad->toChars(), ad->sizeok); + //ad->sizeok = SIZEOKfwd; + } + else + { + // Forward reference + //printf("forward reference - deferring\n"); + scope = scx ? scx : new Scope(*sc); + scope->setNoFree(); + scope->module->addDeferredSemantic(this); + } + return; + } + /* 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. diff --git a/dmd2/template.h b/dmd2/template.h index bd0b872f..108f3c5b 100644 --- a/dmd2/template.h +++ b/dmd2/template.h @@ -89,7 +89,7 @@ struct TemplateDeclaration : ScopeDsymbol char *toChars(); void emitComment(Scope *sc); - void toJsonBuffer(OutBuffer *buf); + void toJson(JsonOut *json); // void toDocBuffer(OutBuffer *buf); MATCH matchWithInstance(TemplateInstance *ti, Objects *atypes, Expressions *fargs, int flag); @@ -328,7 +328,7 @@ struct TemplateInstance : ScopeDsymbol int oneMember(Dsymbol **ps, Identifier *ident); int needsTypeInference(Scope *sc); char *toChars(); - char *mangle(); + char *mangle(bool isv = false); void printInstantiationTrace(); #if IN_DMD @@ -378,6 +378,7 @@ struct TemplateMixin : TemplateInstance char *toChars(); char *mangle(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void toJson(JsonOut *json); #if IN_DMD void toObjFile(int multiobj); // compile to .obj file diff --git a/dmd2/traits.c b/dmd2/traits.c index 0b686777..411bee0d 100644 --- a/dmd2/traits.c +++ b/dmd2/traits.c @@ -267,9 +267,10 @@ Expression *TraitsExp::semantic(Scope *sc) { if (FuncDeclaration *fd = s->isFuncDeclaration()) // Bugzilla 8943 s = fd->toAliasFunc(); - s = s->toParent(); + if (!s->isImport()) // Bugzilla 8922 + s = s->toParent(); } - if (!s) + if (!s || s->isImport()) { error("argument %s has no parent", o->toChars()); goto Lfalse; diff --git a/dmd2/utf.c b/dmd2/utf.c index 52230b28..c05fc101 100644 --- a/dmd2/utf.c +++ b/dmd2/utf.c @@ -1,4 +1,3 @@ -// utf.c // Copyright (c) 2003-2012 by Digital Mars // All Rights Reserved // written by Walter Bright diff --git a/dmd2/utf.h b/dmd2/utf.h index e48ffaab..22e405bc 100644 --- a/dmd2/utf.h +++ b/dmd2/utf.h @@ -1,5 +1,4 @@ // Compiler implementation of the D programming language -// utf.h // Copyright (c) 2003-2010 by Digital Mars // All Rights Reserved // written by Walter Bright diff --git a/driver/main.cpp b/driver/main.cpp index 4dd31edc..2310ca12 100644 --- a/driver/main.cpp +++ b/driver/main.cpp @@ -51,9 +51,10 @@ #include #endif -// stricmp -#if __GNUC__ && !_WIN32 -#include "gnuc.h" +#if _WIN32 +#define strcasecmp(s1, s2) _stricmp(s1, s2) +#else +#define strcasecmp(s1, s2) strcmp(s1, s2) #endif // Needs Type already declared. @@ -166,7 +167,7 @@ int main(int argc, char** argv) llvm::sys::PrintStackTraceOnErrorSignal(); Strings files; - char *p, *ext; + const char *p, *ext; Module *m; int status = EXIT_SUCCESS; @@ -792,8 +793,8 @@ int main(int argc, char** argv) modules.reserve(files.dim); for (unsigned i = 0; i < files.dim; i++) { Identifier *id; - char *ext; - char *name; + const char *ext; + const char *name; p = static_cast(files.data[i]); @@ -805,9 +806,9 @@ int main(int argc, char** argv) if (strcmp(ext, global.obj_ext) == 0 || strcmp(ext, global.bc_ext) == 0) #else - if (stricmp(ext, global.obj_ext) == 0 || - stricmp(ext, global.obj_ext_alt) == 0 || - stricmp(ext, global.bc_ext) == 0) + if (strcasecmp(ext, global.obj_ext) == 0 || + strcasecmp(ext, global.obj_ext_alt) == 0 || + strcasecmp(ext, global.bc_ext) == 0) #endif { global.params.objfiles->push(static_cast(files.data[i])); @@ -819,7 +820,7 @@ int main(int argc, char** argv) #elif __MINGW32__ if (stricmp(ext, "a") == 0) #else - if (stricmp(ext, "lib") == 0) + if (strcasecmp(ext, "lib") == 0) #endif { global.params.libfiles->push(static_cast(files.data[i])); @@ -840,41 +841,40 @@ int main(int argc, char** argv) } #if !POSIX - if (stricmp(ext, "res") == 0) + if (strcasecmp(ext, "res") == 0) { global.params.resfile = static_cast(files.data[i]); continue; } - if (stricmp(ext, "def") == 0) + if (strcasecmp(ext, "def") == 0) { global.params.deffile = static_cast(files.data[i]); continue; } - if (stricmp(ext, "exe") == 0) + if (strcasecmp(ext, "exe") == 0) { global.params.exefile = static_cast(files.data[i]); continue; } #endif - if (stricmp(ext, global.mars_ext) == 0 || - stricmp(ext, global.hdr_ext) == 0) + if (strcasecmp(ext, global.mars_ext) == 0 || + strcasecmp(ext, global.hdr_ext) == 0) { ext--; // skip onto '.' assert(*ext == '.'); - name = static_cast(mem.malloc((ext - p) + 1)); - memcpy(name, p, ext - p); - name[ext - p] = 0; // strip extension + char *tmp = static_cast(mem.malloc((ext - p) + 1)); + memcpy(tmp, p, ext - p); + tmp[ext - p] = 0; // strip extension + name = tmp; if (name[0] == 0 || strcmp(name, "..") == 0 || strcmp(name, ".") == 0) { - Linvalid: - error("invalid file name '%s'", static_cast(files.data[i])); - fatal(); + goto Linvalid; } } else @@ -884,8 +884,13 @@ int main(int argc, char** argv) } else { name = p; - if (!*name) - goto Linvalid; + if (!*p) + { + Linvalid: + error("invalid file name '%s'", static_cast(files.data[i])); + fatal(); + } + name = p; } id = Lexer::idPool(name); @@ -1073,7 +1078,7 @@ int main(int argc, char** argv) { m->deleteObjFile(); writeModule(lm, m->objfile->name->str); - global.params.objfiles->push(m->objfile->name->str); + global.params.objfiles->push(const_cast(m->objfile->name->str)); delete lm; } else @@ -1094,10 +1099,10 @@ int main(int argc, char** argv) Module* m = static_cast(modules.data[0]); char* oname; - char* filename; + const char* filename; if ((oname = global.params.exefile) || (oname = global.params.objname)) { - filename = FileName::forceExt(oname, global.obj_ext)->toChars(); + filename = FileName::forceExt(oname, global.obj_ext); if (global.params.objdir) { filename = FileName::combine(global.params.objdir, FileName::name(filename)); @@ -1108,7 +1113,7 @@ int main(int argc, char** argv) #if 1 // Temporary workaround for http://llvm.org/bugs/show_bug.cgi?id=11479. - char* moduleName = filename; + char* moduleName = const_cast(filename); #else char* moduleName = m->toChars(); #endif @@ -1124,12 +1129,55 @@ int main(int argc, char** argv) m->deleteObjFile(); writeModule(linker.getModule(), filename); - global.params.objfiles->push(filename); + global.params.objfiles->push(const_cast(filename)); } // output json file if (global.params.doXGeneration) - json_generate(&modules); + { + OutBuffer buf; + json_generate(&buf, &modules); + + // Write buf to file + const char *name = global.params.xfilename; + + if (name && name[0] == '-' && name[1] == 0) + { // Write to stdout; assume it succeeds + int n = fwrite(buf.data, 1, buf.offset, stdout); + assert(n == buf.offset); // keep gcc happy about return values + } + else + { + /* The filename generation code here should be harmonized with Module::setOutfile() + */ + + const char *jsonfilename; + + if (name && *name) + { + jsonfilename = FileName::defaultExt(name, global.json_ext); + } + else + { + // Generate json file name from first obj name + const char *n = (*global.params.objfiles)[0]; + n = FileName::name(n); + + //if (!FileName::absolute(name)) + //name = FileName::combine(dir, name); + + jsonfilename = FileName::forceExt(n, global.json_ext); + } + + FileName::ensurePathToNameExists(jsonfilename); + + File *jsonfile = new File(jsonfilename); + + jsonfile->setbuffer(buf.data, buf.offset); + jsonfile->ref = 1; + jsonfile->writev(); + } + } backend_term(); if (global.errors) diff --git a/runtime/druntime b/runtime/druntime index 676c9c8d..72c64613 160000 --- a/runtime/druntime +++ b/runtime/druntime @@ -1 +1 @@ -Subproject commit 676c9c8ddf6f494c59ffb71cec3c2c0cd4e18c4e +Subproject commit 72c646138722d6cf063a19101d01671a4a94327d diff --git a/runtime/phobos b/runtime/phobos index ae03a521..c9efed91 160000 --- a/runtime/phobos +++ b/runtime/phobos @@ -1 +1 @@ -Subproject commit ae03a52195c98d56ee0b78f2a7928f20dbed4b33 +Subproject commit c9efed917c232ac7c79526abec5efab622064c93 From a00091a5fa6b9a1b88f96722bea0935657f4d061 Mon Sep 17 00:00:00 2001 From: kai Date: Mon, 4 Mar 2013 06:51:12 +0100 Subject: [PATCH 2/4] Change naked asm functions to accept enum declaration. An enum defines constant values which can be used without trouble in naked asm functions. --- gen/naked.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gen/naked.cpp b/gen/naked.cpp index 786d5e8b..f2474192 100644 --- a/gen/naked.cpp +++ b/gen/naked.cpp @@ -72,7 +72,7 @@ void ExpStatement::toNakedIR(IRState *p) Statement::toNakedIR(p); return; } - else if (vd && !vd->isDataseg()) + else if (vd && !(vd->storage_class & (STCstatic | STCmanifest))) { error("non-static variable '%s' not allowed in naked function", vd->toChars()); return; From f77fe89fedd2909ab4fe50320fca815bcdf61ab0 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Wed, 6 Mar 2013 23:08:29 +0100 Subject: [PATCH 3/4] Fold in 2.062 test suite. --- tests/d2/dmd-testsuite | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/d2/dmd-testsuite b/tests/d2/dmd-testsuite index a7e9ed61..e1145fcd 160000 --- a/tests/d2/dmd-testsuite +++ b/tests/d2/dmd-testsuite @@ -1 +1 @@ -Subproject commit a7e9ed61ed90e55f6235722c4b3338bcb1d332c7 +Subproject commit e1145fcdd969645204c456d63ee118dbae758fda From 5f2e18ecaeb0c3349cbac3e51a8a3612b4b2a67c Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Wed, 6 Mar 2013 23:08:47 +0100 Subject: [PATCH 4/4] core.atomic fix for 2.062. --- runtime/druntime | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/druntime b/runtime/druntime index 72c64613..d9dfa04d 160000 --- a/runtime/druntime +++ b/runtime/druntime @@ -1 +1 @@ -Subproject commit 72c646138722d6cf063a19101d01671a4a94327d +Subproject commit d9dfa04d41efad2ca7c095e46934102e76d3065c