diff --git a/dmd2/access.c b/dmd2/access.c index f16a3f3b53..4975132dbe 100644 --- a/dmd2/access.c +++ b/dmd2/access.c @@ -37,12 +37,12 @@ bool hasPrivateAccess(AggregateDeclaration *ad, Dsymbol *smember); bool isFriendOf(AggregateDeclaration *ad, AggregateDeclaration *cd); /**************************************** - * Return PROT access for Dsymbol smember in this declaration. + * Return Prot access for Dsymbol smember in this declaration. */ -PROT getAccess(AggregateDeclaration *ad, Dsymbol *smember) +Prot getAccess(AggregateDeclaration *ad, Dsymbol *smember) { - PROT access_ret = PROTnone; + Prot access_ret = Prot(PROTnone); #if LOG printf("+AggregateDeclaration::getAccess(this = '%s', smember = '%s')\n", @@ -64,14 +64,14 @@ PROT getAccess(AggregateDeclaration *ad, Dsymbol *smember) { BaseClass *b = (*cd->baseclasses)[i]; - PROT access = getAccess(b->base, smember); - switch (access) + Prot access = getAccess(b->base, smember); + switch (access.kind) { case PROTnone: break; case PROTprivate: - access_ret = PROTnone; // private members of base class not accessible + access_ret = Prot(PROTnone); // private members of base class not accessible break; case PROTpackage: @@ -79,11 +79,11 @@ PROT getAccess(AggregateDeclaration *ad, Dsymbol *smember) case PROTpublic: case PROTexport: // If access is to be tightened - if (b->protection < access) + if (b->protection.isMoreRestrictiveThan(access)) access = b->protection; // Pick path with loosest access - if (access > access_ret) + if (access_ret.isMoreRestrictiveThan(access)) access_ret = access; break; @@ -133,8 +133,8 @@ static int accessCheckX( { for (size_t i = 0; i < cdthis->baseclasses->dim; i++) { BaseClass *b = (*cdthis->baseclasses)[i]; - PROT access = getAccess(b->base, smember); - if (access >= PROTprotected || + Prot access = getAccess(b->base, smember); + if (access.kind >= PROTprotected || accessCheckX(smember, sfunc, b->base, cdscope) ) return 1; @@ -173,7 +173,7 @@ void accessCheck(AggregateDeclaration *ad, Loc loc, Scope *sc, Dsymbol *smember) FuncDeclaration *f = sc->func; AggregateDeclaration *cdscope = sc->getStructClassScope(); - PROT access; + Prot access; #if LOG printf("AggregateDeclaration::accessCheck() for %s.%s in function %s() in scope %s\n", @@ -196,24 +196,24 @@ void accessCheck(AggregateDeclaration *ad, Loc loc, Scope *sc, Dsymbol *smember) if (smemberparent == ad) { - PROT access2 = smember->prot(); - result = access2 >= PROTpublic || + Prot access2 = smember->prot(); + result = access2.kind >= PROTpublic || hasPrivateAccess(ad, f) || isFriendOf(ad, cdscope) || - (access2 == PROTpackage && hasPackageAccess(sc, ad)) || + (access2.kind == PROTpackage && hasPackageAccess(sc, ad)) || ad->getAccessModule() == sc->module; #if LOG printf("result1 = %d\n", result); #endif } - else if ((access = getAccess(ad, smember)) >= PROTpublic) + else if ((access = getAccess(ad, smember)).kind >= PROTpublic) { result = 1; #if LOG printf("result2 = %d\n", result); #endif } - else if (access == PROTpackage && hasPackageAccess(sc, ad)) + else if (access.kind == PROTpackage && hasPackageAccess(sc, ad)) { result = 1; #if LOG @@ -230,6 +230,8 @@ void accessCheck(AggregateDeclaration *ad, Loc loc, Scope *sc, Dsymbol *smember) if (!result) { ad->error(loc, "member %s is not accessible", smember->toChars()); + //printf("smember = %s %s, prot = %d, semanticRun = %d\n", + // smember->kind(), smember->toPrettyChars(), smember->prot(), smember->semanticRun); } } @@ -268,31 +270,40 @@ bool isFriendOf(AggregateDeclaration *ad, AggregateDeclaration *cd) bool hasPackageAccess(Scope *sc, Dsymbol *s) { #if LOG - printf("hasPackageAccess(s = '%s', sc = '%p')\n", s->toChars(), sc); + printf("hasPackageAccess(s = '%s', sc = '%p', s->protection.pkg = '%s')\n", + s->toChars(), sc, + s->prot().pkg ? s->prot().pkg->toChars() : "NULL"); #endif Package *pkg = NULL; - for (; s; s = s->parent) + + if (s->prot().pkg) + pkg = s->prot().pkg; + else { - if (Module *m = s->isModule()) + // no explicit package for protection, inferring most qualified one + for (; s; s = s->parent) { - DsymbolTable *dst = Package::resolve(m->md ? m->md->packages : NULL, NULL, NULL); - assert(dst); - Dsymbol *s2 = dst->lookup(m->ident); - assert(s2); - Package *p = s2->isPackage(); - if (p && p->isPackageMod()) + if (Module *m = s->isModule()) { - pkg = p; - break; + DsymbolTable *dst = Package::resolve(m->md ? m->md->packages : NULL, NULL, NULL); + assert(dst); + Dsymbol *s2 = dst->lookup(m->ident); + assert(s2); + Package *p = s2->isPackage(); + if (p && p->isPackageMod()) + { + pkg = p; + break; + } } + else if ((pkg = s->isPackage()) != NULL) + break; } - else if ((pkg = s->isPackage()) != NULL) - break; } #if LOG if (pkg) - printf("\tthis is in package '%s'\n", pkg->toChars()); + printf("\tsymbol access binds to package '%s'\n", pkg->toChars()); #endif if (pkg) @@ -300,7 +311,7 @@ bool hasPackageAccess(Scope *sc, Dsymbol *s) if (pkg == sc->module->parent) { #if LOG - printf("\ts is in same package as sc\n"); + printf("\tsc is in permitted package for s\n"); #endif return true; } @@ -311,13 +322,13 @@ bool hasPackageAccess(Scope *sc, Dsymbol *s) #endif return true; } - s = sc->module->parent; - for (; s; s = s->parent) + Dsymbol* ancestor = sc->module->parent; + for (; ancestor; ancestor = ancestor->parent) { - if (s == pkg) + if (ancestor == pkg) { #if LOG - printf("\ts is in ancestor package of sc\n"); + printf("\tsc is in permitted ancestor package for s\n"); #endif return true; } @@ -413,8 +424,8 @@ void accessCheck(Loc loc, Scope *sc, Expression *e, Declaration *d) } if (!e) { - if (d->prot() == PROTprivate && d->getAccessModule() != sc->module || - d->prot() == PROTpackage && !hasPackageAccess(sc, d)) + if (d->prot().kind == PROTprivate && d->getAccessModule() != sc->module || + d->prot().kind == PROTpackage && !hasPackageAccess(sc, d)) { error(loc, "%s %s is not accessible from module %s", d->kind(), d->toPrettyChars(), sc->module->toChars()); diff --git a/dmd2/aggregate.h b/dmd2/aggregate.h index 67240180bc..63383af7d6 100644 --- a/dmd2/aggregate.h +++ b/dmd2/aggregate.h @@ -34,7 +34,6 @@ class DeleteDeclaration; class InterfaceDeclaration; class TypeInfoClassDeclaration; class VarDeclaration; -struct dt_t; enum Sizeok { @@ -67,7 +66,7 @@ class AggregateDeclaration : public ScopeDsymbol public: Type *type; StorageClass storage_class; - PROT protection; + Prot protection; unsigned structsize; // size of struct unsigned alignsize; // size of struct for alignment purposes VarDeclarations fields; // VarDeclaration fields @@ -118,7 +117,7 @@ public: bool isExport(); Dsymbol *searchCtor(); - PROT prot(); + Prot prot(); Type *handleType() { return type; } // 'this' type #if IN_DMD @@ -170,7 +169,6 @@ public: void semantic(Scope *sc); void semanticTypeInfoMembers(); Dsymbol *search(Loc, Identifier *ident, int flags = IgnoreNone); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); const char *kind(); void finalizeSize(Scope *sc); bool fit(Loc loc, Scope *sc, Expressions *elements, Type *stype); @@ -199,7 +197,7 @@ public: struct BaseClass { Type *type; // (before semantic processing) - PROT protection; // protection for the base interface + Prot protection; // protection for the base interface ClassDeclaration *base; unsigned offset; // 'this' pointer offset @@ -212,7 +210,7 @@ struct BaseClass BaseClass *baseInterfaces; BaseClass(); - BaseClass(Type *type, PROT protection); + BaseClass(Type *type, Prot protection); bool fillVtbl(ClassDeclaration *cd, FuncDeclarations *vtbl, int newinstance); void copyBaseInterfaces(BaseClasses *); @@ -234,6 +232,7 @@ struct ClassFlags hasTypeInfo = 0x20, isAbstract = 0x40, isCPPclass = 0x80, + hasDtor = 0x100, }; }; @@ -274,7 +273,6 @@ public: ClassDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses, bool inObject = false); Dsymbol *syntaxCopy(Dsymbol *s); void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); bool isBaseOf2(ClassDeclaration *cd); #define OFFSET_RUNTIME 0x76543210 diff --git a/dmd2/aliasthis.c b/dmd2/aliasthis.c index afee9874c8..779100eded 100644 --- a/dmd2/aliasthis.c +++ b/dmd2/aliasthis.c @@ -127,10 +127,3 @@ const char *AliasThis::kind() { return "alias this"; } - -void AliasThis::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("alias "); - buf->writestring(ident->toChars()); - buf->writestring(" this;\n"); -} diff --git a/dmd2/aliasthis.h b/dmd2/aliasthis.h index 40ec13eee0..6323b27203 100644 --- a/dmd2/aliasthis.h +++ b/dmd2/aliasthis.h @@ -32,7 +32,6 @@ public: Dsymbol *syntaxCopy(Dsymbol *); void semantic(Scope *sc); const char *kind(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); AliasThis *isAliasThis() { return this; } void accept(Visitor *v) { v->visit(this); } }; diff --git a/dmd2/argtypes.c b/dmd2/argtypes.c index 9cf2eaaba7..ab133e014a 100644 --- a/dmd2/argtypes.c +++ b/dmd2/argtypes.c @@ -476,11 +476,6 @@ TypeTuple *toArgTypes(Type *t) t->toBasetype()->accept(this); } - void visit(TypeTypedef *t) - { - t->sym->basetype->accept(this); - } - void visit(TypeClass *) { result = new TypeTuple(Type::tvoidptr); diff --git a/dmd2/arrayop.c b/dmd2/arrayop.c index 4b4d85d82f..d988d8a88c 100644 --- a/dmd2/arrayop.c +++ b/dmd2/arrayop.c @@ -26,8 +26,6 @@ #include "module.h" #include "init.h" -#if IN_DMD -extern int binary(const char *p , const char **tab, int high); void buildArrayIdent(Expression *e, OutBuffer *buf, Expressions *arguments); Expression *buildArrayLoop(Expression *e, Parameters *fparams); @@ -35,10 +33,8 @@ Expression *buildArrayLoop(Expression *e, Parameters *fparams); * Hash table of array op functions already generated or known about. */ +#if IN_DMD AA *arrayfuncs; -#else -void buildArrayIdent(Expression *e, OutBuffer *buf, Expressions *arguments); -Expression *buildArrayLoop(Expression *e, Parameters *fparams); #endif /************************************** @@ -76,7 +72,7 @@ FuncDeclaration *buildArrayOp(Identifier *ident, BinExp *exp, Scope *sc, Loc loc //printf("ftype: %s\n", ftype->toChars()); FuncDeclaration *fd = new FuncDeclaration(Loc(), Loc(), ident, STCundefined, ftype); fd->fbody = fbody; - fd->protection = PROTpublic; + fd->protection = Prot(PROTpublic); fd->linkage = LINKc; fd->isArrayOp = 1; @@ -116,47 +112,31 @@ bool isArrayOpValid(Expression *e) return (t->ty != Tvoid); } Type *tb = e->type->toBasetype(); - - BinExp *be; if (tb->ty == Tarray || tb->ty == Tsarray) { - switch (e->op) + if (isUnaArrayOp(e->op)) { - case TOKadd: - case TOKmin: - case TOKmul: - case TOKdiv: - case TOKmod: - case TOKxor: - case TOKand: - case TOKor: - case TOKassign: - case TOKaddass: - case TOKminass: - case TOKmulass: - case TOKdivass: - case TOKmodass: - case TOKxorass: - case TOKandass: - case TOKorass: - case TOKpow: - case TOKpowass: - be = (BinExp *)e; - return isArrayOpValid(be->e1) && isArrayOpValid(be->e2); - - case TOKconstruct: - be = (BinExp *)e; - return be->e1->op == TOKslice && isArrayOpValid(be->e2); - - case TOKcall: - return false; // TODO: Decide if [] is required after arrayop calls. - - case TOKneg: - case TOKtilde: - return isArrayOpValid(((UnaExp *)e)->e1); - - default: - return false; + return isArrayOpValid(((UnaExp *)e)->e1); + } + if (isBinArrayOp(e->op) || + isBinAssignArrayOp(e->op) || + e->op == TOKassign) + { + BinExp *be = (BinExp *)e; + return isArrayOpValid(be->e1) && isArrayOpValid(be->e2); + } + if (e->op == TOKconstruct) + { + BinExp *be = (BinExp *)e; + return be->e1->op == TOKslice && isArrayOpValid(be->e2); + } + if (e->op == TOKcall) + { + return false; // TODO: Decide if [] is required after arrayop calls. + } + else + { + return false; } } return true; @@ -170,24 +150,20 @@ bool isNonAssignmentArrayOp(Expression *e) if (tb->ty == Tarray || tb->ty == Tsarray) { - switch (e->op) - { - case TOKadd: - case TOKmin: - case TOKmul: - case TOKdiv: - case TOKmod: - case TOKxor: - case TOKand: - case TOKor: - case TOKpow: - case TOKneg: - case TOKtilde: - return true; + return (isUnaArrayOp(e->op) || isBinArrayOp(e->op)); + } + return false; +} - default: - return false; - } +bool checkNonAssignmentArrayOp(Expression *e, bool suggestion) +{ + if (isNonAssignmentArrayOp(e)) + { + const char *s = ""; + if (suggestion) + s = " (possible missing [])"; + e->error("array operation %s without destination memory not allowed%s", e->toChars(), s); + return true; } return false; } @@ -210,7 +186,7 @@ Expression *arrayOp(BinExp *e, Scope *sc) } if (!isArrayOpValid(e)) { - e->error("invalid array operation %s (did you forget a [] ?)", e->toChars()); + e->error("invalid array operation %s (possible missing [])", e->toChars()); return new ErrorExp(); } @@ -524,17 +500,7 @@ Expression *buildArrayLoop(Expression *e, Parameters *fparams) void visit(BinExp *e) { - switch(e->op) - { - case TOKadd: - case TOKmin: - case TOKmul: - case TOKdiv: - case TOKmod: - case TOKxor: - case TOKand: - case TOKor: - case TOKpow: + if (isBinArrayOp(e->op)) { /* Evaluate assign expressions left to right */ @@ -545,7 +511,8 @@ Expression *buildArrayLoop(Expression *e, Parameters *fparams) result = be; return; } - default: + else + { visit((Expression *)e); return; } @@ -562,13 +529,78 @@ Expression *buildArrayLoop(Expression *e, Parameters *fparams) return v.buildArrayLoop(e); } +/*********************************************** + * Test if expression is a unary array op. + */ + +bool isUnaArrayOp(TOK op) +{ + switch (op) + { + case TOKneg: + case TOKtilde: + return true; + default: + break; + } + return false; +} + +/*********************************************** + * Test if expression is a binary array op. + */ + +bool isBinArrayOp(TOK op) +{ + switch (op) + { + case TOKadd: + case TOKmin: + case TOKmul: + case TOKdiv: + case TOKmod: + case TOKxor: + case TOKand: + case TOKor: + case TOKpow: + return true; + default: + break; + } + return false; +} + +/*********************************************** + * Test if expression is a binary assignment array op. + */ + +bool isBinAssignArrayOp(TOK op) +{ + switch (op) + { + case TOKaddass: + case TOKminass: + case TOKmulass: + case TOKdivass: + case TOKmodass: + case TOKxorass: + case TOKandass: + case TOKorass: + case TOKpowass: + return true; + default: + break; + } + return false; +} + /*********************************************** * Test if operand is a valid array op operand. */ -bool isArrayOperand(Expression *e) +bool isArrayOpOperand(Expression *e) { - //printf("Expression::isArrayOperand() %s\n", e->toChars()); + //printf("Expression::isArrayOpOperand() %s\n", e->toChars()); if (e->op == TOKslice) return true; if (e->op == TOKarrayliteral) @@ -578,36 +610,13 @@ bool isArrayOperand(Expression *e) t = t->nextOf()->toBasetype(); return (t->ty != Tvoid); } - if (e->type->toBasetype()->ty == Tarray) + Type *tb = e->type->toBasetype(); + if (tb->ty == Tarray) { - switch (e->op) - { - case TOKadd: - case TOKmin: - case TOKmul: - case TOKdiv: - case TOKmod: - case TOKxor: - case TOKand: - case TOKor: - case TOKassign: - case TOKaddass: - case TOKminass: - case TOKmulass: - case TOKdivass: - case TOKmodass: - case TOKxorass: - case TOKandass: - case TOKorass: - case TOKpow: - case TOKpowass: - case TOKneg: - case TOKtilde: - return true; - - default: - break; - } + return (isUnaArrayOp(e->op) || + isBinArrayOp(e->op) || + isBinAssignArrayOp(e->op) || + e->op == TOKassign); } return false; } diff --git a/dmd2/arraytypes.h b/dmd2/arraytypes.h index 33f254c36f..115bf713d3 100644 --- a/dmd2/arraytypes.h +++ b/dmd2/arraytypes.h @@ -62,6 +62,8 @@ typedef Array ScopeStatements; typedef Array GotoCaseStatements; +typedef Array ReturnStatements; + typedef Array GotoStatements; typedef Array TemplateInstances; @@ -70,6 +72,4 @@ typedef Array Blocks; typedef Array Symbols; -typedef Array Dts; - #endif diff --git a/dmd2/attrib.c b/dmd2/attrib.c index e3b61e209b..b43ae6966c 100644 --- a/dmd2/attrib.c +++ b/dmd2/attrib.c @@ -28,7 +28,6 @@ #include "module.h" #include "parse.h" #include "template.h" -#include "hdrgen.h" #include "utf.h" #if IN_LLVM #include "../gen/pragma.h" @@ -74,19 +73,18 @@ int AttribDeclaration::apply(Dsymbol_apply_ft_t fp, void *param) * the scope after it used. */ Scope *AttribDeclaration::createNewScope(Scope *sc, - StorageClass stc, LINK linkage, PROT protection, int explicitProtection, + StorageClass stc, LINK linkage, Prot protection, int explicitProtection, structalign_t structalign) { Scope *sc2 = sc; if (stc != sc->stc || linkage != sc->linkage || - protection != sc->protection || + !protection.isSubsetOf(sc->protection) || explicitProtection != sc->explicitProtection || structalign != sc->structalign) { // create new one for changes sc2 = sc->copy(); - sc2->flags &= ~SCOPEfree; sc2->stc = stc; sc2->linkage = linkage; sc2->protection = protection; @@ -333,40 +331,6 @@ void AttribDeclaration::addLocalClass(ClassDeclarations *aclasses) } } - -void AttribDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (decl) - { - if (decl->dim == 0) - buf->writestring("{}"); - else if (hgs->hdrgen && decl->dim == 1 && (*decl)[0]->isUnitTestDeclaration()) - { - // hack for bugzilla 8081 - buf->writestring("{}"); - } - else if (decl->dim == 1) - ((*decl)[0])->toCBuffer(buf, hgs); - else - { - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - buf->level++; - for (size_t i = 0; i < decl->dim; i++) - { - Dsymbol *s = (*decl)[i]; - s->toCBuffer(buf, hgs); - } - buf->level--; - buf->writeByte('}'); - } - } - else - buf->writeByte(';'); - buf->writenl(); -} - /************************* StorageClassDeclaration ****************************/ StorageClassDeclaration::StorageClassDeclaration(StorageClass stc, Dsymbols *decl) @@ -377,16 +341,12 @@ StorageClassDeclaration::StorageClassDeclaration(StorageClass stc, Dsymbols *dec Dsymbol *StorageClassDeclaration::syntaxCopy(Dsymbol *s) { - StorageClassDeclaration *scd; - assert(!s); - scd = new StorageClassDeclaration(stc, Dsymbol::arraySyntaxCopy(decl)); - return scd; + return new StorageClassDeclaration(stc, Dsymbol::arraySyntaxCopy(decl)); } bool StorageClassDeclaration::oneMember(Dsymbol **ps, Identifier *ident) { - bool t = Dsymbol::oneMembers(decl, ps, ident); if (t && *ps) { @@ -525,12 +485,6 @@ void StorageClassDeclaration::stcToCBuffer(OutBuffer *buf, StorageClass stc) } } -void StorageClassDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - stcToCBuffer(buf, stc); - AttribDeclaration::toCBuffer(buf, hgs); -} - /********************************* DeprecatedDeclaration ****************************/ DeprecatedDeclaration::DeprecatedDeclaration(Expression *msg, Dsymbols *decl) @@ -561,14 +515,6 @@ void DeprecatedDeclaration::setScope(Scope *sc) scx->pop(); } -void DeprecatedDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("deprecated("); - msg->toCBuffer(buf, hgs); - buf->writestring(") "); - AttribDeclaration::toCBuffer(buf, hgs); -} - /********************************* LinkDeclaration ****************************/ LinkDeclaration::LinkDeclaration(LINK p, Dsymbols *decl) @@ -580,11 +526,8 @@ LinkDeclaration::LinkDeclaration(LINK p, Dsymbols *decl) Dsymbol *LinkDeclaration::syntaxCopy(Dsymbol *s) { - LinkDeclaration *ld; - assert(!s); - ld = new LinkDeclaration(linkage, Dsymbol::arraySyntaxCopy(decl)); - return ld; + return new LinkDeclaration(linkage, Dsymbol::arraySyntaxCopy(decl)); } Scope *LinkDeclaration::newScope(Scope *sc) @@ -592,27 +535,6 @@ Scope *LinkDeclaration::newScope(Scope *sc) return createNewScope(sc, sc->stc, this->linkage, sc->protection, sc->explicitProtection, sc->structalign); } -void LinkDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - const char *p; - - switch (linkage) - { - case LINKd: p = "D"; break; - case LINKc: p = "C"; break; - case LINKcpp: p = "C++"; break; - case LINKwindows: p = "Windows"; break; - case LINKpascal: p = "Pascal"; break; - default: - assert(0); - break; - } - buf->writestring("extern ("); - buf->writestring(p); - buf->writestring(") "); - AttribDeclaration::toCBuffer(buf, hgs); -} - char *LinkDeclaration::toChars() { return (char *)"extern ()"; @@ -620,32 +542,88 @@ char *LinkDeclaration::toChars() /********************************* ProtDeclaration ****************************/ -ProtDeclaration::ProtDeclaration(PROT p, Dsymbols *decl) +/** + * Params: + * loc = source location of attribute token + * p = protection attribute data + * decl = declarations which are affected by this protection attribute + */ +ProtDeclaration::ProtDeclaration(Loc loc, Prot p, Dsymbols *decl) : AttribDeclaration(decl) { - protection = p; + this->loc = loc; + this->protection = p; + this->pkg_identifiers = NULL; //printf("decl = %p\n", decl); } +/** + * Params: + * loc = source location of attribute token + * pkg_identifiers = list of identifiers for a qualified package name + * decl = declarations which are affected by this protection attribute + */ +ProtDeclaration::ProtDeclaration(Loc loc, Identifiers* pkg_identifiers, Dsymbols *decl) + : AttribDeclaration(decl) +{ + this->loc = loc; + this->protection.kind = PROTpackage; + this->protection.pkg = NULL; + this->pkg_identifiers = pkg_identifiers; +} + Dsymbol *ProtDeclaration::syntaxCopy(Dsymbol *s) { - ProtDeclaration *pd; - assert(!s); - pd = new ProtDeclaration(protection, Dsymbol::arraySyntaxCopy(decl)); - return pd; + if (protection.kind == PROTpackage) + return new ProtDeclaration(this->loc, pkg_identifiers, Dsymbol::arraySyntaxCopy(decl)); + else + return new ProtDeclaration(this->loc, protection, Dsymbol::arraySyntaxCopy(decl)); } Scope *ProtDeclaration::newScope(Scope *sc) { + if (pkg_identifiers) + semantic(sc); return createNewScope(sc, sc->stc, sc->linkage, this->protection, 1, sc->structalign); } -void ProtDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +int ProtDeclaration::addMember(Scope *sc, ScopeDsymbol *sds, int memnum) { - protectionToBuffer(buf, protection); - buf->writeByte(' '); - AttribDeclaration::toCBuffer(buf, hgs); + if (pkg_identifiers) + { + Dsymbol* tmp; + Package::resolve(pkg_identifiers, &tmp, NULL); + protection.pkg = tmp ? tmp->isPackage() : NULL; + pkg_identifiers = NULL; + } + + if (protection.kind == PROTpackage && protection.pkg && sc->module) + { + Module *m = sc->module; + Package* pkg = m->parent ? m->parent->isPackage() : NULL; + if (!pkg || !protection.pkg->isAncestorPackageOf(pkg)) + error("does not bind to one of ancestor packages of module '%s'", + m->toPrettyChars(true)); + } + + return AttribDeclaration::addMember(sc, sds, memnum); +} + +const char *ProtDeclaration::kind() +{ + return "protection attribute"; +} + +const char *ProtDeclaration::toPrettyChars(bool) +{ + assert(protection.kind > PROTundefined); + + OutBuffer buf; + buf.writeByte('\''); + protectionToBuffer(&buf, protection); + buf.writeByte('\''); + return buf.extractString(); } /********************************* AlignDeclaration ****************************/ @@ -658,11 +636,8 @@ AlignDeclaration::AlignDeclaration(unsigned sa, Dsymbols *decl) Dsymbol *AlignDeclaration::syntaxCopy(Dsymbol *s) { - AlignDeclaration *ad; - assert(!s); - ad = new AlignDeclaration(salign, Dsymbol::arraySyntaxCopy(decl)); - return ad; + return new AlignDeclaration(salign, Dsymbol::arraySyntaxCopy(decl)); } Scope *AlignDeclaration::newScope(Scope *sc) @@ -670,15 +645,6 @@ Scope *AlignDeclaration::newScope(Scope *sc) return createNewScope(sc, sc->stc, sc->linkage, sc->protection, sc->explicitProtection, this->salign); } -void AlignDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (salign == STRUCTALIGN_DEFAULT) - buf->printf("align"); - else - buf->printf("align (%d)", salign); - AttribDeclaration::toCBuffer(buf, hgs); -} - /********************************* AnonDeclaration ****************************/ AnonDeclaration::AnonDeclaration(Loc loc, bool isunion, Dsymbols *decl) @@ -692,11 +658,8 @@ AnonDeclaration::AnonDeclaration(Loc loc, bool isunion, Dsymbols *decl) Dsymbol *AnonDeclaration::syntaxCopy(Dsymbol *s) { - AnonDeclaration *ad; - assert(!s); - ad = new AnonDeclaration(loc, isunion, Dsymbol::arraySyntaxCopy(decl)); - return ad; + return new AnonDeclaration(loc, isunion, Dsymbol::arraySyntaxCopy(decl)); } void AnonDeclaration::semantic(Scope *sc) @@ -731,7 +694,6 @@ void AnonDeclaration::semantic(Scope *sc) } } - void AnonDeclaration::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion) { //printf("\tAnonDeclaration::setFieldOffset %s %p\n", isunion ? "union" : "struct", this); @@ -757,7 +719,6 @@ void AnonDeclaration::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset for (size_t i = 0; i < decl->dim; i++) { Dsymbol *s = (*decl)[i]; - s->setFieldOffset(ad, &offset, this->isunion); if (this->isunion) offset = 0; @@ -768,7 +729,18 @@ void AnonDeclaration::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset ad->structsize = savestructsize; ad->alignsize = savealignsize; + if (fieldstart == ad->fields.dim) + { + /* Bugzilla 13613: If the fields in this->members had been already + * added in ad->fields, just update *poffset for the subsequent + * field offset calculation. + */ + *poffset = ad->structsize; + return; + } + // 0 sized structs are set to 1 byte + // TODO: is this corect hebavior? if (anonstructsize == 0) { anonstructsize = 1; @@ -795,27 +767,6 @@ void AnonDeclaration::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset } } - -void AnonDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->printf(isunion ? "union" : "struct"); - buf->writenl(); - buf->writestring("{"); - buf->writenl(); - buf->level++; - if (decl) - { - for (size_t i = 0; i < decl->dim; i++) - { - Dsymbol *s = (*decl)[i]; - s->toCBuffer(buf, hgs); - } - } - buf->level--; - buf->writestring("}"); - buf->writenl(); -} - const char *AnonDeclaration::kind() { return (isunion ? "anonymous union" : "anonymous struct"); @@ -834,12 +785,10 @@ PragmaDeclaration::PragmaDeclaration(Loc loc, Identifier *ident, Expressions *ar Dsymbol *PragmaDeclaration::syntaxCopy(Dsymbol *s) { //printf("PragmaDeclaration::syntaxCopy(%s)\n", toChars()); - PragmaDeclaration *pd; - assert(!s); - pd = new PragmaDeclaration(loc, ident, - Expression::arraySyntaxCopy(args), Dsymbol::arraySyntaxCopy(decl)); - return pd; + return new PragmaDeclaration(loc, ident, + Expression::arraySyntaxCopy(args), + Dsymbol::arraySyntaxCopy(decl)); } void PragmaDeclaration::setScope(Scope *sc) @@ -1145,19 +1094,6 @@ const char *PragmaDeclaration::kind() return "pragma"; } -void PragmaDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->printf("pragma (%s", ident->toChars()); - if (args && args->dim) - { - buf->writestring(", "); - argsToCBuffer(buf, args, hgs); - } - buf->writeByte(')'); - AttribDeclaration::toCBuffer(buf, hgs); -} - - /********************************* ConditionalDeclaration ****************************/ ConditionalDeclaration::ConditionalDeclaration(Condition *condition, Dsymbols *decl, Dsymbols *elsedecl) @@ -1170,16 +1106,12 @@ ConditionalDeclaration::ConditionalDeclaration(Condition *condition, Dsymbols *d Dsymbol *ConditionalDeclaration::syntaxCopy(Dsymbol *s) { - ConditionalDeclaration *dd; - assert(!s); - dd = new ConditionalDeclaration(condition->syntaxCopy(), + return new ConditionalDeclaration(condition->syntaxCopy(), Dsymbol::arraySyntaxCopy(decl), Dsymbol::arraySyntaxCopy(elsedecl)); - return dd; } - bool ConditionalDeclaration::oneMember(Dsymbol **ps, Identifier *ident) { //printf("ConditionalDeclaration::oneMember(), inc = %d\n", condition->inc); @@ -1249,47 +1181,6 @@ void ConditionalDeclaration::addComment(const utf8_t *comment) } } -void ConditionalDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - condition->toCBuffer(buf, hgs); - if (decl || elsedecl) - { - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - buf->level++; - if (decl) - { - for (size_t i = 0; i < decl->dim; i++) - { - Dsymbol *s = (*decl)[i]; - s->toCBuffer(buf, hgs); - } - } - buf->level--; - buf->writeByte('}'); - if (elsedecl) - { - buf->writenl(); - buf->writestring("else"); - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - buf->level++; - for (size_t i = 0; i < elsedecl->dim; i++) - { - Dsymbol *s = (*elsedecl)[i]; - s->toCBuffer(buf, hgs); - } - buf->level--; - buf->writeByte('}'); - } - } - else - buf->writeByte(':'); - buf->writenl(); -} - /***************************** StaticIfDeclaration ****************************/ StaticIfDeclaration::StaticIfDeclaration(Condition *condition, @@ -1301,16 +1192,12 @@ StaticIfDeclaration::StaticIfDeclaration(Condition *condition, addisdone = 0; } - Dsymbol *StaticIfDeclaration::syntaxCopy(Dsymbol *s) { - StaticIfDeclaration *dd; - assert(!s); - dd = new StaticIfDeclaration(condition->syntaxCopy(), + return new StaticIfDeclaration(condition->syntaxCopy(), Dsymbol::arraySyntaxCopy(decl), Dsymbol::arraySyntaxCopy(elsedecl)); - return dd; } Dsymbols *StaticIfDeclaration::include(Scope *sc, ScopeDsymbol *sds) @@ -1370,7 +1257,6 @@ int StaticIfDeclaration::addMember(Scope *sc, ScopeDsymbol *sds, int memnum) return m; } - void StaticIfDeclaration::importAll(Scope *sc) { // do not evaluate condition before semantic pass @@ -1410,7 +1296,6 @@ const char *StaticIfDeclaration::kind() return "static if"; } - /***************************** CompileDeclaration *****************************/ // These are mixin declarations, like mixin("int x"); @@ -1428,8 +1313,7 @@ CompileDeclaration::CompileDeclaration(Loc loc, Expression *exp) Dsymbol *CompileDeclaration::syntaxCopy(Dsymbol *s) { //printf("CompileDeclaration::syntaxCopy('%s')\n", toChars()); - CompileDeclaration *sc = new CompileDeclaration(loc, exp->syntaxCopy()); - return sc; + return new CompileDeclaration(loc, exp->syntaxCopy()); } int CompileDeclaration::addMember(Scope *sc, ScopeDsymbol *sds, int memnum) @@ -1472,15 +1356,18 @@ void CompileDeclaration::compileIt(Scope *sc) else { se = se->toUTF8(sc); + unsigned errors = global.errors; Parser p(loc, sc->module, (utf8_t *)se->string, se->len, 0); p.nextToken(); - unsigned errors = global.errors; decl = p.parseDeclDefs(0); if (p.token.value != TOKeof) exp->error("incomplete mixin declaration (%s)", se->toChars()); - if (global.errors != errors) + if (p.errors) + { + assert(global.errors != errors); decl = NULL; + } } } } @@ -1507,20 +1394,11 @@ void CompileDeclaration::semantic(Scope *sc) AttribDeclaration::semantic(sc); } -void CompileDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("mixin("); - exp->toCBuffer(buf, hgs); - buf->writestring(");"); - buf->writenl(); -} - const char *CompileDeclaration::kind() { return "mixin"; } - /***************************** UserAttributeDeclaration *****************************/ UserAttributeDeclaration::UserAttributeDeclaration(Expressions *atts, Dsymbols *decl) @@ -1534,8 +1412,9 @@ Dsymbol *UserAttributeDeclaration::syntaxCopy(Dsymbol *s) { //printf("UserAttributeDeclaration::syntaxCopy('%s')\n", toChars()); assert(!s); - Expressions *atts = Expression::arraySyntaxCopy(this->atts); - return new UserAttributeDeclaration(atts, Dsymbol::arraySyntaxCopy(decl)); + return new UserAttributeDeclaration( + Expression::arraySyntaxCopy(this->atts), + Dsymbol::arraySyntaxCopy(decl)); } Scope *UserAttributeDeclaration::newScope(Scope *sc) @@ -1619,17 +1498,7 @@ Expressions *UserAttributeDeclaration::getAttributes() return exps; } -void UserAttributeDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("@("); - argsToCBuffer(buf, atts, hgs); - buf->writeByte(')'); - AttribDeclaration::toCBuffer(buf, hgs); -} - const char *UserAttributeDeclaration::kind() { return "UserAttribute"; } - - diff --git a/dmd2/attrib.h b/dmd2/attrib.h index bb4f213bbb..2d8121540e 100644 --- a/dmd2/attrib.h +++ b/dmd2/attrib.h @@ -24,7 +24,6 @@ class LabelDsymbol; class Initializer; class Module; class Condition; -struct HdrGenState; /**************************************************************/ @@ -37,7 +36,7 @@ public: virtual Dsymbols *include(Scope *sc, ScopeDsymbol *sds); int apply(Dsymbol_apply_ft_t fp, void *param); static Scope *createNewScope(Scope *sc, - StorageClass newstc, LINK linkage, PROT protection, int explictProtection, + StorageClass newstc, LINK linkage, Prot protection, int explictProtection, structalign_t structalign); virtual Scope *newScope(Scope *sc); int addMember(Scope *sc, ScopeDsymbol *sds, int memnum); @@ -54,7 +53,6 @@ public: bool hasStaticCtorOrDtor(); void checkCtorConstInit(); void addLocalClass(ClassDeclarations *); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); AttribDeclaration *isAttribDeclaration() { return this; } #if IN_DMD @@ -73,7 +71,6 @@ public: Dsymbol *syntaxCopy(Dsymbol *s); Scope *newScope(Scope *sc); bool 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); @@ -88,7 +85,6 @@ public: DeprecatedDeclaration(Expression *msg, Dsymbols *decl); Dsymbol *syntaxCopy(Dsymbol *s); void setScope(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); void accept(Visitor *v) { v->visit(this); } }; @@ -100,7 +96,6 @@ public: LinkDeclaration(LINK p, Dsymbols *decl); Dsymbol *syntaxCopy(Dsymbol *s); Scope *newScope(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); char *toChars(); void accept(Visitor *v) { v->visit(this); } }; @@ -108,12 +103,17 @@ public: class ProtDeclaration : public AttribDeclaration { public: - PROT protection; + Prot protection; + Identifiers* pkg_identifiers; + + ProtDeclaration(Loc loc, Prot p, Dsymbols *decl); + ProtDeclaration(Loc loc, Identifiers* pkg_identifiers, Dsymbols *decl); - ProtDeclaration(PROT p, Dsymbols *decl); Dsymbol *syntaxCopy(Dsymbol *s); Scope *newScope(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + int addMember(Scope *sc, ScopeDsymbol *sds, int memnum); + const char *kind(); + const char *toPrettyChars(bool unused); void accept(Visitor *v) { v->visit(this); } }; @@ -125,7 +125,6 @@ public: AlignDeclaration(unsigned sa, Dsymbols *decl); Dsymbol *syntaxCopy(Dsymbol *s); Scope *newScope(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); void accept(Visitor *v) { v->visit(this); } }; @@ -140,7 +139,6 @@ public: Dsymbol *syntaxCopy(Dsymbol *s); void semantic(Scope *sc); void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); const char *kind(); void accept(Visitor *v) { v->visit(this); } }; @@ -154,7 +152,6 @@ public: Dsymbol *syntaxCopy(Dsymbol *s); void semantic(Scope *sc); void setScope(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); const char *kind(); #if IN_DMD @@ -175,7 +172,6 @@ public: bool oneMember(Dsymbol **ps, Identifier *ident); Dsymbols *include(Scope *sc, ScopeDsymbol *sds); void addComment(const utf8_t *comment); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); void setScope(Scope *sc); void accept(Visitor *v) { v->visit(this); } }; @@ -213,14 +209,13 @@ public: void setScope(Scope *sc); void compileIt(Scope *sc); void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); const char *kind(); void accept(Visitor *v) { v->visit(this); } }; /** * User defined attributes look like: - * [ args, ... ] + * @(args, ...) */ class UserAttributeDeclaration : public AttribDeclaration { @@ -235,7 +230,6 @@ public: void setScope(Scope *sc); static Expressions *concat(Expressions *udas1, Expressions *udas2); Expressions *getAttributes(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); const char *kind(); void accept(Visitor *v) { v->visit(this); } }; diff --git a/dmd2/builtin.c b/dmd2/builtin.c index 96dddd8e7e..8b2834d785 100644 --- a/dmd2/builtin.c +++ b/dmd2/builtin.c @@ -24,6 +24,7 @@ #include "identifier.h" #include "id.h" #include "module.h" +#include "root/port.h" #if IN_LLVM #include "template.h" #include "gen/pragma.h" @@ -366,12 +367,52 @@ Expression *eval_bswap(Loc loc, FuncDeclaration *fd, Expressions *arguments) } #endif +Expression *eval_popcnt(Loc loc, FuncDeclaration *fd, Expressions *arguments) +{ + Expression *arg0 = (*arguments)[0]; + assert(arg0->op == TOKint64); + uinteger_t n = arg0->toInteger(); + int cnt = 0; + while (n) + { + cnt += (n & 1); + n >>= 1; + } + return new IntegerExp(loc, cnt, arg0->type); +} + +Expression *eval_yl2x(Loc loc, FuncDeclaration *fd, Expressions *arguments) +{ + Expression *arg0 = (*arguments)[0]; + assert(arg0->op == TOKfloat64); + Expression *arg1 = (*arguments)[1]; + assert(arg1->op == TOKfloat64); + longdouble x = arg0->toReal(); + longdouble y = arg1->toReal(); + longdouble result; + Port::yl2x_impl(&x, &y, &result); + return new RealExp(loc, result, arg0->type); +} + +Expression *eval_yl2xp1(Loc loc, FuncDeclaration *fd, Expressions *arguments) +{ + Expression *arg0 = (*arguments)[0]; + assert(arg0->op == TOKfloat64); + Expression *arg1 = (*arguments)[1]; + assert(arg1->op == TOKfloat64); + longdouble x = arg0->toReal(); + longdouble y = arg1->toReal(); + longdouble result; + Port::yl2xp1_impl(&x, &y, &result); + return new RealExp(loc, result, arg0->type); +} + void builtin_init() { #if IN_LLVM builtins._init(127); // Prime number like default value #else - builtins._init(45); + builtins._init(47); #endif // @safe @nogc pure nothrow real function(real) @@ -399,8 +440,24 @@ void builtin_init() // @safe @nogc pure nothrow real function(real, real) add_builtin("_D4core4math5atan2FNaNbNiNfeeZe", &eval_unimp); - add_builtin("_D4core4math4yl2xFNaNbNiNfeeZe", &eval_unimp); - add_builtin("_D4core4math6yl2xp1FNaNbNiNfeeZe", &eval_unimp); + + if (Port::yl2x_supported) + { + add_builtin("_D4core4math4yl2xFNaNbNiNfeeZe", &eval_yl2x); + } + else + { + add_builtin("_D4core4math4yl2xFNaNbNiNfeeZe", &eval_unimp); + } + + if (Port::yl2xp1_supported) + { + add_builtin("_D4core4math6yl2xp1FNaNbNiNfeeZe", &eval_yl2xp1); + } + else + { + add_builtin("_D4core4math6yl2xp1FNaNbNiNfeeZe", &eval_unimp); + } // @safe @nogc pure nothrow long function(real) add_builtin("_D4core4math6rndtolFNaNbNiNfeZl", &eval_unimp); @@ -430,8 +487,24 @@ void builtin_init() // @safe @nogc pure nothrow real function(real, real) add_builtin("_D3std4math5atan2FNaNbNiNfeeZe", &eval_unimp); - add_builtin("_D3std4math4yl2xFNaNbNiNfeeZe", &eval_unimp); - add_builtin("_D3std4math6yl2xp1FNaNbNiNfeeZe", &eval_unimp); + + if (Port::yl2x_supported) + { + add_builtin("_D3std4math4yl2xFNaNbNiNfeeZe", &eval_yl2x); + } + else + { + add_builtin("_D3std4math4yl2xFNaNbNiNfeeZe", &eval_unimp); + } + + if (Port::yl2xp1_supported) + { + add_builtin("_D3std4math6yl2xp1FNaNbNiNfeeZe", &eval_yl2xp1); + } + else + { + add_builtin("_D3std4math6yl2xp1FNaNbNiNfeeZe", &eval_unimp); + } // @safe @nogc pure nothrow long function(real) add_builtin("_D3std4math6rndtolFNaNbNiNfeZl", &eval_unimp); @@ -545,6 +618,16 @@ void builtin_init() // @safe @nogc pure nothrow uint function(uint) add_builtin("_D4core5bitop5bswapFNaNbNiNfkZk", &eval_bswap); + + // @safe @nogc pure nothrow int function(uint) + add_builtin("_D4core5bitop7_popcntFNaNbNiNfkZi", &eval_popcnt); + + // @safe @nogc pure nothrow ushort function(ushort) + add_builtin("_D4core5bitop7_popcntFNaNbNiNftZt", &eval_popcnt); + + // @safe @nogc pure nothrow int function(ulong) + if (global.params.is64bit) + add_builtin("_D4core5bitop7_popcntFNaNbNiNfmZi", &eval_popcnt); #endif } diff --git a/dmd2/cast.c b/dmd2/cast.c index 127b2149e6..a53bb8968d 100644 --- a/dmd2/cast.c +++ b/dmd2/cast.c @@ -59,7 +59,7 @@ Expression *implicitCastTo(Expression *e, Scope *sc, Type *t) { if (match == MATCHconst && (e->type->constConv(t) || - !e->isLvalue() && e->type->immutableOf()->equals(t->immutableOf()))) + !e->isLvalue() && e->type->equivalent(t))) { /* Do not emit CastExp for const conversions and * unique conversions on rvalue. @@ -272,7 +272,7 @@ MATCH implicitConvTo(Expression *e, Type *t) Type *t1b = e->e1->type->toBasetype(); Type *t2b = e->e2->type->toBasetype(); if (t1b->ty == Tpointer && t2b->isintegral() && - t1b->immutableOf()->equals(tb->immutableOf())) + t1b->equivalent(tb)) { // ptr + offset // ptr - offset @@ -280,7 +280,7 @@ MATCH implicitConvTo(Expression *e, Type *t) return (m > MATCHconst) ? MATCHconst : m; } if (t2b->ty == Tpointer && t1b->isintegral() && - t2b->immutableOf()->equals(tb->immutableOf())) + t2b->equivalent(tb)) { // offset + ptr MATCH m = e->e2->implicitConvTo(t); @@ -521,7 +521,7 @@ MATCH implicitConvTo(Expression *e, Type *t) * and mutable to immutable. It works because, after all, a null * doesn't actually point to anything. */ - if (t->immutableOf()->equals(e->type->immutableOf())) + if (t->equivalent(e->type)) { result = MATCHconst; return; @@ -849,9 +849,7 @@ MATCH implicitConvTo(Expression *e, Type *t) continue; if (fparam->storageClass & (STCout | STCref)) { - tparam = tparam->pointerTo(); - targ = targ->pointerTo(); - if (targ->implicitConvTo(tparam->addMod(mod)) == MATCHnomatch) + if (targ->constConv(tparam->castMod(mod)) == MATCHnomatch) return; continue; } @@ -1216,11 +1214,11 @@ MATCH implicitConvTo(Expression *e, Type *t) return false; } else - { + { /* Enhancement: handle StructInitializer and ArrayInitializer */ return false; - } + } } else if (!v->type->isZeroInit(loc)) return false; @@ -1249,6 +1247,7 @@ MATCH implicitConvTo(Expression *e, Type *t) void visit(SliceExp *e) { + //printf("SliceExp::implicitConvTo e = %s, type = %s\n", e->toChars(), e->type->toChars()); visit((Expression *)e); if (result != MATCHnomatch) return; @@ -1269,8 +1268,7 @@ MATCH implicitConvTo(Expression *e, Type *t) * same mod bits. */ Type *t1b = e->e1->type->toBasetype(); - if (tb->ty == Tarray && - typeb->immutableOf()->equals(tb->immutableOf())) + if (tb->ty == Tarray && typeb->equivalent(tb)) { Type *tbn = tb->nextOf(); Type *tx = NULL; @@ -2156,25 +2154,22 @@ Expression *castTo(Expression *e, Scope *sc, Type *t) void visit(SliceExp *e) { + //printf("SliceExp::castTo e = %s, type = %s, t = %s\n", e->toChars(), e->type->toChars(), t->toChars()); Type *typeb = e->type->toBasetype(); Type *tb = t->toBasetype(); - if (typeb->ty == Tarray && tb->ty == Tsarray) + if (typeb->ty == Tarray && (tb->ty == Tarray || tb->ty == Tsarray) && + typeb->nextOf()->equivalent(tb->nextOf())) { + // T[] to const(T)[] + // T[] to const(T)[dim] + /* If a SliceExp has Tsarray, it will become lvalue. * That's handled in SliceExp::isLvalue and toLvalue */ result = e->copy(); result->type = t; } - else if (typeb->ty == Tarray && tb->ty == Tarray && - typeb->nextOf()->constConv(tb->nextOf()) == MATCHconst) - { - // immutable(T)[] to const(T)[] - // T [] to const(T)[] - result = e->copy(); - result->type = t; - } else { visit((Expression *)e); @@ -2944,15 +2939,15 @@ Lcc: { goto Lt2; } - else if (e->op != TOKquestion && t1->ty == Tarray && - isArrayOperand(e1) && e2->implicitConvTo(t1->nextOf())) + else if (t1->ty == Tarray && isBinArrayOp(e->op) && + isArrayOpOperand(e1) && e2->implicitConvTo(t1->nextOf())) { // T[] op T e2 = e2->castTo(sc, t1->nextOf()); t = t1->nextOf()->arrayOf(); } - else if (e->op != TOKquestion && t2->ty == Tarray && - isArrayOperand(e2) && e1->implicitConvTo(t2->nextOf())) + else if (t2->ty == Tarray && isBinArrayOp(e->op) && + isArrayOpOperand(e2) && e1->implicitConvTo(t2->nextOf())) { // T op T[] e1 = e1->castTo(sc, t2->nextOf()); diff --git a/dmd2/class.c b/dmd2/class.c index 89d5caa493..d728d44706 100644 --- a/dmd2/class.c +++ b/dmd2/class.c @@ -108,13 +108,6 @@ ClassDeclaration::ClassDeclaration(Loc loc, Identifier *id, BaseClasses *basecla Type::typeinfostruct = this; } - if (id == Id::TypeInfo_Typedef) - { - if (!inObject) - error("%s", msg); - Type::typeinfotypedef = this; - } - if (id == Id::TypeInfo_Pointer) { if (!inObject) @@ -246,13 +239,10 @@ ClassDeclaration::ClassDeclaration(Loc loc, Identifier *id, BaseClasses *basecla Dsymbol *ClassDeclaration::syntaxCopy(Dsymbol *s) { - ClassDeclaration *cd; - //printf("ClassDeclaration::syntaxCopy('%s')\n", toChars()); - if (s) - cd = (ClassDeclaration *)s; - else - cd = new ClassDeclaration(loc, ident, NULL); + ClassDeclaration *cd = + s ? (ClassDeclaration *)s + : new ClassDeclaration(loc, ident, NULL); cd->storage_class |= storage_class; @@ -264,8 +254,7 @@ Dsymbol *ClassDeclaration::syntaxCopy(Dsymbol *s) (*cd->baseclasses)[i] = b2; } - ScopeDsymbol::syntaxCopy(cd); - return cd; + return ScopeDsymbol::syntaxCopy(cd); } void ClassDeclaration::semantic(Scope *sc) @@ -365,7 +354,7 @@ void ClassDeclaration::semantic(Scope *sc) if (tb->ty == Ttuple) { TypeTuple *tup = (TypeTuple *)tb; - PROT protection = b->protection; + Prot protection = b->protection; baseclasses->remove(i); size_t dim = Parameter::dim(tup->arguments); for (size_t j = 0; j < dim; j++) @@ -521,7 +510,7 @@ void ClassDeclaration::semantic(Scope *sc) assert(t->ty == Tclass); TypeClass *tc = (TypeClass *)t; - BaseClass *b = new BaseClass(tc, PROTpublic); + BaseClass *b = new BaseClass(tc, Prot(PROTpublic)); baseclasses->shift(b); baseClass = tc->sym; @@ -554,6 +543,10 @@ void ClassDeclaration::semantic(Scope *sc) // then this is a COM interface too. if (b->base->isCOMinterface()) com = true; + if (cpp && !b->base->isCPPinterface()) + { + ::error(loc, "C++ class '%s' cannot implement D interface '%s'", toPrettyChars(), b->base->toPrettyChars()); + } } } Lancestorsdone: @@ -663,7 +656,7 @@ Lancestorsdone: sc2->linkage = LINKc; } } - sc2->protection = PROTpublic; + sc2->protection = Prot(PROTpublic); sc2->explicitProtection = 0; sc2->structalign = STRUCTALIGN_DEFAULT; sc2->userAttribDecl = NULL; @@ -863,43 +856,6 @@ Lancestorsdone: //printf("-ClassDeclaration::semantic(%s), type = %p, sizeok = %d, this = %p\n", toChars(), type, sizeok, this); } -void ClassDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (!isAnonymous()) - { - buf->printf("%s ", kind()); - buf->writestring(toChars()); - if (baseclasses->dim) - buf->writestring(" : "); - } - for (size_t i = 0; i < baseclasses->dim; i++) - { - BaseClass *b = (*baseclasses)[i]; - - if (i) - buf->writestring(", "); - //buf->writestring(b->base->ident->toChars()); - b->type->toCBuffer(buf, NULL, hgs); - } - if (members) - { - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - buf->level++; - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = (*members)[i]; - s->toCBuffer(buf, hgs); - } - buf->level--; - buf->writestring("}"); - } - else - buf->writeByte(';'); - buf->writenl(); -} - /********************************************* * Determine if 'this' is a base class of cd. * This is used to detect circular inheritance only. @@ -1261,15 +1217,10 @@ InterfaceDeclaration::InterfaceDeclaration(Loc loc, Identifier *id, BaseClasses Dsymbol *InterfaceDeclaration::syntaxCopy(Dsymbol *s) { - InterfaceDeclaration *id; - - if (s) - id = (InterfaceDeclaration *)s; - else - id = new InterfaceDeclaration(loc, ident, NULL); - - ClassDeclaration::syntaxCopy(id); - return id; + InterfaceDeclaration *id = + s ? (InterfaceDeclaration *)s + : new InterfaceDeclaration(loc, ident, NULL); + return ClassDeclaration::syntaxCopy(id); } void InterfaceDeclaration::semantic(Scope *sc) @@ -1347,7 +1298,7 @@ void InterfaceDeclaration::semantic(Scope *sc) if (tb->ty == Ttuple) { TypeTuple *tup = (TypeTuple *)tb; - PROT protection = b->protection; + Prot protection = b->protection; baseclasses->remove(i); size_t dim = Parameter::dim(tup->arguments); for (size_t j = 0; j < dim; j++) @@ -1536,7 +1487,7 @@ Lancestorsdone: sc2->linkage = LINKwindows; else if (cpp) sc2->linkage = LINKcpp; - sc2->protection = PROTpublic; + sc2->protection = Prot(PROTpublic); sc2->explicitProtection = 0; sc2->structalign = STRUCTALIGN_DEFAULT; sc2->userAttribDecl = NULL; @@ -1713,7 +1664,7 @@ BaseClass::BaseClass() memset(this, 0, sizeof(BaseClass)); } -BaseClass::BaseClass(Type *type, PROT protection) +BaseClass::BaseClass(Type *type, Prot protection) { //printf("BaseClass(this = %p, '%s')\n", this, type->toChars()); this->type = type; diff --git a/dmd2/clone.c b/dmd2/clone.c index 784ac3aa55..35df300e5b 100644 --- a/dmd2/clone.c +++ b/dmd2/clone.c @@ -26,7 +26,7 @@ /******************************************* - * Merge function attributes pure, nothrow, @safe, and @disable + * Merge function attributes pure, nothrow, @safe, @nogc, and @disable */ StorageClass mergeFuncAttrs(StorageClass s1, FuncDeclaration *f) { @@ -93,7 +93,8 @@ FuncDeclaration *hasIdentityOpAssign(AggregateDeclaration *ad, Scope *sc) unsigned errors = global.startGagging(); // Do not report errors, even if the sc = sc->push(); - sc->speculative = true; + sc->tinst = NULL; + sc->minst = NULL; for (size_t i = 0; i < 2; i++) { @@ -249,7 +250,7 @@ FuncDeclaration *buildOpAssign(StructDeclaration *sd, Scope *sc) * tmp = this; this = s; tmp.dtor(); */ //printf("\tswap copy\n"); - Identifier *idtmp = Lexer::uniqueId("__tmp"); + Identifier *idtmp = Lexer::uniqueId("__swap"); VarDeclaration *tmp = NULL; AssignExp *ec = NULL; if (sd->dtor) @@ -406,7 +407,8 @@ FuncDeclaration *hasIdentityOpEquals(AggregateDeclaration *ad, Scope *sc) unsigned errors = global.startGagging(); // Do not report errors, even if the sc = sc->push(); - sc->speculative = true; + sc->tinst = NULL; + sc->minst = NULL; for (size_t j = 0; j < 2; j++) { @@ -866,7 +868,12 @@ FuncDeclaration *buildPostBlit(StructDeclaration *sd, Scope *sc) Loc loc = Loc(); // internal code should have no loc to prevent coverage Expression *e = NULL; - for (size_t i = 0; i < sd->fields.dim; i++) + for (size_t i = 0; i < sd->postblits.dim; i++) + { + stc |= sd->postblits[i]->storage_class & STCdisable; + } + + for (size_t i = 0; i < sd->fields.dim && !(stc & STCdisable); i++) { VarDeclaration *v = sd->fields[i]; if (v->storage_class & STCref) diff --git a/dmd2/color.c b/dmd2/color.c deleted file mode 100644 index d6dfc24452..0000000000 --- a/dmd2/color.c +++ /dev/null @@ -1,77 +0,0 @@ - -/* Compiler implementation of the D programming language - * Copyright (c) 1999-2014 by Digital Mars - * All Rights Reserved - * written by Walter Bright - * http://www.digitalmars.com - * Distributed under the Boost Software License, Version 1.0. - * http://www.boost.org/LICENSE_1_0.txt - * https://github.com/D-Programming-Language/dmd/blob/master/src/mars.c - */ - -#include "color.h" - -#include - -#if _WIN32 -#include -#include -#endif - -#if __linux__ || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun -#include -#include -#include -#endif - -#if _WIN32 -static CONSOLE_SCREEN_BUFFER_INFO *consoleAttributes() -{ - static CONSOLE_SCREEN_BUFFER_INFO sbi; - static bool sbi_inited = false; - if (!sbi_inited) - sbi_inited = GetConsoleScreenBufferInfo(GetStdHandle(STD_ERROR_HANDLE), &sbi) != FALSE; - return &sbi; -} -#endif - -bool isConsoleColorSupported() -{ -#if _WIN32 - return _isatty(_fileno(stderr)) != 0; -#elif __linux__ || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun - const char *term = getenv("TERM"); - return isatty(STDERR_FILENO) && term && term[0] && 0 != strcmp(term, "dumb"); -#else - return false; -#endif -} - -void setConsoleColorBright() -{ -#if _WIN32 - SetConsoleTextAttribute(GetStdHandle(STD_ERROR_HANDLE), consoleAttributes()->wAttributes | FOREGROUND_INTENSITY); -#else - fprintf(stderr, "\033[1m"); -#endif -} - -void setConsoleColorError() -{ -#if _WIN32 - enum { FOREGROUND_WHITE = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE }; - SetConsoleTextAttribute(GetStdHandle(STD_ERROR_HANDLE), (consoleAttributes()->wAttributes & ~FOREGROUND_WHITE) | FOREGROUND_RED | FOREGROUND_INTENSITY); -#else - fprintf(stderr, "\033[1;31m"); -#endif -} - -void resetConsoleColor() -{ -#if _WIN32 - SetConsoleTextAttribute(GetStdHandle(STD_ERROR_HANDLE), consoleAttributes()->wAttributes); -#else - fprintf(stderr, "\033[m"); -#endif -} - diff --git a/dmd2/color.h b/dmd2/color.h deleted file mode 100644 index 6c4d41af31..0000000000 --- a/dmd2/color.h +++ /dev/null @@ -1,16 +0,0 @@ - -/* Compiler implementation of the D programming language - * Copyright (c) 1999-2014 by Digital Mars - * All Rights Reserved - * written by Walter Bright - * http://www.digitalmars.com - * Distributed under the Boost Software License, Version 1.0. - * http://www.boost.org/LICENSE_1_0.txt - * https://github.com/D-Programming-Language/dmd/blob/master/src/mars.c - */ - -extern bool isConsoleColorSupported(); -extern void setConsoleColorBright(); -extern void setConsoleColorError(); -extern void resetConsoleColor(); - diff --git a/dmd2/cond.c b/dmd2/cond.c index 9d16e836a6..d3c78ba008 100644 --- a/dmd2/cond.c +++ b/dmd2/cond.c @@ -136,14 +136,6 @@ int DebugCondition::include(Scope *sc, ScopeDsymbol *sds) return (inc == 1); } -void DebugCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (ident) - buf->printf("debug (%s)", ident->toChars()); - else - buf->printf("debug (%u)", level); -} - /* ============================================================ */ void VersionCondition::setGlobalLevel(unsigned level) @@ -221,6 +213,8 @@ bool VersionCondition::isPredefined(const char *ident) "Alpha_HardFloat", "LittleEndian", "BigEndian", + "ELFv1", + "ELFv2", "D_Coverage", "D_Ddoc", "D_InlineAsm_X86", @@ -306,15 +300,6 @@ int VersionCondition::include(Scope *sc, ScopeDsymbol *sds) return (inc == 1); } -void VersionCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (ident) - buf->printf("version (%s)", ident->toChars()); - else - buf->printf("version (%u)", level); -} - - /**************************** StaticIfCondition *******************************/ StaticIfCondition::StaticIfCondition(Loc loc, Expression *exp) @@ -358,7 +343,7 @@ int StaticIfCondition::include(Scope *sc, ScopeDsymbol *sds) sc = sc->push(sc->scopesym); sc->sds = sds; // sds gets any addMember() //sc->speculative = true; // TODO: static if (is(T U)) { /* U is available */ } - sc->flags |= SCOPEstaticif; + sc->flags |= SCOPEcondition; sc = sc->startCTFE(); Expression *e = exp->semantic(sc); @@ -396,10 +381,3 @@ Lerror: inc = 2; // so we don't see the error message again return 0; } - -void StaticIfCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("static if ("); - exp->toCBuffer(buf, hgs); - buf->writeByte(')'); -} diff --git a/dmd2/cond.h b/dmd2/cond.h index 359d676223..a3bc16a39e 100644 --- a/dmd2/cond.h +++ b/dmd2/cond.h @@ -19,9 +19,6 @@ class Module; struct Scope; class ScopeDsymbol; class DebugCondition; -#include "lexer.h" -enum TOK; -struct HdrGenState; int findCondition(Strings *ids, Identifier *ident); @@ -38,8 +35,8 @@ public: virtual Condition *syntaxCopy() = 0; virtual int include(Scope *sc, ScopeDsymbol *sds) = 0; - virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs) = 0; virtual DebugCondition *isDebugCondition() { return NULL; } + virtual void accept(Visitor *v) { v->visit(this); } }; class DVCondition : public Condition @@ -52,6 +49,7 @@ public: DVCondition(Module *mod, unsigned level, Identifier *ident); Condition *syntaxCopy(); + void accept(Visitor *v) { v->visit(this); } }; class DebugCondition : public DVCondition @@ -63,8 +61,8 @@ public: DebugCondition(Module *mod, unsigned level, Identifier *ident); int include(Scope *sc, ScopeDsymbol *sds); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); DebugCondition *isDebugCondition() { return this; } + void accept(Visitor *v) { v->visit(this); } }; class VersionCondition : public DVCondition @@ -83,7 +81,7 @@ public: VersionCondition(Module *mod, unsigned level, Identifier *ident); int include(Scope *sc, ScopeDsymbol *sds); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void accept(Visitor *v) { v->visit(this); } }; class StaticIfCondition : public Condition @@ -95,7 +93,7 @@ public: StaticIfCondition(Loc loc, Expression *exp); Condition *syntaxCopy(); int include(Scope *sc, ScopeDsymbol *sds); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void accept(Visitor *v) { v->visit(this); } }; #endif diff --git a/dmd2/constfold.c b/dmd2/constfold.c index 0f0a3f9824..bb4639868a 100644 --- a/dmd2/constfold.c +++ b/dmd2/constfold.c @@ -14,6 +14,7 @@ #include #include // mem{cpy|set|cmp}() #include +#include #include "rmem.h" #include "root.h" @@ -48,7 +49,7 @@ Expression *expType(Type *type, Expression *e) int isConst(Expression *e) { //printf("Expression::isConst(): %s\n", e->toChars()); - switch(e->op) + switch (e->op) { case TOKint64: case TOKfloat64: @@ -83,29 +84,33 @@ int isConst(Expression *e) /* ========================================================================== */ -Expression *Neg(Type *type, Expression *e1) -{ Expression *e; +UnionExp Neg(Type *type, Expression *e1) +{ + UnionExp ue; Loc loc = e1->loc; if (e1->type->isreal()) { - e = new RealExp(loc, -e1->toReal(), type); + new(&ue) RealExp(loc, -e1->toReal(), type); } else if (e1->type->isimaginary()) { - e = new RealExp(loc, -e1->toImaginary(), type); + new(&ue) RealExp(loc, -e1->toImaginary(), type); } else if (e1->type->iscomplex()) { - e = new ComplexExp(loc, -e1->toComplex(), type); + new(&ue) ComplexExp(loc, -e1->toComplex(), type); } else - e = new IntegerExp(loc, -e1->toInteger(), type); - return e; + { + new(&ue) IntegerExp(loc, -e1->toInteger(), type); + } + return ue; } Expression *Com(Type *type, Expression *e1) -{ Expression *e; +{ + Expression *e; Loc loc = e1->loc; e = new IntegerExp(loc, ~e1->toInteger(), type); @@ -113,7 +118,8 @@ Expression *Com(Type *type, Expression *e1) } Expression *Not(Type *type, Expression *e1) -{ Expression *e; +{ + Expression *e; Loc loc = e1->loc; e = new IntegerExp(loc, e1->isBool(0), type); @@ -121,7 +127,8 @@ Expression *Not(Type *type, Expression *e1) } Expression *Bool(Type *type, Expression *e1) -{ Expression *e; +{ + Expression *e; Loc loc = e1->loc; e = new IntegerExp(loc, e1->isBool(1), type); @@ -129,7 +136,8 @@ Expression *Bool(Type *type, Expression *e1) } Expression *Add(Type *type, Expression *e1, Expression *e2) -{ Expression *e; +{ + Expression *e; Loc loc = e1->loc; #if LOG @@ -159,27 +167,33 @@ Expression *Add(Type *type, Expression *e1, Expression *e2) int x; if (e1->type->isreal()) - { r1 = e1->toReal(); + { + r1 = e1->toReal(); x = 0; } else if (e1->type->isimaginary()) - { i1 = e1->toImaginary(); + { + i1 = e1->toImaginary(); x = 3; } else - { c1 = e1->toComplex(); + { + c1 = e1->toComplex(); x = 6; } if (e2->type->isreal()) - { r2 = e2->toReal(); + { + r2 = e2->toReal(); } else if (e2->type->isimaginary()) - { i2 = e2->toImaginary(); + { + i2 = e2->toImaginary(); x += 1; } else - { c2 = e2->toComplex(); + { + c2 = e2->toComplex(); x += 2; } @@ -217,7 +231,8 @@ Expression *Add(Type *type, Expression *e1, Expression *e2) Expression *Min(Type *type, Expression *e1, Expression *e2) -{ Expression *e; +{ + Expression *e; Loc loc = e1->loc; if (type->isreal()) @@ -244,27 +259,33 @@ Expression *Min(Type *type, Expression *e1, Expression *e2) int x; if (e1->type->isreal()) - { r1 = e1->toReal(); + { + r1 = e1->toReal(); x = 0; } else if (e1->type->isimaginary()) - { i1 = e1->toImaginary(); + { + i1 = e1->toImaginary(); x = 3; } else - { c1 = e1->toComplex(); + { + c1 = e1->toComplex(); x = 6; } if (e2->type->isreal()) - { r2 = e2->toReal(); + { + r2 = e2->toReal(); } else if (e2->type->isimaginary()) - { i2 = e2->toImaginary(); + { + i2 = e2->toImaginary(); x += 1; } else - { c2 = e2->toComplex(); + { + c2 = e2->toComplex(); x += 2; } @@ -297,11 +318,13 @@ Expression *Min(Type *type, Expression *e1, Expression *e2) } Expression *Mul(Type *type, Expression *e1, Expression *e2) -{ Expression *e; +{ + Expression *e; Loc loc = e1->loc; if (type->isfloating()) - { complex_t c; + { + complex_t c; d_float80 r; if (e1->type->isreal()) @@ -348,11 +371,13 @@ Expression *Mul(Type *type, Expression *e1, Expression *e2) } Expression *Div(Type *type, Expression *e1, Expression *e2) -{ Expression *e; +{ + Expression *e; Loc loc = e1->loc; if (type->isfloating()) - { complex_t c; + { + complex_t c; d_float80 r; //e1->type->print(); @@ -389,14 +414,16 @@ Expression *Div(Type *type, Expression *e1, Expression *e2) assert(0); } else - { sinteger_t n1; + { + sinteger_t n1; sinteger_t n2; sinteger_t n; n1 = e1->toInteger(); n2 = e2->toInteger(); if (n2 == 0) - { e2->error("divide by 0"); + { + e2->error("divide by 0"); e2 = new IntegerExp(loc, 1, e2->type); n2 = 1; } @@ -410,7 +437,8 @@ Expression *Div(Type *type, Expression *e1, Expression *e2) } Expression *Mod(Type *type, Expression *e1, Expression *e2) -{ Expression *e; +{ + Expression *e; Loc loc = e1->loc; if (type->isfloating()) @@ -418,12 +446,14 @@ Expression *Mod(Type *type, Expression *e1, Expression *e2) complex_t c; if (e2->type->isreal()) - { real_t r2 = e2->toReal(); + { + real_t r2 = e2->toReal(); c = complex_t(Port::fmodl(e1->toReal(), r2), Port::fmodl(e1->toImaginary(), r2)); } else if (e2->type->isimaginary()) - { real_t i2 = e2->toImaginary(); + { + real_t i2 = e2->toImaginary(); c = complex_t(Port::fmodl(e1->toReal(), i2), Port::fmodl(e1->toImaginary(), i2)); } @@ -440,19 +470,22 @@ Expression *Mod(Type *type, Expression *e1, Expression *e2) assert(0); } else - { sinteger_t n1; + { + sinteger_t n1; sinteger_t n2; sinteger_t n; n1 = e1->toInteger(); n2 = e2->toInteger(); if (n2 == 0) - { e2->error("divide by 0"); + { + e2->error("divide by 0"); e2 = new IntegerExp(loc, 1, e2->type); n2 = 1; } if (n2 == -1 && !type->isunsigned()) - { // Check for int.min % -1 + { + // Check for int.min % -1 if (n1 == 0xFFFFFFFF80000000ULL && type->toBasetype()->ty != Tint64) { e2->error("integer overflow: int.min % -1"); @@ -476,7 +509,8 @@ Expression *Mod(Type *type, Expression *e1, Expression *e2) } Expression *Pow(Type *type, Expression *e1, Expression *e2) -{ Expression *e; +{ + Expression *e; Loc loc = e1->loc; // Handle integer power operations. @@ -550,7 +584,8 @@ Expression *Pow(Type *type, Expression *e1, Expression *e2) } Expression *Shl(Type *type, Expression *e1, Expression *e2) -{ Expression *e; +{ + Expression *e; Loc loc = e1->loc; e = new IntegerExp(loc, e1->toInteger() << e2->toInteger(), type); @@ -665,13 +700,15 @@ Expression *And(Type *type, Expression *e1, Expression *e2) } Expression *Or(Type *type, Expression *e1, Expression *e2) -{ Expression *e; +{ + Expression *e; e = new IntegerExp(e1->loc, e1->toInteger() | e2->toInteger(), type); return e; } Expression *Xor(Type *type, Expression *e1, Expression *e2) -{ Expression *e; +{ + Expression *e; e = new IntegerExp(e1->loc, e1->toInteger() ^ e2->toInteger(), type); return e; } @@ -679,7 +716,8 @@ Expression *Xor(Type *type, Expression *e1, Expression *e2) /* Also returns EXP_CANT_INTERPRET if cannot be computed. */ Expression *Equal(TOK op, Type *type, Expression *e1, Expression *e2) -{ Expression *e; +{ + Expression *e; Loc loc = e1->loc; int cmp = 0; real_t r1; @@ -694,11 +732,13 @@ Expression *Equal(TOK op, Type *type, Expression *e1, Expression *e2) if (e2->op == TOKnull) cmp = 1; else if (e2->op == TOKstring) - { StringExp *es2 = (StringExp *)e2; + { + StringExp *es2 = (StringExp *)e2; cmp = (0 == es2->len); } else if (e2->op == TOKarrayliteral) - { ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2; + { + ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2; cmp = !es2->elements || (0 == es2->elements->dim); } else @@ -707,18 +747,21 @@ Expression *Equal(TOK op, Type *type, Expression *e1, Expression *e2) else if (e2->op == TOKnull) { if (e1->op == TOKstring) - { StringExp *es1 = (StringExp *)e1; + { + StringExp *es1 = (StringExp *)e1; cmp = (0 == es1->len); } else if (e1->op == TOKarrayliteral) - { ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1; + { + ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1; cmp = !es1->elements || (0 == es1->elements->dim); } else return EXP_CANT_INTERPRET; } else if (e1->op == TOKstring && e2->op == TOKstring) - { StringExp *es1 = (StringExp *)e1; + { + StringExp *es1 = (StringExp *)e1; StringExp *es2 = (StringExp *)e2; if (es1->sz != es2->sz) @@ -733,7 +776,8 @@ Expression *Equal(TOK op, Type *type, Expression *e1, Expression *e2) cmp = 0; } else if (e1->op == TOKarrayliteral && e2->op == TOKarrayliteral) - { ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1; + { + ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1; ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2; if ((!es1->elements || !es1->elements->dim) && @@ -746,7 +790,8 @@ Expression *Equal(TOK op, Type *type, Expression *e1, Expression *e2) else { for (size_t i = 0; i < es1->elements->dim; i++) - { Expression *ee1 = (*es1->elements)[i]; + { + Expression *ee1 = (*es1->elements)[i]; Expression *ee2 = (*es2->elements)[i]; Expression *v = Equal(TOKequal, Type::tint32, ee1, ee2); @@ -759,7 +804,8 @@ Expression *Equal(TOK op, Type *type, Expression *e1, Expression *e2) } } else if (e1->op == TOKarrayliteral && e2->op == TOKstring) - { // Swap operands and use common code + { + // Swap operands and use common code Expression *etmp = e1; e1 = e2; e2 = etmp; @@ -790,7 +836,8 @@ Expression *Equal(TOK op, Type *type, Expression *e1, Expression *e2) } } else if (e1->op == TOKstructliteral && e2->op == TOKstructliteral) - { StructLiteralExp *es1 = (StructLiteralExp *)e1; + { + StructLiteralExp *es1 = (StructLiteralExp *)e1; StructLiteralExp *es2 = (StructLiteralExp *)e2; if (es1->sd != es2->sd) @@ -806,13 +853,15 @@ Expression *Equal(TOK op, Type *type, Expression *e1, Expression *e2) { cmp = 1; for (size_t i = 0; i < es1->elements->dim; i++) - { Expression *ee1 = (*es1->elements)[i]; + { + Expression *ee1 = (*es1->elements)[i]; Expression *ee2 = (*es2->elements)[i]; if (ee1 == ee2) continue; if (!ee1 || !ee2) - { cmp = 0; + { + cmp = 0; break; } Expression *v = Equal(TOKequal, Type::tint32, ee1, ee2); @@ -830,7 +879,9 @@ Expression *Equal(TOK op, Type *type, Expression *e1, Expression *e2) } } else if (e1->isConst() != 1 || e2->isConst() != 1) + { return EXP_CANT_INTERPRET; + } else if (e1->type->isreal()) { r1 = e1->toReal(); @@ -861,6 +912,7 @@ Expression *Equal(TOK op, Type *type, Expression *e1, Expression *e2) } else return EXP_CANT_INTERPRET; + if (op == TOKnotequal) cmp ^= 1; e = new IntegerExp(loc, cmp, type); @@ -915,7 +967,8 @@ Expression *Identity(TOK op, Type *type, Expression *e1, Expression *e2) Expression *Cmp(TOK op, Type *type, Expression *e1, Expression *e2) -{ Expression *e; +{ + Expression *e; Loc loc = e1->loc; dinteger_t n; real_t r1; @@ -924,7 +977,8 @@ Expression *Cmp(TOK op, Type *type, Expression *e1, Expression *e2) //printf("Cmp(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars()); if (e1->op == TOKstring && e2->op == TOKstring) - { StringExp *es1 = (StringExp *)e1; + { + StringExp *es1 = (StringExp *)e1; StringExp *es2 = (StringExp *)e2; size_t sz = es1->sz; assert(sz == es2->sz); @@ -958,7 +1012,9 @@ Expression *Cmp(TOK op, Type *type, Expression *e1, Expression *e2) } } else if (e1->isConst() != 1 || e2->isConst() != 1) + { return EXP_CANT_INTERPRET; + } else if (e1->type->isreal()) { r1 = e1->toReal(); @@ -1022,7 +1078,8 @@ Expression *Cmp(TOK op, Type *type, Expression *e1, Expression *e2) assert(0); } else - { sinteger_t n1; + { + sinteger_t n1; sinteger_t n2; n1 = e1->toInteger(); @@ -1082,7 +1139,8 @@ Expression *Cmp(TOK op, Type *type, Expression *e1, Expression *e2) */ Expression *Cast(Type *type, Type *to, Expression *e1) -{ Expression *e = EXP_CANT_INTERPRET; +{ + Expression *e = EXP_CANT_INTERPRET; Loc loc = e1->loc; //printf("Cast(type = %s, to = %s, e1 = %s)\n", type->toChars(), to->toChars(), e1->toChars()); @@ -1091,14 +1149,18 @@ Expression *Cast(Type *type, Type *to, Expression *e1) return e1; if (e1->type->implicitConvTo(to) >= MATCHconst || to->implicitConvTo(e1->type) >= MATCHconst) + { return expType(to, e1); + } // Allow covariant converions of delegates // (Perhaps implicit conversion from pure to impure should be a MATCHconst, // then we wouldn't need this extra check.) if (e1->type->toBasetype()->ty == Tdelegate && e1->type->implicitConvTo(to) == MATCHconvert) + { return expType(to, e1); + } Type *tb = to->toBasetype(); Type *typeb = type->toBasetype(); @@ -1121,11 +1183,14 @@ Expression *Cast(Type *type, Type *to, Expression *e1) return EXP_CANT_INTERPRET; if (tb->ty == Tbool) + { e = new IntegerExp(loc, e1->toInteger() != 0, type); + } else if (type->isintegral()) { if (e1->type->isfloating()) - { dinteger_t result; + { + dinteger_t result; real_t r = e1->toReal(); switch (typeb->ty) @@ -1153,26 +1218,34 @@ Expression *Cast(Type *type, Type *to, Expression *e1) e = new IntegerExp(loc, e1->toInteger(), type); } else if (tb->isreal()) - { real_t value = e1->toReal(); + { + real_t value = e1->toReal(); e = new RealExp(loc, value, type); } else if (tb->isimaginary()) - { real_t value = e1->toImaginary(); + { + real_t value = e1->toImaginary(); e = new RealExp(loc, value, type); } else if (tb->iscomplex()) - { complex_t value = e1->toComplex(); + { + complex_t value = e1->toComplex(); e = new ComplexExp(loc, value, type); } else if (tb->isscalar()) + { e = new IntegerExp(loc, e1->toInteger(), type); + } else if (tb->ty == Tvoid) + { e = EXP_CANT_INTERPRET; + } else if (tb->ty == Tstruct && e1->op == TOKint64) - { // Struct = 0; + { + // Struct = 0; StructDeclaration *sd = tb->toDsymbol(NULL)->isStructDeclaration(); assert(sd); Expressions *elements = new Expressions; @@ -1199,29 +1272,35 @@ Expression *Cast(Type *type, Type *to, Expression *e1) Expression *ArrayLength(Type *type, Expression *e1) -{ Expression *e; +{ + Expression *e; Loc loc = e1->loc; if (e1->op == TOKstring) - { StringExp *es1 = (StringExp *)e1; + { + StringExp *es1 = (StringExp *)e1; e = new IntegerExp(loc, es1->len, type); } else if (e1->op == TOKarrayliteral) - { ArrayLiteralExp *ale = (ArrayLiteralExp *)e1; + { + ArrayLiteralExp *ale = (ArrayLiteralExp *)e1; size_t dim; dim = ale->elements ? ale->elements->dim : 0; e = new IntegerExp(loc, dim, type); } else if (e1->op == TOKassocarrayliteral) - { AssocArrayLiteralExp *ale = (AssocArrayLiteralExp *)e1; + { + AssocArrayLiteralExp *ale = (AssocArrayLiteralExp *)e1; size_t dim = ale->keys->dim; e = new IntegerExp(loc, dim, type); } else if (e1->type->toBasetype()->ty == Tsarray) + { e = ((TypeSArray *)e1->type->toBasetype())->dim; + } else e = EXP_CANT_INTERPRET; return e; @@ -1230,13 +1309,15 @@ Expression *ArrayLength(Type *type, Expression *e1) /* Also return EXP_CANT_INTERPRET if this fails */ Expression *Index(Type *type, Expression *e1, Expression *e2) -{ Expression *e = EXP_CANT_INTERPRET; +{ + Expression *e = EXP_CANT_INTERPRET; Loc loc = e1->loc; //printf("Index(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars()); assert(e1->type); if (e1->op == TOKstring && e2->op == TOKint64) - { StringExp *es1 = (StringExp *)e1; + { + StringExp *es1 = (StringExp *)e1; uinteger_t i = e2->toInteger(); if (i >= es1->len) @@ -1250,7 +1331,8 @@ Expression *Index(Type *type, Expression *e1, Expression *e2) } } else if (e1->type->toBasetype()->ty == Tsarray && e2->op == TOKint64) - { TypeSArray *tsa = (TypeSArray *)e1->type->toBasetype(); + { + TypeSArray *tsa = (TypeSArray *)e1->type->toBasetype(); uinteger_t length = tsa->dim->toInteger(); uinteger_t i = e2->toInteger(); @@ -1260,7 +1342,8 @@ Expression *Index(Type *type, Expression *e1, Expression *e2) e = new ErrorExp(); } else if (e1->op == TOKarrayliteral) - { ArrayLiteralExp *ale = (ArrayLiteralExp *)e1; + { + ArrayLiteralExp *ale = (ArrayLiteralExp *)e1; e = (*ale->elements)[(size_t)i]; e->type = type; e->loc = loc; @@ -1273,14 +1356,16 @@ Expression *Index(Type *type, Expression *e1, Expression *e2) uinteger_t i = e2->toInteger(); if (e1->op == TOKarrayliteral) - { ArrayLiteralExp *ale = (ArrayLiteralExp *)e1; + { + ArrayLiteralExp *ale = (ArrayLiteralExp *)e1; if (i >= ale->elements->dim) { e1->error("array index %llu is out of bounds %s[0 .. %u]", i, e1->toChars(), ale->elements->dim); e = new ErrorExp(); } else - { e = (*ale->elements)[(size_t)i]; + { + e = (*ale->elements)[(size_t)i]; e->type = type; e->loc = loc; if (hasSideEffect(e)) @@ -1301,7 +1386,8 @@ Expression *Index(Type *type, Expression *e1, Expression *e2) if (ex == EXP_CANT_INTERPRET) return ex; if (ex->isBool(true)) - { e = (*ae->values)[i]; + { + e = (*ae->values)[i]; e->type = type; e->loc = loc; if (hasSideEffect(e)) @@ -1316,19 +1402,22 @@ Expression *Index(Type *type, Expression *e1, Expression *e2) /* Also return EXP_CANT_INTERPRET if this fails */ Expression *Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr) -{ Expression *e = EXP_CANT_INTERPRET; +{ + Expression *e = EXP_CANT_INTERPRET; Loc loc = e1->loc; #if LOG printf("Slice()\n"); if (lwr) - { printf("\te1 = %s\n", e1->toChars()); + { + printf("\te1 = %s\n", e1->toChars()); printf("\tlwr = %s\n", lwr->toChars()); printf("\tupr = %s\n", upr->toChars()); } #endif if (e1->op == TOKstring && lwr->op == TOKint64 && upr->op == TOKint64) - { StringExp *es1 = (StringExp *)e1; + { + StringExp *es1 = (StringExp *)e1; uinteger_t ilwr = lwr->toInteger(); uinteger_t iupr = upr->toInteger(); @@ -1358,7 +1447,8 @@ Expression *Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr) else if (e1->op == TOKarrayliteral && lwr->op == TOKint64 && upr->op == TOKint64 && !hasSideEffect(e1)) - { ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1; + { + ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1; uinteger_t ilwr = lwr->toInteger(); uinteger_t iupr = upr->toInteger(); @@ -1418,9 +1508,15 @@ void sliceAssignStringFromArrayLiteral(StringExp *existingSE, ArrayLiteralExp *n unsigned value = (unsigned)((*newae->elements)[j]->toInteger()); switch (existingSE->sz) { - case 1: s[j+firstIndex] = (utf8_t)value; break; - case 2: ((unsigned short *)s)[j+firstIndex] = (unsigned short)value; break; - case 4: ((unsigned *)s)[j+firstIndex] = value; break; + case 1: + s[j + firstIndex] = (utf8_t)value; + break; + case 2: + ((unsigned short *)s)[j + firstIndex] = (unsigned short)value; + break; + case 4: + ((unsigned *)s)[j + firstIndex] = value; + break; default: assert(0); break; @@ -1466,9 +1562,15 @@ int sliceCmpStringWithArray(StringExp *se1, ArrayLiteralExp *ae2, size_t lo1, si unsigned svalue; switch (sz) { - case 1: svalue = s[j + lo1]; break; - case 2: svalue = ((unsigned short *)s)[j+lo1]; break; - case 4: svalue = ((unsigned *)s)[j + lo1]; break; + case 1: + svalue = s[j + lo1]; + break; + case 2: + svalue = ((unsigned short *)s)[j+lo1]; + break; + case 4: + svalue = ((unsigned *)s)[j + lo1]; + break; default: assert(0); } @@ -1482,7 +1584,8 @@ int sliceCmpStringWithArray(StringExp *se1, ArrayLiteralExp *ae2, size_t lo1, si /* Also return EXP_CANT_INTERPRET if this fails */ Expression *Cat(Type *type, Expression *e1, Expression *e2) -{ Expression *e = EXP_CANT_INTERPRET; +{ + Expression *e = EXP_CANT_INTERPRET; Loc loc = e1->loc; Type *t; Type *t1 = e1->type->toBasetype(); @@ -1492,12 +1595,14 @@ Expression *Cat(Type *type, Expression *e1, Expression *e2) //printf("\tt1 = %s, t2 = %s, type = %s\n", t1->toChars(), t2->toChars(), type->toChars()); if (e1->op == TOKnull && (e2->op == TOKint64 || e2->op == TOKstructliteral)) - { e = e2; + { + e = e2; t = t1; goto L2; } else if ((e1->op == TOKint64 || e1->op == TOKstructliteral) && e2->op == TOKnull) - { e = e1; + { + e = e1; t = t2; L2: Type *tn = e->type->toBasetype(); @@ -1537,7 +1642,8 @@ Expression *Cat(Type *type, Expression *e1, Expression *e2) e = es; } else - { // Create an ArrayLiteralExp + { + // Create an ArrayLiteralExp Expressions *elements = new Expressions(); elements->push(e); e = new ArrayLiteralExp(e->loc, elements); @@ -1791,18 +1897,21 @@ Expression *Cat(Type *type, Expression *e1, Expression *e2) goto L1; } else if (e1->op == TOKstring && e2->op == TOKnull) - { e = e1; + { + e = e1; t = e2->type; L1: Type *tb = t->toBasetype(); if (tb->ty == Tarray && tb->nextOf()->equals(e->type)) - { Expressions *expressions = new Expressions(); + { + Expressions *expressions = new Expressions(); expressions->push(e); e = new ArrayLiteralExp(loc, expressions); e->type = t; } if (!e->type->equals(type)) - { StringExp *se = (StringExp *)e->copy(); + { + StringExp *se = (StringExp *)e->copy(); e = se->castTo(NULL, type); } } @@ -1813,11 +1922,14 @@ Expression *Ptr(Type *type, Expression *e1) { //printf("Ptr(e1 = %s)\n", e1->toChars()); if (e1->op == TOKadd) - { AddExp *ae = (AddExp *)e1; + { + AddExp *ae = (AddExp *)e1; if (ae->e1->op == TOKaddress && ae->e2->op == TOKint64) - { AddrExp *ade = (AddrExp *)ae->e1; + { + AddrExp *ade = (AddrExp *)ae->e1; if (ade->e1->op == TOKstructliteral) - { StructLiteralExp *se = (StructLiteralExp *)ade->e1; + { + StructLiteralExp *se = (StructLiteralExp *)ade->e1; unsigned offset = (unsigned)ae->e2->toInteger(); Expression *e = se->getField(type, offset); if (!e) diff --git a/dmd2/cppmangle.c b/dmd2/cppmangle.c index c364d05871..bf16ab77a0 100644 --- a/dmd2/cppmangle.c +++ b/dmd2/cppmangle.c @@ -49,6 +49,7 @@ class CppMangleVisitor : public Visitor Objects components; OutBuffer buf; bool is_top_level; + bool components_on; void writeBase36(size_t i) { @@ -67,50 +68,55 @@ class CppMangleVisitor : public Visitor int substitute(RootObject *p) { - for (size_t i = 0; i < components.dim; i++) - { - if (p == components[i]) + //printf("substitute %s\n", p ? p->toChars() : NULL); + if (components_on) + for (size_t i = 0; i < components.dim; i++) { - /* Sequence is S_, S0_, .., S9_, SA_, ..., SZ_, S10_, ... - */ - buf.writeByte('S'); - if (i) - writeBase36(i - 1); - buf.writeByte('_'); - return 1; + if (p == components[i]) + { + /* Sequence is S_, S0_, .., S9_, SA_, ..., SZ_, S10_, ... + */ + buf.writeByte('S'); + if (i) + writeBase36(i - 1); + buf.writeByte('_'); + return 1; + } } - } return 0; } int exist(RootObject *p) { - for (size_t i = 0; i < components.dim; i++) - { - if (p == components[i]) + //printf("exist %s\n", p ? p->toChars() : NULL); + if (components_on) + for (size_t i = 0; i < components.dim; i++) { - return 1; + if (p == components[i]) + { + return 1; + } } - } return 0; } void store(RootObject *p) { - //printf("push %s\n", p ? p->toChars() : NULL); - components.push(p); + //printf("store %s\n", p ? p->toChars() : NULL); + if (components_on) + components.push(p); } - void source_name(Dsymbol *s) + void source_name(Dsymbol *s, bool skipname = false) { - char *name = s->ident->toChars(); + //printf("source_name(%s)\n", s->toChars()); TemplateInstance *ti = s->isTemplateInstance(); if (ti) { - if (!substitute(ti->tempdecl)) + if (!skipname && !substitute(ti->tempdecl)) { store(ti->tempdecl); - name = ti->name->toChars(); + const char *name = ti->toAlias()->ident->toChars(); buf.printf("%d%s", strlen(name), name); } buf.writeByte('I'); @@ -208,8 +214,7 @@ class CppMangleVisitor : public Visitor { if (!substitute(d)) { - cpp_mangle_name(d); - store(d); + cpp_mangle_name(d, false); } } else @@ -234,12 +239,14 @@ class CppMangleVisitor : public Visitor } else { + const char *name = s->ident->toChars(); buf.printf("%d%s", strlen(name), name); } } void prefix_name(Dsymbol *s) { + //printf("prefix_name(%s)\n", s->toChars()); if (!substitute(s)) { store(s); @@ -265,13 +272,32 @@ class CppMangleVisitor : public Visitor } } - void cpp_mangle_name(Dsymbol *s) + /* Is s the initial qualifier? + */ + bool is_initial_qualifier(Dsymbol *s) { Dsymbol *p = s->toParent(); + if (p && p->isTemplateInstance()) + { + if (exist(p->isTemplateInstance()->tempdecl)) + { + return true; + } + p = p->toParent(); + } + + return !p || p->isModule(); + } + + void cpp_mangle_name(Dsymbol *s, bool qualified) + { + //printf("cpp_mangle_name(%s, %d)\n", s->toChars(), qualified); + Dsymbol *p = s->toParent(); + Dsymbol *se = s; bool dont_write_prefix = false; if (p && p->isTemplateInstance()) { - s = p; + se = p; if (exist(p->isTemplateInstance()->tempdecl)) dont_write_prefix = true; p = p->toParent(); @@ -279,14 +305,93 @@ class CppMangleVisitor : public Visitor if (p && !p->isModule()) { - buf.writeByte('N'); - if (!dont_write_prefix) - prefix_name(p); - source_name(s); - buf.writeByte('E'); + /* The N..E is not required if: + * 1. the parent is 'std' + * 2. 'std' is the initial qualifier + * 3. there is no CV-qualifier or a ref-qualifier for a member function + * ABI 5.1.8 + */ + if (p->ident == Id::std && + is_initial_qualifier(p) && + !qualified) + { + if (s->ident == Id::allocator) + { + buf.writestring("Sa"); // "Sa" is short for ::std::allocator + source_name(se, true); + } + else if (s->ident == Id::basic_string) + { + components_on = false; // turn off substitutions + buf.writestring("Sb"); // "Sb" is short for ::std::basic_string + size_t off = buf.offset; + source_name(se, true); + components_on = true; + + // Replace ::std::basic_string < char, ::std::char_traits, ::std::allocator > + // with Ss + //printf("xx: '%.*s'\n", (int)(buf.offset - off), buf.data + off); + if (buf.offset - off >= 26 && + memcmp(buf.data + off, "IcSt11char_traitsIcESaIcEE", 26) == 0) + { + buf.remove(off - 2, 28); + buf.insert(off - 2, "Ss", 2); + return; + } + buf.setsize(off); + source_name(se, true); + } + else if (s->ident == Id::basic_istream || + s->ident == Id::basic_ostream || + s->ident == Id::basic_iostream) + { + /* Replace + * ::std::basic_istream > with Si + * ::std::basic_ostream > with So + * ::std::basic_iostream > with Sd + */ + size_t off = buf.offset; + components_on = false; // turn off substitutions + source_name(se, true); + components_on = true; + + //printf("xx: '%.*s'\n", (int)(buf.offset - off), buf.data + off); + if (buf.offset - off >= 21 && + memcmp(buf.data + off, "IcSt11char_traitsIcEE", 21) == 0) + { + buf.remove(off, 21); + char mbuf[2]; + mbuf[0] = 'S'; + mbuf[1] = 'i'; + if (s->ident == Id::basic_ostream) + mbuf[1] = 'o'; + else if(s->ident == Id::basic_iostream) + mbuf[1] = 'd'; + buf.insert(off, mbuf, 2); + return; + } + buf.setsize(off); + buf.writestring("St"); + source_name(se); + } + else + { + buf.writestring("St"); + source_name(se); + } + } + else + { + buf.writeByte('N'); + if (!dont_write_prefix) + prefix_name(p); + source_name(se); + buf.writeByte('E'); + } } else - source_name(s); + source_name(se); + store(s); } void mangle_variable(VarDeclaration *d, bool is_temp_arg_ref) @@ -324,6 +429,7 @@ class CppMangleVisitor : public Visitor void mangle_function(FuncDeclaration *d) { + //printf("mangle_function(%s)\n", d->toChars()); /* * ::= _Z * ::= @@ -340,6 +446,30 @@ class CppMangleVisitor : public Visitor if (d->type->isConst()) buf.writeByte('K'); prefix_name(p); + + // See ABI 5.1.8 Compression + + // Replace ::std::allocator with Sa + if (buf.offset >= 17 && memcmp(buf.data, "_ZN3std9allocator", 17) == 0) + { + buf.remove(3, 14); + buf.insert(3, "Sa", 2); + } + + // Replace ::std::basic_string with Sb + if (buf.offset >= 21 && memcmp(buf.data, "_ZN3std12basic_string", 21) == 0) + { + buf.remove(3, 18); + buf.insert(3, "Sb", 2); + } + + // Replace ::std with St + if (buf.offset >= 7 && memcmp(buf.data, "_ZN3std", 7) == 0) + { + buf.remove(3, 4); + buf.insert(3, "St", 2); + } + if (d->isDtorDeclaration()) { buf.writestring("D1"); @@ -408,7 +538,7 @@ class CppMangleVisitor : public Visitor public: CppMangleVisitor() - : buf(), components(), is_top_level(false) + : buf(), components(), is_top_level(false), components_on(true) { } @@ -483,14 +613,14 @@ public: case Tint32: c = 'i'; break; case Tuns32: c = 'j'; break; case Tfloat32: c = 'f'; break; - case Tint64: c = (Target::longsize == 8 ? 'l' : 'x'); break; - case Tuns64: c = (Target::longsize == 8 ? 'm' : 'y'); break; + case Tint64: c = (Target::c_longsize == 8 ? 'l' : 'x'); break; + case Tuns64: c = (Target::c_longsize == 8 ? 'm' : 'y'); break; case Tfloat64: c = 'd'; break; case Tfloat80: c = (Target::realsize - Target::realpad == 16) ? 'g' : 'e'; break; case Tbool: c = 'b'; break; case Tchar: c = 'c'; break; - case Twchar: c = 't'; break; - case Tdchar: c = 'w'; break; + case Twchar: c = 't'; break; // unsigned short + case Tdchar: c = 'w'; break; // wchar_t (UTF-32) case Timaginary32: p = 'G'; c = 'f'; break; case Timaginary64: p = 'G'; c = 'd'; break; @@ -639,7 +769,42 @@ public: void visit(TypeStruct *t) { + Identifier *id = t->sym->ident; + //printf("struct id = '%s'\n", id->toChars()); + char c; + if (id == Id::__c_long) + c = 'l'; + else if (id == Id::__c_ulong) + c = 'm'; + else + c = 0; + if (c) + { + if (t->isImmutable() || t->isShared()) + { + visit((Type *)t); + } + if (t->isConst()) + { + if (substitute(t)) + { + return; + } + else + { + store(t); + } + } + + if (t->isConst()) + buf.writeByte('K'); + + buf.writeByte(c); + return; + } + is_top_level = false; + if (substitute(t)) return; if (t->isImmutable() || t->isShared()) { @@ -650,8 +815,7 @@ public: if (!substitute(t->sym)) { - cpp_mangle_name(t->sym); - store(t->sym); + cpp_mangle_name(t->sym, t->isConst()); } if (t->isImmutable() || t->isShared()) @@ -667,13 +831,13 @@ public: { is_top_level = false; if (substitute(t)) return; + if (t->isConst()) buf.writeByte('K'); if (!substitute(t->sym)) { - cpp_mangle_name(t->sym); - store(t->sym); + cpp_mangle_name(t->sym, t->isConst()); } if (t->isImmutable() || t->isShared()) @@ -685,11 +849,6 @@ public: store(t); } - void visit(TypeTypedef *t) - { - visit((Type *)t); - } - void visit(TypeClass *t) { if (substitute(t)) return; @@ -701,12 +860,13 @@ public: buf.writeByte('K'); is_top_level = false; buf.writeByte('P'); + if (t->isConst()) buf.writeByte('K'); + if (!substitute(t->sym)) { - cpp_mangle_name(t->sym); - store(t->sym); + cpp_mangle_name(t->sym, t->isConst()); } if (t->isConst()) store(NULL); @@ -716,6 +876,7 @@ public: char *toCppMangle(Dsymbol *s) { + //printf("toCppMangle(%s)\n", s->toChars()); CppMangleVisitor v; return v.mangleOf(s); } @@ -818,7 +979,7 @@ public: case Tfloat64: buf.writeByte('N'); break; case Tbool: buf.writestring("_N"); break; case Tchar: buf.writeByte('D'); break; - case Twchar: buf.writeByte('G'); break; // unsigned short + case Tdchar: buf.writeByte('I'); break; // unsigned int case Tfloat80: if (flags & IS_DMC) @@ -827,7 +988,7 @@ public: buf.writestring("_T"); // Intel long double break; - case Tdchar: + case Twchar: if (flags & IS_DMC) buf.writestring("_Y"); // DigitalMars wchar_t else @@ -981,14 +1142,44 @@ public: void visit(TypeStruct *type) { - if (checkTypeSaved(type)) return; - //printf("visit(TypeStruct); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE)); - mangleModifier(type); - if (type->sym->isUnionDeclaration()) - buf.writeByte('T'); + Identifier *id = type->sym->ident; + char c; + if (id == Id::__c_long_double) + c = 'O'; // VC++ long double + else if (id == Id::__c_long) + c = 'J'; // VC++ long + else if (id == Id::__c_ulong) + c = 'K'; // VC++ unsigned long else - buf.writeByte('U'); - mangleIdent(type->sym); + c = 0; + + if (c) + { + if (type->isImmutable() || type->isShared()) + { + visit((Type*)type); + return; + } + + if (type->isConst() && ((flags & IS_NOT_TOP_TYPE) || (flags & IS_DMC))) + { + if (checkTypeSaved(type)) return; + } + + mangleModifier(type); + buf.writeByte(c); + } + else + { + if (checkTypeSaved(type)) return; + //printf("visit(TypeStruct); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE)); + mangleModifier(type); + if (type->sym->isUnionDeclaration()) + buf.writeByte('T'); + else + buf.writeByte('U'); + mangleIdent(type->sym); + } flags &= ~IS_NOT_TOP_TYPE; flags &= ~IGNORE_CONST; } @@ -1096,7 +1287,7 @@ private: // Pivate methods always non-virtual in D and it should be mangled as non-virtual in C++ if (d->isVirtual() && d->vtblIndex != -1) { - switch (d->protection) + switch (d->protection.kind) { case PROTprivate: buf.writeByte('E'); @@ -1111,7 +1302,7 @@ private: } else { - switch (d->protection) + switch (d->protection.kind) { case PROTprivate: buf.writeByte('A'); @@ -1137,7 +1328,7 @@ private: } else if (d->isMember2()) // static function { // ::= - switch (d->protection) + switch (d->protection.kind) { case PROTprivate: buf.writeByte('C'); @@ -1179,7 +1370,7 @@ private: } else { - switch (d->protection) + switch (d->protection.kind) { case PROTprivate: buf.writeByte('0'); @@ -1608,8 +1799,14 @@ private: flags &= ~IGNORE_CONST; if (rettype->ty == Tstruct || rettype->ty == Tenum) { - tmp.buf.writeByte('?'); - tmp.buf.writeByte('A'); + Identifier *id = rettype->toDsymbol(NULL)->ident; + if (id != Id::__c_long_double && + id != Id::__c_long && + id != Id::__c_ulong) + { + tmp.buf.writeByte('?'); + tmp.buf.writeByte('A'); + } } tmp.flags |= MANGLE_RETURN_TYPE; rettype->accept(&tmp); @@ -1673,7 +1870,7 @@ private: char *toCppMangle(Dsymbol *s) { - VisualCPPMangler v(!global.params.is64bit); + VisualCPPMangler v(!global.params.mscoff); return v.mangleOf(s); } diff --git a/dmd2/ctfe.h b/dmd2/ctfe.h index 34f39fd221..4de6c91afb 100644 --- a/dmd2/ctfe.h +++ b/dmd2/ctfe.h @@ -96,6 +96,24 @@ public: void accept(Visitor *v) { v->visit(this); } }; +/****************************************************************/ + +// This type is only used by the interpreter. + +class CTFEExp : public Expression +{ +public: + CTFEExp(TOK tok); + + // Handy instances to share + static CTFEExp* voidexp; + static CTFEExp* breakexp; + static CTFEExp* continueexp; + static CTFEExp* gotoexp; +}; + +/****************************************************************/ + /// True if 'e' is EXP_CANT_INTERPRET, or an exception bool exceptionOrCantInterpret(Expression *e); diff --git a/dmd2/ctfeexpr.c b/dmd2/ctfeexpr.c index 531a498d59..4c45d68987 100644 --- a/dmd2/ctfeexpr.c +++ b/dmd2/ctfeexpr.c @@ -141,7 +141,7 @@ char *ThrownExceptionExp::toChars() void ThrownExceptionExp::generateUncaughtError() { Expression *e = (*thrown->value->elements)[0]; - StringExp* se = e->toStringExp(); + StringExp *se = e->toStringExp(); thrown->error("Uncaught CTFE exception %s(%s)", thrown->type->toChars(), se ? se->toChars() : e->toChars()); /* Also give the line where the throw statement was. We won't have it @@ -158,13 +158,31 @@ bool exceptionOrCantInterpret(Expression *e) { assert(EXP_CANT_INTERPRET && "EXP_CANT_INTERPRET must be distinct from " "null, Expression::init not called?"); - if (e == EXP_CANT_INTERPRET) return true; - if (!e || e == EXP_GOTO_INTERPRET || e == EXP_VOID_INTERPRET - || e == EXP_BREAK_INTERPRET || e == EXP_CONTINUE_INTERPRET) + if (e == EXP_CANT_INTERPRET) + return true; + if (!e || + e->op == TOKgoto || + e->op == TOKbreak || + e->op == TOKcontinue) + { return false; + } return e->op == TOKthrownexception; } +/********************** CTFEExp ******************************************/ + +CTFEExp *CTFEExp::voidexp; +CTFEExp *CTFEExp::breakexp; +CTFEExp *CTFEExp::continueexp; +CTFEExp *CTFEExp::gotoexp; + +CTFEExp::CTFEExp(TOK tok) + : Expression(Loc(), tok, sizeof(CTFEExp)) +{ + type = Type::tvoid; +} + /************** Aggregate literals (AA/string/array/struct) ******************/ // Given expr, which evaluates to an array/AA/string literal, @@ -234,7 +252,7 @@ Expression *copyLiteral(Expression *e) se2->ownedByCtfe = true; return se2; } - else if (e->op == TOKarrayliteral) + if (e->op == TOKarrayliteral) { ArrayLiteralExp *ae = (ArrayLiteralExp *)e; ArrayLiteralExp *r = new ArrayLiteralExp(e->loc, @@ -243,7 +261,7 @@ Expression *copyLiteral(Expression *e) r->ownedByCtfe = true; return r; } - else if (e->op == TOKassocarrayliteral) + if (e->op == TOKassocarrayliteral) { AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)e; AssocArrayLiteralExp *r = new AssocArrayLiteralExp(e->loc, @@ -252,7 +270,7 @@ Expression *copyLiteral(Expression *e) r->ownedByCtfe = true; return r; } - else if (e->op == TOKstructliteral) + if (e->op == TOKstructliteral) { /* syntaxCopy doesn't work for struct literals, because of a nasty special * case: block assignment is permitted inside struct literals, eg, @@ -285,22 +303,22 @@ Expression *copyLiteral(Expression *e) StructLiteralExp *r = new StructLiteralExp(e->loc, se->sd, newelems, se->stype); r->type = e->type; r->ownedByCtfe = true; - r->origin = ((StructLiteralExp*)e)->origin; + r->origin = ((StructLiteralExp *)e)->origin; return r; } - else if (e->op == TOKfunction || e->op == TOKdelegate - || e->op == TOKsymoff || e->op == TOKnull - || e->op == TOKvar || e->op == TOKdotvar - || e->op == TOKint64 || e->op == TOKfloat64 - || e->op == TOKchar || e->op == TOKcomplex80 - || e->op == TOKvoid || e->op == TOKvector) + if (e->op == TOKfunction || e->op == TOKdelegate || + e->op == TOKsymoff || e->op == TOKnull || + e->op == TOKvar || e->op == TOKdotvar || + e->op == TOKint64 || e->op == TOKfloat64 || + e->op == TOKchar || e->op == TOKcomplex80 || + e->op == TOKvoid || e->op == TOKvector) { // Simple value types Expression *r = e->copy(); // keep e1 for DelegateExp and DotVarExp r->type = e->type; return r; } - else if (isPointer(e->type)) + if (isPointer(e->type)) { // For pointers, we only do a shallow copy. Expression *r; @@ -318,7 +336,7 @@ Expression *copyLiteral(Expression *e) r->type = e->type; return r; } - else if (e->op == TOKslice) + if (e->op == TOKslice) { // Array slices only do a shallow copy Expression *r = new SliceExp(e->loc, ((SliceExp *)e)->e1, @@ -326,16 +344,14 @@ Expression *copyLiteral(Expression *e) r->type = e->type; return r; } - else if (e->op == TOKclassreference) + if (e->op == TOKclassreference) return new ClassReferenceExp(e->loc, ((ClassReferenceExp *)e)->value, e->type); - else if (e->op == TOKerror) + if (e->op == TOKerror) return e; - else - { - e->error("Internal Compiler Error: CTFE literal %s", e->toChars()); - assert(0); - return e; - } + + e->error("Internal Compiler Error: CTFE literal %s", e->toChars()); + assert(0); + return e; } /* Deal with type painting. @@ -393,7 +409,7 @@ Expression *paintTypeOntoLiteral(Type *type, Expression *lit) { // Can't type paint from struct to struct*; this needs another // level of indirection - if (lit->op == TOKstructliteral && isPointer(type) ) + if (lit->op == TOKstructliteral && isPointer(type)) lit->error("CTFE internal error painting %s", type->toChars()); e = copyLiteral(lit); } @@ -403,10 +419,11 @@ Expression *paintTypeOntoLiteral(Type *type, Expression *lit) Expression *resolveSlice(Expression *e) { - if ( ((SliceExp *)e)->e1->op == TOKnull) - return ((SliceExp *)e)->e1; - return Slice(e->type, ((SliceExp *)e)->e1, - ((SliceExp *)e)->lwr, ((SliceExp *)e)->upr); + assert(e->op == TOKslice); + SliceExp *se = (SliceExp *)e; + if (se->e1->op == TOKnull) + return se->e1; + return Slice(e->type, se->e1, se->lwr, se->upr); } /* Determine the array length, without interpreting it. @@ -419,19 +436,23 @@ uinteger_t resolveArrayLength(Expression *e) if (e->op == TOKnull) return 0; if (e->op == TOKslice) - { uinteger_t ilo = ((SliceExp *)e)->lwr->toInteger(); + { + uinteger_t ilo = ((SliceExp *)e)->lwr->toInteger(); uinteger_t iup = ((SliceExp *)e)->upr->toInteger(); return iup - ilo; } if (e->op == TOKstring) - { return ((StringExp *)e)->len; + { + return ((StringExp *)e)->len; } if (e->op == TOKarrayliteral) - { ArrayLiteralExp *ale = (ArrayLiteralExp *)e; + { + ArrayLiteralExp *ale = (ArrayLiteralExp *)e; return ale->elements ? ale->elements->dim : 0; } if (e->op == TOKassocarrayliteral) - { AssocArrayLiteralExp *ale = (AssocArrayLiteralExp *)e; + { + AssocArrayLiteralExp *ale = (AssocArrayLiteralExp *)e; return ale->keys->dim; } assert(0); @@ -456,7 +477,8 @@ ArrayLiteralExp *createBlockDuplicatedArrayLiteral(Loc loc, Type *type, } bool mustCopy = needToCopyLiteral(elem); for (size_t i = 0; i < dim; i++) - { if (mustCopy) + { + if (mustCopy) elem = copyLiteral(elem); (*elements)[i] = elem; } @@ -517,8 +539,8 @@ TypeAArray *toBuiltinAAType(Type *t) bool isTypeInfo_Class(Type *type) { return type->ty == Tclass && - (( Type::dtypeinfo == ((TypeClass*)type)->sym) - || Type::dtypeinfo->isBaseOf(((TypeClass*)type)->sym, NULL)); + (Type::dtypeinfo == ((TypeClass *)type)->sym || + Type::dtypeinfo->isBaseOf(((TypeClass *)type)->sym, NULL)); } /************** Pointer operations ************************************/ @@ -533,8 +555,8 @@ bool isPointer(Type *t) // For CTFE only. Returns true if 'e' is true or a non-null pointer. int isTrueBool(Expression *e) { - return e->isBool(true) || ((e->type->ty == Tpointer || e->type->ty == Tclass) - && e->op != TOKnull); + return e->isBool(true) || + ((e->type->ty == Tpointer || e->type->ty == Tclass) && e->op != TOKnull); } /* Is it safe to convert from srcPointee* to destPointee* ? @@ -599,8 +621,8 @@ Expression *getAggregateFromPointer(Expression *e, dinteger_t *ofs) { IndexExp *ie = (IndexExp *)e; // Note that each AA element is part of its own memory block - if ((ie->e1->type->ty == Tarray || ie->e1->type->ty == Tsarray - || ie->e1->op == TOKstring || ie->e1->op==TOKarrayliteral) && + if ((ie->e1->type->ty == Tarray || ie->e1->type->ty == Tsarray || + ie->e1->op == TOKstring || ie->e1->op==TOKarrayliteral) && ie->e2->op == TOKint64) { *ofs = ie->e2->toInteger(); @@ -614,19 +636,31 @@ Expression *getAggregateFromPointer(Expression *e, dinteger_t *ofs) */ bool pointToSameMemoryBlock(Expression *agg1, Expression *agg2) { + if (agg1 == agg2) + return true; + // For integers cast to pointers, we regard them as non-comparable // unless they are identical. (This may be overly strict). - if (agg1->op == TOKint64 && agg2->op == TOKint64 - && agg1->toInteger() == agg2->toInteger()) + if (agg1->op == TOKint64 && agg2->op == TOKint64 && + agg1->toInteger() == agg2->toInteger()) + { return true; + } // Note that type painting can occur with VarExp, so we // must compare the variables being pointed to. - return agg1 == agg2 || - (agg1->op == TOKvar && agg2->op == TOKvar && - ((VarExp *)agg1)->var == ((VarExp *)agg2)->var) || - (agg1->op == TOKsymoff && agg2->op == TOKsymoff && - ((SymOffExp *)agg1)->var == ((SymOffExp *)agg2)->var); + if (agg1->op == TOKvar && agg2->op == TOKvar && + ((VarExp *)agg1)->var == ((VarExp *)agg2)->var) + { + return true; + } + if (agg1->op == TOKsymoff && agg2->op == TOKsymoff && + ((SymOffExp *)agg1)->var == ((SymOffExp *)agg2)->var) + { + return true; + } + + return false; } // return e1 - e2 as an integer, or error if not possible @@ -639,21 +673,21 @@ Expression *pointerDifference(Loc loc, Type *type, Expression *e1, Expression *e { Type *pointee = ((TypePointer *)agg1->type)->next; dinteger_t sz = pointee->size(); - return new IntegerExp(loc, (ofs1-ofs2)*sz, type); + return new IntegerExp(loc, (ofs1 - ofs2) * sz, type); } - else if (agg1->op == TOKstring && agg2->op == TOKstring) + if (agg1->op == TOKstring && agg2->op == TOKstring) { if (((StringExp *)agg1)->string == ((StringExp *)agg2)->string) { Type *pointee = ((TypePointer *)agg1->type)->next; dinteger_t sz = pointee->size(); - return new IntegerExp(loc, (ofs1-ofs2)*sz, type); + return new IntegerExp(loc, (ofs1 - ofs2) * sz, type); } } else if (agg1->op == TOKsymoff && agg2->op == TOKsymoff && - ((SymOffExp *)agg1)->var == ((SymOffExp *)agg2)->var) + ((SymOffExp *)agg1)->var == ((SymOffExp *)agg2)->var) { - return new IntegerExp(loc, ofs1-ofs2, type); + return new IntegerExp(loc, ofs1 - ofs2, type); } error(loc, "%s - %s cannot be interpreted at compile time: cannot subtract " "pointers to two different memory blocks", @@ -746,10 +780,10 @@ Expression *pointerArithmetic(Loc loc, TOK op, Type *type, int comparePointers(Loc loc, TOK op, Type *type, Expression *agg1, dinteger_t ofs1, Expression *agg2, dinteger_t ofs2) { - if ( pointToSameMemoryBlock(agg1, agg2) ) + if (pointToSameMemoryBlock(agg1, agg2)) { int n; - switch(op) + switch (op) { case TOKlt: n = (ofs1 < ofs2); break; case TOKle: n = (ofs1 <= ofs2); break; @@ -764,18 +798,18 @@ int comparePointers(Loc loc, TOK op, Type *type, Expression *agg1, dinteger_t of } return n; } - bool null1 = ( agg1->op == TOKnull ); - bool null2 = ( agg2->op == TOKnull ); + bool null1 = (agg1->op == TOKnull); + bool null2 = (agg2->op == TOKnull); int cmp; if (null1 || null2) { switch (op) { - case TOKlt: cmp = null1 && !null2; break; - case TOKgt: cmp = !null1 && null2; break; - case TOKle: cmp = null1; break; - case TOKge: cmp = null2; break; + case TOKlt: cmp = null1 && !null2; break; + case TOKgt: cmp = !null1 && null2; break; + case TOKle: cmp = null1; break; + case TOKge: cmp = null2; break; case TOKidentity: case TOKequal: case TOKnotidentity: // 'cmp' gets inverted below @@ -788,7 +822,7 @@ int comparePointers(Loc loc, TOK op, Type *type, Expression *agg1, dinteger_t of } else { - switch(op) + switch (op) { case TOKidentity: case TOKequal: @@ -809,9 +843,9 @@ int comparePointers(Loc loc, TOK op, Type *type, Expression *agg1, dinteger_t of // floating point -> integer or integer -> floating point bool isFloatIntPaint(Type *to, Type *from) { - return (from->size() == to->size()) && - ( (from->isintegral() && to->isfloating()) - || (from->isfloating() && to->isintegral()) ); + return from->size() == to->size() && + (from->isintegral() && to->isfloating() || + from->isfloating() && to->isintegral()); } // Reinterpret float/int value 'fromVal' as a float/integer of type 'to'. @@ -873,151 +907,158 @@ void intBinary(TOK op, IntegerExp *dest, Type *type, IntegerExp *e1, IntegerExp result = e1->getInteger() * e2->getInteger(); break; case TOKdiv: + { + sinteger_t n1 = e1->getInteger(); + sinteger_t n2 = e2->getInteger(); + + if (n2 == 0) { - sinteger_t n1 = e1->getInteger(); - sinteger_t n2 = e2->getInteger(); - - if (n2 == 0) - { e2->error("divide by 0"); - result = 1; - } - else if (e1->type->isunsigned() || e2->type->isunsigned()) - result = ((d_uns64) n1) / ((d_uns64) n2); - else - result = n1 / n2; + e2->error("divide by 0"); + result = 1; } + else if (e1->type->isunsigned() || e2->type->isunsigned()) + result = ((d_uns64) n1) / ((d_uns64) n2); + else + result = n1 / n2; break; + } case TOKmod: - { sinteger_t n1 = e1->getInteger(); - sinteger_t n2 = e2->getInteger(); + { + sinteger_t n1 = e1->getInteger(); + sinteger_t n2 = e2->getInteger(); - if (n2 == 0) - { e2->error("divide by 0"); + if (n2 == 0) + { + e2->error("divide by 0"); + n2 = 1; + } + if (n2 == -1 && !type->isunsigned()) + { + // Check for int.min % -1 + if (n1 == 0xFFFFFFFF80000000ULL && type->toBasetype()->ty != Tint64) + { + e2->error("integer overflow: int.min % -1"); n2 = 1; } - if (n2 == -1 && !type->isunsigned()) - { // Check for int.min % -1 - if (n1 == 0xFFFFFFFF80000000ULL && type->toBasetype()->ty != Tint64) - { - e2->error("integer overflow: int.min % -1"); - n2 = 1; - } - else if (n1 == 0x8000000000000000LL) // long.min % -1 - { - e2->error("integer overflow: long.min % -1"); - n2 = 1; - } + else if (n1 == 0x8000000000000000LL) // long.min % -1 + { + e2->error("integer overflow: long.min % -1"); + n2 = 1; } - if (e1->type->isunsigned() || e2->type->isunsigned()) - result = ((d_uns64) n1) % ((d_uns64) n2); - else - result = n1 % n2; } + if (e1->type->isunsigned() || e2->type->isunsigned()) + result = ((d_uns64) n1) % ((d_uns64) n2); + else + result = n1 % n2; break; + } case TOKpow: - { dinteger_t n = e2->getInteger(); - if (!e2->type->isunsigned() && (sinteger_t)n < 0) - { - e2->error("integer ^^ -integer: total loss of precision"); - n = 1; - } - uinteger_t r = e1->getInteger(); - result = 1; - while (n != 0) - { - if (n & 1) - result = result * r; - n >>= 1; - r = r * r; - } + { + dinteger_t n = e2->getInteger(); + if (!e2->type->isunsigned() && (sinteger_t)n < 0) + { + e2->error("integer ^^ -integer: total loss of precision"); + n = 1; + } + uinteger_t r = e1->getInteger(); + result = 1; + while (n != 0) + { + if (n & 1) + result = result * r; + n >>= 1; + r = r * r; } break; + } case TOKshl: result = e1->getInteger() << e2->getInteger(); break; case TOKshr: - { dinteger_t value = e1->getInteger(); - dinteger_t dcount = e2->getInteger(); - assert(dcount <= 0xFFFFFFFF); - unsigned count = (unsigned)dcount; - switch (e1->type->toBasetype()->ty) - { - case Tint8: - result = (d_int8)(value) >> count; - break; + { + dinteger_t value = e1->getInteger(); + dinteger_t dcount = e2->getInteger(); + assert(dcount <= 0xFFFFFFFF); + unsigned count = (unsigned)dcount; + switch (e1->type->toBasetype()->ty) + { + case Tint8: + result = (d_int8)(value) >> count; + break; - case Tuns8: - case Tchar: - result = (d_uns8)(value) >> count; - break; + case Tuns8: + case Tchar: + result = (d_uns8)(value) >> count; + break; - case Tint16: - result = (d_int16)(value) >> count; - break; + case Tint16: + result = (d_int16)(value) >> count; + break; - case Tuns16: - case Twchar: - result = (d_uns16)(value) >> count; - break; + case Tuns16: + case Twchar: + result = (d_uns16)(value) >> count; + break; - case Tint32: - result = (d_int32)(value) >> count; - break; + case Tint32: + result = (d_int32)(value) >> count; + break; - case Tuns32: - case Tdchar: - result = (d_uns32)(value) >> count; - break; + case Tuns32: + case Tdchar: + result = (d_uns32)(value) >> count; + break; - case Tint64: - result = (d_int64)(value) >> count; - break; + case Tint64: + result = (d_int64)(value) >> count; + break; - case Tuns64: - result = (d_uns64)(value) >> count; - break; - default: - assert(0); - } + case Tuns64: + result = (d_uns64)(value) >> count; + break; + default: + assert(0); } break; + } case TOKushr: - { dinteger_t value = e1->getInteger(); - dinteger_t dcount = e2->getInteger(); - assert(dcount <= 0xFFFFFFFF); - unsigned count = (unsigned)dcount; - switch (e1->type->toBasetype()->ty) - { - case Tint8: - case Tuns8: - case Tchar: - // Possible only with >>>=. >>> always gets promoted to int. - result = (value & 0xFF) >> count; - break; + { + dinteger_t value = e1->getInteger(); + dinteger_t dcount = e2->getInteger(); + assert(dcount <= 0xFFFFFFFF); + unsigned count = (unsigned)dcount; + switch (e1->type->toBasetype()->ty) + { + case Tint8: + case Tuns8: + case Tchar: + // Possible only with >>>=. >>> always gets promoted to int. + result = (value & 0xFF) >> count; + break; - case Tint16: - case Tuns16: - case Twchar: - // Possible only with >>>=. >>> always gets promoted to int. - result = (value & 0xFFFF) >> count; - break; + case Tint16: + case Tuns16: + case Twchar: + // Possible only with >>>=. >>> always gets promoted to int. + result = (value & 0xFFFF) >> count; + break; - case Tint32: - case Tuns32: - case Tdchar: - result = (value & 0xFFFFFFFF) >> count; - break; + case Tint32: + case Tuns32: + case Tdchar: + result = (value & 0xFFFFFFFF) >> count; + break; - case Tint64: - case Tuns64: - result = (d_uns64)(value) >> count; - break; + case Tint64: + case Tuns64: + result = (d_uns64)(value) >> count; + break; - default: - assert(0); - } + default: + assert(0); } break; + } case TOKequal: case TOKidentity: result = (e1->getInteger() == e2->getInteger()); @@ -1179,16 +1220,18 @@ int ctfeCmpArrays(Loc loc, Expression *e1, Expression *e2, uinteger_t len) Expression *x = e1; if (x->op == TOKslice) - { lo1 = ((SliceExp *)x)->lwr->toInteger(); - x = ((SliceExp*)x)->e1; + { + lo1 = ((SliceExp *)x)->lwr->toInteger(); + x = ((SliceExp *)x)->e1; } StringExp *se1 = (x->op == TOKstring) ? (StringExp *)x : NULL; ArrayLiteralExp *ae1 = (x->op == TOKarrayliteral) ? (ArrayLiteralExp *)x : NULL; x = e2; if (x->op == TOKslice) - { lo2 = ((SliceExp *)x)->lwr->toInteger(); - x = ((SliceExp*)x)->e1; + { + lo2 = ((SliceExp *)x)->lwr->toInteger(); + x = ((SliceExp *)x)->e1; } StringExp *se2 = (x->op == TOKstring) ? (StringExp *)x : NULL; ArrayLiteralExp *ae2 = (x->op == TOKarrayliteral) ? (ArrayLiteralExp *)x : NULL; @@ -1207,17 +1250,20 @@ int ctfeCmpArrays(Loc loc, Expression *e1, Expression *e2, uinteger_t len) // a full cmp. bool needCmp = ae1->type->nextOf()->isintegral(); for (size_t i = 0; i < len; i++) - { Expression *ee1 = (*ae1->elements)[(size_t)(lo1 + i)]; + { + Expression *ee1 = (*ae1->elements)[(size_t)(lo1 + i)]; Expression *ee2 = (*ae2->elements)[(size_t)(lo2 + i)]; if (needCmp) - { sinteger_t c = ee1->toInteger() - ee2->toInteger(); + { + sinteger_t c = ee1->toInteger() - ee2->toInteger(); if (c > 0) return 1; if (c < 0) return -1; } else - { if (ctfeRawCmp(loc, ee1, ee2)) + { + if (ctfeRawCmp(loc, ee1, ee2)) return 1; } } @@ -1251,7 +1297,8 @@ bool isArray(Expression *e) int ctfeRawCmp(Loc loc, Expression *e1, Expression *e2) { if (e1->op == TOKclassreference || e2->op == TOKclassreference) - { if (e1->op == TOKclassreference && e2->op == TOKclassreference && + { + if (e1->op == TOKclassreference && e2->op == TOKclassreference && ((ClassReferenceExp *)e1)->value == ((ClassReferenceExp *)e2)->value) return 0; return 1; @@ -1271,7 +1318,8 @@ int ctfeRawCmp(Loc loc, Expression *e1, Expression *e2) Expression *agg2 = getAggregateFromPointer(e2, &ofs2); if ((agg1 == agg2) || (agg1->op == TOKvar && agg2->op == TOKvar && ((VarExp *)agg1)->var == ((VarExp *)agg2)->var)) - { if (ofs1 == ofs2) + { + if (ofs1 == ofs2) return 0; } return 1; @@ -1311,8 +1359,8 @@ int ctfeRawCmp(Loc loc, Expression *e1, Expression *e2) uinteger_t len2 = resolveArrayLength(e2); // workaround for dmc optimizer bug calculating wrong len for // uinteger_t len = (len1 < len2 ? len1 : len2); - // if(len == 0) ... - if(len1 > 0 && len2 > 0) + // if (len == 0) ... + if (len1 > 0 && len2 > 0) { uinteger_t len = (len1 < len2 ? len1 : len2); int res = ctfeCmpArrays(loc, e1, e2, len); @@ -1353,7 +1401,8 @@ int ctfeRawCmp(Loc loc, Expression *e1, Expression *e2) } if (e1->op == TOKstructliteral && e2->op == TOKstructliteral) - { StructLiteralExp *es1 = (StructLiteralExp *)e1; + { + StructLiteralExp *es1 = (StructLiteralExp *)e1; StructLiteralExp *es2 = (StructLiteralExp *)e2; // For structs, we only need to return 0 or 1 (< and > aren't legal). @@ -1369,7 +1418,8 @@ int ctfeRawCmp(Loc loc, Expression *e1, Expression *e2) else { for (size_t i = 0; i < es1->elements->dim; i++) - { Expression *ee1 = (*es1->elements)[i]; + { + Expression *ee1 = (*es1->elements)[i]; Expression *ee2 = (*es2->elements)[i]; if (ee1 == ee2) @@ -1459,7 +1509,8 @@ int ctfeIdentity(Loc loc, TOK op, Expression *e1, Expression *e2) else if (e1->type->isimaginary()) cmp = RealEquals(e1->toImaginary(), e2->toImaginary()); else if (e1->type->iscomplex()) - { complex_t v1 = e1->toComplex(); + { + complex_t v1 = e1->toComplex(); complex_t v2 = e2->toComplex(); cmp = RealEquals(creall(v1), creall(v2)) && RealEquals(cimagl(v1), cimagl(v1)); @@ -1567,7 +1618,7 @@ Expression *ctfeCat(Type *type, Expression *e1, Expression *e2) e = es; return e; } - else if (e1->op == TOKstring && e2->op == TOKarrayliteral && + if (e1->op == TOKstring && e2->op == TOKarrayliteral && t2->nextOf()->isintegral()) { // string ~ [chars] => string (only valid for CTFE) @@ -1607,7 +1658,7 @@ Expression *ctfeCat(Type *type, Expression *e1, Expression *e2) e = es; return e; } - else if (e1->op == TOKarrayliteral && e2->op == TOKarrayliteral && + if (e1->op == TOKarrayliteral && e2->op == TOKarrayliteral && t1->nextOf()->equals(t2->nextOf())) { // [ e1 ] ~ [ e2 ] ---> [ e1, e2 ] @@ -1620,13 +1671,13 @@ Expression *ctfeCat(Type *type, Expression *e1, Expression *e2) e->type = type; return e; } - else if (e1->op == TOKarrayliteral && e2->op == TOKnull && + if (e1->op == TOKarrayliteral && e2->op == TOKnull && t1->nextOf()->equals(t2->nextOf())) { // [ e1 ] ~ null ----> [ e1 ].dup return paintTypeOntoLiteral(type, copyLiteral(e1)); } - else if (e1->op == TOKnull && e2->op == TOKarrayliteral && + if (e1->op == TOKnull && e2->op == TOKarrayliteral && t1->nextOf()->equals(t2->nextOf())) { // null ~ [ e2 ] ----> [ e2 ].dup @@ -1789,8 +1840,9 @@ void recursiveBlockAssign(ArrayLiteralExp *ae, Expression *val, bool wantRef) Type *desttype = ((TypeArray *)ae->type)->next->toBasetype()->castMod(0); bool directblk = (val->type->toBasetype()->castMod(0))->equals(desttype); - bool cow = !(val->op == TOKstructliteral || val->op == TOKarrayliteral - || val->op == TOKstring); + bool cow = val->op != TOKstructliteral && + val->op != TOKarrayliteral && + val->op != TOKstring; for (size_t k = 0; k < ae->elements->dim; k++) { @@ -1849,7 +1901,8 @@ Expression *assignAssocArrayElement(Loc loc, AssocArrayLiteralExp *aae, Expressions *valuesx = aae->values; int updated = 0; for (size_t j = valuesx->dim; j; ) - { j--; + { + j--; Expression *ekey = (*aae->keys)[j]; int eq = ctfeEqual(loc, TOKequal, ekey, index); if (eq) @@ -1859,7 +1912,8 @@ Expression *assignAssocArrayElement(Loc loc, AssocArrayLiteralExp *aae, } } if (!updated) - { // Append index/newval to keysx[]/valuesx[] + { + // Append index/newval to keysx[]/valuesx[] valuesx->push(newval); keysx->push(index); } @@ -1881,7 +1935,8 @@ Expression *changeArrayLiteralLength(Loc loc, TypeArray *arrayType, // Resolve slices size_t indxlo = 0; if (oldval->op == TOKslice) - { indxlo = (size_t)((SliceExp *)oldval)->lwr->toInteger(); + { + indxlo = (size_t)((SliceExp *)oldval)->lwr->toInteger(); oldval = ((SliceExp *)oldval)->e1; } size_t copylen = oldlen < newlen ? oldlen : newlen; @@ -1916,7 +1971,8 @@ Expression *changeArrayLiteralLength(Loc loc, TypeArray *arrayType, for (size_t i = 0; i < copylen; i++) (*elements)[i] = (*ae->elements)[indxlo + i]; if (elemType->ty == Tstruct || elemType->ty == Tsarray) - { /* If it is an aggregate literal representing a value type, + { + /* If it is an aggregate literal representing a value type, * we need to create a unique copy for each element */ for (size_t i = copylen; i < newlen; i++) @@ -2029,17 +2085,19 @@ bool isCtfeValueValid(Expression *newval) if (newval->op == TOKassocarrayliteral) assert(((AssocArrayLiteralExp *)newval)->ownedByCtfe); - if ((newval->op ==TOKarrayliteral) || ( newval->op==TOKstructliteral) || - (newval->op==TOKstring) || (newval->op == TOKassocarrayliteral) || - (newval->op == TOKnull)) - { return true; + if (newval->op == TOKarrayliteral || newval->op == TOKstructliteral || + newval->op == TOKstring || newval->op == TOKassocarrayliteral || + newval->op == TOKnull) + { + return true; } // Dynamic arrays passed by ref may be null. When this happens // they may originate from an index or dotvar expression. if (newval->type->ty == Tarray || newval->type->ty == Taarray) + { if (newval->op == TOKdotvar || newval->op == TOKindex) return true; // actually must be null - + } if (newval->op == TOKslice) { SliceExp *se = (SliceExp *)newval; @@ -2065,13 +2123,15 @@ void showCtfeExpr(Expression *e, int level) StructDeclaration *sd = NULL; ClassDeclaration *cd = NULL; if (e->op == TOKstructliteral) - { elements = ((StructLiteralExp *)e)->elements; + { + elements = ((StructLiteralExp *)e)->elements; sd = ((StructLiteralExp *)e)->sd; printf("STRUCT type = %s %p:\n", e->type->toChars(), e); } else if (e->op == TOKclassreference) - { elements = ((ClassReferenceExp *)e)->value->elements; + { + elements = ((ClassReferenceExp *)e)->value->elements; cd = ((ClassReferenceExp *)e)->originalClass(); printf("CLASS type = %s %p:\n", e->type->toChars(), ((ClassReferenceExp *)e)->value); @@ -2121,9 +2181,11 @@ void showCtfeExpr(Expression *e, int level) { size_t fieldsSoFar = 0; for (size_t i = 0; i < elements->dim; i++) - { Expression *z = NULL; + { + Expression *z = NULL; VarDeclaration *v = NULL; - if (i > 15) { + if (i > 15) + { printf("...(total %d elements)\n", (int)elements->dim); return; } @@ -2196,7 +2258,7 @@ Expression *voidInitLiteral(Type *t, VarDeclaration *var) ae->ownedByCtfe = true; return ae; } - else if (t->ty == Tstruct) + if (t->ty == Tstruct) { TypeStruct *ts = (TypeStruct *)t; Expressions *exps = new Expressions(); @@ -2210,8 +2272,5 @@ Expression *voidInitLiteral(Type *t, VarDeclaration *var) se->ownedByCtfe = true; return se; } - else - { - return new VoidInitExp(var, t); - } + return new VoidInitExp(var, t); } diff --git a/dmd2/declaration.c b/dmd2/declaration.c index b063d6ce4d..52f8794b72 100644 --- a/dmd2/declaration.c +++ b/dmd2/declaration.c @@ -24,7 +24,6 @@ #include "id.h" #include "expression.h" #include "statement.h" -#include "hdrgen.h" #include "ctfe.h" #include "target.h" @@ -85,7 +84,7 @@ Declaration::Declaration(Identifier *id) type = NULL; originalType = NULL; storage_class = STCundefined; - protection = PROTundefined; + protection = Prot(PROTundefined); linkage = LINKdefault; inuse = 0; sem = SemanticStart; @@ -127,7 +126,7 @@ bool Declaration::isCodeseg() return false; } -PROT Declaration::prot() +Prot Declaration::prot() { return protection; } @@ -296,146 +295,6 @@ void TupleDeclaration::semantic3(Scope *sc) #endif -/********************************* TypedefDeclaration ****************************/ - -TypedefDeclaration::TypedefDeclaration(Loc loc, Identifier *id, Type *basetype, Initializer *init) - : Declaration(id) -{ - this->type = new TypeTypedef(this); - this->basetype = basetype->toBasetype(); - this->init = init; - this->htype = NULL; - this->hbasetype = NULL; - this->loc = loc; -#if IN_DMD - this->sinit = NULL; -#endif -} - -Dsymbol *TypedefDeclaration::syntaxCopy(Dsymbol *s) -{ - Type *basetype = this->basetype->syntaxCopy(); - - Initializer *init = NULL; - if (this->init) - init = this->init->syntaxCopy(); - - assert(!s); - TypedefDeclaration *st; - st = new TypedefDeclaration(loc, ident, basetype, init); - - // Syntax copy for header file - if (!htype) // Don't overwrite original - { if (type) // Make copy for both old and new instances - { htype = type->syntaxCopy(); - st->htype = type->syntaxCopy(); - } - } - else // Make copy of original for new instance - st->htype = htype->syntaxCopy(); - if (!hbasetype) - { if (basetype) - { hbasetype = basetype->syntaxCopy(); - st->hbasetype = basetype->syntaxCopy(); - } - } - else - st->hbasetype = hbasetype->syntaxCopy(); - - return st; -} - -void TypedefDeclaration::semantic(Scope *sc) -{ - //printf("TypedefDeclaration::semantic(%s) sem = %d\n", toChars(), sem); - if (sem == SemanticStart) - { - sem = SemanticIn; - parent = sc->parent; - unsigned int errors = global.errors; - Type *savedbasetype = basetype; - basetype = basetype->semantic(loc, sc); - if (errors != global.errors) - { - basetype = savedbasetype; - sem = SemanticStart; - return; - } - sem = SemanticDone; - type = type->addStorageClass(storage_class); - Type *savedtype = type; - type = type->semantic(loc, sc); - if (sc->parent->isFuncDeclaration() && init) - semantic2(sc); - if (errors != global.errors) - { - basetype = savedbasetype; - type = savedtype; - sem = SemanticStart; - return; - } - storage_class |= sc->stc & STCdeprecated; - userAttribDecl = sc->userAttribDecl; - } - else if (sem == SemanticIn) - { - error("circular definition"); - basetype = Type::terror; - errors = true; - } -} - -void TypedefDeclaration::semantic2(Scope *sc) -{ - //printf("TypedefDeclaration::semantic2(%s) sem = %d\n", toChars(), sem); - if (sem == SemanticDone) - { - sem = Semantic2Done; - basetype->alignment(); // used to detect circular typedef declarations - if (init) - { - Initializer *savedinit = init; - unsigned int errors = global.errors; - init = init->semantic(sc, basetype, INITinterpret); - if (errors != global.errors || init->isErrorInitializer()) - { - init = savedinit; - return; - } - - ExpInitializer *ie = init->isExpInitializer(); - if (ie) - { - if (ie->exp->type == basetype) - ie->exp->type = type; - } - } - } -} - -const char *TypedefDeclaration::kind() -{ - return "typedef"; -} - -Type *TypedefDeclaration::getType() -{ - return type; -} - -void TypedefDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("typedef "); - basetype->toCBuffer(buf, ident, hgs); - if (init) - { - buf->writestring(" = "); - init->toCBuffer(buf, hgs); - } - buf->writeByte(';'); - buf->writenl(); -} - /********************************* AliasDeclaration ****************************/ AliasDeclaration::AliasDeclaration(Loc loc, Identifier *id, Type *type) @@ -447,8 +306,6 @@ AliasDeclaration::AliasDeclaration(Loc loc, Identifier *id, Type *type) this->type = type; this->aliassym = NULL; this->import = NULL; - this->htype = NULL; - this->haliassym = NULL; this->overnext = NULL; this->inSemantic = 0; assert(type); @@ -463,8 +320,6 @@ AliasDeclaration::AliasDeclaration(Loc loc, Identifier *id, Dsymbol *s) this->type = NULL; this->aliassym = s; this->import = NULL; - this->htype = NULL; - this->haliassym = NULL; this->overnext = NULL; this->inSemantic = 0; assert(s); @@ -474,31 +329,10 @@ Dsymbol *AliasDeclaration::syntaxCopy(Dsymbol *s) { //printf("AliasDeclaration::syntaxCopy()\n"); assert(!s); - AliasDeclaration *sa; - if (type) - sa = new AliasDeclaration(loc, ident, type->syntaxCopy()); - else - sa = new AliasDeclaration(loc, ident, aliassym->syntaxCopy(NULL)); + AliasDeclaration *sa = + type ? new AliasDeclaration(loc, ident, type->syntaxCopy()) + : new AliasDeclaration(loc, ident, aliassym->syntaxCopy(NULL)); sa->storage_class = storage_class; - - // Syntax copy for header file - if (!htype) // Don't overwrite original - { if (type) // Make copy for both old and new instances - { htype = type->syntaxCopy(); - sa->htype = type->syntaxCopy(); - } - } - else // Make copy of original for new instance - sa->htype = htype->syntaxCopy(); - if (!haliassym) - { if (aliassym) - { haliassym = aliassym->syntaxCopy(s); - sa->haliassym = aliassym->syntaxCopy(s); - } - } - else - sa->haliassym = haliassym->syntaxCopy(s); - return sa; } @@ -777,25 +611,6 @@ Dsymbol *AliasDeclaration::toAlias() return s; } -void AliasDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("alias "); - if (aliassym) - { -#if IN_LLVM - buf->writestring(aliassym->toChars()); -#else - aliassym->toCBuffer(buf, hgs); -#endif - buf->writeByte(' '); - buf->writestring(ident->toChars()); - } - else - type->toCBuffer(buf, ident, hgs); - buf->writeByte(';'); - buf->writenl(); -} - /****************************** OverDeclaration **************************/ OverDeclaration::OverDeclaration(Dsymbol *s, bool hasOverloads) @@ -928,8 +743,6 @@ VarDeclaration::VarDeclaration(Loc loc, Type *type, Identifier *id, Initializer assert(type || init); this->type = type; this->init = init; - this->htype = NULL; - this->hinit = NULL; this->loc = loc; offset = 0; noscope = 0; @@ -950,48 +763,19 @@ VarDeclaration::VarDeclaration(Loc loc, Type *type, Identifier *id, Initializer Dsymbol *VarDeclaration::syntaxCopy(Dsymbol *s) { //printf("VarDeclaration::syntaxCopy(%s)\n", toChars()); - - VarDeclaration *sv; - if (s) - { sv = (VarDeclaration *)s; - } - else - { - Initializer *init = NULL; - if (this->init) - { init = this->init->syntaxCopy(); - //init->isExpInitializer()->exp->print(); - } - - sv = new VarDeclaration(loc, type ? type->syntaxCopy() : NULL, ident, init); - sv->storage_class = storage_class; - } - - // Syntax copy for header file - if (!htype) // Don't overwrite original - { if (type) // Make copy for both old and new instances - { htype = type->syntaxCopy(); - sv->htype = type->syntaxCopy(); - } - } - else // Make copy of original for new instance - sv->htype = htype->syntaxCopy(); - if (!hinit) - { if (init) - { hinit = init->syntaxCopy(); - sv->hinit = init->syntaxCopy(); - } - } - else - sv->hinit = hinit->syntaxCopy(); - - return sv; + assert(!s); + VarDeclaration *v = new VarDeclaration(loc, + type ? type->syntaxCopy() : NULL, + ident, + init ? init->syntaxCopy() : NULL); + v->storage_class = storage_class; + return v; } void VarDeclaration::semantic(Scope *sc) { #if 0 - printf("VarDeclaration::semantic('%s', parent = '%s')\n", toChars(), sc->parent->toChars()); + printf("VarDeclaration::semantic('%s', parent = '%s') sem = %d\n", toChars(), sc->parent ? sc->parent->toChars() : NULL, sem); printf(" type = %s\n", type ? type->toChars() : "null"); printf(" stc = x%x\n", sc->stc); printf(" storage_class = x%llx\n", storage_class); @@ -1057,9 +841,18 @@ void VarDeclaration::semantic(Scope *sc) { if (!originalType) originalType = type->syntaxCopy(); + + /* Prefix function attributes of variable declaration can affect + * its type: + * pure nothrow void function() fp; + * static assert(is(typeof(fp) == void function() pure nothrow)); + */ + Scope *sc2 = sc->push(); + sc2->stc |= (storage_class & STC_FUNCATTR); inuse++; - type = type->semantic(loc, sc); + type = type->semantic(loc, sc2); inuse--; + sc2->pop(); } //printf(" semantic type = %s\n", type ? type->toChars() : "null"); @@ -1338,22 +1131,18 @@ Lnomatch: AggregateDeclaration *aad = parent->isAggregateDeclaration(); if (aad) { - if (storage_class & (STCconst | STCimmutable) && init && !init->isVoidInitializer()) + if (global.params.vfield && + storage_class & (STCconst | STCimmutable) && init && !init->isVoidInitializer()) { - StorageClass stc = storage_class & (STCconst | STCimmutable); - deprecation(loc, "%s field with initializer should be static, __gshared, or an enum", - StorageClassDeclaration::stcToChars(NULL, stc)); - if (!tb->isTypeBasic()) - storage_class |= STCstatic; + const char *p = loc.toChars(); + const char *s = (storage_class & STCimmutable) ? "immutable" : "const"; + fprintf(global.stdmsg, "%s: %s.%s is %s field\n", p ? p : "", ad->toPrettyChars(), toChars(), s); } - else + storage_class |= STCfield; + if (tbn->ty == Tstruct && ((TypeStruct *)tbn)->sym->noDefaultCtor) { - storage_class |= STCfield; - if ((tbn->ty == Tstruct && ((TypeStruct *)tbn)->sym->noDefaultCtor)) - { - if (!isThisDeclaration() && !init) - aad->noDefaultCtor = true; - } + if (!isThisDeclaration() && !init) + aad->noDefaultCtor = true; } } @@ -1509,20 +1298,6 @@ Lnomatch: init = new ExpInitializer(loc, e); goto Ldtor; } - else if (type->ty == Ttypedef) - { - TypeTypedef *td = (TypeTypedef *)type; - if (td->sym->init) - { - init = td->sym->init; - ExpInitializer *ie = init->isExpInitializer(); - if (ie) - // Make copy so we can modify it - init = new ExpInitializer(ie->loc, ie->exp); - } - else - init = getExpInitializer(); - } else if (type->baseElemOf()->ty == Tvoid) { error("%s does not have a default initializer", type->toChars()); @@ -1598,7 +1373,7 @@ Lnomatch: { // See if initializer is a NewExp that can be allocated on the stack NewExp *ne = (NewExp *)ex; - if (!(ne->newargs && ne->newargs->dim) && type->toBasetype()->ty == Tclass) + if (!(ne->newargs && ne->newargs->dim > 1) && type->toBasetype()->ty == Tclass) { ne->onstack = 1; onstack = 1; @@ -1721,6 +1496,9 @@ Ldtor: void VarDeclaration::semantic2(Scope *sc) { + if (sem < SemanticDone && inuse) + return; + //printf("VarDeclaration::semantic2('%s')\n", toChars()); // Inside unions, default to void initializers if (!init && sc->inunion && !toParent()->isFuncDeclaration()) @@ -1818,11 +1596,13 @@ void VarDeclaration::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, //printf("VarDeclaration::setFieldOffset(ad = %s) %s\n", ad->toChars(), toChars()); if (aliassym) - { // If this variable was really a tuple, set the offsets for the tuple fields + { + // If this variable was really a tuple, set the offsets for the tuple fields TupleDeclaration *v2 = aliassym->isTupleDeclaration(); assert(v2); for (size_t i = 0; i < v2->objects->dim; i++) - { RootObject *o = (*v2->objects)[i]; + { + RootObject *o = (*v2->objects)[i]; assert(o->dyncast() == DYNCAST_EXPRESSION); Expression *e = (Expression *)o; assert(e->op == TOKdsymbol); @@ -1840,17 +1620,26 @@ void VarDeclaration::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, * as members. That means ignore them if they are already a field. */ if (offset) - return; // already a field + { + // already a field + *poffset = ad->structsize; // Bugzilla 13613 + return; + } for (size_t i = 0; i < ad->fields.dim; i++) { if (ad->fields[i] == this) - return; // already a field + { + // already a field + *poffset = ad->structsize; // Bugzilla 13613 + return; + } } // Check for forward referenced types which will fail the size() call Type *t = type->toBasetype(); if (storage_class & STCref) - { // References are the size of a pointer + { + // References are the size of a pointer t = Type::tvoidptr; } if (t->ty == Tstruct || t->ty == Tsarray) @@ -1888,7 +1677,7 @@ void VarDeclaration::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, offset = AggregateDeclaration::placeField(poffset, memsize, memalignsize, alignment, &ad->structsize, &ad->alignsize, isunion); - //printf("\t%s: alignsize = %d\n", toChars(), alignsize); + //printf("\t%s: memalignsize = %d\n", toChars(), memalignsize); //printf(" addField '%s' to '%s' at offset %d, size = %d\n", toChars(), ad->toChars(), offset, memsize); ad->fields.push(this); @@ -1907,29 +1696,6 @@ Dsymbol *VarDeclaration::toAlias() return s; } -void VarDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - StorageClassDeclaration::stcToCBuffer(buf, storage_class); - - /* If changing, be sure and fix CompoundDeclarationStatement::toCBuffer() - * too. - */ - if (type) - type->toCBuffer(buf, ident, hgs); - else - buf->writestring(ident->toChars()); - if (init) - { buf->writestring(" = "); - ExpInitializer *ie = init->isExpInitializer(); - if (ie && (ie->exp->op == TOKconstruct || ie->exp->op == TOKblit)) - ((AssignExp *)ie->exp)->e2->toCBuffer(buf, hgs); - else - init->toCBuffer(buf, hgs); - } - buf->writeByte(';'); - buf->writenl(); -} - AggregateDeclaration *VarDeclaration::isThis() { AggregateDeclaration *ad = NULL; @@ -1937,8 +1703,6 @@ AggregateDeclaration *VarDeclaration::isThis() if (!(storage_class & (STCstatic | STCextern | STCmanifest | STCtemplateparameter | STCtls | STCgshared | STCctfe))) { - if ((storage_class & (STCconst | STCimmutable | STCwild)) && init) - return NULL; for (Dsymbol *s = this; s; s = s->parent) { ad = s->isMember(); @@ -1958,12 +1722,12 @@ bool VarDeclaration::needThis() bool VarDeclaration::isExport() { - return protection == PROTexport; + return protection.kind == PROTexport; } bool VarDeclaration::isImportedSymbol() { - if (protection == PROTexport && !init && + if (protection.kind == PROTexport && !init && (storage_class & STCstatic || parent->isModule())) return true; return false; @@ -2026,7 +1790,7 @@ void VarDeclaration::checkNestedReference(Scope *sc, Loc loc) if (FuncLiteralDeclaration *fld = s->isFuncLiteralDeclaration()) { fld->tok = TOKdelegate; - +#if 0 /* This is necessary to avoid breaking tests for 8751 & 8793. * See: compilable/testInference.d */ @@ -2039,6 +1803,7 @@ void VarDeclaration::checkNestedReference(Scope *sc, Loc loc) { fld->setImpure(); // Bugzilla 9415 } +#endif } } @@ -2330,7 +2095,7 @@ TypeInfoDeclaration::TypeInfoDeclaration(Type *tinfo, int internal) { this->tinfo = tinfo; storage_class = STCstatic | STCgshared; - protection = PROTpublic; + protection = Prot(PROTpublic); linkage = LINKc; } @@ -2479,23 +2244,6 @@ TypeInfoInterfaceDeclaration *TypeInfoInterfaceDeclaration::create(Type *tinfo) return new TypeInfoInterfaceDeclaration(tinfo); } -/***************************** TypeInfoTypedefDeclaration *********************/ - -TypeInfoTypedefDeclaration::TypeInfoTypedefDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ - if (!Type::typeinfotypedef) - { - ObjectNotFound(Id::TypeInfo_Typedef); - } - type = Type::typeinfotypedef->type; -} - -TypeInfoTypedefDeclaration *TypeInfoTypedefDeclaration::create(Type *tinfo) -{ - return new TypeInfoTypedefDeclaration(tinfo); -} - /***************************** TypeInfoPointerDeclaration *********************/ TypeInfoPointerDeclaration::TypeInfoPointerDeclaration(Type *tinfo) diff --git a/dmd2/declaration.h b/dmd2/declaration.h index 4ad24f6297..d959df5a21 100644 --- a/dmd2/declaration.h +++ b/dmd2/declaration.h @@ -34,10 +34,8 @@ class FuncDeclaration; class ExpInitializer; class StructDeclaration; struct InterState; -struct IRState; struct CompiledCtfeFunction; -enum PROT; enum LINK; enum TOK; enum MATCH; @@ -59,7 +57,6 @@ enum PURE; #define STCout 0x1000LL // out parameter #define STClazy 0x2000LL // lazy parameter #define STCforeach 0x4000LL // variable for foreach loop -#define STCcomdat 0x8000LL // should go into COMDAT record #define STCvariadic 0x10000LL // variadic function argument #define STCctorinit 0x20000LL // can only be set inside constructor #define STCtemplateparameter 0x40000LL // template parameter @@ -90,7 +87,8 @@ enum PURE; #define STCnodefaultctor 0x8000000000LL // must be set inside constructor #define STCtemp 0x10000000000LL // temporary variable #define STCrvalue 0x20000000000LL // force rvalue for variables -#define STCnogc 0x40000000000LL // @nogc +#define STCnogc 0x40000000000LL // @nogc +#define STCvolatile 0x80000000000LL // destined for volatile in the back end const StorageClass STCStorageClass = (STCauto | STCscope | STCstatic | STCextern | STCconst | STCfinal | STCabstract | STCsynchronized | STCdeprecated | STCoverride | STClazy | STCalias | @@ -128,7 +126,7 @@ public: Type *type; Type *originalType; // before semantic analysis StorageClass storage_class; - PROT protection; + Prot protection; LINK linkage; int inuse; // used to detect cycles const char *mangleOverride; // overridden symbol with pragma(mangle, "...") @@ -166,7 +164,7 @@ public: bool isOut() { return (storage_class & STCout) != 0; } bool isRef() { return (storage_class & STCref) != 0; } - PROT prot(); + Prot prot(); Declaration *isDeclaration() { return this; } void accept(Visitor *v) { v->visit(this); } @@ -198,36 +196,6 @@ public: /**************************************************************/ -class TypedefDeclaration : public Declaration -{ -public: - Type *basetype; - Initializer *init; - - TypedefDeclaration(Loc loc, Identifier *ident, Type *basetype, Initializer *init); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void semantic2(Scope *sc); - const char *kind(); - Type *getType(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Type *htype; - Type *hbasetype; - - void toObjFile(bool multiobj); // compile to .obj file - - TypedefDeclaration *isTypedefDeclaration() { return this; } - -#if IN_DMD - Symbol *sinit; - Symbol *toInitializer(); -#endif - - void accept(Visitor *v) { v->visit(this); } -}; - -/**************************************************************/ - class AliasDeclaration : public Declaration { public: @@ -244,9 +212,6 @@ public: const char *kind(); Type *getType(); Dsymbol *toAlias(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Type *htype; - Dsymbol *haliassym; AliasDeclaration *isAliasDeclaration() { return this; } void accept(Visitor *v) { v->visit(this); } @@ -309,9 +274,6 @@ public: void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion); void semantic2(Scope *sc); const char *kind(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Type *htype; - Initializer *hinit; AggregateDeclaration *isThis(); bool needThis(); bool isExport(); @@ -410,15 +372,6 @@ public: void accept(Visitor *v) { v->visit(this); } }; -class TypeInfoTypedefDeclaration : public TypeInfoDeclaration -{ -public: - TypeInfoTypedefDeclaration(Type *tinfo); - static TypeInfoTypedefDeclaration *create(Type *tinfo); - - void accept(Visitor *v) { v->visit(this); } -}; - class TypeInfoPointerDeclaration : public TypeInfoDeclaration { public: @@ -569,7 +522,6 @@ BUILTIN isBuiltin(FuncDeclaration *fd); typedef Expression *(*builtin_fp)(Loc loc, FuncDeclaration *fd, Expressions *arguments); void add_builtin(const char *mangle, builtin_fp fp); void builtin_init(); -void buildClosure(FuncDeclaration *fd, IRState *irs); #define FUNCFLAGpurityInprocess 1 // working on determining purity #define FUNCFLAGsafetyInprocess 2 // working on determining safety @@ -598,7 +550,6 @@ public: Identifier *outId; // identifier for out statement VarDeclaration *vresult; // variable corresponding to outId LabelDsymbol *returnLabel; // where the return goes - Scope *scout; // out contract scope for vresult->semantic DsymbolTable *localsymtab; // used to prevent symbols in different // scopes from having the same name @@ -645,9 +596,11 @@ public: Symbol *shidden; // hidden pointer passed to function #endif + ReturnStatements *returns; + GotoStatements *gotos; // Gotos with forward references - BUILTIN builtin; // set if this is a known, builtin + BUILTIN builtin; // set if this is a known, builtin // function we can evaluate at compile // time @@ -673,8 +626,6 @@ public: VarDeclaration *declareThis(Scope *sc, AggregateDeclaration *ad); bool equals(RootObject *o); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void bodyToCBuffer(OutBuffer *buf, HdrGenState *hgs); int overrides(FuncDeclaration *fd); int findVtblIndex(Dsymbols *vtbl, int dim); bool overloadInsert(Dsymbol *s); @@ -686,8 +637,6 @@ public: AggregateDeclaration *isThis(); AggregateDeclaration *isMember2(); int getLevel(Loc loc, Scope *sc, FuncDeclaration *fd); // lexical nesting level difference - void appendExp(Expression *e); - void appendState(Statement *s); const char *toPrettyChars(bool QualifyTypes = false); const char *toFullSignature(); // for diagnostics, e.g. 'int foo(int x, int y) pure' bool isMain(); @@ -726,13 +675,13 @@ public: void checkNestedReference(Scope *sc, Loc loc); bool needsClosure(); bool hasNestedFrameRefs(); - void buildResultVar(); + void buildResultVar(Scope *sc, Type *tret); Statement *mergeFrequire(Statement *, Expressions *params = 0); Statement *mergeFensure(Statement *, Identifier *oid, Expressions *params = 0); Parameters *getParameters(int *pvarargs); - static FuncDeclaration *genCfunc(Parameters *args, Type *treturn, const char *name); - static FuncDeclaration *genCfunc(Parameters *args, Type *treturn, Identifier *id); + static FuncDeclaration *genCfunc(Parameters *args, Type *treturn, const char *name, StorageClass stc=0); + static FuncDeclaration *genCfunc(Parameters *args, Type *treturn, Identifier *id, StorageClass stc=0); #if IN_DMD Symbol *toThunkSymbol(int offset); // thunk version @@ -785,7 +734,6 @@ public: FuncLiteralDeclaration(Loc loc, Loc endloc, Type *type, TOK tok, ForeachStatement *fes, Identifier *id = NULL); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); Dsymbol *syntaxCopy(Dsymbol *); bool isNested(); bool isVirtual(); @@ -822,7 +770,6 @@ public: PostBlitDeclaration(Loc loc, Loc endloc, StorageClass stc, Identifier *id); Dsymbol *syntaxCopy(Dsymbol *); void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); bool isVirtual(); bool addPreInvariant(); bool addPostInvariant(); @@ -839,7 +786,6 @@ public: DtorDeclaration(Loc loc, Loc endloc, StorageClass stc, Identifier *id); Dsymbol *syntaxCopy(Dsymbol *); void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); const char *kind(); char *toChars(); bool isVirtual(); @@ -863,7 +809,6 @@ public: bool addPreInvariant(); bool addPostInvariant(); bool hasStaticCtorOrDtor(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); StaticCtorDeclaration *isStaticCtorDeclaration() { return this; } void accept(Visitor *v) { v->visit(this); } @@ -874,7 +819,6 @@ class SharedStaticCtorDeclaration : public StaticCtorDeclaration public: SharedStaticCtorDeclaration(Loc loc, Loc endloc, StorageClass stc); Dsymbol *syntaxCopy(Dsymbol *); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); SharedStaticCtorDeclaration *isSharedStaticCtorDeclaration() { return this; } void accept(Visitor *v) { v->visit(this); } @@ -894,7 +838,6 @@ public: bool hasStaticCtorOrDtor(); bool addPreInvariant(); bool addPostInvariant(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); StaticDtorDeclaration *isStaticDtorDeclaration() { return this; } void accept(Visitor *v) { v->visit(this); } @@ -905,7 +848,6 @@ class SharedStaticDtorDeclaration : public StaticDtorDeclaration public: SharedStaticDtorDeclaration(Loc loc, Loc endloc, StorageClass stc); Dsymbol *syntaxCopy(Dsymbol *); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); SharedStaticDtorDeclaration *isSharedStaticDtorDeclaration() { return this; } void accept(Visitor *v) { v->visit(this); } @@ -920,7 +862,6 @@ public: bool isVirtual(); bool addPreInvariant(); bool addPostInvariant(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); InvariantDeclaration *isInvariantDeclaration() { return this; } void accept(Visitor *v) { v->visit(this); } @@ -934,14 +875,13 @@ public: // toObjFile() these nested functions after this one FuncDeclarations deferredNested; - UnitTestDeclaration(Loc loc, Loc endloc, char *codedoc); + UnitTestDeclaration(Loc loc, Loc endloc, StorageClass stc, char *codedoc); Dsymbol *syntaxCopy(Dsymbol *); void semantic(Scope *sc); AggregateDeclaration *isThis(); bool isVirtual(); bool addPreInvariant(); bool addPostInvariant(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); UnitTestDeclaration *isUnitTestDeclaration() { return this; } void accept(Visitor *v) { v->visit(this); } @@ -953,10 +893,9 @@ public: Parameters *arguments; int varargs; - NewDeclaration(Loc loc, Loc endloc, Parameters *arguments, int varargs); + NewDeclaration(Loc loc, Loc endloc, StorageClass stc, Parameters *arguments, int varargs); Dsymbol *syntaxCopy(Dsymbol *); void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); const char *kind(); bool isVirtual(); bool addPreInvariant(); @@ -972,15 +911,15 @@ class DeleteDeclaration : public FuncDeclaration public: Parameters *arguments; - DeleteDeclaration(Loc loc, Loc endloc, Parameters *arguments); + DeleteDeclaration(Loc loc, Loc endloc, StorageClass stc, Parameters *arguments); Dsymbol *syntaxCopy(Dsymbol *); void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); const char *kind(); bool isDelete(); bool isVirtual(); bool addPreInvariant(); bool addPostInvariant(); + DeleteDeclaration *isDeleteDeclaration() { return this; } void accept(Visitor *v) { v->visit(this); } }; diff --git a/dmd2/doc.c b/dmd2/doc.c index acdd8a245f..83475d5fe0 100644 --- a/dmd2/doc.c +++ b/dmd2/doc.c @@ -20,6 +20,7 @@ #include "rmem.h" #include "root.h" #include "port.h" +#include "aav.h" #include "attrib.h" #include "cond.h" @@ -129,6 +130,14 @@ bool isCVariadicParameter(Dsymbol *s, const utf8_t *p, size_t len) return tf && tf->varargs == 1 && cmp("...", p, len) == 0; } +static TemplateDeclaration *getEponymousParentTemplate(Dsymbol *s) +{ + if (!s->parent) + return NULL; + TemplateDeclaration *td = s->parent->isTemplateDeclaration(); + return (td && td->onemember == s) ? td : NULL; +} + static const char ddoc_default[] = "\ DDOC = \n\ \n\ @@ -522,39 +531,59 @@ static bool emitAnchorName(OutBuffer *buf, Dsymbol *s, Scope *sc) if (!s || s->isPackage() || s->isModule()) return false; - TemplateDeclaration *td; - bool dot = false; - // Add parent names first + bool dot = false; if (s->parent) dot = emitAnchorName(buf, s->parent, sc); else if (sc) dot = emitAnchorName(buf, sc->scopesym, skipNonQualScopes(sc->enclosing)); // Eponymous template members can share the parent anchor name - if (s->parent && (td = s->parent->isTemplateDeclaration()) != NULL && - td->onemember == s) + if (getEponymousParentTemplate(s)) return dot; if (dot) buf->writeByte('.'); + // Use "this" not "__ctor" + TemplateDeclaration *td; if (s->isCtorDeclaration() || ((td = s->isTemplateDeclaration()) != NULL && td->onemember && td->onemember->isCtorDeclaration())) + { buf->writestring("this"); + } else { /* We just want the identifier, not overloads like TemplateDeclaration::toChars. * We don't want the template parameter list and constraints. */ buf->writestring(s->Dsymbol::toChars()); } - return true; } static void emitAnchor(OutBuffer *buf, Dsymbol *s, Scope *sc) { + Identifier *ident; + { + OutBuffer anc; + emitAnchorName(&anc, s, skipNonQualScopes(sc)); + ident = Lexer::idPool(anc.peekString()); + } + size_t *count = (size_t*)dmd_aaGet(&sc->anchorCounts, (void *)ident); + TemplateDeclaration *td = getEponymousParentTemplate(s); + // don't write an anchor for matching consecutive ditto symbols + if (*count > 0 && sc->prevAnchor == ident && + sc->lastdc && (isDitto(s->comment) || (td && isDitto(td->comment)))) + return; + + (*count)++; + // cache anchor name + sc->prevAnchor = ident; + buf->writestring("$(DDOC_ANCHOR "); - emitAnchorName(buf, s, skipNonQualScopes(sc)); + buf->writestring(ident->string); + // only append count once there's a duplicate + if (*count != 1) + buf->printf(".%u", *count); buf->writeByte(')'); } @@ -563,7 +592,7 @@ static void emitAnchor(OutBuffer *buf, Dsymbol *s, Scope *sc) /** Get leading indentation from 'src' which represents lines of code. */ static size_t getCodeIndent(const char *src) { - while (src && *src == '\n') + while (src && (*src == '\r' || *src == '\n')) ++src; // skip until we find the first non-empty line size_t codeIndent = 0; @@ -581,7 +610,7 @@ void emitUnittestComment(Scope *sc, Dsymbol *s, size_t ofs) for (UnitTestDeclaration *utd = s->ddocUnittest; utd; utd = utd->ddocUnittest) { - if (utd->protection == PROTprivate || !utd->comment || !utd->fbody) + if (utd->protection.kind == PROTprivate || !utd->comment || !utd->fbody) continue; // Strip whitespaces to avoid showing empty summary @@ -627,13 +656,7 @@ void emitDitto(Dsymbol *s, Scope *sc) /* If 'this' is a function template, then highlightCode() was * already run by FuncDeclaration::toDocbuffer(). */ - TemplateDeclaration *td; - if (s->parent && - (td = s->parent->isTemplateDeclaration()) != NULL && - td->onemember == s) - { - } - else + if (!getEponymousParentTemplate(s)) highlightCode(sc, s, &b, o); b.writeByte(')'); buf->spread(sc->lastoffset, b.offset); @@ -713,11 +736,13 @@ void emitMemberComments(ScopeDsymbol *sds, Scope *sc) } } -void emitProtection(OutBuffer *buf, PROT prot) +void emitProtection(OutBuffer *buf, Prot prot) { - const char *p = (prot == PROTpublic) ? NULL : protectionToChars(prot); - if (p) - buf->printf("%s ", p); + if (prot.kind != PROTundefined && prot.kind != PROTpublic) + { + protectionToBuffer(buf, prot); + buf->writeByte(' '); + } } void emitComment(Dsymbol *s, Scope *sc) @@ -747,7 +772,7 @@ void emitComment(Dsymbol *s, Scope *sc) //printf("Declaration::emitComment(%p '%s'), comment = '%s'\n", d, d->toChars(), d->comment); //printf("type = %p\n", d->type); - if (d->protection == PROTprivate || sc->protection == PROTprivate || + if (d->protection.kind == PROTprivate || sc->protection.kind == PROTprivate || !d->ident || (!d->type && !d->isCtorDeclaration() && !d->isAliasDeclaration())) return; if (!d->comment) @@ -778,7 +803,7 @@ void emitComment(Dsymbol *s, Scope *sc) void visit(AggregateDeclaration *ad) { //printf("AggregateDeclaration::emitComment() '%s'\n", ad->toChars()); - if (ad->prot() == PROTprivate || sc->protection == PROTprivate) + if (ad->prot().kind == PROTprivate || sc->protection.kind == PROTprivate) return; if (!ad->comment) return; @@ -809,7 +834,7 @@ void emitComment(Dsymbol *s, Scope *sc) void visit(TemplateDeclaration *td) { //printf("TemplateDeclaration::emitComment() '%s', kind = %s\n", td->toChars(), td->kind()); - if (td->prot() == PROTprivate || sc->protection == PROTprivate) + if (td->prot().kind == PROTprivate || sc->protection.kind == PROTprivate) return; const utf8_t *com = td->comment; @@ -865,7 +890,7 @@ void emitComment(Dsymbol *s, Scope *sc) void visit(EnumDeclaration *ed) { - if (ed->prot() == PROTprivate || sc->protection == PROTprivate) + if (ed->prot().kind == PROTprivate || sc->protection.kind == PROTprivate) return; if (ed->isAnonymous() && ed->members) { @@ -907,7 +932,7 @@ void emitComment(Dsymbol *s, Scope *sc) void visit(EnumMember *em) { //printf("EnumMember::emitComment(%p '%s'), comment = '%s'\n", em, em->toChars(), em->comment); - if (em->prot() == PROTprivate || sc->protection == PROTprivate) + if (em->prot().kind == PROTprivate || sc->protection.kind == PROTprivate) return; if (!em->comment) return; @@ -1015,8 +1040,8 @@ void toDocBuffer(Dsymbol *s, OutBuffer *buf, Scope *sc) { //printf("Dsymbol::toDocbuffer() %s\n", s->toChars()); HdrGenState hgs; - hgs.ddoc = 1; - s->toCBuffer(buf, &hgs); + hgs.ddoc = true; + ::toCBuffer(s, buf, &hgs); } void prefix(Dsymbol *s) @@ -1060,14 +1085,14 @@ void toDocBuffer(Dsymbol *s, OutBuffer *buf, Scope *sc) if (decl->type) { HdrGenState hgs; - hgs.ddoc = 1; + hgs.ddoc = true; Type *origType = decl->originalType ? decl->originalType : decl->type; if (origType->ty == Tfunction) { functionToBufferFull((TypeFunction *)origType, buf, decl->ident, &hgs, td); } else - origType->toCBuffer(buf, decl->ident, &hgs); + ::toCBuffer(origType, buf, decl->ident, &hgs); } else buf->writestring(decl->ident->toChars()); @@ -1076,9 +1101,9 @@ void toDocBuffer(Dsymbol *s, OutBuffer *buf, Scope *sc) if (td && td->constraint) { HdrGenState hgs; - hgs.ddoc = 1; + hgs.ddoc = true; buf->writestring(" if ("); - td->constraint->toCBuffer(buf, &hgs); + ::toCBuffer(td->constraint, buf, &hgs); buf->writeByte(')'); } @@ -1177,37 +1202,19 @@ void toDocBuffer(Dsymbol *s, OutBuffer *buf, Scope *sc) } } - void visit(TypedefDeclaration *d) - { - if (d->ident) - { - if (d->isDeprecated()) - buf->writestring("deprecated "); - - emitProtection(buf, d->protection); - buf->writestring("typedef "); - buf->writestring(d->toChars()); - buf->writestring(";\n"); - } - } - void visit(FuncDeclaration *fd) { //printf("FuncDeclaration::toDocbuffer() %s\n", fd->toChars()); if (fd->ident) { - TemplateDeclaration *td; + TemplateDeclaration *td = getEponymousParentTemplate(fd); - if (fd->parent && - (td = fd->parent->isTemplateDeclaration()) != NULL && - td->onemember == fd) + if (td) { /* It's a function template */ size_t o = buf->offset; - declarationToDocBuffer(fd, td); - highlightCode(sc, fd, buf, o); } else @@ -1237,11 +1244,9 @@ void toDocBuffer(Dsymbol *s, OutBuffer *buf, Scope *sc) #if 0 emitProtection(buf, sd->protection); #endif - TemplateDeclaration *td; + TemplateDeclaration *td = getEponymousParentTemplate(sd); - if (sd->parent && - (td = sd->parent->isTemplateDeclaration()) != NULL && - td->onemember == sd) + if (td) { size_t o = buf->offset; toDocBuffer(td, buf, sc); @@ -1263,11 +1268,9 @@ void toDocBuffer(Dsymbol *s, OutBuffer *buf, Scope *sc) #if 0 emitProtection(buf, cd->protection); #endif - TemplateDeclaration *td; + TemplateDeclaration *td = getEponymousParentTemplate(cd); - if (cd->parent && - (td = cd->parent->isTemplateDeclaration()) != NULL && - td->onemember == cd) + if (td) { size_t o = buf->offset; toDocBuffer(td, buf, sc); @@ -1284,7 +1287,7 @@ void toDocBuffer(Dsymbol *s, OutBuffer *buf, Scope *sc) { BaseClass *bc = (*cd->baseclasses)[i]; - if (bc->protection == PROTprivate) + if (bc->protection.kind == PROTprivate) continue; if (bc->base && bc->base->ident == Id::Object) continue; @@ -1304,7 +1307,7 @@ void toDocBuffer(Dsymbol *s, OutBuffer *buf, Scope *sc) else { HdrGenState hgs; - bc->type->toCBuffer(buf, NULL, &hgs); + ::toCBuffer(bc->type, buf, NULL, &hgs); } } buf->writestring(";\n"); @@ -1320,7 +1323,7 @@ void toDocBuffer(Dsymbol *s, OutBuffer *buf, Scope *sc) { buf->writestring(": $(DDOC_ENUM_BASETYPE "); HdrGenState hgs; - ed->memtype->toCBuffer(buf, NULL, &hgs); + ::toCBuffer(ed->memtype, buf, NULL, &hgs); buf->writestring(")"); } buf->writestring(";\n"); @@ -1423,7 +1426,7 @@ void DocComment::parseSections(const utf8_t *comment) p++; } // BUG: handle UTF PS and LS too - if (!*p || *p == '\r' || *p == '\n' && numdash >= 3) + if ((!*p || *p == '\r' || *p == '\n') && numdash >= 3) inCode ^= 1; pend = p; } @@ -1666,7 +1669,7 @@ void ParamSection::write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf) } else if (arg && arg->type && arg->ident) { - arg->type->toCBuffer(buf, arg->ident, &hgs); + ::toCBuffer(arg->type, buf, arg->ident, &hgs); } else { @@ -1779,6 +1782,7 @@ void DocComment::parseMacros(Escape **pescapetable, Macro **pmacrotable, const u p++; continue; + case '\r': case '\n': p++; goto Lcont; @@ -1843,14 +1847,10 @@ void DocComment::parseMacros(Escape **pescapetable, Macro **pmacrotable, const u textstart = p; Ltext: - while (p < pend && *p != '\n') + while (p < pend && *p != '\r' && *p != '\n') p++; textlen = p - textstart; - // Remove trailing \r if there is one - if (p > m && p[-1] == '\r') - textlen--; - p++; //printf("p = %p, pend = %p\n", p, pend); @@ -1859,8 +1859,8 @@ void DocComment::parseMacros(Escape **pescapetable, Macro **pmacrotable, const u Lskipline: // Ignore this line - while (p < pend && *p++ != '\n') - ; + while (p < pend && *p != '\r' && *p != '\n') + p++; } Ldone: if (namelen) @@ -1893,7 +1893,7 @@ void DocComment::parseEscapes(Escape **pescapetable, const utf8_t *textstart, si { if (p + 4 >= pend) return; - if (!(*p == ' ' || *p == '\t' || *p == '\n' || *p == ',')) + if (!(*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n' || *p == ',')) break; p++; } @@ -2440,7 +2440,7 @@ void highlightText(Scope *sc, Dsymbol *s, OutBuffer *buf, size_t offset) } // leading '_' means no highlight unless it's a reserved symbol name - if (buf->data[i] == '_' && + if (buf->data[i] == '_' && (i == 0 || !isdigit(buf->data[i-1])) && (i == buf->size-1 || !isReservedName((utf8_t *)(buf->data + i), j - i))) { buf->remove(i, 1); diff --git a/dmd2/dsymbol.c b/dmd2/dsymbol.c index 3696f83e3b..1335a77487 100644 --- a/dmd2/dsymbol.c +++ b/dmd2/dsymbol.c @@ -528,11 +528,6 @@ bool Dsymbol::overloadInsert(Dsymbol *s) return false; } -void Dsymbol::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(toChars()); -} - unsigned Dsymbol::size(Loc loc) { error("Dsymbol '%s' has no size", toChars()); @@ -786,16 +781,15 @@ Module *Dsymbol::getAccessModule() /************************************* */ -PROT Dsymbol::prot() +Prot Dsymbol::prot() { - return PROTpublic; + return Prot(PROTpublic); } /************************************* * Do syntax copy of an array of Dsymbol's. */ - Dsymbols *Dsymbol::arraySyntaxCopy(Dsymbols *a) { @@ -805,16 +799,12 @@ Dsymbols *Dsymbol::arraySyntaxCopy(Dsymbols *a) b = a->copy(); for (size_t i = 0; i < b->dim; i++) { - Dsymbol *s = (*b)[i]; - - s = s->syntaxCopy(NULL); - (*b)[i] = s; + (*b)[i] = (*b)[i]->syntaxCopy(NULL); } } return b; } - /**************************************** * Add documentation comment to Dsymbol. * Ignore NULL comments. @@ -846,7 +836,7 @@ bool Dsymbol::inNonRoot() { if (ti->isTemplateMixin()) continue; - if (!ti->instantiatingModule || !ti->instantiatingModule->isRoot()) + if (!ti->minst || !ti->minst->isRoot()) return true; return false; } @@ -901,12 +891,7 @@ ScopeDsymbol::ScopeDsymbol(Identifier *id) Dsymbol *ScopeDsymbol::syntaxCopy(Dsymbol *s) { //printf("ScopeDsymbol::syntaxCopy('%s')\n", toChars()); - - ScopeDsymbol *sds; - if (s) - sds = (ScopeDsymbol *)s; - else - sds = new ScopeDsymbol(ident); + ScopeDsymbol *sds = s ? (ScopeDsymbol *)s : new ScopeDsymbol(ident); sds->members = arraySyntaxCopy(members); return sds; } @@ -965,7 +950,7 @@ Dsymbol *ScopeDsymbol::search(Loc loc, Identifier *ident, int flags) * the other. */ if (s->isDeprecated() || - s2->prot() > s->prot() && s2->prot() != PROTnone) + s->prot().isMoreRestrictiveThan(s2->prot()) && s2->prot().kind != PROTnone) s = s2; } else @@ -1021,7 +1006,7 @@ Dsymbol *ScopeDsymbol::search(Loc loc, Identifier *ident, int flags) s = a; } - if (!(flags & IgnoreErrors) && s->prot() == PROTprivate && !s->parent->isTemplateMixin()) + if (!(flags & IgnoreErrors) && s->prot().kind == PROTprivate && !s->parent->isTemplateMixin()) { if (!s->isImport()) error(loc, "%s %s is private", s->kind(), s->toPrettyChars()); @@ -1068,7 +1053,8 @@ OverloadSet *ScopeDsymbol::mergeOverloadSet(OverloadSet *os, Dsymbol *s) if (s->toAlias() == s2->toAlias()) { if (s2->isDeprecated() || - s->prot() > s2->prot() && s->prot() != PROTnone) + (s2->prot().isMoreRestrictiveThan(s->prot()) && + s->prot().kind != PROTnone)) { os->a[j] = s; } @@ -1082,7 +1068,7 @@ OverloadSet *ScopeDsymbol::mergeOverloadSet(OverloadSet *os, Dsymbol *s) return os; } -void ScopeDsymbol::importScope(Dsymbol *s, PROT protection) +void ScopeDsymbol::importScope(Dsymbol *s, Prot protection) { //printf("%s->ScopeDsymbol::importScope(%s, %d)\n", toChars(), s->toChars(), protection); @@ -1098,15 +1084,15 @@ void ScopeDsymbol::importScope(Dsymbol *s, PROT protection) Dsymbol *ss = (*imports)[i]; if (ss == s) // if already imported { - if (protection > prots[i]) - prots[i] = protection; // upgrade access + if (protection.kind > prots[i]) + prots[i] = protection.kind; // upgrade access return; } } } imports->push(s); - prots = (PROT *)mem.realloc(prots, imports->dim * sizeof(prots[0])); - prots[imports->dim - 1] = protection; + prots = (PROTKIND *)mem.realloc(prots, imports->dim * sizeof(prots[0])); + prots[imports->dim - 1] = protection.kind; } } @@ -1519,7 +1505,7 @@ Dsymbol *ArrayScopeSymbol::search(Loc loc, Identifier *ident, int flags) if (t && t->ty == Tfunction) e = new CallExp(e->loc, e); v = new VarDeclaration(loc, NULL, Id::dollar, new ExpInitializer(Loc(), e)); - v->storage_class |= STCtemp | STCctfe; + v->storage_class |= STCtemp | STCctfe | STCrvalue; } else { @@ -1583,3 +1569,68 @@ Dsymbol *DsymbolTable::update(Dsymbol *s) *ps = s; return s; } + +/****************************** Prot ******************************/ + +Prot::Prot() +{ + this->kind = PROTundefined; + this->pkg = NULL; +} + +Prot::Prot(PROTKIND kind) +{ + this->kind = kind; + this->pkg = NULL; +} + +/** + * Checks if `this` is superset of `other` restrictions. + * For example, "protected" is more restrictive than "public". + */ +bool Prot::isMoreRestrictiveThan(Prot other) +{ + return this->kind < other.kind; +} + +/** + * Checks if `this` is absolutely identical protection attribute to `other` + */ +bool Prot::operator==(Prot other) +{ + if (this->kind == other.kind) + { + if (this->kind == PROTpackage) + return this->pkg == other.pkg; + return true; + } + return false; +} + +/** + * Checks if parent defines different access restrictions than this one. + * + * Params: + * parent = protection attribute for scope that hosts this one + * + * Returns: + * 'true' if parent is already more restrictive than this one and thus + * no differentiation is needed. + */ +bool Prot::isSubsetOf(Prot parent) +{ + if (this->kind != parent.kind) + return false; + + if (this->kind == PROTpackage) + { + if (!this->pkg) + return true; + if (!parent.pkg) + return false; + if (parent.pkg->isAncestorPackageOf(this->pkg)) + return true; + } + + return true; +} diff --git a/dmd2/dsymbol.h b/dmd2/dsymbol.h index 24b0425220..90dcb964d4 100644 --- a/dmd2/dsymbol.h +++ b/dmd2/dsymbol.h @@ -38,7 +38,6 @@ class Declaration; class ThisDeclaration; class TypeInfoDeclaration; class TupleDeclaration; -class TypedefDeclaration; class AliasDeclaration; class AggregateDeclaration; class EnumDeclaration; @@ -83,7 +82,6 @@ class ArrayScopeSymbol; class SymbolDeclaration; class Expression; class DeleteDeclaration; -struct HdrGenState; class OverloadSet; struct AA; #if IN_LLVM @@ -115,7 +113,7 @@ struct Ungag const char *mangle(Dsymbol *s); const char *mangleExact(FuncDeclaration *fd); -enum PROT +enum PROTKIND { PROTundefined, PROTnone, // no access @@ -126,9 +124,22 @@ enum PROT PROTexport, }; +struct Prot +{ + PROTKIND kind; + Package *pkg; + + Prot(); + Prot(PROTKIND kind); + + bool isMoreRestrictiveThan(Prot other); + bool operator==(Prot other); + bool isSubsetOf(Prot other); +}; + // in hdrgen.c -void protectionToBuffer(OutBuffer *buf, PROT prot); -const char *protectionToChars(PROT prot); +void protectionToBuffer(OutBuffer *buf, Prot prot); +const char *protectionToChars(PROTKIND kind); /* State of symbol in winding its way through the passes of the compiler */ @@ -167,7 +178,7 @@ public: Symbol *csym; // symbol for code generator Symbol *isym; // import version of csym #endif - const utf8_t *comment; // documentation comment for this Dsymbol + const utf8_t *comment; // documentation comment for this Dsymbol Loc loc; // where defined Scope *scope; // !=NULL means context to use for semantic() bool errors; // this symbol failed to pass semantic() @@ -219,7 +230,6 @@ public: Dsymbol *search_correct(Identifier *id); Dsymbol *searchX(Loc loc, Scope *sc, RootObject *id); virtual bool overloadInsert(Dsymbol *s); - virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs); virtual unsigned size(Loc loc); virtual bool isforwardRef(); virtual AggregateDeclaration *isThis(); // is a 'this' required to access the member @@ -235,7 +245,7 @@ public: virtual AggregateDeclaration *isMember(); // is this symbol a member of an AggregateDeclaration? virtual Type *getType(); // is this a type? virtual bool needThis(); // need a 'this' pointer? - virtual PROT prot(); + virtual Prot prot(); virtual Dsymbol *syntaxCopy(Dsymbol *s); // copy only syntax trees virtual bool oneMember(Dsymbol **ps, Identifier *ident); static bool oneMembers(Dsymbols *members, Dsymbol **ps, Identifier *ident); @@ -271,7 +281,6 @@ public: virtual ThisDeclaration *isThisDeclaration() { return NULL; } virtual TypeInfoDeclaration *isTypeInfoDeclaration() { return NULL; } virtual TupleDeclaration *isTupleDeclaration() { return NULL; } - virtual TypedefDeclaration *isTypedefDeclaration() { return NULL; } virtual AliasDeclaration *isAliasDeclaration() { return NULL; } virtual AggregateDeclaration *isAggregateDeclaration() { return NULL; } virtual FuncDeclaration *isFuncDeclaration() { return NULL; } @@ -323,7 +332,7 @@ public: private: Dsymbols *imports; // imported Dsymbol's - PROT *prots; // array of PROT, one for each import + PROTKIND *prots; // array of PROTKIND, one for each import public: ScopeDsymbol(); @@ -331,7 +340,7 @@ public: Dsymbol *syntaxCopy(Dsymbol *s); Dsymbol *search(Loc loc, Identifier *ident, int flags = IgnoreNone); OverloadSet *mergeOverloadSet(OverloadSet *os, Dsymbol *s); - void importScope(Dsymbol *s, PROT protection); + void importScope(Dsymbol *s, Prot protection); bool isforwardRef(); static void multiplyDefined(Loc loc, Dsymbol *s1, Dsymbol *s2); const char *kind(); diff --git a/dmd2/enum.c b/dmd2/enum.c index fa32ac016b..de58d90805 100644 --- a/dmd2/enum.c +++ b/dmd2/enum.c @@ -38,7 +38,7 @@ EnumDeclaration::EnumDeclaration(Loc loc, Identifier *id, Type *memtype) sinit = NULL; #endif isdeprecated = false; - protection = PROTundefined; + protection = Prot(PROTundefined); parent = NULL; added = false; inuse = 0; @@ -46,27 +46,10 @@ EnumDeclaration::EnumDeclaration(Loc loc, Identifier *id, Type *memtype) Dsymbol *EnumDeclaration::syntaxCopy(Dsymbol *s) { - Type *t = NULL; - if (memtype) - t = memtype->syntaxCopy(); - - EnumDeclaration *ed; - if (s) - { ed = (EnumDeclaration *)s; - ed->memtype = t; - } - else - ed = new EnumDeclaration(loc, ident, t); - ScopeDsymbol::syntaxCopy(ed); - if (isAnonymous()) - { - for (size_t i = 0; i < members->dim; i++) - { - EnumMember *em = (*members)[i]->isEnumMember(); - em->ed = ed; - } - } - return ed; + assert(!s); + EnumDeclaration *ed = new EnumDeclaration(loc, ident, + memtype ? memtype->syntaxCopy() : NULL); + return ScopeDsymbol::syntaxCopy(ed); } void EnumDeclaration::setScope(Scope *sc) @@ -445,42 +428,6 @@ bool EnumDeclaration::oneMember(Dsymbol **ps, Identifier *ident) return Dsymbol::oneMember(ps, ident); } -void EnumDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("enum "); - if (ident) - { buf->writestring(ident->toChars()); - buf->writeByte(' '); - } - if (memtype) - { - buf->writestring(": "); - memtype->toCBuffer(buf, NULL, hgs); - } - if (!members) - { - buf->writeByte(';'); - buf->writenl(); - return; - } - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - buf->level++; - for (size_t i = 0; i < members->dim; i++) - { - EnumMember *em = (*members)[i]->isEnumMember(); - if (!em) - continue; - em->toCBuffer(buf, hgs); - buf->writeByte(','); - buf->writenl(); - } - buf->level--; - buf->writeByte('}'); - buf->writenl(); -} - Type *EnumDeclaration::getType() { return type; @@ -496,7 +443,7 @@ bool EnumDeclaration::isDeprecated() return isdeprecated; } -PROT EnumDeclaration::prot() +Prot EnumDeclaration::prot() { return protection; } @@ -534,41 +481,10 @@ EnumMember::EnumMember(Loc loc, Identifier *id, Expression *value, Type *type) Dsymbol *EnumMember::syntaxCopy(Dsymbol *s) { - Expression *e = NULL; - if (value) - e = value->syntaxCopy(); - - Type *t = NULL; - if (type) - t = type->syntaxCopy(); - - EnumMember *em; - if (s) - { em = (EnumMember *)s; - em->loc = loc; - em->value = e; - em->type = t; - em->origValue = origValue ? origValue->syntaxCopy() : NULL; - } - else - { - em = new EnumMember(loc, ident, e, t); - em->origValue = origValue ? origValue->syntaxCopy() : NULL; - } - return em; -} - -void EnumMember::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (type) - type->toCBuffer(buf, ident, hgs); - else - buf->writestring(ident->toChars()); - if (value) - { - buf->writestring(" = "); - value->toCBuffer(buf, hgs); - } + assert(!s); + return new EnumMember(loc, ident, + value ? value->syntaxCopy() : NULL, + type ? type->syntaxCopy() : NULL); } const char *EnumMember::kind() @@ -763,10 +679,11 @@ Expression *EnumMember::getVarExp(Loc loc, Scope *sc) vd->storage_class = STCmanifest; vd->semantic(sc); - vd->protection = ed->isAnonymous() ? ed->protection : PROTpublic; + vd->protection = ed->isAnonymous() ? ed->protection : Prot(PROTpublic); vd->parent = ed->isAnonymous() ? ed->parent : ed; vd->userAttribDecl = ed->isAnonymous() ? ed->userAttribDecl : NULL; } + accessCheck(loc, sc, NULL, vd); Expression *e = new VarExp(loc, vd); return e->semantic(sc); } diff --git a/dmd2/enum.h b/dmd2/enum.h index 7c1ce3458a..6d5b26e65b 100644 --- a/dmd2/enum.h +++ b/dmd2/enum.h @@ -22,7 +22,6 @@ class Identifier; class Type; class Expression; -struct HdrGenState; class VarDeclaration; class EnumDeclaration : public ScopeDsymbol @@ -38,7 +37,7 @@ public: */ Type *type; // the TypeEnum Type *memtype; // type of the members - PROT protection; + Prot protection; private: Expression *maxval; @@ -56,12 +55,11 @@ public: void setScope(Scope *sc); void semantic(Scope *sc); bool oneMember(Dsymbol **ps, Identifier *ident); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); Type *getType(); const char *kind(); Dsymbol *search(Loc, Identifier *ident, int flags = IgnoreNone); bool isDeprecated(); // is Dsymbol deprecated? - PROT prot(); + Prot prot(); Expression *getMaxMinValue(Loc loc, Identifier *id); Expression *getDefaultValue(Loc loc); Type *getMemtype(Loc loc); @@ -98,7 +96,6 @@ public: EnumMember(Loc loc, Identifier *id, Expression *value, Type *type); Dsymbol *syntaxCopy(Dsymbol *s); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); const char *kind(); void semantic(Scope *sc); Expression *getVarExp(Loc loc, Scope *sc); diff --git a/dmd2/errors.c b/dmd2/errors.c new file mode 100644 index 0000000000..774539e3a2 --- /dev/null +++ b/dmd2/errors.c @@ -0,0 +1,262 @@ + +/* Compiler implementation of the D programming language + * Copyright (c) 1999-2014 by Digital Mars + * All Rights Reserved + * written by Walter Bright + * http://www.digitalmars.com + * Distributed under the Boost Software License, Version 1.0. + * http://www.boost.org/LICENSE_1_0.txt + * https://github.com/D-Programming-Language/dmd/blob/master/src/mars.c + */ + +#include + +#if _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#include +#if IN_LLVM +#undef min +#undef max +#endif +#endif + +#if __linux__ || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun +#include +#include +#include +#endif + +#include "errors.h" +#include "outbuffer.h" +#include "rmem.h" + +enum COLOR +{ + COLOR_BLACK = 0, + COLOR_RED = 1, + COLOR_GREEN = 2, + COLOR_BLUE = 4, + + COLOR_YELLOW = COLOR_RED | COLOR_GREEN, + COLOR_MAGENTA = COLOR_RED | COLOR_BLUE, + COLOR_CYAN = COLOR_GREEN | COLOR_BLUE, + COLOR_WHITE = COLOR_RED | COLOR_GREEN | COLOR_BLUE, +}; + +#if _WIN32 +static WORD consoleAttributes(HANDLE h) +{ + static CONSOLE_SCREEN_BUFFER_INFO sbi; + static bool sbi_inited = false; + if (!sbi_inited) + sbi_inited = GetConsoleScreenBufferInfo(h, &sbi) != FALSE; + return sbi.wAttributes; +} + +enum +{ + FOREGROUND_WHITE = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, +}; +#endif + +bool isConsoleColorSupported() +{ +#if _WIN32 + return _isatty(_fileno(stderr)) != 0; +#elif __linux__ || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun + const char *term = getenv("TERM"); + return isatty(STDERR_FILENO) && term && term[0] && 0 != strcmp(term, "dumb"); +#else + return false; +#endif +} + +void setConsoleColorBright(bool bright) +{ +#if _WIN32 + HANDLE h = GetStdHandle(STD_ERROR_HANDLE); + WORD attr = consoleAttributes(h); + SetConsoleTextAttribute(h, attr | (bright ? FOREGROUND_INTENSITY : 0)); +#else + fprintf(stderr, "\033[%dm", bright ? 1 : 0); +#endif +} + +void setConsoleColor(COLOR color, bool bright) +{ +#if _WIN32 + HANDLE h = GetStdHandle(STD_ERROR_HANDLE); + WORD attr = consoleAttributes(h); + attr = (attr & ~(FOREGROUND_WHITE | FOREGROUND_INTENSITY)) | + ((color & COLOR_RED) ? FOREGROUND_RED : 0) | + ((color & COLOR_GREEN) ? FOREGROUND_GREEN : 0) | + ((color & COLOR_BLUE) ? FOREGROUND_BLUE : 0) | + (bright ? FOREGROUND_INTENSITY : 0); + SetConsoleTextAttribute(h, attr); +#else + fprintf(stderr, "\033[%d;%dm", bright ? 1 : 0, 30 + (int)color); +#endif +} + +void resetConsoleColor() +{ +#if _WIN32 + HANDLE h = GetStdHandle(STD_ERROR_HANDLE); + SetConsoleTextAttribute(h, consoleAttributes(h)); +#else + fprintf(stderr, "\033[m"); +#endif +} + +/************************************** + * Print error message + */ + +void error(Loc loc, const char *format, ...) +{ + va_list ap; + va_start(ap, format); + verror(loc, format, ap); + va_end( ap ); +} + +void error(const char *filename, unsigned linnum, unsigned charnum, const char *format, ...) +{ + Loc loc; + loc.filename = (char *)filename; + loc.linnum = linnum; + loc.charnum = charnum; + va_list ap; + va_start(ap, format); + verror(loc, format, ap); + va_end( ap ); +} + +void warning(Loc loc, const char *format, ...) +{ + va_list ap; + va_start(ap, format); + vwarning(loc, format, ap); + va_end( ap ); +} + +/************************************** + * Print supplementary message about the last error + * Used for backtraces, etc + */ +void errorSupplemental(Loc loc, const char *format, ...) +{ + va_list ap; + va_start(ap, format); + verrorSupplemental(loc, format, ap); + va_end( ap ); +} + +void deprecation(Loc loc, const char *format, ...) +{ + va_list ap; + va_start(ap, format); + vdeprecation(loc, format, ap); + + va_end( ap ); +} + +// Just print, doesn't care about gagging +void verrorPrint(Loc loc, COLOR headerColor, const char *header, const char *format, va_list ap, + const char *p1 = NULL, const char *p2 = NULL) +{ + char *p = loc.toChars(); + + if (global.params.color) + setConsoleColorBright(true); + if (*p) + fprintf(stderr, "%s: ", p); + mem.free(p); + + if (global.params.color) + setConsoleColor(headerColor, true); + fputs(header, stderr); + if (global.params.color) + resetConsoleColor(); + if (p1) + fprintf(stderr, "%s ", p1); + if (p2) + fprintf(stderr, "%s ", p2); + OutBuffer tmp; + tmp.vprintf(format, ap); + fprintf(stderr, "%s\n", tmp.peekString()); + fflush(stderr); +} + +// header is "Error: " by default (see errors.h) +void verror(Loc loc, const char *format, va_list ap, + const char *p1, const char *p2, const char *header) +{ + if (!global.gag) + { + verrorPrint(loc, COLOR_RED, header, format, ap, p1, p2); + if (global.errors >= 20) // moderate blizzard of cascading messages + fatal(); +//halt(); + } + else + { + //fprintf(stderr, "(gag:%d) ", global.gag); + //verrorPrint(loc, COLOR_RED, header, format, ap, p1, p2); + global.gaggedErrors++; + } + global.errors++; +} + +// Doesn't increase error count, doesn't print "Error:". +void verrorSupplemental(Loc loc, const char *format, va_list ap) +{ + if (!global.gag) + verrorPrint(loc, COLOR_RED, " ", format, ap); +} + +void vwarning(Loc loc, const char *format, va_list ap) +{ + if (global.params.warnings && !global.gag) + { + verrorPrint(loc, COLOR_YELLOW, "Warning: ", format, ap); +//halt(); + if (global.params.warnings == 1) + global.warnings++; // warnings don't count if gagged + } +} + +void vdeprecation(Loc loc, const char *format, va_list ap, + const char *p1, const char *p2) +{ + static const char *header = "Deprecation: "; + if (global.params.useDeprecated == 0) + verror(loc, format, ap, p1, p2, header); + else if (global.params.useDeprecated == 2 && !global.gag) + verrorPrint(loc, COLOR_BLUE, header, format, ap, p1, p2); +} + +/*************************************** + * Call this after printing out fatal error messages to clean up and exit + * the compiler. + */ + +void fatal() +{ +#if 0 + halt(); +#endif + exit(EXIT_FAILURE); +} + +/************************************** + * Try to stop forgetting to remove the breakpoints from + * release builds. + */ +void halt() +{ +#ifdef DEBUG + *(volatile char*)0=0; +#endif +} diff --git a/dmd2/errors.h b/dmd2/errors.h new file mode 100644 index 0000000000..fdecfb3ccd --- /dev/null +++ b/dmd2/errors.h @@ -0,0 +1,44 @@ + +/* Compiler implementation of the D programming language + * Copyright (c) 1999-2014 by Digital Mars + * All Rights Reserved + * written by Walter Bright + * http://www.digitalmars.com + * Distributed under the Boost Software License, Version 1.0. + * http://www.boost.org/LICENSE_1_0.txt + * https://github.com/D-Programming-Language/dmd/blob/master/src/mars.h + */ + +#ifndef DMD_ERRORS_H +#define DMD_ERRORS_H + +#ifdef __DMC__ +#pragma once +#endif + +#include "mars.h" + +bool isConsoleColorSupported(); + +void warning(Loc loc, const char *format, ...); +void deprecation(Loc loc, const char *format, ...); +void error(Loc loc, const char *format, ...); +void errorSupplemental(Loc loc, const char *format, ...); +void verror(Loc loc, const char *format, va_list ap, const char *p1 = NULL, const char *p2 = NULL, const char *header = "Error: "); +void vwarning(Loc loc, const char *format, va_list); +void verrorSupplemental(Loc loc, const char *format, va_list ap); +void vdeprecation(Loc loc, const char *format, va_list ap, const char *p1 = NULL, const char *p2 = NULL); + +#if defined(__GNUC__) || defined(__clang__) +__attribute__((noreturn)) +void fatal(); +#elif _MSC_VER +__declspec(noreturn) +void fatal(); +#else +void fatal(); +#endif + +void halt(); + +#endif /* DMD_ERRORS_H */ diff --git a/dmd2/expression.c b/dmd2/expression.c index 78d7c89412..1754a8b964 100644 --- a/dmd2/expression.c +++ b/dmd2/expression.c @@ -40,20 +40,18 @@ #include "doc.h" #include "aav.h" #include "nspace.h" +#include "ctfe.h" #if IN_LLVM #include "gen/pragma.h" #endif bool isArrayOpValid(Expression *e); -bool isNonAssignmentArrayOp(Expression *e); #if IN_DMD Expression *createTypeInfoArray(Scope *sc, Expression *args[], size_t dim); #endif Expression *expandVar(int result, VarDeclaration *v); -void functionToBufferWithIdent(TypeFunction *t, OutBuffer *buf, const char *ident); TypeTuple *toArgTypes(Type *t); -void toBufferShort(Type *t, OutBuffer *buf, HdrGenState *hgs); void accessCheck(AggregateDeclaration *ad, Loc loc, Scope *sc, Dsymbol *smember); bool checkFrameAccess(Loc loc, Scope *sc, AggregateDeclaration *ad, size_t istart = 0); @@ -834,6 +832,8 @@ Expression *resolveUFCS(Scope *sc, CallExp *ce) { if (Expression *ey = die->semanticY(sc, 1)) { + if (ey->op == TOKerror) + return ey; ce->e1 = ey; if (isDotOpDispatch(ey)) { @@ -996,6 +996,10 @@ int arrayExpressionCanThrow(Expressions *exps, FuncDeclaration *func, bool mustN /**************************************** * Expand tuples. + * Input: + * exps aray of Expressions + * Output: + * exps rewritten in place */ void expandTuples(Expressions *exps) @@ -1116,10 +1120,17 @@ int expandAliasThisTuples(Expressions *exps, size_t starti) return -1; } +/**************************************** + * The common type is determined by applying ?: to each pair. + * Output: + * exps[] properties resolved, implicitly cast to common type, rewritten in place + * *pt if pt is not NULL, set to the common type + * Returns: + * true a semantic error was detected + */ + bool arrayExpressionToCommonType(Scope *sc, Expressions *exps, Type **pt) { - /* The type is determined by applying ?: to each pair. - */ /* Still have a problem with: * ubyte[][] = [ cast(ubyte[])"hello", [1]]; * which works if the array literal is initialized top down with the ubyte[][] @@ -1148,9 +1159,8 @@ bool arrayExpressionToCommonType(Scope *sc, Expressions *exps, Type **pt) t0 = Type::terror; continue; } - if (isNonAssignmentArrayOp(e)) + if (checkNonAssignmentArrayOp(e)) { - e->error("array operation %s without assignment not implemented", e->toChars()); t0 = Type::terror; continue; } @@ -1231,6 +1241,10 @@ TemplateDeclaration *getFuncTemplateDecl(Dsymbol *s) /**************************************** * Preprocess arguments to function. + * Output: + * exps[] tuples expanded, properties resolved, rewritten in place + * Returns: + * true a semantic error occurred */ bool preFunctionParameters(Loc loc, Scope *sc, Expressions *exps) @@ -1251,9 +1265,8 @@ bool preFunctionParameters(Loc loc, Scope *sc, Expressions *exps) arg = new ErrorExp(); err = true; } - if (isNonAssignmentArrayOp(arg)) + else if (checkNonAssignmentArrayOp(arg)) { - arg->error("array operation %s without assignment not implemented", arg->toChars()); arg = new ErrorExp(); err = true; } @@ -1307,7 +1320,10 @@ Expression *valueNoDtor(Expression *e) } /******************************************** - * Determine if t is an array of structs that need a default construction. + * Issue an error if default construction is disabled for type t. + * Default construction is required for arrays and 'out' parameters. + * Returns: + * true an error was issued */ bool checkDefCtor(Loc loc, Type *t) { @@ -1353,7 +1369,9 @@ bool Expression::checkPostblit(Scope *sc, Type *t) } /********************************************* - * Call copy constructor for struct value argument. + * If e is an instance of a struct, and that struct has a copy constructor, + * rewrite e as: + * (tmp = e),tmp * Input: * sc just used to specify the scope of created temporary variable */ @@ -1395,24 +1413,33 @@ Expression *callCpCtor(Scope *sc, Expression *e) * 4. add hidden _arguments[] argument * 5. call copy constructor for struct value arguments * Input: + * tf type of the function * fd the function being called, NULL if called indirectly + * Output: + * *prettype return type of function + * *peprefix expression to execute before arguments[] are evaluated, NULL if none * Returns: - * return type from function + * true errors happened */ -Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, - Type *tthis, Expressions *arguments, FuncDeclaration *fd) +bool functionParameters(Loc loc, Scope *sc, TypeFunction *tf, + Type *tthis, Expressions *arguments, FuncDeclaration *fd, Type **prettype, Expression **peprefix) { //printf("functionParameters()\n"); assert(arguments); assert(fd || tf->next); size_t nargs = arguments ? arguments->dim : 0; size_t nparams = Parameter::dim(tf->parameters); + unsigned olderrors = global.errors; + bool err = false; + *prettype = Type::terror; + Expression *eprefix = NULL; + *peprefix = NULL; if (nargs > nparams && tf->varargs == 0) { error(loc, "expected %llu arguments, not %llu for non-variadic function type %s", (ulonglong)nparams, (ulonglong)nargs, tf->toChars()); - return Type::terror; + return true; } // If inferring return type, and semantic3() needs to be run if not already run @@ -1432,7 +1459,10 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, size_t n = (nargs > nparams) ? nargs : nparams; // n = max(nargs, nparams) - unsigned char wildmatch = 0; + /* If the function return type has wildcards in it, we'll need to figure out the actual type + * based on the actual argument types. + */ + MOD wildmatch = 0; if (tthis && tf->isWild() && !isCtorCall) { Type *t = tthis; @@ -1469,7 +1499,7 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, if (tf->varargs == 2 && i + 1 == nparams) goto L2; error(loc, "expected %llu function arguments, not %llu", (ulonglong)nparams, (ulonglong)nargs); - return Type::terror; + return true; } arg = p->defaultArg; arg = inlineCopy(arg, sc); @@ -1490,7 +1520,7 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, goto L2; else if (nargs != nparams) { error(loc, "expected %llu function arguments, not %llu", (ulonglong)nparams, (ulonglong)nargs); - return Type::terror; + return true; } goto L1; } @@ -1503,24 +1533,20 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, case Tsarray: case Tarray: { - // Create a static array variable v of type arg->type - Identifier *id = Lexer::uniqueId("__arrayArg"); - Type *t = new TypeSArray(((TypeArray *)tb)->next, new IntegerExp(nargs - i)); - t = t->semantic(loc, sc); - VarDeclaration *v = new VarDeclaration(loc, t, id, - (sc->func && sc->func->isSafe()) ? NULL : new VoidInitializer(loc)); - v->storage_class |= STCtemp | STCctfe; - v->semantic(sc); - v->parent = sc->parent; + /* Create a static array variable v of type arg->type: + * T[dim] __arrayArg = [ arguments[i], ..., arguments[nargs-1] ]; + * + * The array literal in the initializer of the hidden variable + * is now optimized. See Bugzilla 2356. + */ + Type *tbn = ((TypeArray *)tb)->next; + Type *tsa = tbn->sarrayOf(nargs - i); - Expression *c = new DeclarationExp(loc, v); - c->type = v->type; - - for (size_t u = i; u < nargs; u++) + Expressions *elements = new Expressions(); + elements->setDim(nargs - i); + for (size_t u = 0; u < elements->dim; u++) { - Expression *a = (*arguments)[u]; - TypeArray *ta = (TypeArray *)tb; - (*arguments)[u] = a; + Expression *a = (*arguments)[i + u]; if (tret && a->implicitConvTo(tret)) { a = a->implicitCastTo(sc, tret); @@ -1528,18 +1554,21 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, a = toDelegate(a, sc); } else - a = a->implicitCastTo(sc, ta->next); - Expression *e = new VarExp(loc, v); - e = new IndexExp(loc, e, new IntegerExp(u + 1 - nparams)); - ConstructExp *ae = new ConstructExp(loc, e, a); - if (c) - c = new CommaExp(loc, c, ae); - else - c = ae; + a = a->implicitCastTo(sc, tbn); + (*elements)[u] = a; } - arg = new VarExp(loc, v); - if (c) - arg = new CommaExp(loc, c, arg); + ArrayLiteralExp *ale = new ArrayLiteralExp(loc, elements); + ale->type = tsa; + + Identifier *id = Lexer::uniqueId("__arrayArg"); + VarDeclaration *v = new VarDeclaration(loc, tsa, id, new ExpInitializer(loc, ale)); + v->storage_class |= STCtemp | STCctfe; + v->semantic(sc); + v->parent = sc->parent; + + Expression *de = new DeclarationExp(loc, v); + Expression *ve = new VarExp(loc, v); + arg = Expression::combine(de, ve); break; } case Tclass: @@ -1558,7 +1587,7 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, if (!arg) { error(loc, "not enough arguments"); - return Type::terror; + return true; } break; } @@ -1625,7 +1654,7 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, Linouterr: const char *s = wildmatch == MODmutable ? "mutable" : MODtoChars(wildmatch); error(loc, "modify inout to %s is not allowed inside inout function", s); - return Type::terror; + return true; } } @@ -1658,9 +1687,12 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, { Type *t = arg->type; if (!t->isMutable() || !t->isAssignable()) // check blit assignable + { arg->error("cannot modify struct %s with immutable members", arg->toChars()); + err = true; + } else - checkDefCtor(arg->loc, t); + err |= checkDefCtor(arg->loc, t); // t must be default constructible arg = arg->toLvalue(sc, arg); } else if (p->storageClass & STClazy) @@ -1670,7 +1702,7 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, } else { - arg = arg->isLvalue() ? callCpCtor(sc, arg) : valueNoDtor(arg); +// arg = arg->isLvalue() ? callCpCtor(sc, arg) : valueNoDtor(arg); } //printf("arg: %s\n", arg->toChars()); @@ -1713,6 +1745,7 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, } else { + // These will be the trailing ... arguments // If not D linkage, do promotions #if IN_LLVM @@ -1743,12 +1776,12 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, if (arg->type->ty == Tarray) { arg->error("cannot pass dynamic arrays to %s vararg functions", p); - arg = new ErrorExp(); + err = true; } if (arg->type->ty == Tsarray) { arg->error("cannot pass static arrays to %s vararg functions", p); - arg = new ErrorExp(); + err = true; } } } @@ -1757,12 +1790,9 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, if (arg->type->needsDestruction()) { arg->error("cannot pass types that need destruction as variadic arguments"); - arg = new ErrorExp(); + err = true; } -#if 0 - arg = arg->isLvalue() ? callCpCtor(sc, arg) : valueNoDtor(arg); -#else // Convert static arrays to dynamic arrays // BUG: I don't think this is right for D2 Type *tb = arg->type->toBasetype(); @@ -1777,9 +1807,8 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, } if (tb->ty == Tstruct) { - arg = callCpCtor(sc, arg); +// arg = callCpCtor(sc, arg); } -#endif // Give error for overloaded function addresses if (arg->op == TOKsymoff) @@ -1787,16 +1816,153 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, if (se->hasOverloads && !se->var->isFuncDeclaration()->isUnique()) { arg->error("function %s is overloaded", arg->toChars()); - arg = new ErrorExp(); + err = true; } } arg->rvalue(); arg = arg->optimize(WANTvalue); } - L3: (*arguments)[i] = arg; } + /* Remaining problems: + * 1. order of evaluation - some function push L-to-R, others R-to-L. Until we resolve what array assignment does (which is + * implemented by calling a function) we'll defer this for now. + * 2. value structs (or static arrays of them) that need to be copy constructed + * 3. value structs (or static arrays of them) that have destructors, and subsequent arguments that may throw before the + * function gets called (functions normally destroy their parameters) + * 2 and 3 are handled by doing the argument construction in 'eprefix' so that if a later argument throws, they are cleaned + * up properly. Pushing arguments on the stack then cannot fail. + */ + if (1) + { + /* Compute indices of first and last throwing argument. + * Used to not set up destructors unless a throw can happen in a later argument. + */ + bool anythrow = false; + size_t firstthrow = ~0; + size_t lastthrow = ~0; + for (size_t i = 0; i < arguments->dim; ++i) + { + Expression *arg = (*arguments)[i]; + if (canThrow(arg, sc->func, false)) + { + if (!anythrow) + { + anythrow = true; + firstthrow = i; + } + lastthrow = i; + } + } + + bool appendToPrefix = false; + VarDeclaration *gate = NULL; + for (size_t i = 0; i < arguments->dim; ++i) + { + Expression *arg = (*arguments)[i]; + + /* Skip reference parameters + */ + if (i < nparams) + { + Parameter *p = Parameter::getNth(tf->parameters, i); + if (p->storageClass & (STClazy | STCref | STCout)) + continue; + } + + TypeStruct *ts = NULL; + Type *tv = arg->type->baseElemOf(); + if (tv->ty == Tstruct) + ts = (TypeStruct *)tv; + + if (anythrow && i < lastthrow) // if there are throws after this arg + { + if (ts && ts->sym->dtor) + { + appendToPrefix = true; + + // Need the gate because throws may occur after this arg is constructed + if (!gate) + { + Identifier *idtmp = Lexer::uniqueId("__gate"); + gate = new VarDeclaration(loc, Type::tbool, idtmp, NULL); + gate->storage_class |= STCtemp | STCctfe | STCvolatile; + gate->semantic(sc); + + Expression *ae = new DeclarationExp(loc, gate); + ae = ae->semantic(sc); + eprefix = Expression::combine(eprefix, ae); + } + } + } + if (anythrow && i == lastthrow) + { + appendToPrefix = false; + } + if (appendToPrefix) // don't need to add to prefix until there's something to destruct + { + Identifier *idtmp = Lexer::uniqueId("__pfx"); + VarDeclaration *tmp = new VarDeclaration(loc, arg->type, idtmp, new ExpInitializer(loc, arg)); + tmp->storage_class |= STCtemp | STCctfe; + tmp->semantic(sc); + + /* Modify the destructor so it only runs if gate==false + */ + if (tmp->edtor) + { + Expression *e = tmp->edtor; + e = new OrOrExp(e->loc, new VarExp(e->loc, gate), e); // (gate || destructor) + tmp->edtor = e->semantic(sc); + //printf("edtor: %s\n", tmp->edtor->toChars()); + } + + // auto __pfx = arg + Expression *ae = new DeclarationExp(loc, tmp); + ae = ae->semantic(sc); + eprefix = Expression::combine(eprefix, ae); + + arg = new VarExp(loc, tmp); + arg = arg->semantic(sc); + } + else if (ts) + { + arg = arg->isLvalue() ? callCpCtor(sc, arg) : valueNoDtor(arg); + } + else if (anythrow && firstthrow <= i && i <= lastthrow && gate) + { + Identifier *id = Lexer::uniqueId("__pfy"); + VarDeclaration *tmp = new VarDeclaration(loc, arg->type, id, new ExpInitializer(loc, arg)); + tmp->storage_class |= STCtemp | STCctfe; + tmp->semantic(sc); + + Expression *ae = new DeclarationExp(loc, tmp); + ae = ae->semantic(sc); + eprefix = Expression::combine(eprefix, ae); + + arg = new VarExp(loc, tmp); + arg = arg->semantic(sc); + } + + if (anythrow && i == lastthrow) + { + /* Set gate to true after prefix runs + */ + if (eprefix) + { + assert(gate); + // (gate = true) + Expression *e = new AssignExp(gate->loc, new VarExp(gate->loc, gate), new IntegerExp(gate->loc, 1, Type::tbool)); + e = e->semantic(sc); + eprefix = Expression::combine(eprefix, e); + gate = NULL; + } + } + (*arguments)[i] = arg; + } + } + //if (eprefix) printf("eprefix: %s\n", eprefix->toChars()); + #if !IN_LLVM // If D linkage and variadic, add _arguments[] as first argument if (tf->linkage == LINKd && tf->varargs == 1) @@ -1826,6 +1992,7 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, const char* s2 = tthis->isNaked() ? " mutable" : tthis->modToChars(); ::error(loc, "inout constructor %s creates%s object, not%s", fd->toPrettyChars(), s1, s2); + err = true; } } tret = tthis; @@ -1836,28 +2003,9 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, //printf("wildmatch = x%x, tret = %s\n", wildmatch, tret->toChars()); tret = tret->substWildTo(wildmatch); } - return tret; -} - -/************************************************** - * Write out argument types to buf. - */ - -void argExpTypesToCBuffer(OutBuffer *buf, Expressions *arguments, HdrGenState *hgs) -{ - if (arguments && arguments->dim) - { - OutBuffer argbuf; - for (size_t i = 0; i < arguments->dim; i++) - { - Expression *e = (*arguments)[i]; - if (i) - buf->writestring(", "); - argbuf.reset(); - toBufferShort(e->type, &argbuf, hgs); - buf->write(&argbuf); - } - } + *prettype = tret; + *peprefix = eprefix; + return (err || olderrors != global.errors); } /******************************** Expression **************************/ @@ -1877,18 +2025,15 @@ Expression::Expression(Loc loc, TOK op, int size) } Expression *EXP_CANT_INTERPRET; -Expression *EXP_CONTINUE_INTERPRET; -Expression *EXP_BREAK_INTERPRET; -Expression *EXP_GOTO_INTERPRET; -Expression *EXP_VOID_INTERPRET; void Expression::init() { EXP_CANT_INTERPRET = new ErrorExp(); - EXP_CONTINUE_INTERPRET = new ErrorExp(); - EXP_BREAK_INTERPRET = new ErrorExp(); - EXP_GOTO_INTERPRET = new ErrorExp(); - EXP_VOID_INTERPRET = new ErrorExp(); + + CTFEExp::voidexp = new CTFEExp(TOKvoidexp); + CTFEExp::breakexp = new CTFEExp(TOKbreak); + CTFEExp::continueexp = new CTFEExp(TOKcontinue); + CTFEExp::gotoexp = new CTFEExp(TOKgoto); } Expression *Expression::syntaxCopy() @@ -1962,11 +2107,9 @@ void Expression::print() char *Expression::toChars() { - HdrGenState hgs; - memset(&hgs, 0, sizeof(hgs)); - OutBuffer buf; - toCBuffer(&buf, &hgs); + HdrGenState hgs; + toCBuffer(this, &buf, &hgs); return buf.extractString(); } @@ -2045,25 +2188,33 @@ Expression *Expression::combine(Expression *e1, Expression *e2) */ Expression *Expression::extractLast(Expression *e, Expression **pe0) { - if (e->op == TOKcomma) + if (e->op != TOKcomma) { - CommaExp *ce = (CommaExp *)e; - *pe0 = ce; + *pe0 = NULL; + return e; + } - Expression **pe = &e; - while (((CommaExp *)(*pe))->e2->op == TOKcomma) - { - ce = (CommaExp *)(*pe); - pe = &ce->e2; - } - - *pe = ce->e2; - if (pe == &e) - *pe0 = ce->e1; + CommaExp *ce = (CommaExp *)e; + if (ce->e2->op != TOKcomma) + { + *pe0 = ce->e1; + return ce->e2; } else - *pe0 = NULL; - return e; + { + *pe0 = e; + + Expression **pce = &ce->e2; + while (((CommaExp *)(*pce))->e2->op == TOKcomma) + { + pce = &((CommaExp *)(*pce))->e2; + } + assert((*pce)->op == TOKcomma); + ce = (CommaExp *)(*pce); + *pce = ce->e1; + + return ce->e2; + } } dinteger_t Expression::toInteger() @@ -2102,11 +2253,6 @@ StringExp *Expression::toStringExp() return NULL; } -void Expression::toMangleBuffer(OutBuffer *buf) -{ - error("expression %s is not a valid template value argument", toChars()); -} - /*************************************** * Return !=0 if expression is an lvalue. */ @@ -2281,13 +2427,11 @@ void Expression::checkPurity(Scope *sc, FuncDeclaration *f) return; /* Given: - * void f() - * { pure void g() - * { - * void h() - * { - * void i() { } - * } + * void f() { + * pure void g() { + * /+pure+/ void h() { + * /+pure+/ void i() { } + * } * } * } * g() can call h() but not f() @@ -2319,10 +2463,11 @@ void Expression::checkPurity(Scope *sc, FuncDeclaration *f) // OR, they must have the same pure parent. if (!f->isPure() && calledparent != outerfunc) { - if (sc->flags & SCOPEcompile ? outerfunc->isPureBypassingInferenceX() : outerfunc->setImpure()) + FuncDeclaration *ff = outerfunc; + if (sc->flags & SCOPEcompile ? ff->isPureBypassingInferenceX() : ff->setImpure()) { error("pure function '%s' cannot call impure function '%s'", - outerfunc->toPrettyChars(), f->toPrettyChars()); + ff->toPrettyChars(), f->toPrettyChars()); } } } @@ -2363,50 +2508,24 @@ void Expression::checkPurity(Scope *sc, VarDeclaration *v) * Therefore, this function and all its immediately enclosing * functions must be pure. */ - for (Dsymbol *s = sc->func; s; s = s->toParent2()) + FuncDeclaration *ff = sc->func; + if (sc->flags & SCOPEcompile ? ff->isPureBypassingInferenceX() : ff->setImpure()) { - FuncDeclaration *ff = s->isFuncDeclaration(); - if (!ff) - break; - if (sc->flags & SCOPEcompile ? ff->isPureBypassingInferenceX() : ff->setImpure()) - { - error("pure function '%s' cannot access mutable static data '%s'", - sc->func->toPrettyChars(), v->toChars()); - break; - } + error("pure function '%s' cannot access mutable static data '%s'", + ff->toPrettyChars(), v->toChars()); } } else { - /* Bugzilla 10981: Special case for the contracts of pure virtual function. - * Rewrite: - * tret foo(int i) pure - * in { assert(i); } out { assert(i); } body { ... } - * - * as: - * tret foo(int i) pure { - * void __require() pure { assert(i); } // allow accessing to i - * void __ensure() pure { assert(i); } // allow accessing to i - * __require(); - * ... - * __ensure(); - * } - */ - if ((sc->func->ident == Id::require || sc->func->ident == Id::ensure) && - v->isParameter() && sc->func->parent == v->parent) - { - return; - } - /* Given: - * void f() - * { int fx; - * pure void g() - * { int gx; - * void h() - * { int hx; - * void i() { } - * } + * void f() { + * int fx; + * pure void g() { + * int gx; + * /+pure+/ void h() { + * int hx; + * /+pure+/ void i() { } + * } * } * } * i() can modify hx and gx but not fx @@ -2417,15 +2536,37 @@ void Expression::checkPurity(Scope *sc, VarDeclaration *v) { if (s == vparent) break; + + if (AggregateDeclaration *ad = s->isAggregateDeclaration()) + { + if (ad->isNested()) + continue; + break; + } FuncDeclaration *ff = s->isFuncDeclaration(); if (!ff) break; - if (sc->flags & SCOPEcompile ? ff->isPureBypassingInferenceX() : ff->setImpure()) + if (ff->isNested()) { - error("pure nested function '%s' cannot access mutable data '%s'", - ff->toChars(), v->toChars()); - break; + if (ff->type->isImmutable()) + { + error("pure immutable nested function '%s' cannot access mutable data '%s'", + ff->toPrettyChars(), v->toChars()); + break; + } + continue; } + if (ff->isThis()) + { + if (ff->type->isImmutable()) + { + error("pure immutable member function '%s' cannot access mutable data '%s'", + ff->toPrettyChars(), v->toChars()); + break; + } + continue; + } + break; } } @@ -2602,18 +2743,16 @@ Expression *Expression::resolveLoc(Loc loc, Scope *sc) } Expressions *Expression::arraySyntaxCopy(Expressions *exps) -{ Expressions *a = NULL; - +{ + Expressions *a = NULL; if (exps) { a = new Expressions(); a->setDim(exps->dim); for (size_t i = 0; i < a->dim; i++) - { Expression *e = (*exps)[i]; - - if (e) - e = e->syntaxCopy(); - (*a)[i] = e; + { + Expression *e = (*exps)[i]; + (*a)[i] = e ? e->syntaxCopy() : NULL; } } return a; @@ -2671,11 +2810,6 @@ bool IntegerExp::equals(RootObject *o) return false; } -char *IntegerExp::toChars() -{ - return Expression::toChars(); -} - void IntegerExp::setInteger(dinteger_t value) { this->value = value; @@ -2747,9 +2881,10 @@ int IntegerExp::isBool(int result) Expression *IntegerExp::semantic(Scope *sc) { - assert(type && type->deco); + assert(type); if (type->ty == Terror) return new ErrorExp(); + assert(type->deco); normalize(); return this; } @@ -2764,14 +2899,6 @@ Expression *IntegerExp::toLvalue(Scope *sc, Expression *e) return new ErrorExp(); } -void IntegerExp::toMangleBuffer(OutBuffer *buf) -{ - if ((sinteger_t)value < 0) - buf->printf("N%lld", -value); - else - buf->printf("i%lld", value); -} - /******************************** ErrorExp **************************/ /* Use this expression for error recovery. @@ -2799,24 +2926,6 @@ RealExp::RealExp(Loc loc, real_t value, Type *type) this->type = type; } -char *RealExp::toChars() -{ - /** sizeof(value)*3 is because each byte of mantissa is max - of 256 (3 characters). The string will be "-M.MMMMe-4932". - (ie, 8 chars more than mantissa). Plus one for trailing \0. - Plus one for rounding. */ - const size_t BUFFER_LEN = sizeof(value) * 3 + 8 + 1 + 1; - char buffer[BUFFER_LEN]; - - ld_sprint(buffer, 'g', value); - - if (type->isimaginary()) - strcat(buffer, "i"); - - assert(strlen(buffer) < BUFFER_LEN); - return mem.strdup(buffer); -} - dinteger_t RealExp::toInteger() { return (sinteger_t) toReal(); @@ -2885,61 +2994,6 @@ int RealExp::isBool(int result) : (value == 0); } -void realToMangleBuffer(OutBuffer *buf, real_t value) -{ - /* Rely on %A to get portable mangling. - * Must munge result to get only identifier characters. - * - * Possible values from %A => mangled result - * NAN => NAN - * -INF => NINF - * INF => INF - * -0X1.1BC18BA997B95P+79 => N11BC18BA997B95P79 - * 0X1.9P+2 => 19P2 - */ - - if (Port::isNan(value)) - buf->writestring("NAN"); // no -NAN bugs - else if (Port::isInfinity(value)) - buf->writestring(value < 0 ? "NINF" : "INF"); - else - { - const size_t BUFFER_LEN = 36; - char buffer[BUFFER_LEN]; - size_t n = ld_sprint(buffer, 'A', value); - assert(n < BUFFER_LEN); - for (size_t i = 0; i < n; i++) - { char c = buffer[i]; - - switch (c) - { - case '-': - buf->writeByte('N'); - break; - - case '+': - case 'X': - case '.': - break; - - case '0': - if (i < 2) - break; // skip leading 0X - default: - buf->writeByte(c); - break; - } - } - } -} - -void RealExp::toMangleBuffer(OutBuffer *buf) -{ - buf->writeByte('e'); - realToMangleBuffer(buf, value); -} - - /******************************** ComplexExp **************************/ ComplexExp::ComplexExp(Loc loc, complex_t value, Type *type) @@ -2950,21 +3004,6 @@ ComplexExp::ComplexExp(Loc loc, complex_t value, Type *type) //printf("ComplexExp::ComplexExp(%s)\n", toChars()); } -char *ComplexExp::toChars() -{ - const size_t BUFFER_LEN = sizeof(value) * 3 + 8 + 1 + 1; - char buffer[BUFFER_LEN]; - - char buf1[BUFFER_LEN]; - char buf2[BUFFER_LEN]; - - ld_sprint(buf1, 'g', creall(value)); - ld_sprint(buf2, 'g', cimagl(value)); - sprintf(buffer, "(%s+%si)", buf1, buf2); - assert(strlen(buffer) < BUFFER_LEN); - return mem.strdup(buffer); -} - dinteger_t ComplexExp::toInteger() { return (sinteger_t) toReal(); @@ -3024,16 +3063,6 @@ int ComplexExp::isBool(int result) return !value; } -void ComplexExp::toMangleBuffer(OutBuffer *buf) -{ - buf->writeByte('c'); - real_t r = toReal(); - realToMangleBuffer(buf, r); - buf->writeByte('c'); // separate the two - r = toImaginary(); - realToMangleBuffer(buf, r); -} - /******************************** IdentifierExp **************************/ IdentifierExp::IdentifierExp(Loc loc, Identifier *ident) @@ -3109,6 +3138,13 @@ Expression *IdentifierExp::semantic(Scope *sc) } else { + if (withsym) + { + Declaration *d = s->isDeclaration(); + if (d) + accessCheck(loc, sc, NULL, d); + } + /* If f is really a function template, * then replace f with the function template declaration. */ @@ -3148,6 +3184,12 @@ Expression *IdentifierExp::semantic(Scope *sc) if (ident == Id::ctfe) { + if (sc->flags & SCOPEctfe) + { + error("variable __ctfe cannot be read at compile time"); + return new ErrorExp(); + } + // Create the magic __ctfe bool variable VarDeclaration *vd = new VarDeclaration(loc, Type::tbool, Id::ctfe, NULL); vd->storage_class |= STCtemp; @@ -3170,11 +3212,6 @@ Expression *IdentifierExp::semantic(Scope *sc) return new ErrorExp(); } -char *IdentifierExp::toChars() -{ - return ident->toChars(); -} - int IdentifierExp::isLvalue() { return 1; @@ -3393,11 +3430,6 @@ Lagain: return new ErrorExp(); } -char *DsymbolExp::toChars() -{ - return s->toChars(); -} - int DsymbolExp::isLvalue() { return 1; @@ -3479,22 +3511,18 @@ int ThisExp::isBool(int result) int ThisExp::isLvalue() { - return 1; + // Class `this` is an rvalue; struct `this` is an lvalue. + return (type->toBasetype()->ty != Tclass); } Expression *ThisExp::toLvalue(Scope *sc, Expression *e) -{ - return this; -} - -Expression *ThisExp::modifiableLvalue(Scope *sc, Expression *e) { if (type->toBasetype()->ty == Tclass) { - error("cannot modify '%s' reference", toChars()); - return toLvalue(sc, e); + // Class `this` is an rvalue; struct `this` is an lvalue. + return Expression::toLvalue(sc, e); } - return Expression::modifiableLvalue(sc, e); + return this; } /******************************** SuperExp **************************/ @@ -3634,11 +3662,6 @@ StringExp *NullExp::toStringExp() return NULL; } -void NullExp::toMangleBuffer(OutBuffer *buf) -{ - buf->writeByte('n'); -} - /******************************** StringExp **************************/ StringExp::StringExp(Loc loc, char *string) @@ -3679,14 +3702,6 @@ StringExp *StringExp::create(Loc loc, char *s) return new StringExp(loc, s); } -#if 0 -Expression *StringExp::syntaxCopy() -{ - printf("StringExp::syntaxCopy() %s\n", toChars()); - return copy(); -} -#endif - bool StringExp::equals(RootObject *o) { //printf("StringExp::equals('%s') %s\n", o->toChars(), toChars()); @@ -3960,66 +3975,6 @@ unsigned StringExp::charAt(uinteger_t i) return value; } -void StringExp::toMangleBuffer(OutBuffer *buf) -{ char m; - OutBuffer tmp; - unsigned c; - size_t u; - utf8_t *q; - size_t qlen; - - /* Write string in UTF-8 format - */ - switch (sz) - { case 1: - m = 'a'; - q = (utf8_t *)string; - qlen = len; - break; - case 2: - m = 'w'; - for (u = 0; u < len; ) - { - const char *p = utf_decodeWchar((unsigned short *)string, len, &u, &c); - if (p) - error("%s", p); - else - tmp.writeUTF8(c); - } - q = (utf8_t *)tmp.data; - qlen = tmp.offset; - break; - case 4: - m = 'd'; - for (u = 0; u < len; u++) - { - c = ((unsigned *)string)[u]; - if (!utf_isValidDchar(c)) - error("invalid UCS-32 char \\U%08x", c); - else - tmp.writeUTF8(c); - } - q = (utf8_t *)tmp.data; - qlen = tmp.offset; - break; - default: - assert(0); - } - buf->reserve(1 + 11 + 2 * qlen); - buf->writeByte(m); - buf->printf("%d_", (int)qlen); // nbytes <= 11 - - for (utf8_t *p = (utf8_t *)buf->data + buf->offset, *pend = p + 2 * qlen; - p < pend; p += 2, ++q) - { - utf8_t hi = *q >> 4 & 0xF; - p[0] = (utf8_t)(hi < 10 ? hi + '0' : hi - 10 + 'a'); - utf8_t lo = *q & 0xF; - p[1] = (utf8_t)(lo < 10 ? lo + '0' : lo - 10 + 'a'); - } - buf->offset += 2 * qlen; -} - /************************ ArrayLiteralExp ************************************/ // [ e1, e2, e3, ... ] @@ -4152,16 +4107,6 @@ StringExp *ArrayLiteralExp::toStringExp() return NULL; } -void ArrayLiteralExp::toMangleBuffer(OutBuffer *buf) -{ - size_t dim = elements ? elements->dim : 0; - buf->printf("A%zu", dim); - for (size_t i = 0; i < dim; i++) - { Expression *e = (*elements)[i]; - e->toMangleBuffer(buf); - } -} - /************************ AssocArrayLiteralExp ************************************/ // [ key0 : value0, key1 : value1, ... ] @@ -4256,19 +4201,6 @@ int AssocArrayLiteralExp::isBool(int result) return result ? (dim != 0) : (dim == 0); } -void AssocArrayLiteralExp::toMangleBuffer(OutBuffer *buf) -{ - size_t dim = keys->dim; - buf->printf("A%zu", dim); - for (size_t i = 0; i < dim; i++) - { Expression *key = (*keys)[i]; - Expression *value = (*values)[i]; - - key->toMangleBuffer(buf); - value->toMangleBuffer(buf); - } -} - /************************ StructLiteralExp ************************************/ // sd( e1, e2, e3, ... ) @@ -4382,7 +4314,17 @@ Expression *StructLiteralExp::addDtorHook(Scope *sc) */ if (sd->dtor && sc->func) { - Identifier *idtmp = Lexer::uniqueId("__sl"); + /* Make an identifier for the temporary of the form: + * __sl%s%d, where %s is the struct name + */ + const size_t len = 10; + char buf[len + 1]; + buf[len] = 0; + strcpy(buf, "__sl"); + strncat(buf, sd->ident->toChars(), len - 4 - 1); + assert(buf[len] == 0); + Identifier *idtmp = Lexer::uniqueId(buf); + VarDeclaration *tmp = new VarDeclaration(loc, type, idtmp, new ExpInitializer(loc, this)); tmp->storage_class |= STCtemp | STCctfe; Expression *ae = new DeclarationExp(loc, tmp); @@ -4481,19 +4423,6 @@ int StructLiteralExp::getFieldIndex(Type *type, unsigned offset) return -1; } -void StructLiteralExp::toMangleBuffer(OutBuffer *buf) -{ - size_t dim = elements ? elements->dim : 0; - buf->printf("S%zu", dim); - for (size_t i = 0; i < dim; i++) - { Expression *e = (*elements)[i]; - if (e) - e->toMangleBuffer(buf); - else - buf->writeByte('v'); // 'v' for void - } -} - /************************ TypeDotIdExp ************************************/ /* Things like: @@ -4522,7 +4451,6 @@ TypeExp::TypeExp(Loc loc, Type *type) Expression *TypeExp::syntaxCopy() { - //printf("TypeExp::syntaxCopy()\n"); return new TypeExp(loc, type->syntaxCopy()); } @@ -4577,8 +4505,7 @@ ScopeExp::ScopeExp(Loc loc, ScopeDsymbol *pkg) Expression *ScopeExp::syntaxCopy() { - ScopeExp *se = new ScopeExp(loc, (ScopeDsymbol *)sds->syntaxCopy(NULL)); - return se; + return new ScopeExp(loc, (ScopeDsymbol *)sds->syntaxCopy(NULL)); } Expression *ScopeExp::semantic(Scope *sc) @@ -4724,6 +4651,7 @@ NewExp::NewExp(Loc loc, Expression *thisexp, Expressions *newargs, this->newargs = newargs; this->newtype = newtype; this->arguments = arguments; + argprefix = NULL; member = NULL; allocator = NULL; onstack = 0; @@ -4737,7 +4665,6 @@ Expression *NewExp::syntaxCopy() newtype->syntaxCopy(), arraySyntaxCopy(arguments)); } - Expression *NewExp::semantic(Scope *sc) { #if LOGSEMANTIC @@ -4752,6 +4679,7 @@ Expression *NewExp::semantic(Scope *sc) Type *tb; ClassDeclaration *cdthis = NULL; size_t nargs; + Expression *newprefix = NULL; Lagain: if (thisexp) @@ -4932,9 +4860,7 @@ Lagain: if (!arguments) arguments = new Expressions(); - unsigned olderrors = global.errors; - type = functionParameters(loc, sc, tf, type, arguments, f); - if (olderrors != global.errors) + if (functionParameters(loc, sc, tf, type, arguments, f, &type, &argprefix)) return new ErrorExp(); } else @@ -4961,9 +4887,8 @@ Lagain: assert(allocator); TypeFunction *tf = (TypeFunction *)f->type; - unsigned olderrors = global.errors; - functionParameters(loc, sc, tf, NULL, newargs, f); - if (olderrors != global.errors) + Type *rettype; + if (functionParameters(loc, sc, tf, NULL, newargs, f, &rettype, &newprefix)) return new ErrorExp(); } else @@ -5003,9 +4928,8 @@ Lagain: assert(allocator); TypeFunction *tf = (TypeFunction *)f->type; - unsigned olderrors = global.errors; - functionParameters(loc, sc, tf, NULL, newargs, f); - if (olderrors != global.errors) + Type *rettype; + if (functionParameters(loc, sc, tf, NULL, newargs, f, &rettype, &newprefix)) return new ErrorExp(); } else @@ -5035,9 +4959,7 @@ Lagain: if (!arguments) arguments = new Expressions(); - unsigned olderrors = global.errors; - type = functionParameters(loc, sc, tf, type, arguments, f); - if (olderrors != global.errors) + if (functionParameters(loc, sc, tf, type, arguments, f, &type, &argprefix)) return new ErrorExp(); } else @@ -5111,6 +5033,8 @@ Lagain: //printf("NewExp:type '%s'\n", type->toChars()); semanticTypeInfo(sc, type); + if (newprefix) + return combine(newprefix, this); return this; Lerr: @@ -5138,7 +5062,6 @@ Expression *NewAnonClassExp::syntaxCopy() arraySyntaxCopy(arguments)); } - Expression *NewAnonClassExp::semantic(Scope *sc) { #if LOGSEMANTIC @@ -5299,11 +5222,6 @@ Expression *VarExp::semantic(Scope *sc) return this; } -char *VarExp::toChars() -{ - return var->toChars(); -} - void VarExp::checkEscape() { VarDeclaration *v = var->isVarDeclaration(); @@ -5354,6 +5272,11 @@ Expression *VarExp::toLvalue(Scope *sc, Expression *e) error("compiler-generated variable __ctfe is not an lvalue"); return new ErrorExp(); } + if (var->ident == Id::dollar) // Bugzilla 13574 + { + error("'$' is not an lvalue"); + return new ErrorExp(); + } return this; } @@ -5597,11 +5520,17 @@ Expression *FuncExp::syntaxCopy() fd2 = (*td2->members)[0]->isFuncLiteralDeclaration(); assert(fd2); } - else + else if (fd->semanticRun == PASSinit) { td2 = NULL; fd2 = (FuncLiteralDeclaration *)fd->syntaxCopy(NULL); } + else + { + // Bugzilla 13481: Prevent multiple semantic analysis of lambda body. + td2 = NULL; + fd2 = fd; + } return new FuncExp(loc, fd2, td2); } @@ -5615,7 +5544,7 @@ Expression *FuncExp::semantic(Scope *sc) sc = sc->push(); // just create new scope sc->flags &= ~SCOPEctfe; // temporary stop CTFE - sc->protection = PROTpublic; // Bugzilla 12506 + sc->protection = Prot(PROTpublic); // Bugzilla 12506 if (!type || type == Type::tvoid) { @@ -6009,7 +5938,6 @@ Expression *DeclarationExp::semantic(Scope *sc) { // Bugzilla 11720 - include Dataseg variables if ((s->isFuncDeclaration() || - s->isTypedefDeclaration() || s->isAggregateDeclaration() || s->isEnumDeclaration() || v && v->isDataseg()) && @@ -6072,13 +6000,11 @@ TypeidExp::TypeidExp(Loc loc, RootObject *o) this->obj = o; } - Expression *TypeidExp::syntaxCopy() { return new TypeidExp(loc, objectSyntaxCopy(obj)); } - Expression *TypeidExp::semantic(Scope *sc) { #if LOGSEMANTIC @@ -6154,7 +6080,6 @@ TraitsExp::TraitsExp(Loc loc, Identifier *ident, Objects *args) this->args = args; } - Expression *TraitsExp::syntaxCopy() { return new TraitsExp(loc, ident, TemplateInstance::arraySyntaxCopy(args)); @@ -6204,11 +6129,8 @@ Expression *IsExp::syntaxCopy() p = new TemplateParameters(); p->setDim(parameters->dim); for (size_t i = 0; i < p->dim; i++) - { TemplateParameter *tp = (*parameters)[i]; - (*p)[i] = tp->syntaxCopy(); - } + (*p)[i] = (*parameters)[i]->syntaxCopy(); } - return new IsExp(loc, targ->syntaxCopy(), id, @@ -6218,6 +6140,8 @@ Expression *IsExp::syntaxCopy() p); } +void unSpeculative(Scope *sc, RootObject *o); + Expression *IsExp::semantic(Scope *sc) { /* is(targ id tok tspec) @@ -6226,14 +6150,18 @@ Expression *IsExp::semantic(Scope *sc) */ //printf("IsExp::semantic(%s)\n", toChars()); - if (id && !(sc->flags & (SCOPEstaticif | SCOPEstaticassert))) + if (id && !(sc->flags & SCOPEcondition)) { error("can only declare type aliases within static if conditionals or static asserts"); return new ErrorExp(); } Type *tded = NULL; - Type *t = targ->trySemantic(loc, sc); + Scope *sc2 = sc->copy(); // keep sc->flags + sc2->tinst = NULL; + sc2->minst = NULL; + Type *t = targ->trySemantic(loc, sc2); + sc2->pop(); if (!t) goto Lno; // errors, so condition is false targ = t; @@ -6242,10 +6170,7 @@ Expression *IsExp::semantic(Scope *sc) switch (tok2) { case TOKtypedef: - if (targ->ty != Ttypedef) - goto Lno; - tded = ((TypeTypedef *)targ)->sym->basetype; - break; + goto Lno; case TOKstruct: if (targ->ty != Tstruct) @@ -6307,13 +6232,15 @@ Expression *IsExp::semantic(Scope *sc) if (targ->ty != Tclass) goto Lno; else - { ClassDeclaration *cd = ((TypeClass *)targ)->sym; + { + ClassDeclaration *cd = ((TypeClass *)targ)->sym; Parameters *args = new Parameters; args->reserve(cd->baseclasses->dim); if (cd->scope && !cd->symtab) cd->semantic(cd->scope); for (size_t i = 0; i < cd->baseclasses->dim; i++) - { BaseClass *b = (*cd->baseclasses)[i]; + { + BaseClass *b = (*cd->baseclasses)[i]; args->push(new Parameter(STCin, b->type, NULL, NULL)); } tded = new TypeTuple(args); @@ -6352,7 +6279,8 @@ Expression *IsExp::semantic(Scope *sc) Parameters *args = new Parameters; args->reserve(dim); for (size_t i = 0; i < dim; i++) - { Parameter *arg = Parameter::getNth(params, 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 @@ -6374,12 +6302,14 @@ Expression *IsExp::semantic(Scope *sc) if (targ->ty == Tfunction) tded = ((TypeFunction *)targ)->next; else if (targ->ty == Tdelegate) - { tded = ((TypeDelegate *)targ)->next; + { + tded = ((TypeDelegate *)targ)->next; tded = ((TypeFunction *)tded)->next; } else if (targ->ty == Tpointer && ((TypePointer *)targ)->next->ty == Tfunction) - { tded = ((TypePointer *)targ)->next; + { + tded = ((TypePointer *)targ)->next; tded = ((TypeFunction *)tded)->next; } else @@ -6412,13 +6342,15 @@ Expression *IsExp::semantic(Scope *sc) //printf("targ = %s, %s\n", targ->toChars(), targ->deco); //printf("tspec = %s, %s\n", tspec->toChars(), tspec->deco); if (tok == TOKcolon) - { if (targ->implicitConvTo(tspec)) + { + if (targ->implicitConvTo(tspec)) goto Lyes; else goto Lno; } else /* == */ - { if (targ->equals(tspec)) + { + if (targ->equals(tspec)) goto Lyes; else goto Lno; @@ -6463,7 +6395,8 @@ Expression *IsExp::semantic(Scope *sc) /* Declare trailing parameters */ for (size_t i = 1; i < parameters->dim; i++) - { TemplateParameter *tp = (*parameters)[i]; + { + TemplateParameter *tp = (*parameters)[i]; Declaration *s = NULL; m = tp->matchArg(loc, sc, &tiargs, i, parameters, &dedtypes, &s); @@ -6474,6 +6407,8 @@ Expression *IsExp::semantic(Scope *sc) s->addMember(sc, sc->sds, 1); else if (!sc->insert(s)) error("declaration %s is already defined", s->toChars()); + + unSpeculative(sc, s); } goto Lyes; } @@ -6504,6 +6439,8 @@ Lyes: error("declaration %s is already defined", s->toChars()); if (sc->sds) s->addMember(sc, sc->sds, 1); + + unSpeculative(sc, s); } //printf("Lyes\n"); return new IntegerExp(loc, 1, Type::tbool); @@ -6786,7 +6723,12 @@ Expression *BinAssignExp::semantic(Scope *sc) if (e1->op == TOKslice || e1->type->ty == Tarray || e1->type->ty == Tsarray) { // T[] op= ... - if (Expression *ex = typeCombine(this, sc)) + if (e2->implicitConvTo(e1->type->nextOf())) + { + // T[] op= T + e2 = e2->castTo(sc, e1->type->nextOf()); + } + else if (Expression *ex = typeCombine(this, sc)) return ex; type = e1->type; return arrayOp(this, sc); @@ -6942,13 +6884,16 @@ Expression *CompileExp::semantic(Scope *sc) return new ErrorExp(); } se = se->toUTF8(sc); + unsigned errors = global.errors; Parser p(loc, sc->module, (utf8_t *)se->string, se->len, 0); p.nextToken(); //printf("p.loc.linnum = %d\n", p.loc.linnum); - unsigned errors = global.errors; Expression *e = p.parseExpression(); - if (global.errors != errors) + if (p.errors) + { + assert(global.errors != errors); // should have caught all these cases return new ErrorExp(); + } if (p.token.value != TOKeof) { error("incomplete mixin expression (%s)", se->toChars()); return new ErrorExp(); @@ -7049,9 +6994,7 @@ AssertExp::AssertExp(Loc loc, Expression *e, Expression *msg) Expression *AssertExp::syntaxCopy() { - AssertExp *ae = new AssertExp(loc, e1->syntaxCopy(), - msg ? msg->syntaxCopy() : NULL); - return ae; + return new AssertExp(loc, e1->syntaxCopy(), msg ? msg->syntaxCopy() : NULL); } Expression *AssertExp::semantic(Scope *sc) @@ -7627,16 +7570,19 @@ Expression *DotVarExp::semantic(Scope *sc) accessCheck(loc, sc, e1, var); VarDeclaration *v = var->isVarDeclaration(); - Expression *e = expandVar(WANTvalue, v); - if (e) - return e; + if (v && (v->isDataseg() || (v->storage_class & STCmanifest))) + { + Expression *e = expandVar(WANTvalue, v); + if (e) + return e; + } if (v && v->isDataseg()) // fix bugzilla 8238 { // (e1, v) accessCheck(loc, sc, e1, v); - VarExp *ve = new VarExp(loc, v); - e = new CommaExp(loc, e1, ve); + Expression *e = new VarExp(loc, v); + e = new CommaExp(loc, e1, e); e = e->semantic(sc); return e; } @@ -7794,11 +7740,10 @@ DotTemplateInstanceExp::DotTemplateInstanceExp(Loc loc, Expression *e, TemplateI Expression *DotTemplateInstanceExp::syntaxCopy() { - DotTemplateInstanceExp *de = new DotTemplateInstanceExp(loc, + return new DotTemplateInstanceExp(loc, e1->syntaxCopy(), ti->name, TemplateInstance::arraySyntaxCopy(ti->tiargs)); - return de; } bool DotTemplateInstanceExp::findTempDecl(Scope *sc) @@ -8886,21 +8831,14 @@ Lagain: OutBuffer buf; buf.writeByte('('); - if (arguments) - { - HdrGenState hgs; - - argExpTypesToCBuffer(&buf, arguments, &hgs); - buf.writeByte(')'); - if (tthis) - tthis->modToBuffer(&buf); - } - else - buf.writeByte(')'); + argExpTypesToCBuffer(&buf, arguments); + buf.writeByte(')'); + if (tthis) + tthis->modToBuffer(&buf); //printf("tf = %s, args = %s\n", tf->deco, (*arguments)[0]->type->deco); ::error(loc, "%s %s %s is not callable using argument types %s", - p, e1->toChars(), Parameter::argsTypesToChars(tf->parameters, tf->varargs), + p, e1->toChars(), parametersTypeToChars(tf->parameters, tf->varargs), buf.peekString()); return new ErrorExp(); @@ -8964,17 +8902,12 @@ Lagain: OutBuffer buf; buf.writeByte('('); - if (arguments && arguments->dim) - { - HdrGenState hgs; - - argExpTypesToCBuffer(&buf, arguments, &hgs); - } + argExpTypesToCBuffer(&buf, arguments); buf.writeByte(')'); //printf("tf = %s, args = %s\n", tf->deco, (*arguments)[0]->type->deco); ::error(loc, "%s %s is not callable using argument types %s", - e1->toChars(), Parameter::argsTypesToChars(tf->parameters, tf->varargs), + e1->toChars(), parametersTypeToChars(tf->parameters, tf->varargs), buf.peekString()); f = NULL; @@ -9019,11 +8952,10 @@ Lagain: } assert(t1->ty == Tfunction); + Expression *argprefix; if (!arguments) arguments = new Expressions(); - unsigned int olderrors = global.errors; - type = functionParameters(loc, sc, (TypeFunction *)(t1), tthis, arguments, f); - if (olderrors != global.errors) + if (functionParameters(loc, sc, (TypeFunction *)(t1), tthis, arguments, f, &type, &argprefix)) return new ErrorExp(); if (!type) @@ -9042,7 +8974,7 @@ Lagain: if (tf->next->isBaseOf(t, &offset) && offset) { type = tf->next; - return castTo(sc, t); + return combine(argprefix, castTo(sc, t)); } } @@ -9053,7 +8985,7 @@ Lagain: f->tookAddressOf = 0; } - return this; + return combine(argprefix, this); } @@ -9354,7 +9286,7 @@ Expression *PtrExp::semantic(Scope *sc) case Tsarray: case Tarray: - deprecation("using * on an array is deprecated; use *(%s).ptr instead", e1->toChars()); + error("using * on an array is no longer supported; use *(%s).ptr instead", e1->toChars()); type = ((TypeArray *)tb)->next; e1 = e1->castTo(sc, type->pointerTo()); break; @@ -9430,7 +9362,7 @@ Expression *NegExp::semantic(Scope *sc) { if (!isArrayOpValid(e1)) { - error("invalid array operation %s (did you forget a [] ?)", toChars()); + error("invalid array operation %s (possible missing [])", toChars()); return new ErrorExp(); } return this; @@ -9489,7 +9421,7 @@ Expression *ComExp::semantic(Scope *sc) { if (!isArrayOpValid(e1)) { - error("invalid array operation %s (did you forget a [] ?)", toChars()); + error("invalid array operation %s (possible missing [])", toChars()); return new ErrorExp(); } return this; @@ -9592,7 +9524,7 @@ Expression *DeleteExp::semantic(Scope *sc) FuncDeclaration *f = sd->aggDelete; FuncDeclaration *fd = sd->dtor; - if (!f && !fd) + if (!f) break; /* Construct: @@ -9606,7 +9538,7 @@ Expression *DeleteExp::semantic(Scope *sc) VarDeclaration *v; if (fd && f) - { Identifier *id = Lexer::idPool("__tmp"); + { Identifier *id = Lexer::idPool("__tmpea"); v = new VarDeclaration(loc, e1->type, id, new ExpInitializer(loc, e1)); v->storage_class |= STCtemp; v->semantic(sc); @@ -9649,28 +9581,10 @@ Expression *DeleteExp::semantic(Scope *sc) break; } default: - if (e1->op == TOKindex) - { - IndexExp *ae = (IndexExp *)(e1); - Type *tb1 = ae->e1->type->toBasetype(); - if (tb1->ty == Taarray) - break; - } error("cannot delete type %s", e1->type->toChars()); goto Lerr; } - if (e1->op == TOKindex) - { - IndexExp *ae = (IndexExp *)(e1); - Type *tb1 = ae->e1->type->toBasetype(); - if (tb1->ty == Taarray) - { - error("use 'aa.remove(key)' instead of 'delete aa[key]'"); - goto Lerr; - } - } - return this; Lerr: @@ -9708,7 +9622,6 @@ Expression *CastExp::syntaxCopy() : new CastExp(loc, e1->syntaxCopy(), mod); } - Expression *CastExp::semantic(Scope *sc) { #if LOGSEMANTIC @@ -9781,23 +9694,23 @@ Expression *CastExp::semantic(Scope *sc) return e; } + if (!t1b->equals(tob) && (t1b->ty == Tarray || t1b->ty == Tsarray)) + { + if (checkNonAssignmentArrayOp(e1)) + return new ErrorExp; + } + // Struct casts are possible only when the sizes match // Same with static array -> static array if (tob->ty == Tstruct || t1b->ty == Tstruct || (tob->ty == Tsarray && t1b->ty == Tsarray)) { if (t1b->ty == Tnull || tob->ty == Tnull || t1b->size(loc) != tob->size(loc)) - { - error("cannot cast from %s to %s", e1->type->toChars(), to->toChars()); - return new ErrorExp(); - } + goto Lfail; } if ((t1b->ty == Tarray || t1b->ty == Tsarray) && tob->ty == Tclass) - { - error("cannot cast from %s to %s", e1->type->toChars(), to->toChars()); - return new ErrorExp(); - } + goto Lfail; // Look for casting to a vector type if (tob->ty == Tvector && t1b->ty != Tvector) @@ -9905,7 +9818,7 @@ Lsafe: } Lfail: - error("cannot cast %s of type %s to %s", e1->toChars(), e1->type->toChars(), to->toChars()); + error("cannot cast expression %s of type %s to %s", e1->toChars(), e1->type->toChars(), to->toChars()); return new ErrorExp(); } @@ -9973,15 +9886,9 @@ SliceExp::SliceExp(Loc loc, Expression *e1, Expression *lwr, Expression *upr) Expression *SliceExp::syntaxCopy() { - Expression *lwr = NULL; - if (this->lwr) - lwr = this->lwr->syntaxCopy(); - - Expression *upr = NULL; - if (this->upr) - upr = this->upr->syntaxCopy(); - - SliceExp *se = new SliceExp(loc, e1->syntaxCopy(), lwr, upr); + SliceExp *se = new SliceExp(loc, e1->syntaxCopy(), + lwr ? lwr->syntaxCopy() : NULL, + upr ? upr->syntaxCopy() : NULL); se->lengthVar = this->lengthVar; // bug7871 return se; } @@ -10014,7 +9921,8 @@ Lagain: if (!lwr && !upr) { if (e1->op == TOKarrayliteral) - { // Convert [a,b,c][] to [a,b,c] + { + // Convert [a,b,c][] to [a,b,c] Type *t1b = e1->type->toBasetype(); e = e1; if (t1b->ty == Tsarray) @@ -10025,11 +9933,17 @@ Lagain: return e; } if (e1->op == TOKslice) - { // Convert e[][] to e[] + { + // Convert e[][] to e[] SliceExp *se = (SliceExp *)e1; if (!se->lwr && !se->upr) return se; } + if (isArrayOpOperand(e1)) + { + // Convert (a[]+b[])[] to a[]+b[] + return e1; + } } e = this; @@ -10692,8 +10606,11 @@ Expression *IndexExp::semantic(Scope *sc) if (t1->ty == Ttuple) sc = sc->endCTFE(); if (e2->type == Type::terror) return new ErrorExp(); - if (e2->type->ty == Ttuple && ((TupleExp *)e2)->exps->dim == 1) // bug 4444 fix + if (e2->type->ty == Ttuple && ((TupleExp *)e2)->exps && + ((TupleExp *)e2)->exps->dim == 1) // bug 4444 fix + { e2 = (*((TupleExp *)e2)->exps)[0]; + } if (t1->ty == Tsarray || t1->ty == Tarray || t1->ty == Ttuple) sc = sc->pop(); @@ -11317,6 +11234,16 @@ Expression *AssignExp::semantic(Scope *sc) { //printf("[%s] change to init - %s\n", loc.toChars(), toChars()); op = TOKconstruct; + + // Bugzilla 13515: set Index::modifiable flag for complex AA element initialization + if (e1->op == TOKindex && + ((IndexExp *)e1)->e1->type->toBasetype()->ty == Taarray) + { + Expression *e1x = e1->modifiableLvalue(sc, e1old); + if (e1x->op == TOKerror) + return e1x; + e1 = e1x; + } } /* If it is an assignment from a 'foreign' type, @@ -11457,6 +11384,12 @@ Expression *AssignExp::semantic(Scope *sc) return new ErrorExp(); } } + else // Bugzilla 11355 + { + Expression *e = op_overload(sc); + if (e) + return e; + } } else if (op == TOKassign) { @@ -11772,7 +11705,7 @@ Expression *AssignExp::semantic(Scope *sc) Type *t2n = t2->nextOf(); Type *t1n = t1->nextOf(); int offset; - if (t2n->immutableOf()->equals(t1n->immutableOf()) || + if (t2n->equivalent(t1n) || t1n->isBaseOf(t2n, &offset) && offset == 0) { /* Allow copy of distinct qualifier elements. @@ -11818,20 +11751,27 @@ Expression *AssignExp::semantic(Scope *sc) if (e2x->op == TOKerror) return e2x; e2 = e2x; + t2 = e2->type->toBasetype(); /* Look for array operations */ - if ((e1->op == TOKslice || e1->type->ty == Tarray) && - !ismemset && - (e2->op == TOKadd || e2->op == TOKmin || - e2->op == TOKmul || e2->op == TOKdiv || - e2->op == TOKmod || e2->op == TOKxor || - e2->op == TOKand || e2->op == TOKor || - e2->op == TOKpow || - e2->op == TOKtilde || e2->op == TOKneg)) + if ((t2->ty == Tarray || t2->ty == Tsarray) && isArrayOpValid(e2)) { - type = e1->type; - return arrayOp(this, sc); + // Look for valid array operations + if (!ismemset && e1->op == TOKslice && + (isUnaArrayOp(e2->op) || isBinArrayOp(e2->op))) + { + type = e1->type; + return arrayOp(this, sc); + } + + // Drop invalid array operations in e2 + // d = a[] + b[], d = (a[] + b[])[0..2], etc + if (checkNonAssignmentArrayOp(e2, !ismemset && op == TOKassign)) + return new ErrorExp(); + + // Remains valid array assignments + // d = d[], d = [1,2,3], etc } if (e1->op == TOKvar && @@ -11840,7 +11780,7 @@ Expression *AssignExp::semantic(Scope *sc) { error("cannot rebind scope variables"); } - if (e1->op == TOKvar && ((VarExp*)e1)->var->ident == Id::ctfe) + if (e1->op == TOKvar && ((VarExp *)e1)->var->ident == Id::ctfe) { error("cannot modify compiler-generated variable __ctfe"); } @@ -11950,22 +11890,19 @@ Expression *CatAssignExp::semantic(Scope *sc) if (e2->op == TOKerror) return e2; - if (isNonAssignmentArrayOp(e2)) - { - error("array operation %s without assignment not implemented", e2->toChars()); + if (checkNonAssignmentArrayOp(e2)) return new ErrorExp(); - } Type *tb1 = e1->type->toBasetype(); Type *tb1next = tb1->nextOf(); Type *tb2 = e2->type->toBasetype(); + Type *tb2next = tb2->nextOf(); if ((tb1->ty == Tarray) && (tb2->ty == Tarray || tb2->ty == Tsarray) && (e2->implicitConvTo(e1->type) || (tb2->nextOf()->implicitConvTo(tb1next) && - (tb2->nextOf()->size(Loc()) == tb1next->size(Loc()) || - tb1next->ty == Tchar || tb1next->ty == Twchar || tb1next->ty == Tdchar)) + (tb2->nextOf()->size(Loc()) == tb1next->size(Loc()))) ) ) { @@ -12093,7 +12030,12 @@ Expression *PowAssignExp::semantic(Scope *sc) if (e1->op == TOKslice || e1->type->ty == Tarray || e1->type->ty == Tsarray) { // T[] ^^= ... - if (Expression *ex = typeCombine(this, sc)) + if (e2->implicitConvTo(e1->type->nextOf())) + { + // T[] ^^= T + e2 = e2->castTo(sc, e1->type->nextOf()); + } + else if (Expression *ex = typeCombine(this, sc)) return ex; // Check element types are arithmetic @@ -12205,7 +12147,7 @@ Expression *AddExp::semantic(Scope *sc) { if (!isArrayOpValid(this)) { - error("invalid array operation %s (did you forget a [] ?)", toChars()); + error("invalid array operation %s (possible missing [])", toChars()); return new ErrorExp(); } return this; @@ -12328,7 +12270,7 @@ Expression *MinExp::semantic(Scope *sc) { if (!isArrayOpValid(this)) { - error("invalid array operation %s (did you forget a [] ?)", toChars()); + error("invalid array operation %s (possible missing [])", toChars()); return new ErrorExp(); } return this; @@ -12536,7 +12478,7 @@ Expression *MulExp::semantic(Scope *sc) { if (!isArrayOpValid(this)) { - error("invalid array operation %s (did you forget a [] ?)", toChars()); + error("invalid array operation %s (possible missing [])", toChars()); return new ErrorExp(); } return this; @@ -12624,7 +12566,7 @@ Expression *DivExp::semantic(Scope *sc) { if (!isArrayOpValid(this)) { - error("invalid array operation %s (did you forget a [] ?)", toChars()); + error("invalid array operation %s (possible missing [])", toChars()); return new ErrorExp(); } return this; @@ -12711,7 +12653,7 @@ Expression *ModExp::semantic(Scope *sc) { if (!isArrayOpValid(this)) { - error("invalid array operation %s (did you forget a [] ?)", toChars()); + error("invalid array operation %s (possible missing [])", toChars()); return new ErrorExp(); } return this; @@ -12786,7 +12728,7 @@ Expression *PowExp::semantic(Scope *sc) { if (!isArrayOpValid(this)) { - error("invalid array operation %s (did you forget a [] ?)", toChars()); + error("invalid array operation %s (possible missing [])", toChars()); return new ErrorExp(); } return this; @@ -12996,7 +12938,7 @@ Expression *AndExp::semantic(Scope *sc) { if (!isArrayOpValid(this)) { - error("invalid array operation %s (did you forget a [] ?)", toChars()); + error("invalid array operation %s (possible missing [])", toChars()); return new ErrorExp(); } return this; @@ -13045,7 +12987,7 @@ Expression *OrExp::semantic(Scope *sc) { if (!isArrayOpValid(this)) { - error("invalid array operation %s (did you forget a [] ?)", toChars()); + error("invalid array operation %s (possible missing [])", toChars()); return new ErrorExp(); } return this; @@ -13094,7 +13036,7 @@ Expression *XorExp::semantic(Scope *sc) { if (!isArrayOpValid(this)) { - error("invalid array operation %s (did you forget a [] ?)", toChars()); + error("invalid array operation %s (possible missing [])", toChars()); return new ErrorExp(); } return this; @@ -13127,7 +13069,7 @@ Expression *OrOrExp::semantic(Scope *sc) e1 = e1->checkToBoolean(sc); unsigned cs1 = sc->callSuper; - if (sc->flags & SCOPEstaticif) + if (sc->flags & SCOPEcondition) { /* If in static if, don't evaluate e2 if we don't have to. */ @@ -13185,7 +13127,7 @@ Expression *AndAndExp::semantic(Scope *sc) e1 = e1->checkToBoolean(sc); unsigned cs1 = sc->callSuper; - if (sc->flags & SCOPEstaticif) + if (sc->flags & SCOPEcondition) { /* If in static if, don't evaluate e2 if we don't have to. */ @@ -13333,14 +13275,6 @@ Expression *CmpExp::semantic(Scope *sc) return e; } - /* Disallow comparing T[]==T and T==T[] - */ - if (e1->op == TOKslice && t1->ty == Tarray && e2->implicitConvTo(t1->nextOf()) || - e2->op == TOKslice && t2->ty == Tarray && e1->implicitConvTo(t2->nextOf())) - { - return incompatibleTypes(); - } - if (Expression *ex = typeCombine(this, sc)) return ex; @@ -13419,18 +13353,18 @@ Expression *CmpExp::semantic(Scope *sc) if (altop == TOKerror) { const char *s = op == TOKunord ? "false" : "true"; - warning("floating point operator '%s' always returns %s for non-floating comparisons", + deprecation("floating point operator '%s' always returns %s for non-floating comparisons", Token::toChars(op), s); } else { - warning("use '%s' for non-floating comparisons rather than floating point operator '%s'", + deprecation("use '%s' for non-floating comparisons rather than floating point operator '%s'", Token::toChars(altop), Token::toChars(op)); } } else { - warning("use std.math.isNaN to deal with NaN operands rather than floating point operator '%s'", + deprecation("use std.math.isNaN to deal with NaN operands rather than floating point operator '%s'", Token::toChars(op)); } } @@ -13551,14 +13485,6 @@ Expression *EqualExp::semantic(Scope *sc) return e; } - /* Disallow comparing T[]==T and T==T[] - */ - if (e1->op == TOKslice && t1->ty == Tarray && e2->implicitConvTo(t1->nextOf()) || - e2->op == TOKslice && t2->ty == Tarray && e1->implicitConvTo(t2->nextOf())) - { - return incompatibleTypes(); - } - if (t1->ty == Tstruct && t2->ty == Tstruct) { StructDeclaration *sd = ((TypeStruct *)t1)->sym; @@ -13685,7 +13611,6 @@ Expression *CondExp::syntaxCopy() return new CondExp(loc, econd->syntaxCopy(), e1->syntaxCopy(), e2->syntaxCopy()); } - Expression *CondExp::semantic(Scope *sc) { #if LOGSEMANTIC @@ -13777,11 +13702,10 @@ int CondExp::isLvalue() Expression *CondExp::toLvalue(Scope *sc, Expression *ex) { // convert (econd ? e1 : e2) to *(econd ? &e1 : &e2) - PtrExp *e = new PtrExp(loc, this, type); - e1 = e1->toLvalue(sc, NULL)->addressOf(); - e2 = e2->toLvalue(sc, NULL)->addressOf(); - type = e2->type; - return e; + CondExp *e = (CondExp *)copy(); + e->e1 = e1->toLvalue(sc, NULL)->addressOf(); + e->e2 = e2->toLvalue(sc, NULL)->addressOf(); + return new PtrExp(loc, e, type); } int CondExp::checkModifiable(Scope *sc, int flag) @@ -13970,6 +13894,8 @@ Expression *PrettyFuncInitExp::resolveLoc(Loc loc, Scope *sc) return e; } +/****************************************************************/ + Expression *extractOpDollarSideEffect(Scope *sc, UnaExp *ue) { Expression *e0; diff --git a/dmd2/expression.h b/dmd2/expression.h index ed4190c5ad..92887940be 100644 --- a/dmd2/expression.h +++ b/dmd2/expression.h @@ -40,7 +40,6 @@ class StructDeclaration; class TemplateInstance; class TemplateDeclaration; class ClassDeclaration; -struct HdrGenState; class BinExp; struct InterState; #if IN_DMD @@ -58,20 +57,6 @@ class SymbolDeclaration; enum TOK; -#if IN_DMD -// Back end -struct IRState; -struct dt_t; -#endif - -#ifdef IN_GCC -typedef union tree_node elem; -#elif IN_LLVM -class DValue; typedef class DValue elem; -#else -struct elem; -#endif - #if IN_LLVM struct IRState; namespace llvm { @@ -87,8 +72,6 @@ Expression *resolvePropertiesOnly(Scope *sc, Expression *e1); void accessCheck(Loc loc, Scope *sc, Expression *e, Declaration *d); Expression *build_overload(Loc loc, Scope *sc, Expression *ethis, Expression *earg, Dsymbol *d); Dsymbol *search_function(ScopeDsymbol *ad, Identifier *funcid); -void argExpTypesToCBuffer(OutBuffer *buf, Expressions *arguments, HdrGenState *hgs); -void argsToCBuffer(OutBuffer *buf, Expressions *arguments, HdrGenState *hgs); void expandTuples(Expressions *exps); TupleDeclaration *isAliasThisTuple(Expression *e); int expandAliasThisTuples(Expressions *exps, size_t starti = 0); @@ -111,18 +94,19 @@ int isConst(Expression *e); Expression *toDelegate(Expression *e, Scope *sc); AggregateDeclaration *isAggregate(Type *t); IntRange getIntRange(Expression *e); -bool isArrayOperand(Expression *e); +bool checkNonAssignmentArrayOp(Expression *e, bool suggestion = false); +bool isUnaArrayOp(TOK op); +bool isBinArrayOp(TOK op); +bool isBinAssignArrayOp(TOK op); +bool isArrayOpOperand(Expression *e); Expression *arrayOp(BinExp *e, Scope *sc); Expression *arrayOp(BinAssignExp *e, Scope *sc); bool hasSideEffect(Expression *e); bool canThrow(Expression *e, FuncDeclaration *func, bool mustNotThrow); Expression *Expression_optimize(Expression *e, int result, bool keepLvalue); -dt_t **Expression_toDt(Expression *e, dt_t **pdt); -elem *toElem(Expression *e, IRState *irs); MATCH implicitConvTo(Expression *e, Type *t); Expression *implicitCastTo(Expression *e, Scope *sc, Type *t); Expression *castTo(Expression *e, Scope *sc, Type *t); -void toCBuffer(Expression *e, OutBuffer *buf, HdrGenState *hgs); Expression *ctfeInterpret(Expression *); Expression *inlineCopy(Expression *e, Scope *sc); Expression *op_overload(Expression *e, Scope *sc); @@ -196,11 +180,6 @@ public: virtual real_t toImaginary(); virtual complex_t toComplex(); virtual StringExp *toStringExp(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs) - { - ::toCBuffer(this, buf, hgs); - } - virtual void toMangleBuffer(OutBuffer *buf); virtual int isLvalue(); virtual Expression *toLvalue(Scope *sc, Expression *e); virtual Expression *modifiableLvalue(Scope *sc, Expression *e); @@ -260,11 +239,6 @@ public: return ::op_overload(this, sc); } -#if IN_DMD - // Back end - elem *toElem(IRState *irs) { return ::toElem(this, irs); } - dt_t **toDt(dt_t **pdt) { return ::Expression_toDt(this, pdt); } -#endif virtual void accept(Visitor *v) { v->visit(this); } #if IN_LLVM llvm::Value* cachedLvalue; @@ -273,21 +247,18 @@ public: class IntegerExp : public Expression { -private: +public: dinteger_t value; -public: IntegerExp(Loc loc, dinteger_t value, Type *type); IntegerExp(dinteger_t value); bool equals(RootObject *o); Expression *semantic(Scope *sc); - char *toChars(); dinteger_t toInteger(); real_t toReal(); real_t toImaginary(); complex_t toComplex(); int isBool(int result); - void toMangleBuffer(OutBuffer *buf); Expression *toLvalue(Scope *sc, Expression *e); void accept(Visitor *v) { v->visit(this); } dinteger_t getInteger() { return value; } @@ -314,14 +285,12 @@ public: RealExp(Loc loc, real_t value, Type *type); bool equals(RootObject *o); Expression *semantic(Scope *sc); - char *toChars(); dinteger_t toInteger(); uinteger_t toUInteger(); real_t toReal(); real_t toImaginary(); complex_t toComplex(); int isBool(int result); - void toMangleBuffer(OutBuffer *buf); void accept(Visitor *v) { v->visit(this); } }; @@ -333,14 +302,12 @@ public: ComplexExp(Loc loc, complex_t value, Type *type); bool equals(RootObject *o); Expression *semantic(Scope *sc); - char *toChars(); dinteger_t toInteger(); uinteger_t toUInteger(); real_t toReal(); real_t toImaginary(); complex_t toComplex(); int isBool(int result); - void toMangleBuffer(OutBuffer *buf); void accept(Visitor *v) { v->visit(this); } }; @@ -353,7 +320,6 @@ public: IdentifierExp(Loc loc, Identifier *ident); static IdentifierExp *create(Loc loc, Identifier *ident); Expression *semantic(Scope *sc); - char *toChars(); int isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); void accept(Visitor *v) { v->visit(this); } @@ -374,7 +340,6 @@ public: DsymbolExp(Loc loc, Dsymbol *s, bool hasOverloads = false); Expression *semantic(Scope *sc); - char *toChars(); int isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); void accept(Visitor *v) { v->visit(this); } @@ -390,7 +355,6 @@ public: int isBool(int result); int isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); - Expression *modifiableLvalue(Scope *sc, Expression *e); void accept(Visitor *v) { v->visit(this); } }; @@ -414,7 +378,6 @@ public: Expression *semantic(Scope *sc); int isBool(int result); StringExp *toStringExp(); - void toMangleBuffer(OutBuffer *buf); void accept(Visitor *v) { v->visit(this); } }; @@ -432,7 +395,6 @@ public: StringExp(Loc loc, void *s, size_t len); StringExp(Loc loc, void *s, size_t len, utf8_t postfix); static StringExp *create(Loc loc, char *s); - //Expression *syntaxCopy(); bool equals(RootObject *o); Expression *semantic(Scope *sc); size_t length(); @@ -444,7 +406,6 @@ public: Expression *toLvalue(Scope *sc, Expression *e); Expression *modifiableLvalue(Scope *sc, Expression *e); unsigned charAt(uinteger_t i); - void toMangleBuffer(OutBuffer *buf); void accept(Visitor *v) { v->visit(this); } }; @@ -488,7 +449,6 @@ public: Expression *semantic(Scope *sc); int isBool(int result); StringExp *toStringExp(); - void toMangleBuffer(OutBuffer *buf); void accept(Visitor *v) { v->visit(this); } }; @@ -505,7 +465,6 @@ public: Expression *syntaxCopy(); Expression *semantic(Scope *sc); int isBool(int result); - void toMangleBuffer(OutBuffer *buf); void accept(Visitor *v) { v->visit(this); } }; @@ -561,7 +520,6 @@ public: Expression *semantic(Scope *sc); Expression *getField(Type *type, unsigned offset); int getFieldIndex(Type *type, unsigned offset); - void toMangleBuffer(OutBuffer *buf); Expression *addDtorHook(Scope *sc); #if IN_LLVM // With the introduction of pointers returned from CTFE, struct literals can @@ -632,6 +590,8 @@ public: Type *newtype; Expressions *arguments; // Array of Expression's + Expression *argprefix; // expression to be evaluated just before arguments[] + CtorDeclaration *member; // constructor function NewDeclaration *allocator; // allocator function int onstack; // allocate on stack @@ -696,7 +656,6 @@ public: static VarExp *create(Loc loc, Declaration *var, bool hasOverloads = false); bool equals(RootObject *o); Expression *semantic(Scope *sc); - char *toChars(); void checkEscape(); void checkEscapeRef(); int checkModifiable(Scope *sc, int flag); @@ -1630,17 +1589,46 @@ public: /****************************************************************/ +/* A type meant as a union of all the Expression types, + * to serve essentially as a Variant that will sit on the stack + * during CTFE to reduce memory consumption. + */ +struct UnionExp +{ + /* Extract pointer to Expression + */ + Expression *exp() { return (Expression *)&u; } + + /* Convert to an allocated Expression + */ + Expression *copy() + { + Expression *e = exp(); + assert(e->size <= sizeof(u)); + return e->copy(); + } + + private: + union U + { + char exp [sizeof(Expression)]; + char integerexp[sizeof(IntegerExp)]; + char errorexp [sizeof(ErrorExp)]; + char realexp [sizeof(RealExp)]; + char complexexp[sizeof(ComplexExp)]; + }; + U u; +}; + +/****************************************************************/ + /* Special values used by the interpreter */ extern Expression *EXP_CANT_INTERPRET; -extern Expression *EXP_CONTINUE_INTERPRET; -extern Expression *EXP_BREAK_INTERPRET; -extern Expression *EXP_GOTO_INTERPRET; -extern Expression *EXP_VOID_INTERPRET; Expression *expType(Type *type, Expression *e); -Expression *Neg(Type *type, Expression *e1); +UnionExp Neg(Type *type, Expression *e1); Expression *Com(Type *type, Expression *e1); Expression *Not(Type *type, Expression *e1); Expression *Bool(Type *type, Expression *e1); diff --git a/dmd2/func.c b/dmd2/func.c index 0fa1a75beb..7bd33119b3 100644 --- a/dmd2/func.c +++ b/dmd2/func.c @@ -31,9 +31,9 @@ #include "rmem.h" #include "visitor.h" -void functionToBufferWithIdent(TypeFunction *t, OutBuffer *buf, const char *ident); +Expression *addInvariant(Scope *sc, AggregateDeclaration *ad, VarDeclaration *vthis, bool direct); + void genCmain(Scope *sc); -void toBufferShort(Type *t, OutBuffer *buf, HdrGenState *hgs); /* A visitor to walk entire statements and provides ability to replace any sub-statements. */ @@ -43,8 +43,8 @@ class StatementRewriteWalker : public Visitor * By using replaceCurrent() method, you can replace AST during walking. */ Statement **ps; - void visitStmt(Statement *&s) { ps = &s; s->accept(this); } public: + void visitStmt(Statement *&s) { ps = &s; s->accept(this); } void replaceCurrent(Statement *s) { *ps = s; } void visit(ErrorStatement *s) { } @@ -208,28 +208,22 @@ public: void visit(ReturnStatement *s) { - Expression *exp = s->exp; - if (exp) + // See if all returns are instead to be replaced with a goto returnLabel; + if (fd->returnLabel) { - TypeFunction *tf = (TypeFunction *)fd->type; - - /* Bugzilla 10789: - * If NRVO is not possible, all returned lvalues should call their postblits. + /* Rewrite: + * return exp; + * as: + * vresult = exp; goto Lresult; */ - if (!fd->nrvo_can && !tf->isref && exp->isLvalue()) - exp = callCpCtor(sc, exp); + GotoStatement *gs = new GotoStatement(s->loc, Id::returnLabel); + gs->label = fd->returnLabel; - /* Bugzilla 8665: - * If auto function has multiple return statements, returned values - * should be fixed to the determined return type. - */ - if (!fd->tintro && !tf->next->immutableOf()->equals(exp->type->immutableOf())) - { - exp = exp->castTo(sc, tf->next); - exp = exp->optimize(WANTvalue); - } + Statement *s1 = gs; + if (s->exp) + s1 = new CompoundStatement(s->loc, new ExpStatement(s->loc, s->exp), gs); - s->exp = exp; + replaceCurrent(s1); } } void visit(TryFinallyStatement *s) @@ -305,7 +299,6 @@ FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, StorageCla outId = NULL; vresult = NULL; returnLabel = NULL; - scout = NULL; fensure = NULL; fbody = NULL; localsymtab = NULL; @@ -322,7 +315,7 @@ FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, StorageCla overnext0 = NULL; vtblIndex = -1; hasReturnExp = 0; - naked = 0; + naked = false; inlineStatusExp = ILSuninitialized; inlineStatusStmt = ILSuninitialized; inlineNest = 0; @@ -347,6 +340,7 @@ FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, StorageCla tookAddressOf = 0; requiresClosure = false; flags = 0; + returns = NULL; gotos = NULL; #if IN_LLVM @@ -359,13 +353,10 @@ FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, StorageCla Dsymbol *FuncDeclaration::syntaxCopy(Dsymbol *s) { - FuncDeclaration *f; - //printf("FuncDeclaration::syntaxCopy('%s')\n", toChars()); - if (s) - f = (FuncDeclaration *)s; - else - f = new FuncDeclaration(loc, endloc, ident, storage_class, type->syntaxCopy()); + FuncDeclaration *f = + s ? (FuncDeclaration *)s + : new FuncDeclaration(loc, endloc, ident, storage_class, type->syntaxCopy()); f->outId = outId; f->frequire = frequire ? frequire->syntaxCopy() : NULL; f->fensure = fensure ? fensure->syntaxCopy() : NULL; @@ -490,27 +481,49 @@ void FuncDeclaration::semantic(Scope *sc) sc = sc->push(); sc->stc |= storage_class & (STCdisable | STCdeprecated); // forward to function type TypeFunction *tf = (TypeFunction *)type; -#if 1 - /* If the parent is @safe, then this function defaults to safe - * too. - * If the parent's @safe-ty is inferred, then this function's @safe-ty needs - * to be inferred first. - */ - if (tf->trust == TRUSTdefault && - !isInstantiated()) + + if (sc->func) { - for (Dsymbol *p = sc->func; p; p = p->toParent2()) + /* If the parent is @safe, then this function defaults to safe too. + */ + if (tf->trust == TRUSTdefault) { - FuncDeclaration *fd = p->isFuncDeclaration(); - if (fd) + FuncDeclaration *fd = sc->func; + + /* If the parent's @safe-ty is inferred, then this function's @safe-ty needs + * to be inferred first. + * If this function's @safe-ty is inferred, then it needs to be infeerd first. + * (local template function inside @safe function can be inferred to @system). + */ + if (fd->isSafeBypassingInference() && !isInstantiated()) + tf->trust = TRUSTsafe; // default to @safe + } + + /* If the nesting parent is pure, then this function defaults to pure too. + */ + if (tf->purity == PUREimpure && (isNested() || isThis())) + { + FuncDeclaration *fd = NULL; + for (Dsymbol *p = toParent2(); p; p = p->toParent2()) { - if (fd->isSafeBypassingInference()) - tf->trust = TRUSTsafe; // default to @safe - break; + if (AggregateDeclaration *ad = p->isAggregateDeclaration()) + { + if (ad->isNested()) + continue; + break; + } + if ((fd = p->isFuncDeclaration()) != NULL) + break; } + + /* If the parent's purity is inferred, then this function's purity needs + * to be inferred first. + */ + if (fd && fd->isPureBypassingInferenceX()) + tf->purity = PUREfwdref; // default to pure } } -#endif + if (tf->isref) sc->stc |= STCref; if (tf->isnothrow) sc->stc |= STCnothrow; if (tf->isnogc) sc->stc |= STCnogc; @@ -657,8 +670,8 @@ void FuncDeclaration::semantic(Scope *sc) const char *sfunc; if (isStatic()) sfunc = "static"; - else if (protection == PROTprivate || protection == PROTpackage) - sfunc = protectionToChars(protection); + else if (protection.kind == PROTprivate || protection.kind == PROTpackage) + sfunc = protectionToChars(protection.kind); else sfunc = "non-virtual"; error("%s functions cannot be abstract", sfunc); @@ -666,8 +679,9 @@ void FuncDeclaration::semantic(Scope *sc) if (isOverride() && !isVirtual()) { - if ((prot() == PROTprivate || prot() == PROTpackage) && isMember()) - error("%s method is not virtual and cannot override", protectionToChars(prot())); + PROTKIND kind = prot().kind; + if ((kind == PROTprivate || kind == PROTpackage) && isMember()) + error("%s method is not virtual and cannot override", protectionToChars(kind)); else error("cannot override a non-virtual function"); } @@ -792,7 +806,7 @@ void FuncDeclaration::semantic(Scope *sc) if (f2) { f2 = f2->overloadExactMatch(type); - if (f2 && f2->isFinalFunc() && f2->prot() != PROTprivate) + if (f2 && f2->isFinalFunc() && f2->prot().kind != PROTprivate) error("cannot override final function %s", f2->toPrettyChars()); } } @@ -1031,7 +1045,7 @@ void FuncDeclaration::semantic(Scope *sc) if (f2) { f2 = f2->overloadExactMatch(type); - if (f2 && f2->isFinalFunc() && f2->prot() != PROTprivate) + if (f2 && f2->isFinalFunc() && f2->prot().kind != PROTprivate) error("cannot override final function %s.%s", b->base->toChars(), f2->toPrettyChars()); } } @@ -1280,7 +1294,6 @@ void FuncDeclaration::semantic2(Scope *sc) void FuncDeclaration::semantic3(Scope *sc) { - TypeFunction *f; VarDeclaration *argptr = NULL; VarDeclaration *_arguments = NULL; int nerrors = global.errors; @@ -1306,11 +1319,11 @@ void FuncDeclaration::semantic3(Scope *sc) if (!type || type->ty != Tfunction) return; - f = (TypeFunction *)type; + TypeFunction *f = (TypeFunction *)type; if (!inferRetType && f->next->ty == Terror) return; - if (!fbody && inferRetType && !type->nextOf()) + if (!fbody && inferRetType && !f->next) { error("has no function body with return type inference"); return; @@ -1356,7 +1369,7 @@ void FuncDeclaration::semantic3(Scope *sc) STCdeprecated | STCoverride | STC_TYPECTOR | STCfinal | STCtls | STCgshared | STCref | STCproperty | STCnothrow | STCpure | STCsafe | STCtrusted | STCsystem); - sc2->protection = PROTpublic; + sc2->protection = Prot(PROTpublic); sc2->explicitProtection = 0; sc2->structalign = STRUCTALIGN_DEFAULT; if (this->ident != Id::require && this->ident != Id::ensure) @@ -1579,70 +1592,7 @@ void FuncDeclaration::semantic3(Scope *sc) Statement *fpreinv = NULL; if (addPreInvariant()) { - Expression *e = NULL; - if (isDtorDeclaration()) - { - // Call invariant directly only if it exists - FuncDeclaration *inv = ad->inv; - ClassDeclaration *cd = ad->isClassDeclaration(); - - while (!inv && cd) - { - cd = cd->baseClass; - if (!cd) - break; - inv = cd->inv; - } - if (inv) - { - #if 1 - // Workaround for bugzilla 13394: For the correct mangling, - // run attribute inference on inv if needed. - inv->functionSemantic(); - #endif - - //e = new DsymbolExp(Loc(), inv); - //e = new CallExp(Loc(), e); - //e = e->semantic(sc2); - - /* Bugzilla 13113: Currently virtual invariant calls completely - * bypass attribute enforcement. - * Change the behavior of pre-invariant call by following it. - */ - e = new ThisExp(Loc()); - e->type = vthis->type; - e = new DotVarExp(Loc(), e, inv, 0); - e->type = inv->type; - e = new CallExp(Loc(), e); - e->type = Type::tvoid; - } - } - else - { - #if 1 - // Workaround for bugzilla 13394: For the correct mangling, - // run attribute inference on inv if needed. - if (ad->isStructDeclaration() && ad->inv) - ad->inv->functionSemantic(); - #endif - - // Call invariant virtually -#if IN_LLVM - // We actually need a valid 'var' for codegen. - ThisExp* tv = new ThisExp(Loc()); - tv->var = vthis; - Expression *v = tv; -#else - Expression *v = new ThisExp(Loc()); -#endif - v->type = vthis->type; - if (ad->isStructDeclaration()) - v = v->addressOf(); - Expression *se = new StringExp(Loc(), (char *)"null this"); - se = se->semantic(sc); - se->type = Type::tchar->arrayOf(); - e = new AssertExp(loc, v, se); - } + Expression *e = addInvariant(sc, ad, vthis, isDtorDeclaration()); if (e) fpreinv = new ExpStatement(Loc(), e); } @@ -1651,70 +1601,12 @@ void FuncDeclaration::semantic3(Scope *sc) Statement *fpostinv = NULL; if (addPostInvariant()) { - Expression *e = NULL; - if (isCtorDeclaration()) - { - // Call invariant directly only if it exists - FuncDeclaration *inv = ad->inv; - ClassDeclaration *cd = ad->isClassDeclaration(); - - while (!inv && cd) - { - cd = cd->baseClass; - if (!cd) - break; - inv = cd->inv; - } - if (inv) - { - #if 1 - // Workaround for bugzilla 13394: For the correct mangling, - // run attribute inference on inv if needed. - inv->functionSemantic(); - #endif - - //e = new DsymbolExp(Loc(), inv); - //e = new CallExp(Loc(), e); - //e = e->semantic(sc2); - - /* Bugzilla 13113: As same as pre-invariant in destructor, - * change the behavior of post-invariant call. - */ - e = new ThisExp(Loc()); - e->type = vthis->type; - e = new DotVarExp(Loc(), e, inv, 0); - e->type = inv->type; - e = new CallExp(Loc(), e); - e->type = Type::tvoid; - } - } - else - { - #if 1 - // Workaround for bugzilla 13394: For the correct mangling, - // run attribute inference on inv if needed. - if (ad->isStructDeclaration() && ad->inv) - ad->inv->functionSemantic(); - #endif - - // Call invariant virtually -#if IN_LLVM - // We actually need a valid 'var' for codegen. - ThisExp* tv = new ThisExp(Loc()); - tv->var = vthis; - Expression *v = tv; -#else - Expression *v = new ThisExp(Loc()); -#endif - v->type = vthis->type; - if (ad->isStructDeclaration()) - v = v->addressOf(); - e = new AssertExp(Loc(), v); - } + Expression *e = addInvariant(sc, ad, vthis, isCtorDeclaration()); if (e) fpostinv = new ExpStatement(Loc(), e); } + Scope *scout = NULL; if (fensure || addPostInvariant()) { if ((fensure && global.params.useOut) || fpostinv) @@ -1755,29 +1647,46 @@ void FuncDeclaration::semantic3(Scope *sc) if (!inferRetType && retStyle(f) != RETstack) nrvo_can = 0; + bool inferRef = (f->isref && (storage_class & STCauto)); + fbody = fbody->semantic(sc2); if (!fbody) fbody = new CompoundStatement(Loc(), new Statements()); - if (inferRetType) - { - // If no return type inferred yet, then infer a void - if (!type->nextOf()) - { - f->next = Type::tvoid; - //type = type->semantic(loc, sc); // Removed with 6902 - } - } - if (f->next->ty != Tvoid) - { - NrvoWalker nw; - nw.fd = this; - nw.sc = sc2; - fbody->accept(&nw); - } assert(type == f); - if (isStaticCtorDeclaration()) + // If no return type inferred yet, then infer a void + if (inferRetType && !f->next) + f->next = Type::tvoid; + + if (returns && !fbody->isErrorStatement()) + { + for (size_t i = 0; i < returns->dim; ) + { + Expression *exp = (*returns)[i]->exp; + if (exp->op == TOKvar && ((VarExp *)exp)->var == vresult) + { + exp->type = f->next; + // Remove `return vresult;` from returns + returns->remove(i); + continue; + } + if (inferRef && f->isref && !exp->type->constConv(f->next)) // Bugzilla 13336 + f->isref = false; + i++; + } + } + if (f->isref) // Function returns a reference + { + if (storage_class & STCauto) + storage_class &= ~STCauto; + } + if (retStyle(f) != RETstack) + nrvo_can = 0; + + if (fbody->isErrorStatement()) + ; + else if (isStaticCtorDeclaration()) { /* It's a static constructor. Ensure that all * ctor consts were initialized. @@ -1798,9 +1707,6 @@ void FuncDeclaration::semantic3(Scope *sc) } } } - - if (fbody->isErrorStatement()) - ; else if (ad2 && isCtorDeclaration()) { ClassDeclaration *cd = ad2->isClassDeclaration(); @@ -1861,47 +1767,41 @@ void FuncDeclaration::semantic3(Scope *sc) fbody = new CompoundStatement(Loc(), s, fbody); } } + //printf("callSuper = x%x\n", sc2->callSuper); + } + int blockexit = BEnone; + if (!fbody->isErrorStatement()) + { // Check for errors related to 'nothrow'. unsigned int nothrowErrors = global.errors; - int blockexit = fbody->blockExit(this, f->isnothrow); - if (f->isnothrow && (global.errors != nothrowErrors) ) + blockexit = fbody->blockExit(this, f->isnothrow); + if (f->isnothrow && (global.errors != nothrowErrors)) ::error(loc, "%s '%s' is nothrow yet may throw", kind(), toPrettyChars()); if (flags & FUNCFLAGnothrowInprocess) { if (type == f) f = (TypeFunction *)f->copy(); f->isnothrow = !(blockexit & BEthrow); } - //printf("callSuper = x%x\n", sc2->callSuper); + } + if (fbody->isErrorStatement()) + ; + else if (ad2 && isCtorDeclaration()) + { /* 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); + Statement *s = new ReturnStatement(loc, NULL); s = s->semantic(sc2); fbody = new CompoundStatement(loc, fbody, s); } } else if (fes) { - // Check for errors related to 'nothrow'. - int nothrowErrors = global.errors; - int blockexit = fbody->blockExit(this, f->isnothrow); - if (f->isnothrow && (global.errors != nothrowErrors) ) - ::error(loc, "%s '%s' is nothrow yet may throw", kind(), toPrettyChars()); - if (flags & FUNCFLAGnothrowInprocess) - { - if (type == f) f = (TypeFunction *)f->copy(); - f->isnothrow = !(blockexit & BEthrow); - } - //printf("callSuper = x%x\n", sc2->callSuper); - // For foreach(){} body, append a return 0; if (blockexit & BEfallthru) { @@ -1911,29 +1811,16 @@ void FuncDeclaration::semantic3(Scope *sc) } assert(!returnLabel); } - else if (!hasReturnExp && type->nextOf()->ty != Tvoid) - error("has no return statement, but is expected to return a value of type %s", type->nextOf()->toChars()); - else if (hasReturnExp & 8) // if inline asm - { - flags &= ~FUNCFLAGnothrowInprocess; - } else { - // Check for errors related to 'nothrow'. - unsigned int nothrowErrors = global.errors; - int blockexit = fbody->blockExit(this, f->isnothrow); - if (f->isnothrow && (global.errors != nothrowErrors) ) - ::error(loc, "%s '%s' is nothrow yet may throw", kind(), toPrettyChars()); - if (flags & FUNCFLAGnothrowInprocess) - { - if (type == f) f = (TypeFunction *)f->copy(); - f->isnothrow = !(blockexit & BEthrow); - } - - if ((blockexit & BEfallthru) && type->nextOf()->ty != Tvoid) + const bool inlineAsm = (hasReturnExp & 8) != 0; + if ((blockexit & BEfallthru) && f->next->ty != Tvoid && !inlineAsm) { Expression *e; - error("no return exp; or assert(0); at end of function"); + if (!hasReturnExp) + error("has no return statement, but is expected to return a value of type %s", f->next->toChars()); + else + error("no return exp; or assert(0); at end of function"); if (global.params.useAssert && !global.params.useInline) { @@ -1948,13 +1835,89 @@ void FuncDeclaration::semantic3(Scope *sc) } else e = new HaltExp(endloc); - e = new CommaExp(Loc(), e, type->nextOf()->defaultInit()); + e = new CommaExp(Loc(), e, f->next->defaultInit()); e = e->semantic(sc2); Statement *s = new ExpStatement(Loc(), e); fbody = new CompoundStatement(Loc(), fbody, s); } } + if (returns && !fbody->isErrorStatement()) + { + bool implicit0 = (f->next->ty == Tvoid && isMain()); + Type *tret = implicit0 ? Type::tint32 : f->next; + assert(tret->ty != Tvoid); + if (vresult || returnLabel) + buildResultVar(scout ? scout : sc2, tret); + + /* Cannot move this loop into NrvoWalker, because + * returns[i] may be in the nested delegate for foreach-body. + */ + for (size_t i = 0; i < returns->dim; i++) + { + ReturnStatement *rs = (*returns)[i]; + Expression *exp = rs->exp; + + if (!exp->implicitConvTo(tret) && + parametersIntersect(exp->type)) + { + if (exp->type->immutableOf()->implicitConvTo(tret)) + exp = exp->castTo(sc2, exp->type->immutableOf()); + else if (exp->type->wildOf()->implicitConvTo(tret)) + exp = exp->castTo(sc2, exp->type->wildOf()); + } + exp = exp->implicitCastTo(sc2, tret); + + if (f->isref) + { + // Function returns a reference + exp = exp->toLvalue(sc2, exp); + exp->checkEscapeRef(); + } + else + { + exp = exp->optimize(WANTvalue); + + /* Bugzilla 10789: + * If NRVO is not possible, all returned lvalues should call their postblits. + */ + if (!nrvo_can && exp->isLvalue()) + exp = callCpCtor(sc2, exp); + + exp->checkEscape(); + } + + exp = checkGC(sc2, exp); + + if (vresult) + { + // Create: return vresult = exp; + VarExp *ve = new VarExp(Loc(), vresult); + ve->type = vresult->type; + if (f->isref) + exp = new ConstructExp(rs->loc, ve, exp); + else + exp = new BlitExp(rs->loc, ve, exp); + exp->type = ve->type; + + if (rs->caseDim) + exp = Expression::combine(exp, new IntegerExp(rs->caseDim)); + } + else if (tintro && !tret->equals(tintro->nextOf())) + { + exp = exp->implicitCastTo(sc2, tintro->nextOf()); + } + rs->exp = exp; + } + } + if (nrvo_var || returnLabel) + { + NrvoWalker nw; + nw.fd = this; + nw.sc = sc2; + nw.visitStmt(fbody); + } + if (fieldinit) mem.free(fieldinit); sc2 = sc2->pop(); @@ -1991,13 +1954,11 @@ void FuncDeclaration::semantic3(Scope *sc) { /* fensure is composed of the [out] contracts */ - if (type->nextOf()->ty == Tvoid && outId) - { + if (f->next->ty == Tvoid && outId) error("void functions have no result"); - } - if (type->nextOf()->ty != Tvoid) - buildResultVar(); + if (fensure && f->next->ty != Tvoid) + buildResultVar(scout, f->next); sc2 = scout; //push sc2->flags = (sc2->flags & ~SCOPEcontract) | SCOPEensure; @@ -2008,7 +1969,7 @@ void FuncDeclaration::semantic3(Scope *sc) { // Return type was unknown in the first semantic pass Parameter *p = (*((TypeFunction *)fdensure->type)->parameters)[0]; - p->type = ((TypeFunction *)type)->nextOf(); + p->type = f->next; } fens = fens->semantic(sc2); @@ -2175,7 +2136,7 @@ void FuncDeclaration::semantic3(Scope *sc) returnLabel->statement = ls; a->push(returnLabel->statement); - if (type->nextOf()->ty != Tvoid && vresult) + if (f->next->ty != Tvoid && vresult) { #if IN_LLVM Expression *e = 0; @@ -2200,7 +2161,7 @@ void FuncDeclaration::semantic3(Scope *sc) a->push(s); } } - if (isMain() && type->nextOf()->ty == Tvoid) + if (isMain() && f->next->ty == Tvoid) { // Add a return 0; statement Statement *s = new ReturnStatement(Loc(), new IntegerExp(0)); @@ -2299,6 +2260,9 @@ void FuncDeclaration::semantic3(Scope *sc) } } + if (naked && (fensure || frequire)) + error("naked assembly functions with contracts are not supported"); + sc2->callSuper = 0; sc2->pop(); } @@ -2431,36 +2395,6 @@ bool FuncDeclaration::functionSemantic3() 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); - if (hgs->hdrgen == 1) - { - if (storage_class & STCauto) - { - hgs->autoMember++; - bodyToCBuffer(buf, hgs); - hgs->autoMember--; - } - else if(hgs->tpltMember == 0 && -#if IN_LLVM - !global.params.hdrKeepAllBodies -#else - global.params.useInline -#endif - ) - buf->writestring(";"); - else - bodyToCBuffer(buf, hgs); - } - else - bodyToCBuffer(buf, hgs); - buf->writenl(); -} - VarDeclaration *FuncDeclaration::declareThis(Scope *sc, AggregateDeclaration *ad) { if (ad && !isFuncLiteralDeclaration()) @@ -2534,108 +2468,47 @@ bool FuncDeclaration::equals(RootObject *o) return false; } -void FuncDeclaration::bodyToCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (fbody && (!hgs->hdrgen || -#if IN_LLVM - global.params.hdrKeepAllBodies || -#else - global.params.useInline || -#endif - 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->writenl(); - ::toCBuffer(frequire, buf, hgs); - } - - // out{} - if (fensure) - { - buf->writestring("out"); - if (outId) - { - buf->writeByte('('); - buf->writestring(outId->toChars()); - buf->writeByte(')'); - } - buf->writenl(); - ::toCBuffer(fensure, buf, hgs); - } - - if (frequire || fensure) - { - buf->writestring("body"); - buf->writenl(); - } - - buf->writeByte('{'); - buf->writenl(); - buf->level++; - ::toCBuffer(fbody, buf, hgs); - buf->level--; - buf->writeByte('}'); - buf->writenl(); - - hgs->tpltMember = savetlpt; - hgs->autoMember = saveauto; - } - else - { - buf->writeByte(';'); - buf->writenl(); - } -} - /**************************************************** * Declare result variable lazily. */ -void FuncDeclaration::buildResultVar() +void FuncDeclaration::buildResultVar(Scope *sc, Type *tret) { - if (vresult) - return; - - assert(type->nextOf()); - assert(type->nextOf()->toBasetype()->ty != Tvoid); - TypeFunction *tf = (TypeFunction *)type; - - Loc loc = this->loc; - - if (fensure) - loc = fensure->loc; - - if (!outId) - outId = Id::result; // provide a default - - VarDeclaration *v = new VarDeclaration(loc, type->nextOf(), outId, NULL); - if (outId == Id::result) v->storage_class |= STCtemp; - v->noscope = 1; - v->storage_class |= STCresult; - if (!isVirtual()) - v->storage_class |= STCconst; - if (tf->isref) + if (!vresult) { - v->storage_class |= STCref | STCforeach; - } - v->semantic(scout); - if (!scout->insert(v)) - error("out result %s is already defined", v->toChars()); - v->parent = this; - vresult = v; + Loc loc = fensure ? fensure->loc : loc; - // vresult gets initialized with the function return value - // in ReturnStatement::semantic() + /* If inferRetType is true, tret may not be a correct return type yet. + * So, in here it may be a temporary type for vresult, and after + * fbody->semantic() running, vresult->type might be modified. + */ + vresult = new VarDeclaration(loc, tret, outId ? outId : Id::result, NULL); + vresult->noscope = true; + + if (outId == Id::result) + vresult->storage_class |= STCtemp; + if (!isVirtual()) + vresult->storage_class |= STCconst; + vresult->storage_class |= STCresult; + + // set before the semantic() for checkNestedReference() + vresult->parent = this; + } + + if (sc && vresult->sem == SemanticStart) + { + assert(type->ty == Tfunction); + TypeFunction *tf = (TypeFunction *)type; + if (tf->isref) + vresult->storage_class |= STCref | STCforeach; + vresult->type = tret; + + vresult->semantic(sc); + + if (!sc->insert(vresult)) + error("out result %s is already defined", vresult->toChars()); + assert(vresult->parent == this); + } } /**************************************************** @@ -3377,12 +3250,14 @@ struct FuncCandidateWalker static int fp(void *param, Dsymbol *s) { FuncDeclaration *f = s->isFuncDeclaration(); - if (!f) return 0; + if (!f || f->errors || f->type->ty == Terror) + return 0; FuncCandidateWalker *p = (FuncCandidateWalker *)param; + TypeFunction *tf = (TypeFunction *)f->type; ::errorSupplemental(f->loc, "%s%s", f->toPrettyChars(), - Parameter::argsTypesToChars(((TypeFunction *)f->type)->parameters, ((TypeFunction *)f->type)->varargs)); + parametersTypeToChars(tf->parameters, tf->varargs)); if (!global.params.verbose && --(p->numToDisplay) == 0 && f->overnext) { @@ -3475,26 +3350,17 @@ FuncDeclaration *resolveFuncCall(Loc loc, Scope *sc, Dsymbol *s, return NULL; // no match } - HdrGenState hgs; - FuncDeclaration *fd = s->isFuncDeclaration(); TemplateDeclaration *td = s->isTemplateDeclaration(); if (td && td->funcroot) s = fd = td->funcroot; OutBuffer tiargsBuf; - size_t dim = tiargs ? tiargs->dim : 0; - for (size_t i = 0; i < dim; i++) - { - if (i) - tiargsBuf.writestring(", "); - RootObject *oarg = (*tiargs)[i]; - ObjectToCBuffer(&tiargsBuf, &hgs, oarg); - } + arrayObjectsToBuffer(&tiargsBuf, tiargs); OutBuffer fargsBuf; fargsBuf.writeByte('('); - argExpTypesToCBuffer(&fargsBuf, fargs, &hgs); + argExpTypesToCBuffer(&fargsBuf, fargs); fargsBuf.writeByte(')'); if (tthis) tthis->modToBuffer(&fargsBuf); @@ -3541,7 +3407,7 @@ FuncDeclaration *resolveFuncCall(Loc loc, Scope *sc, Dsymbol *s, fd->ident->toChars(), fargsBuf.peekString()); else fd->error(loc, "%s%s is not callable using argument types %s", - Parameter::argsTypesToChars(tf->parameters, tf->varargs), + parametersTypeToChars(tf->parameters, tf->varargs), tf->modToChars(), fargsBuf.peekString()); } @@ -3560,8 +3426,8 @@ FuncDeclaration *resolveFuncCall(Loc loc, Scope *sc, Dsymbol *s, { TypeFunction *tf1 = (TypeFunction *)m.lastf->type; TypeFunction *tf2 = (TypeFunction *)m.nextf->type; - const char *lastprms = Parameter::argsTypesToChars(tf1->parameters, tf1->varargs); - const char *nextprms = Parameter::argsTypesToChars(tf2->parameters, tf2->varargs); + const char *lastprms = parametersTypeToChars(tf1->parameters, tf1->varargs); + const char *nextprms = parametersTypeToChars(tf2->parameters, tf2->varargs); ::error(loc, "%s.%s called with argument types %s matches both:\n" "%s: %s%s\nand:\n%s: %s%s", s->parent->toPrettyChars(), s->ident->toChars(), @@ -3691,7 +3557,7 @@ int FuncDeclaration::getLevel(Loc loc, Scope *sc, FuncDeclaration *fd) Lerr: // Don't give error if in template constraint - if (!(sc->flags & SCOPEstaticif)) + if (!(sc->flags & SCOPEconstraint)) { const char *xstatic = isStatic() ? "static " : ""; // better diagnostics for static functions @@ -3701,32 +3567,6 @@ Lerr: return 1; } -void FuncDeclaration::appendExp(Expression *e) -{ Statement *s; - - s = new ExpStatement(Loc(), e); - appendState(s); -} - -void FuncDeclaration::appendState(Statement *s) -{ - if (!fbody) - fbody = s; - else - { - CompoundStatement *cs = fbody->isCompoundStatement(); - if (cs) - { - if (!cs->statements) - fbody = s; - else - cs->statements->push(s); - } - else - fbody = new CompoundStatement(Loc(), fbody, s); - } -} - const char *FuncDeclaration::toPrettyChars(bool QualifyTypes) { if (isMain()) @@ -3771,14 +3611,14 @@ bool FuncDeclaration::isDllMain() bool FuncDeclaration::isExport() { - return protection == PROTexport; + return protection.kind == PROTexport; } bool FuncDeclaration::isImportedSymbol() { //printf("isImportedSymbol()\n"); //printf("protection = %d\n", protection); - return (protection == PROTexport) && !fbody; + return (protection.kind == PROTexport) && !fbody; } // Determine if function goes into virtual function pointer table @@ -3799,7 +3639,7 @@ bool FuncDeclaration::isVirtual() !(p->isInterfaceDeclaration() && isFinalFunc())); #endif return isMember() && - !(isStatic() || protection == PROTprivate || protection == PROTpackage) && + !(isStatic() || protection.kind == PROTprivate || protection.kind == PROTpackage) && p->isClassDeclaration() && !(p->isInterfaceDeclaration() && isFinalFunc()); } @@ -3908,6 +3748,8 @@ bool FuncDeclaration::setImpure() if (flags & FUNCFLAGpurityInprocess) { flags &= ~FUNCFLAGpurityInprocess; + if (fes) + fes->func->setImpure(); } else if (isPure()) return true; @@ -3946,6 +3788,8 @@ bool FuncDeclaration::setUnsafe() { flags &= ~FUNCFLAGsafetyInprocess; ((TypeFunction *)type)->trust = TRUSTsystem; + if (fes) + fes->func->setUnsafe(); } else if (isSafe()) return true; @@ -3977,6 +3821,8 @@ bool FuncDeclaration::setGC() { flags &= ~FUNCFLAGnogcInprocess; ((TypeFunction *)type)->isnogc = false; + if (fes) + fes->func->setGC(); } else if (isNogc()) return true; @@ -4160,7 +4006,7 @@ bool FuncDeclaration::addPreInvariant() ClassDeclaration *cd = ad ? ad->isClassDeclaration() : NULL; return (ad && !(cd && cd->isCPPclass()) && global.params.useInvariants && - (protection == PROTprotected || protection == PROTpublic || protection == PROTexport) && + (protection.kind == PROTprotected || protection.kind == PROTpublic || protection.kind == PROTexport) && !naked && ident != Id::cpctor); } @@ -4172,21 +4018,97 @@ bool FuncDeclaration::addPostInvariant() return (ad && !(cd && cd->isCPPclass()) && ad->inv && global.params.useInvariants && - (protection == PROTprotected || protection == PROTpublic || protection == PROTexport) && + (protection.kind == PROTprotected || protection.kind == PROTpublic || protection.kind == PROTexport) && !naked && ident != Id::cpctor); } +/******************************************************** + * Generate Expression to call the invariant. + * Input: + * ad aggregate with the invariant + * vthis variable with 'this' + * direct call invariant directly + */ +Expression *addInvariant(Scope *sc, AggregateDeclaration *ad, VarDeclaration *vthis, bool direct) +{ + Expression *e = NULL; + if (direct) + { + // Call invariant directly only if it exists + FuncDeclaration *inv = ad->inv; + ClassDeclaration *cd = ad->isClassDeclaration(); + + while (!inv && cd) + { + cd = cd->baseClass; + if (!cd) + break; + inv = cd->inv; + } + if (inv) + { + #if 1 + // Workaround for bugzilla 13394: For the correct mangling, + // run attribute inference on inv if needed. + inv->functionSemantic(); + #endif + + //e = new DsymbolExp(Loc(), inv); + //e = new CallExp(Loc(), e); + //e = e->semantic(sc2); + + /* Bugzilla 13113: Currently virtual invariant calls completely + * bypass attribute enforcement. + * Change the behavior of pre-invariant call by following it. + */ + e = new ThisExp(Loc()); + e->type = vthis->type; + e = new DotVarExp(Loc(), e, inv, 0); + e->type = inv->type; + e = new CallExp(Loc(), e); + e->type = Type::tvoid; + } + } + else + { + #if 1 + // Workaround for bugzilla 13394: For the correct mangling, + // run attribute inference on inv if needed. + if (ad->isStructDeclaration() && ad->inv) + ad->inv->functionSemantic(); + #endif + + // Call invariant virtually +#if IN_LLVM + // We actually need a valid 'var' for codegen. + ThisExp* tv = new ThisExp(Loc()); + tv->var = vthis; + Expression *v = tv; +#else + Expression *v = new ThisExp(Loc()); +#endif + v->type = vthis->type; + if (ad->isStructDeclaration()) + v = v->addressOf(); + Expression *se = new StringExp(Loc(), (char *)"null this"); + se = se->semantic(sc); + se->type = Type::tchar->arrayOf(); + e = new AssertExp(Loc(), v, se); + } + return e; +} + /********************************** * Generate a FuncDeclaration for a runtime library function. */ -FuncDeclaration *FuncDeclaration::genCfunc(Parameters *args, Type *treturn, const char *name) +FuncDeclaration *FuncDeclaration::genCfunc(Parameters *args, Type *treturn, const char *name, StorageClass stc) { - return genCfunc(args, treturn, Lexer::idPool(name)); + return genCfunc(args, treturn, Lexer::idPool(name), stc); } -FuncDeclaration *FuncDeclaration::genCfunc(Parameters *args, Type *treturn, Identifier *id) +FuncDeclaration *FuncDeclaration::genCfunc(Parameters *args, Type *treturn, Identifier *id, StorageClass stc) { FuncDeclaration *fd; TypeFunction *tf; @@ -4208,9 +4130,9 @@ FuncDeclaration *FuncDeclaration::genCfunc(Parameters *args, Type *treturn, Iden } else { - tf = new TypeFunction(args, treturn, 0, LINKc); + tf = new TypeFunction(args, treturn, 0, LINKc, stc); fd = new FuncDeclaration(Loc(), Loc(), id, STCstatic, tf); - fd->protection = PROTpublic; + fd->protection = Prot(PROTpublic); fd->linkage = LINKc; st->insert(fd); @@ -4563,16 +4485,12 @@ FuncLiteralDeclaration::FuncLiteralDeclaration(Loc loc, Loc endloc, Type *type, Dsymbol *FuncLiteralDeclaration::syntaxCopy(Dsymbol *s) { - FuncLiteralDeclaration *f; - //printf("FuncLiteralDeclaration::syntaxCopy('%s')\n", toChars()); - if (s) - f = (FuncLiteralDeclaration *)s; - else - f = new FuncLiteralDeclaration(loc, endloc, type->syntaxCopy(), tok, fes, ident); + assert(!s); + FuncLiteralDeclaration *f = new FuncLiteralDeclaration(loc, endloc, + type->syntaxCopy(), tok, fes, ident); f->treq = treq; // don't need to copy - FuncDeclaration::syntaxCopy(f); - return f; + return FuncDeclaration::syntaxCopy(f); } bool FuncLiteralDeclaration::isNested() @@ -4629,11 +4547,20 @@ void FuncLiteralDeclaration::modifyReturns(Scope *sc, Type *tret) if (semanticRun < PASSsemantic3done) return; + if (fes) + return; + RetWalker w; w.sc = sc; w.tret = tret; w.fld = this; fbody->accept(&w); + + // Also update the inferred function type to match the new return type. + // This is required so the code generator does not try to cast the + // modified returns back to the original type. + if (inferRetType && type->nextOf() != tret) + ((TypeFunction *)type)->next = tret; } const char *FuncLiteralDeclaration::kind() @@ -4642,48 +4569,6 @@ const char *FuncLiteralDeclaration::kind() return (tok != TOKfunction) ? (char*)"delegate" : (char*)"function"; } -void FuncLiteralDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (type->ty == Terror) - { - buf->writestring("__error"); - return; - } - - if (tok != TOKreserved) - { - buf->writestring(kind()); - buf->writeByte(' '); - } - - TypeFunction *tf = (TypeFunction *)type; - // Don't print tf->mod, tf->trust, and tf->linkage - if (!inferRetType && tf->next) - toBufferShort(tf->next, buf, hgs); - Parameter::argsToCBuffer(buf, hgs, tf->parameters, tf->varargs); - - CompoundStatement *cs = fbody->isCompoundStatement(); - Statement *s1; - if (semanticRun >= PASSsemantic3done && cs) - { - s1 = (*cs->statements)[cs->statements->dim - 1]; - } - else - s1 = !cs ? fbody : NULL; - ReturnStatement *rs = s1 ? s1->isReturnStatement() : NULL; - if (rs && rs->exp) - { - buf->writestring(" => "); - rs->exp->toCBuffer(buf, hgs); - } - else - { - hgs->tpltMember++; - bodyToCBuffer(buf, hgs); - hgs->tpltMember--; - } -} - const char *FuncLiteralDeclaration::toPrettyChars(bool QualifyTypes) { if (parent) @@ -4705,23 +4590,17 @@ CtorDeclaration::CtorDeclaration(Loc loc, Loc endloc, StorageClass stc, Type *ty Dsymbol *CtorDeclaration::syntaxCopy(Dsymbol *s) { + assert(!s); CtorDeclaration *f = new CtorDeclaration(loc, endloc, storage_class, type->syntaxCopy()); - - f->outId = outId; - f->frequire = frequire ? frequire->syntaxCopy() : NULL; - f->fensure = fensure ? fensure->syntaxCopy() : NULL; - f->fbody = fbody ? fbody->syntaxCopy() : NULL; - assert(!fthrows); // deprecated - - return f; + return FuncDeclaration::syntaxCopy(f); } - void CtorDeclaration::semantic(Scope *sc) { //printf("CtorDeclaration::semantic() %s\n", toChars()); if (scope) - { sc = scope; + { + sc = scope; scope = NULL; } @@ -4806,14 +4685,14 @@ Dsymbol *PostBlitDeclaration::syntaxCopy(Dsymbol *s) return FuncDeclaration::syntaxCopy(dd); } - void PostBlitDeclaration::semantic(Scope *sc) { //printf("PostBlitDeclaration::semantic() %s\n", toChars()); //printf("ident: %s, %s, %p, %p\n", ident->toChars(), Id::dtor->toChars(), ident, Id::dtor); //printf("stc = x%llx\n", sc->stc); if (scope) - { sc = scope; + { + sc = scope; scope = NULL; } parent = sc->parent; @@ -4858,12 +4737,6 @@ bool PostBlitDeclaration::isVirtual() return false; } -void PostBlitDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("this(this)"); - bodyToCBuffer(buf, hgs); -} - /********************************* DtorDeclaration ****************************/ DtorDeclaration::DtorDeclaration(Loc loc, Loc endloc) @@ -4883,13 +4756,13 @@ Dsymbol *DtorDeclaration::syntaxCopy(Dsymbol *s) return FuncDeclaration::syntaxCopy(dd); } - void DtorDeclaration::semantic(Scope *sc) { //printf("DtorDeclaration::semantic() %s\n", toChars()); //printf("ident: %s, %s, %p, %p\n", ident->toChars(), Id::dtor->toChars(), ident, Id::dtor); if (scope) - { sc = scope; + { + sc = scope; scope = NULL; } parent = sc->parent; @@ -4945,12 +4818,6 @@ bool DtorDeclaration::isVirtual() return false; } -void DtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("~this()"); - bodyToCBuffer(buf, hgs); -} - /********************************* StaticCtorDeclaration ****************************/ StaticCtorDeclaration::StaticCtorDeclaration(Loc loc, Loc endloc, StorageClass stc) @@ -4972,7 +4839,6 @@ Dsymbol *StaticCtorDeclaration::syntaxCopy(Dsymbol *s) return FuncDeclaration::syntaxCopy(scd); } - void StaticCtorDeclaration::semantic(Scope *sc) { //printf("StaticCtorDeclaration::semantic()\n"); @@ -4983,21 +4849,6 @@ void StaticCtorDeclaration::semantic(Scope *sc) scope = NULL; } - if (storage_class & STCshared && !isSharedStaticCtorDeclaration()) - { - ::error(loc, "to create a shared static constructor, use 'shared static this'"); - storage_class &= ~STCshared; - } - - if (storage_class & (STCimmutable | STCconst | STCshared | STCwild)) - { - OutBuffer buf; - StorageClassDeclaration::stcToCBuffer(&buf, storage_class & (STCimmutable | STCconst | STCshared | STCwild)); - ::error(loc, "static constructors cannot be %s", buf.peekString()); - } - - storage_class &= ~STC_TYPECTOR; // remove qualifiers - if (!type) type = new TypeFunction(NULL, Type::tvoid, false, LINKd, storage_class); @@ -5065,18 +4916,6 @@ bool StaticCtorDeclaration::addPostInvariant() return false; } -void StaticCtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (hgs->hdrgen && !hgs->tpltMember) - { - buf->writestring("static this();"); - buf->writenl(); - return; - } - buf->writestring("static this()"); - bodyToCBuffer(buf, hgs); -} - /********************************* SharedStaticCtorDeclaration ****************************/ SharedStaticCtorDeclaration::SharedStaticCtorDeclaration(Loc loc, Loc endloc, StorageClass stc) @@ -5091,12 +4930,6 @@ Dsymbol *SharedStaticCtorDeclaration::syntaxCopy(Dsymbol *s) return FuncDeclaration::syntaxCopy(scd); } -void SharedStaticCtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("shared "); - StaticCtorDeclaration::toCBuffer(buf, hgs); -} - /********************************* StaticDtorDeclaration ****************************/ StaticDtorDeclaration::StaticDtorDeclaration(Loc loc, Loc endloc, StorageClass stc) @@ -5120,11 +4953,11 @@ Dsymbol *StaticDtorDeclaration::syntaxCopy(Dsymbol *s) return FuncDeclaration::syntaxCopy(sdd); } - void StaticDtorDeclaration::semantic(Scope *sc) { if (scope) - { sc = scope; + { + sc = scope; scope = NULL; } @@ -5197,14 +5030,6 @@ bool StaticDtorDeclaration::addPostInvariant() return false; } -void StaticDtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (hgs->hdrgen) - return; - buf->writestring("static ~this()"); - bodyToCBuffer(buf, hgs); -} - /********************************* SharedStaticDtorDeclaration ****************************/ SharedStaticDtorDeclaration::SharedStaticDtorDeclaration(Loc loc, Loc endloc, StorageClass stc) @@ -5219,16 +5044,6 @@ Dsymbol *SharedStaticDtorDeclaration::syntaxCopy(Dsymbol *s) return FuncDeclaration::syntaxCopy(sdd); } -void SharedStaticDtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (!hgs->hdrgen) - { - buf->writestring("shared "); - StaticDtorDeclaration::toCBuffer(buf, hgs); - } -} - - /********************************* InvariantDeclaration ****************************/ InvariantDeclaration::InvariantDeclaration(Loc loc, Loc endloc, StorageClass stc, Identifier *id) @@ -5240,19 +5055,16 @@ InvariantDeclaration::InvariantDeclaration(Loc loc, Loc endloc, StorageClass stc Dsymbol *InvariantDeclaration::syntaxCopy(Dsymbol *s) { - InvariantDeclaration *id; - assert(!s); - id = new InvariantDeclaration(loc, endloc, storage_class); - FuncDeclaration::syntaxCopy(id); - return id; + InvariantDeclaration *id = new InvariantDeclaration(loc, endloc, storage_class); + return FuncDeclaration::syntaxCopy(id); } - void InvariantDeclaration::semantic(Scope *sc) { if (scope) - { sc = scope; + { + sc = scope; scope = NULL; } parent = sc->parent; @@ -5296,15 +5108,6 @@ bool InvariantDeclaration::addPostInvariant() return false; } -void InvariantDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (hgs->hdrgen) - return; - buf->writestring("invariant"); - bodyToCBuffer(buf, hgs); -} - - /********************************* UnitTestDeclaration ****************************/ /******************************* @@ -5319,22 +5122,19 @@ static Identifier *unitTestId(Loc loc) return Lexer::uniqueId(buf.peekString()); } -UnitTestDeclaration::UnitTestDeclaration(Loc loc, Loc endloc, char *codedoc) - : FuncDeclaration(loc, endloc, unitTestId(loc), STCundefined, NULL) +UnitTestDeclaration::UnitTestDeclaration(Loc loc, Loc endloc, StorageClass stc, char *codedoc) + : FuncDeclaration(loc, endloc, unitTestId(loc), stc, NULL) { this->codedoc = codedoc; } Dsymbol *UnitTestDeclaration::syntaxCopy(Dsymbol *s) { - UnitTestDeclaration *utd; - assert(!s); - utd = new UnitTestDeclaration(loc, endloc, codedoc); + UnitTestDeclaration *utd = new UnitTestDeclaration(loc, endloc, storage_class, codedoc); return FuncDeclaration::syntaxCopy(utd); } - void UnitTestDeclaration::semantic(Scope *sc) { protection = sc->protection; @@ -5351,7 +5151,7 @@ void UnitTestDeclaration::semantic(Scope *sc) if (global.params.useUnitTests) { if (!type) - type = new TypeFunction(NULL, Type::tvoid, false, LINKd); + type = new TypeFunction(NULL, Type::tvoid, false, LINKd, storage_class); Scope *sc2 = sc->push(); sc2->linkage = LINKd; FuncDeclaration::semantic(sc2); @@ -5394,18 +5194,10 @@ bool UnitTestDeclaration::addPostInvariant() return false; } -void UnitTestDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (hgs->hdrgen) - return; - buf->writestring("unittest"); - bodyToCBuffer(buf, hgs); -} - /********************************* NewDeclaration ****************************/ -NewDeclaration::NewDeclaration(Loc loc, Loc endloc, Parameters *arguments, int varargs) - : FuncDeclaration(loc, endloc, Id::classNew, STCstatic, NULL) +NewDeclaration::NewDeclaration(Loc loc, Loc endloc, StorageClass stc, Parameters *arguments, int varargs) + : FuncDeclaration(loc, endloc, Id::classNew, STCstatic | stc, NULL) { this->arguments = arguments; this->varargs = varargs; @@ -5413,24 +5205,19 @@ NewDeclaration::NewDeclaration(Loc loc, Loc endloc, Parameters *arguments, int v Dsymbol *NewDeclaration::syntaxCopy(Dsymbol *s) { - NewDeclaration *f; - - f = new NewDeclaration(loc, endloc, NULL, varargs); - - FuncDeclaration::syntaxCopy(f); - - f->arguments = Parameter::arraySyntaxCopy(arguments); - - return f; + assert(!s); + NewDeclaration *f = new NewDeclaration(loc, endloc, + storage_class, Parameter::arraySyntaxCopy(arguments), varargs); + return FuncDeclaration::syntaxCopy(f); } - void NewDeclaration::semantic(Scope *sc) { //printf("NewDeclaration::semantic()\n"); if (scope) - { sc = scope; + { + sc = scope; scope = NULL; } @@ -5443,7 +5230,7 @@ void NewDeclaration::semantic(Scope *sc) } Type *tret = Type::tvoid->pointerTo(); if (!type) - type = new TypeFunction(arguments, tret, varargs, LINKd); + type = new TypeFunction(arguments, tret, varargs, LINKd, storage_class); type = type->semantic(loc, sc); assert(type->ty == Tfunction); @@ -5484,42 +5271,29 @@ bool NewDeclaration::addPostInvariant() return false; } -void NewDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("new"); - Parameter::argsToCBuffer(buf, hgs, arguments, varargs); - bodyToCBuffer(buf, hgs); -} - - /********************************* DeleteDeclaration ****************************/ -DeleteDeclaration::DeleteDeclaration(Loc loc, Loc endloc, Parameters *arguments) - : FuncDeclaration(loc, endloc, Id::classDelete, STCstatic, NULL) +DeleteDeclaration::DeleteDeclaration(Loc loc, Loc endloc, StorageClass stc, Parameters *arguments) + : FuncDeclaration(loc, endloc, Id::classDelete, STCstatic | stc, NULL) { this->arguments = arguments; } Dsymbol *DeleteDeclaration::syntaxCopy(Dsymbol *s) { - DeleteDeclaration *f; - - f = new DeleteDeclaration(loc, endloc, NULL); - - FuncDeclaration::syntaxCopy(f); - - f->arguments = Parameter::arraySyntaxCopy(arguments); - - return f; + assert(!s); + DeleteDeclaration *f = new DeleteDeclaration(loc, endloc, + storage_class, Parameter::arraySyntaxCopy(arguments)); + return FuncDeclaration::syntaxCopy(f); } - void DeleteDeclaration::semantic(Scope *sc) { //printf("DeleteDeclaration::semantic()\n"); if (scope) - { sc = scope; + { + sc = scope; scope = NULL; } @@ -5531,7 +5305,7 @@ void DeleteDeclaration::semantic(Scope *sc) error("new allocators only are for class or struct definitions"); } if (!type) - type = new TypeFunction(arguments, Type::tvoid, 0, LINKd); + type = new TypeFunction(arguments, Type::tvoid, 0, LINKd, storage_class); type = type->semantic(loc, sc); assert(type->ty == Tfunction); @@ -5576,14 +5350,3 @@ bool DeleteDeclaration::addPostInvariant() { return false; } - -void DeleteDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("delete"); - Parameter::argsToCBuffer(buf, hgs, arguments, 0); - bodyToCBuffer(buf, hgs); -} - - - - diff --git a/dmd2/hdrgen.c b/dmd2/hdrgen.c index 64b9f68902..fdf380a41e 100644 --- a/dmd2/hdrgen.c +++ b/dmd2/hdrgen.c @@ -45,74 +45,41 @@ #include "expression.h" #include "ctfe.h" #include "statement.h" +#include "aliasthis.h" +#include "nspace.h" #include "hdrgen.h" -void argsToCBuffer(OutBuffer *buf, Expressions *arguments, HdrGenState *hgs); -void sizeToCBuffer(OutBuffer *buf, HdrGenState *hgs, Expression *e); -void toBufferShort(Type *t, OutBuffer *buf, HdrGenState *hgs); -void expToCBuffer(OutBuffer *buf, HdrGenState *hgs, Expression *e, PREC pr); -void toCBuffer(Module *m, OutBuffer *buf, HdrGenState *hgs); +void linkageToBuffer(OutBuffer *buf, LINK linkage); void genhdrfile(Module *m) { - OutBuffer hdrbufr; - hdrbufr.doindent = 1; + OutBuffer buf; + buf.doindent = 1; - hdrbufr.printf("// D import file generated from '%s'", m->srcfile->toChars()); - hdrbufr.writenl(); + buf.printf("// D import file generated from '%s'", m->srcfile->toChars()); + buf.writenl(); HdrGenState hgs; - memset(&hgs, 0, sizeof(hgs)); - hgs.hdrgen = 1; + hgs.hdrgen = true; - toCBuffer(m, &hdrbufr, &hgs); + toCBuffer(m, &buf, &hgs); // Transfer image to file - m->hdrfile->setbuffer(hdrbufr.data, hdrbufr.offset); - hdrbufr.data = NULL; + m->hdrfile->setbuffer(buf.data, buf.offset); + buf.data = NULL; ensurePathToNameExists(Loc(), m->hdrfile->toChars()); writeFile(m->loc, m->hdrfile); } - -void toCBuffer(Module *m, OutBuffer *buf, HdrGenState *hgs) -{ - if (m->md) - { - if (m->md->isdeprecated) - { - if (m->md->msg) - { - buf->writestring("deprecated("); - toCBuffer(m->md->msg, buf, hgs); - buf->writestring(") "); - } - else - buf->writestring("deprecated "); - } - buf->writestring("module "); - buf->writestring(m->md->toChars()); - buf->writeByte(';'); - buf->writenl(); - } - - for (size_t i = 0; i < m->members->dim; i++) - { - Dsymbol *s = (*m->members)[i]; - s->toCBuffer(buf, hgs); - } -} - class PrettyPrintVisitor : public Visitor { public: OutBuffer *buf; HdrGenState *hgs; - unsigned char modMask; PrettyPrintVisitor(OutBuffer *buf, HdrGenState *hgs) - : buf(buf), hgs(hgs), modMask(0) + : buf(buf), hgs(hgs) { } @@ -133,18 +100,18 @@ public: { if (s->exp) { - s->exp->toCBuffer(buf, hgs); + s->exp->accept(this); if (s->exp->op != TOKdeclaration) { buf->writeByte(';'); - if (!hgs->FLinit.init) + if (!hgs->forStmtInit) buf->writenl(); } } else { buf->writeByte(';'); - if (!hgs->FLinit.init) + if (!hgs->forStmtInit) buf->writenl(); } } @@ -152,9 +119,9 @@ public: void visit(CompileStatement *s) { buf->writestring("mixin("); - s->exp->toCBuffer(buf, hgs); + s->exp->accept(this); buf->writestring(");"); - if (!hgs->FLinit.init) + if (!hgs->forStmtInit) buf->writenl(); } @@ -174,51 +141,20 @@ public: for (size_t i = 0; i < s->statements->dim; i++) { Statement *sx = (*s->statements)[i]; - ExpStatement *ds; - if (sx && - (ds = sx->isExpStatement()) != NULL && - ds->exp->op == TOKdeclaration) + ExpStatement *ds = sx ? sx->isExpStatement() : NULL; + if (ds && ds->exp->op == TOKdeclaration) { - DeclarationExp *de = (DeclarationExp *)ds->exp; - Declaration *d = de->declaration->isDeclaration(); - assert(d); - VarDeclaration *v = d->isVarDeclaration(); - if (v) - { - /* This essentially copies the part of VarDeclaration::toCBuffer() - * that does not print the type. - * Should refactor this. - */ - if (anywritten) - { - buf->writestring(", "); - buf->writestring(v->ident->toChars()); - } - else - { - StorageClassDeclaration::stcToCBuffer(buf, v->storage_class); - if (v->type) - v->type->toCBuffer(buf, v->ident, hgs); - else - buf->writestring(v->ident->toChars()); - } - - if (v->init) - { buf->writestring(" = "); - ExpInitializer *ie = v->init->isExpInitializer(); - if (ie && (ie->exp->op == TOKconstruct || ie->exp->op == TOKblit)) - ((AssignExp *)ie->exp)->e2->toCBuffer(buf, hgs); - else - v->init->toCBuffer(buf, hgs); - } - } + Dsymbol *d = ((DeclarationExp *)ds->exp)->declaration; + assert(d->isDeclaration()); + if (VarDeclaration *v = d->isVarDeclaration()) + visitVarDecl(v, anywritten); else - d->toCBuffer(buf, hgs); + d->accept(this); anywritten = true; } } buf->writeByte(';'); - if (!hgs->FLinit.init) + if (!hgs->forStmtInit) buf->writenl(); } @@ -257,7 +193,7 @@ public: void visit(WhileStatement *s) { buf->writestring("while ("); - s->condition->toCBuffer(buf, hgs); + s->condition->accept(this); buf->writeByte(')'); buf->writenl(); if (s->body) @@ -271,7 +207,7 @@ public: if (s->body) s->body->accept(this); buf->writestring("while ("); - s->condition->toCBuffer(buf, hgs); + s->condition->accept(this); buf->writestring(");"); buf->writenl(); } @@ -281,22 +217,22 @@ public: buf->writestring("for ("); if (s->init) { - hgs->FLinit.init++; + hgs->forStmtInit++; s->init->accept(this); - hgs->FLinit.init--; + hgs->forStmtInit--; } else buf->writeByte(';'); if (s->condition) { buf->writeByte(' '); - s->condition->toCBuffer(buf, hgs); + s->condition->accept(this); } buf->writeByte(';'); if (s->increment) { buf->writeByte(' '); - s->increment->toCBuffer(buf, hgs); + s->increment->accept(this); } buf->writeByte(')'); buf->writenl(); @@ -318,15 +254,14 @@ public: Parameter *a = (*s->arguments)[i]; if (i) buf->writestring(", "); - if (a->storageClass & STCref) - buf->writestring((char*)"ref "); + StorageClassDeclaration::stcToCBuffer(buf, a->storageClass); if (a->type) - a->type->toCBuffer(buf, a->ident, hgs); + typeToBuffer(a->type, a->ident); else buf->writestring(a->ident->toChars()); } buf->writestring("; "); - s->aggr->toCBuffer(buf, hgs); + s->aggr->accept(this); buf->writeByte(')'); buf->writenl(); buf->writeByte('{'); @@ -345,14 +280,14 @@ public: buf->writestring(" ("); if (s->arg->type) - s->arg->type->toCBuffer(buf, s->arg->ident, hgs); + typeToBuffer(s->arg->type, s->arg->ident); else buf->writestring(s->arg->ident->toChars()); buf->writestring("; "); - s->lwr->toCBuffer(buf, hgs); + s->lwr->accept(this); buf->writestring(" .. "); - s->upr->toCBuffer(buf, hgs); + s->upr->accept(this); buf->writeByte(')'); buf->writenl(); buf->writeByte('{'); @@ -368,18 +303,19 @@ public: void visit(IfStatement *s) { buf->writestring("if ("); - if (s->arg) + if (Parameter *a = s->arg) { - if (s->arg->type) - s->arg->type->toCBuffer(buf, s->arg->ident, hgs); + StorageClass stc = a->storageClass; + if (!a->type && !stc) + stc = STCauto; + StorageClassDeclaration::stcToCBuffer(buf, stc); + if (a->type) + typeToBuffer(a->type, a->ident); else - { - buf->writestring("auto "); - buf->writestring(s->arg->ident->toChars()); - } + buf->writestring(a->ident->toChars()); buf->writestring(" = "); } - s->condition->toCBuffer(buf, hgs); + s->condition->accept(this); buf->writeByte(')'); buf->writenl(); if (!s->ifbody->isScopeStatement()) @@ -401,7 +337,7 @@ public: void visit(ConditionalStatement *s) { - s->condition->toCBuffer(buf, hgs); + s->condition->accept(this); buf->writenl(); buf->writeByte('{'); buf->writenl(); @@ -421,7 +357,6 @@ public: s->elsebody->accept(this); buf->level--; buf->writeByte('}'); - buf->writenl(); } buf->writenl(); } @@ -433,7 +368,7 @@ public: if (s->args && s->args->dim) { buf->writestring(", "); - argsToCBuffer(buf, s->args, hgs); + argsToBuffer(s->args); } buf->writeByte(')'); if (s->body) @@ -458,13 +393,13 @@ public: void visit(StaticAssertStatement *s) { - s->sa->toCBuffer(buf, hgs); + s->sa->accept(this); } void visit(SwitchStatement *s) { buf->writestring(s->isFinal ? "final switch (" : "switch ("); - s->condition->toCBuffer(buf, hgs); + s->condition->accept(this); buf->writeByte(')'); buf->writenl(); if (s->body) @@ -489,7 +424,7 @@ public: void visit(CaseStatement *s) { buf->writestring("case "); - s->exp->toCBuffer(buf, hgs); + s->exp->accept(this); buf->writeByte(':'); buf->writenl(); s->statement->accept(this); @@ -498,9 +433,9 @@ public: void visit(CaseRangeStatement *s) { buf->writestring("case "); - s->first->toCBuffer(buf, hgs); + s->first->accept(this); buf->writestring(": .. case "); - s->last->toCBuffer(buf, hgs); + s->last->accept(this); buf->writeByte(':'); buf->writenl(); s->statement->accept(this); @@ -525,7 +460,7 @@ public: if (s->exp) { buf->writeByte(' '); - s->exp->toCBuffer(buf, hgs); + s->exp->accept(this); } buf->writeByte(';'); buf->writenl(); @@ -541,7 +476,7 @@ public: { buf->printf("return "); if (s->exp) - s->exp->toCBuffer(buf, hgs); + s->exp->accept(this); buf->writeByte(';'); buf->writenl(); } @@ -576,7 +511,7 @@ public: if (s->exp) { buf->writeByte('('); - s->exp->toCBuffer(buf, hgs); + s->exp->accept(this); buf->writeByte(')'); } if (s->body) @@ -589,7 +524,7 @@ public: void visit(WithStatement *s) { buf->writestring("with ("); - s->exp->toCBuffer(buf, hgs); + s->exp->accept(this); buf->writestring(")"); buf->writenl(); if (s->body) @@ -641,7 +576,7 @@ public: void visit(ThrowStatement *s) { buf->printf("throw "); - s->exp->toCBuffer(buf, hgs); + s->exp->accept(this); buf->writeByte(';'); buf->writenl(); } @@ -680,17 +615,17 @@ public: { buf->writestring(t->toChars()); if (t->next && - t->value != TOKmin && - t->value != TOKcomma && - t->next->value != TOKcomma && - t->value != TOKlbracket && - t->next->value != TOKlbracket && - t->next->value != TOKrbracket && - t->value != TOKlparen && - t->next->value != TOKlparen && - t->next->value != TOKrparen && - t->value != TOKdot && - t->next->value != TOKdot) + t->value != TOKmin && + t->value != TOKcomma && + t->next->value != TOKcomma && + t->value != TOKlbracket && + t->next->value != TOKlbracket && + t->next->value != TOKrbracket && + t->value != TOKlparen && + t->next->value != TOKlparen && + t->next->value != TOKrparen && + t->value != TOKdot && + t->next->value != TOKdot) { buf->writeByte(' '); } @@ -718,7 +653,7 @@ public: for (size_t i = 0; i < s->imports->dim; i++) { Dsymbol *imp = (*s->imports)[i]; - imp->toCBuffer(buf, hgs); + imp->accept(this); } } @@ -728,7 +663,7 @@ public: if (c->type) { buf->writeByte('('); - c->type->toCBuffer(buf, c->ident, hgs); + typeToBuffer(c->type, c->ident); buf->writeByte(')'); } buf->writenl(); @@ -744,11 +679,28 @@ public: //////////////////////////////////////////////////////////////////////////// - void visitWithMask(Type *t, unsigned char mod) + /************************************************** + * An entry point to pretty-print type. + */ + void typeToBuffer(Type *t, Identifier *ident) { - unsigned char save = modMask; - modMask = mod; + if (t->ty == Tfunction) + { + visitFuncIdentWithPrefix((TypeFunction *)t, ident, NULL, true); + return; + } + visitWithMask(t, 0); + + if (ident) + { + buf->writeByte(' '); + buf->writestring(ident->toChars()); + } + } + + void visitWithMask(Type *t, unsigned char modMask) + { // Tuples and functions don't use the type constructor syntax if (modMask == t->mod || t->ty == Tfunction || @@ -784,7 +736,6 @@ public: if (m & MODshared) buf->writeByte(')'); } - modMask = save; } void visit(Type *t) @@ -793,15 +744,20 @@ public: assert(0); } + void visit(TypeError *t) + { + buf->writestring("_error_"); + } + void visit(TypeBasic *t) { - //printf("TypeBasic::toCBuffer2(modMask = %d, t->mod = %d)\n", modMask, t->mod); + //printf("TypeBasic::toCBuffer2(t->mod = %d)\n", t->mod); buf->writestring(t->dstring); } void visit(TypeVector *t) { - //printf("TypeVector::toCBuffer2(modMask = %d, t->mod = %d)\n", modMask, t->mod); + //printf("TypeVector::toCBuffer2(t->mod = %d)\n", t->mod); buf->writestring("__vector("); visitWithMask(t->basetype, t->mod); buf->writestring(")"); @@ -811,7 +767,7 @@ public: { visitWithMask(t->next, t->mod); buf->writeByte('['); - sizeToCBuffer(buf, hgs, t->dim); + sizeToBuffer(t->dim); buf->writeByte(']'); } @@ -837,9 +793,13 @@ public: void visit(TypePointer *t) { //printf("TypePointer::toCBuffer2() next = %d\n", t->next->ty); - visitWithMask(t->next, t->mod); - if (t->next->ty != Tfunction) + if (t->next->ty == Tfunction) + visitFuncIdentWithPostfix((TypeFunction *)t->next, "function"); + else + { + visitWithMask(t->next, t->mod); buf->writeByte('*'); + } } void visit(TypeReference *t) @@ -851,32 +811,45 @@ public: void visit(TypeFunction *t) { //printf("TypeFunction::toCBuffer2() t = %p, ref = %d\n", t, t->isref); + visitFuncIdentWithPostfix(t, NULL); + } + + // callback for TypeFunction::attributesApply + struct PrePostAppendStrings + { + OutBuffer *buf; + bool isPostfixStyle; + bool isCtor; + + static int fp(void *param, const char *str) + { + PrePostAppendStrings *p = (PrePostAppendStrings *)param; + + // don't write 'ref' for ctors + if (p->isCtor && strcmp(str, "ref") == 0) + return 0; + + if ( p->isPostfixStyle) p->buf->writeByte(' '); + p->buf->writestring(str); + if (!p->isPostfixStyle) p->buf->writeByte(' '); + return 0; + } + }; + + void visitFuncIdentWithPostfix(TypeFunction *t, const char *ident) + { if (t->inuse) { t->inuse = 2; // flag error to caller return; } t->inuse++; - visitFuncIdent(t, "function"); - t->inuse--; - } - // callback for TypeFunction::attributesApply, prepends spaces - struct PreAppendStrings - { - OutBuffer *buf; + PrePostAppendStrings pas; + pas.buf = buf; + pas.isCtor = false; + pas.isPostfixStyle = true; - static int fp(void *param, const char *str) - { - PreAppendStrings *p = (PreAppendStrings *)param; - p->buf->writeByte(' '); - p->buf->writestring(str); - return 0; - } - }; - - void visitFuncIdent(TypeFunction *t, const char *ident) - { if (t->linkage > LINKd && hgs->ddoc != 1 && !hgs->hdrgen) { linkageToBuffer(buf, t->linkage); @@ -885,27 +858,93 @@ public: if (t->next) { - visitWithMask(t->next, 0); - buf->writeByte(' '); + typeToBuffer(t->next, NULL); + if (ident) + buf->writeByte(' '); } - buf->writestring(ident); - Parameter::argsToCBuffer(buf, hgs, t->parameters, t->varargs); + else if (hgs->ddoc) + buf->writestring("auto "); + + if (ident) + buf->writestring(ident); + + parametersToBuffer(t->parameters, t->varargs); /* Use postfix style for attributes */ - if (modMask != t->mod) + if (t->mod) { - t->modToBuffer(buf); + buf->writeByte(' '); + MODtoBuffer(buf, t->mod); + } + t->attributesApply(&pas, &PrePostAppendStrings::fp); + + t->inuse--; + } + void visitFuncIdentWithPrefix(TypeFunction *t, Identifier *ident, TemplateDeclaration *td, bool isPostfixStyle) + { + if (t->inuse) + { + t->inuse = 2; // flag error to caller + return; + } + t->inuse++; + + PrePostAppendStrings pas; + pas.buf = buf; + pas.isCtor = (ident == Id::ctor); + pas.isPostfixStyle = false; + + /* Use 'storage class' (prefix) style for attributes + */ + if (t->mod) + { + MODtoBuffer(buf, t->mod); + buf->writeByte(' '); + } + t->attributesApply(&pas, &PrePostAppendStrings::fp); + + if (t->linkage > LINKd && hgs->ddoc != 1 && !hgs->hdrgen) + { + linkageToBuffer(buf, t->linkage); + buf->writeByte(' '); } - PreAppendStrings pas; - pas.buf = buf; - t->attributesApply(&pas, &PreAppendStrings::fp); + if (ident && ident->toHChars2() != ident->toChars()) + { + // Don't print return type for ctor, dtor, unittest, etc + } + else if (t->next) + { + typeToBuffer(t->next, NULL); + if (ident) + buf->writeByte(' '); + } + else if (hgs->ddoc) + buf->writestring("auto "); + + if (ident) + buf->writestring(ident->toHChars2()); + + if (td) + { + buf->writeByte('('); + for (size_t i = 0; i < td->origParameters->dim; i++) + { + if (i) + buf->writestring(", "); + (*td->origParameters)[i]->accept(this); + } + buf->writeByte(')'); + } + parametersToBuffer(t->parameters, t->varargs); + + t->inuse--; } void visit(TypeDelegate *t) { - visitFuncIdent((TypeFunction *)t->next, "delegate"); + visitFuncIdentWithPostfix((TypeFunction *)t->next, "delegate"); } void visitTypeQualifiedHelper(TypeQualified *t) @@ -918,7 +957,7 @@ public: if (id->dyncast() == DYNCAST_DSYMBOL) { TemplateInstance *ti = (TemplateInstance *)id; - ti->toCBuffer(buf, hgs); + ti->accept(this); } else buf->writestring(id->toChars()); @@ -933,14 +972,14 @@ public: void visit(TypeInstance *t) { - t->tempinst->toCBuffer(buf, hgs); + t->tempinst->accept(this); visitTypeQualifiedHelper(t); } void visit(TypeTypeof *t) { buf->writestring("typeof("); - t->exp->toCBuffer(buf, hgs); + t->exp->accept(this); buf->writeByte(')'); visitTypeQualifiedHelper(t); } @@ -956,33 +995,27 @@ public: buf->writestring(t->sym->toChars()); } - void visit(TypeTypedef *t) - { - //printf("TypeTypedef::toCBuffer2() '%s'\n", t->sym->toChars()); - buf->writestring(t->sym->toChars()); - } - void visit(TypeStruct *t) { TemplateInstance *ti = t->sym->parent->isTemplateInstance(); if (ti && ti->toAlias() == t->sym) - buf->writestring((hgs->fullQualification) ? ti->toPrettyChars() : ti->toChars()); + buf->writestring(hgs->fullQual ? ti->toPrettyChars() : ti->toChars()); else - buf->writestring((hgs->fullQualification) ? t->sym->toPrettyChars() : t->sym->toChars()); + buf->writestring(hgs->fullQual ? t->sym->toPrettyChars() : t->sym->toChars()); } void visit(TypeClass *t) { TemplateInstance *ti = t->sym->parent->isTemplateInstance(); if (ti && ti->toAlias() == t->sym) - buf->writestring((hgs->fullQualification) ? ti->toPrettyChars() : ti->toChars()); + buf->writestring(hgs->fullQual ? ti->toPrettyChars() : ti->toChars()); else - buf->writestring((hgs->fullQualification) ? t->sym->toPrettyChars() : t->sym->toChars()); + buf->writestring(hgs->fullQual ? t->sym->toPrettyChars() : t->sym->toChars()); } void visit(TypeTuple *t) { - Parameter::argsToCBuffer(buf, hgs, t->arguments, 0); + parametersToBuffer(t->arguments, 0); } void visit(TypeSlice *t) @@ -990,9 +1023,9 @@ public: visitWithMask(t->next, t->mod); buf->writeByte('['); - sizeToCBuffer(buf, hgs, t->lwr); + sizeToBuffer(t->lwr); buf->writestring(" .. "); - sizeToCBuffer(buf, hgs, t->upr); + sizeToBuffer(t->upr); buf->writeByte(']'); } @@ -1001,7 +1034,997 @@ public: buf->writestring("typeof(null)"); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + + void visit(Dsymbol *s) + { + buf->writestring(s->toChars()); + } + + void visit(StaticAssert *s) + { + buf->writestring(s->kind()); + buf->writeByte('('); + s->exp->accept(this); + if (s->msg) + { + buf->writestring(", "); + s->msg->accept(this); + } + buf->writestring(");"); + buf->writenl(); + } + + void visit(DebugSymbol *s) + { + buf->writestring("debug = "); + if (s->ident) + buf->writestring(s->ident->toChars()); + else + buf->printf("%u", s->level); + buf->writestring(";"); + buf->writenl(); + } + + void visit(VersionSymbol *s) + { + buf->writestring("version = "); + if (s->ident) + buf->writestring(s->ident->toChars()); + else + buf->printf("%u", s->level); + buf->writestring(";"); + buf->writenl(); + } + + void visit(EnumMember *em) + { + if (em->type) + typeToBuffer(em->type, em->ident); + else + buf->writestring(em->ident->toChars()); + if (em->value) + { + buf->writestring(" = "); + em->value->accept(this); + } + } + + void visit(Import *imp) + { + if (hgs->hdrgen && imp->id == Id::object) + return; // object is imported by default + + if (imp->isstatic) + buf->writestring("static "); + buf->writestring("import "); + if (imp->aliasId) + { + buf->printf("%s = ", imp->aliasId->toChars()); + } + if (imp->packages && imp->packages->dim) + { + for (size_t i = 0; i < imp->packages->dim; i++) + { + Identifier *pid = (*imp->packages)[i]; + buf->printf("%s.", pid->toChars()); + } + } + buf->printf("%s", imp->id->toChars()); + if (imp->names.dim) + { + buf->writestring(" : "); + for (size_t i = 0; i < imp->names.dim; i++) + { + if (i) + buf->writestring(", "); + + Identifier *name = imp->names[i]; + Identifier *alias = imp->aliases[i]; + if (alias) + buf->printf("%s = %s", alias->toChars(), name->toChars()); + else + buf->printf("%s", name->toChars()); + } + } + buf->printf(";"); + buf->writenl(); + } + + void visit(AliasThis *d) + { + buf->writestring("alias "); + buf->writestring(d->ident->toChars()); + buf->writestring(" this;\n"); + } + + void visit(AttribDeclaration *d) + { + if (!d->decl) + { + buf->writeByte(';'); + buf->writenl(); + return; + } + + if (d->decl->dim == 0) + buf->writestring("{}"); + else if (hgs->hdrgen && d->decl->dim == 1 && (*d->decl)[0]->isUnitTestDeclaration()) + { + // hack for bugzilla 8081 + buf->writestring("{}"); + } + else if (d->decl->dim == 1) + { + ((*d->decl)[0])->accept(this); + return; + } + else + { + buf->writenl(); + buf->writeByte('{'); + buf->writenl(); + buf->level++; + for (size_t i = 0; i < d->decl->dim; i++) + (*d->decl)[i]->accept(this); + buf->level--; + buf->writeByte('}'); + } + buf->writenl(); + } + + void visit(StorageClassDeclaration *d) + { + StorageClassDeclaration::stcToCBuffer(buf, d->stc); + visit((AttribDeclaration *)d); + } + + void visit(DeprecatedDeclaration *d) + { + buf->writestring("deprecated("); + d->msg->accept(this); + buf->writestring(") "); + visit((AttribDeclaration *)d); + } + + void visit(LinkDeclaration *d) + { + const char *p; + + switch (d->linkage) + { + case LINKd: p = "D"; break; + case LINKc: p = "C"; break; + case LINKcpp: p = "C++"; break; + case LINKwindows: p = "Windows"; break; + case LINKpascal: p = "Pascal"; break; + default: + assert(0); + break; + } + buf->writestring("extern ("); + buf->writestring(p); + buf->writestring(") "); + visit((AttribDeclaration *)d); + } + + void visit(ProtDeclaration *d) + { + protectionToBuffer(buf, d->protection); + buf->writeByte(' '); + visit((AttribDeclaration *)d); + } + + void visit(AlignDeclaration *d) + { + if (d->salign == STRUCTALIGN_DEFAULT) + buf->printf("align"); + else + buf->printf("align (%d)", d->salign); + visit((AttribDeclaration *)d); + } + + void visit(AnonDeclaration *d) + { + buf->printf(d->isunion ? "union" : "struct"); + buf->writenl(); + buf->writestring("{"); + buf->writenl(); + buf->level++; + if (d->decl) + { + for (size_t i = 0; i < d->decl->dim; i++) + (*d->decl)[i]->accept(this); + } + buf->level--; + buf->writestring("}"); + buf->writenl(); + } + + void visit(PragmaDeclaration *d) + { + buf->printf("pragma (%s", d->ident->toChars()); + if (d->args && d->args->dim) + { + buf->writestring(", "); + argsToBuffer(d->args); + } + buf->writeByte(')'); + visit((AttribDeclaration *)d); + } + + void visit(ConditionalDeclaration *d) + { + d->condition->accept(this); + if (d->decl || d->elsedecl) + { + buf->writenl(); + buf->writeByte('{'); + buf->writenl(); + buf->level++; + if (d->decl) + { + for (size_t i = 0; i < d->decl->dim; i++) + (*d->decl)[i]->accept(this); + } + buf->level--; + buf->writeByte('}'); + if (d->elsedecl) + { + buf->writenl(); + buf->writestring("else"); + buf->writenl(); + buf->writeByte('{'); + buf->writenl(); + buf->level++; + for (size_t i = 0; i < d->elsedecl->dim; i++) + (*d->elsedecl)[i]->accept(this); + buf->level--; + buf->writeByte('}'); + } + } + else + buf->writeByte(':'); + buf->writenl(); + } + + void visit(CompileDeclaration *d) + { + buf->writestring("mixin("); + d->exp->accept(this); + buf->writestring(");"); + buf->writenl(); + } + + void visit(UserAttributeDeclaration *d) + { + buf->writestring("@("); + argsToBuffer(d->atts); + buf->writeByte(')'); + visit((AttribDeclaration *)d); + } + + void visit(TemplateDeclaration *d) + { + #if 0 // Should handle template functions for doc generation + if (onemember && onemember->isFuncDeclaration()) + buf->writestring("foo "); + #endif + if (hgs->hdrgen && visitEponymousMember(d)) + return; + + if (hgs->ddoc) + buf->writestring(d->kind()); + else + buf->writestring("template"); + buf->writeByte(' '); + buf->writestring(d->ident->toChars()); + buf->writeByte('('); + visitTemplateParameters(hgs->ddoc ? d->origParameters : d->parameters); + buf->writeByte(')'); + visitTemplateConstraint(d->constraint); + + if (hgs->hdrgen) + { + hgs->tpltMember++; + buf->writenl(); + buf->writeByte('{'); + buf->writenl(); + buf->level++; + for (size_t i = 0; i < d->members->dim; i++) + (*d->members)[i]->accept(this); + buf->level--; + buf->writeByte('}'); + buf->writenl(); + hgs->tpltMember--; + } + } + + bool visitEponymousMember(TemplateDeclaration *d) + { + if (!d->members || d->members->dim != 1) + return false; + + Dsymbol *onemember = (*d->members)[0]; + if (onemember->ident != d->ident) + return false; + + if (FuncDeclaration *fd = onemember->isFuncDeclaration()) + { + assert(fd->type); + StorageClassDeclaration::stcToCBuffer(buf, fd->storage_class); + functionToBufferFull((TypeFunction *)fd->type, buf, d->ident, hgs, d); + visitTemplateConstraint(d->constraint); + + hgs->tpltMember++; + bodyToBuffer(fd); + hgs->tpltMember--; + return true; + } + if (AggregateDeclaration *ad = onemember->isAggregateDeclaration()) + { + buf->writestring(ad->kind()); + buf->writeByte(' '); + buf->writestring(ad->ident->toChars()); + buf->writeByte('('); + visitTemplateParameters(hgs->ddoc ? d->origParameters : d->parameters); + buf->writeByte(')'); + visitTemplateConstraint(d->constraint); + visitBaseClasses(ad->isClassDeclaration()); + + hgs->tpltMember++; + if (ad->members) + { + buf->writenl(); + buf->writeByte('{'); + buf->writenl(); + buf->level++; + for (size_t i = 0; i < ad->members->dim; i++) + (*ad->members)[i]->accept(this); + buf->level--; + buf->writeByte('}'); + } + else + buf->writeByte(';'); + buf->writenl(); + hgs->tpltMember--; + return true; + } + + return false; + } + void visitTemplateParameters(TemplateParameters *parameters) + { + if (!parameters || !parameters->dim) + return; + for (size_t i = 0; i < parameters->dim; i++) + { + if (i) + buf->writestring(", "); + (*parameters)[i]->accept(this); + } + } + void visitTemplateConstraint(Expression *constraint) + { + if (!constraint) + return; + buf->writestring(" if ("); + constraint->accept(this); + buf->writeByte(')'); + } + + void visit(TemplateInstance *ti) + { + buf->writestring(ti->name->toChars()); + tiargsToBuffer(ti); + } + + void visit(TemplateMixin *tm) + { + buf->writestring("mixin "); + + typeToBuffer(tm->tqual, NULL); + tiargsToBuffer(tm); + + if (tm->ident && memcmp(tm->ident->string, "__mixin", 7) != 0) + { + buf->writeByte(' '); + buf->writestring(tm->ident->toChars()); + } + buf->writeByte(';'); + buf->writenl(); + } + + void tiargsToBuffer(TemplateInstance *ti) + { + buf->writeByte('!'); + if (ti->nest) + { + buf->writestring("(...)"); + return; + } + if (!ti->tiargs) + { + buf->writestring("()"); + return; + } + + if (ti->tiargs->dim == 1) + { + RootObject *oarg = (*ti->tiargs)[0]; + if (Type *t = isType(oarg)) + { + if (t->equals(Type::tstring) || + t->mod == 0 && + (t->isTypeBasic() || + t->ty == Tident && ((TypeIdentifier *)t)->idents.dim == 0)) + { + buf->writestring(t->toChars()); + return; + } + } + else if (Expression *e = isExpression(oarg)) + { + if (e->op == TOKint64 || + e->op == TOKfloat64 || + e->op == TOKnull || + e->op == TOKstring || + e->op == TOKthis) + { + buf->writestring(e->toChars()); + return; + } + } + } + buf->writeByte('('); + ti->nest++; + for (size_t i = 0; i < ti->tiargs->dim; i++) + { + if (i) + buf->writestring(", "); + objectToBuffer((*ti->tiargs)[i]); + } + ti->nest--; + buf->writeByte(')'); + } + + /**************************************** + * This makes a 'pretty' version of the template arguments. + * It's analogous to genIdent() which makes a mangled version. + */ + void objectToBuffer(RootObject *oarg) + { + //printf("objectToBuffer()\n"); + + /* The logic of this should match what genIdent() does. The _dynamic_cast() + * function relies on all the pretty strings to be unique for different classes + * (see Bugzilla 7375). + * Perhaps it would be better to demangle what genIdent() does. + */ + if (Type *t = isType(oarg)) + { + //printf("\tt: %s ty = %d\n", t->toChars(), t->ty); + typeToBuffer(t, NULL); + } + else if (Expression *e = isExpression(oarg)) + { + if (e->op == TOKvar) + e = e->optimize(WANTvalue); // added to fix Bugzilla 7375 + e->accept(this); + } + else if (Dsymbol *s = isDsymbol(oarg)) + { + const char *p = s->ident ? s->ident->toChars() : s->toChars(); + buf->writestring(p); + } + else if (Tuple *v = isTuple(oarg)) + { + Objects *args = &v->objects; + for (size_t i = 0; i < args->dim; i++) + { + if (i) + buf->writestring(", "); + objectToBuffer((*args)[i]); + } + } + else if (!oarg) + { + buf->writestring("NULL"); + } + else + { + #ifdef DEBUG + printf("bad Object = %p\n", oarg); + #endif + assert(0); + } + } + + void visit(EnumDeclaration *d) + { + buf->writestring("enum "); + if (d->ident) + { + buf->writestring(d->ident->toChars()); + buf->writeByte(' '); + } + if (d->memtype) + { + buf->writestring(": "); + typeToBuffer(d->memtype, NULL); + } + if (!d->members) + { + buf->writeByte(';'); + buf->writenl(); + return; + } + buf->writenl(); + buf->writeByte('{'); + buf->writenl(); + buf->level++; + for (size_t i = 0; i < d->members->dim; i++) + { + EnumMember *em = (*d->members)[i]->isEnumMember(); + if (!em) + continue; + em->accept(this); + buf->writeByte(','); + buf->writenl(); + } + buf->level--; + buf->writeByte('}'); + buf->writenl(); + } + + void visit(Nspace *d) + { + buf->writestring("extern (C++, "); + buf->writestring(d->ident->string); + buf->writeByte(')'); + buf->writenl(); + buf->writeByte('{'); + buf->writenl(); + buf->level++; + for (size_t i = 0; i < d->members->dim; i++) + (*d->members)[i]->accept(this); + buf->level--; + buf->writeByte('}'); + buf->writenl(); + } + + void visit(StructDeclaration *d) + { + buf->printf("%s ", d->kind()); + if (!d->isAnonymous()) + buf->writestring(d->toChars()); + if (!d->members) + { + buf->writeByte(';'); + buf->writenl(); + return; + } + buf->writenl(); + buf->writeByte('{'); + buf->writenl(); + buf->level++; + for (size_t i = 0; i < d->members->dim; i++) + (*d->members)[i]->accept(this); + buf->level--; + buf->writeByte('}'); + buf->writenl(); + } + + void visit(ClassDeclaration *d) + { + if (!d->isAnonymous()) + { + buf->writestring(d->kind()); + buf->writeByte(' '); + buf->writestring(d->ident->toChars()); + } + visitBaseClasses(d); + if (d->members) + { + buf->writenl(); + buf->writeByte('{'); + buf->writenl(); + buf->level++; + for (size_t i = 0; i < d->members->dim; i++) + (*d->members)[i]->accept(this); + buf->level--; + buf->writeByte('}'); + } + else + buf->writeByte(';'); + buf->writenl(); + } + + void visitBaseClasses(ClassDeclaration *d) + { + if (!d || !d->baseclasses->dim) + return; + + buf->writestring(" : "); + for (size_t i = 0; i < d->baseclasses->dim; i++) + { + if (i) + buf->writestring(", "); + BaseClass *b = (*d->baseclasses)[i]; + typeToBuffer(b->type, NULL); + } + } + + void visit(AliasDeclaration *d) + { + buf->writestring("alias "); + if (d->aliassym) + { + d->aliassym->accept(this); + buf->writeByte(' '); + buf->writestring(d->ident->toChars()); + } + else + typeToBuffer(d->type, d->ident); + buf->writeByte(';'); + buf->writenl(); + } + + void visit(VarDeclaration *d) + { + visitVarDecl(d, false); + buf->writeByte(';'); + buf->writenl(); + } + void visitVarDecl(VarDeclaration *v, bool anywritten) + { + if (anywritten) + { + buf->writestring(", "); + buf->writestring(v->ident->toChars()); + } + else + { + StorageClassDeclaration::stcToCBuffer(buf, v->storage_class); + if (v->type) + typeToBuffer(v->type, v->ident); + else + buf->writestring(v->ident->toChars()); + } + if (v->init) + { + buf->writestring(" = "); + ExpInitializer *ie = v->init->isExpInitializer(); + if (ie && (ie->exp->op == TOKconstruct || ie->exp->op == TOKblit)) + ((AssignExp *)ie->exp)->e2->accept(this); + else + v->init->accept(this); + } + } + + void visit(FuncDeclaration *f) + { + //printf("FuncDeclaration::toCBuffer() '%s'\n", toChars()); + + StorageClassDeclaration::stcToCBuffer(buf, f->storage_class); + typeToBuffer(f->type, f->ident); + if (hgs->hdrgen == 1) + { + if (f->storage_class & STCauto) + { + hgs->autoMember++; + bodyToBuffer(f); + hgs->autoMember--; + } + else if (hgs->tpltMember == 0 && !global.params.useInline) + { + buf->writeByte(';'); + buf->writenl(); + } + else + bodyToBuffer(f); + } + else + bodyToBuffer(f); + } + + void bodyToBuffer(FuncDeclaration *f) + { + if (!f->fbody || (hgs->hdrgen && !global.params.useInline && !hgs->autoMember && !hgs->tpltMember)) + { + buf->writeByte(';'); + buf->writenl(); + return; + } + + int savetlpt = hgs->tpltMember; + int saveauto = hgs->autoMember; + hgs->tpltMember = 0; + hgs->autoMember = 0; + + buf->writenl(); + + // in{} + if (f->frequire) + { + buf->writestring("in"); + buf->writenl(); + f->frequire->accept(this); + } + + // out{} + if (f->fensure) + { + buf->writestring("out"); + if (f->outId) + { + buf->writeByte('('); + buf->writestring(f->outId->toChars()); + buf->writeByte(')'); + } + buf->writenl(); + f->fensure->accept(this); + } + + if (f->frequire || f->fensure) + { + buf->writestring("body"); + buf->writenl(); + } + + buf->writeByte('{'); + buf->writenl(); + buf->level++; + f->fbody->accept(this); + buf->level--; + buf->writeByte('}'); + buf->writenl(); + + hgs->tpltMember = savetlpt; + hgs->autoMember = saveauto; + } + + void visit(FuncLiteralDeclaration *f) + { + if (f->type->ty == Terror) + { + buf->writestring("__error"); + return; + } + + if (f->tok != TOKreserved) + { + buf->writestring(f->kind()); + buf->writeByte(' '); + } + + TypeFunction *tf = (TypeFunction *)f->type; + // Don't print tf->mod, tf->trust, and tf->linkage + if (!f->inferRetType && tf->next) + typeToBuffer(tf->next, NULL); + parametersToBuffer(tf->parameters, tf->varargs); + + CompoundStatement *cs = f->fbody->isCompoundStatement(); + Statement *s1; + if (f->semanticRun >= PASSsemantic3done && cs) + { + s1 = (*cs->statements)[cs->statements->dim - 1]; + } + else + s1 = !cs ? f->fbody : NULL; + ReturnStatement *rs = s1 ? s1->isReturnStatement() : NULL; + if (rs && rs->exp) + { + buf->writestring(" => "); + rs->exp->accept(this); + } + else + { + hgs->tpltMember++; + bodyToBuffer(f); + hgs->tpltMember--; + } + } + + void visit(PostBlitDeclaration *d) + { + buf->writestring("this(this)"); + bodyToBuffer(d); + } + + void visit(DtorDeclaration *d) + { + buf->writestring("~this()"); + bodyToBuffer(d); + } + + void visit(StaticCtorDeclaration *d) + { + StorageClassDeclaration::stcToCBuffer(buf, d->storage_class & ~STCstatic); + if (d->isSharedStaticCtorDeclaration()) + buf->writestring("shared "); + buf->writestring("static this()"); + if (hgs->hdrgen && !hgs->tpltMember) + { + buf->writeByte(';'); + buf->writenl(); + } + else + bodyToBuffer(d); + } + + void visit(StaticDtorDeclaration *d) + { + if (hgs->hdrgen) + return; + StorageClassDeclaration::stcToCBuffer(buf, d->storage_class & ~STCstatic); + if (d->isSharedStaticDtorDeclaration()) + buf->writestring("shared "); + buf->writestring("static ~this()"); + bodyToBuffer(d); + } + + void visit(InvariantDeclaration *d) + { + if (hgs->hdrgen) + return; + StorageClassDeclaration::stcToCBuffer(buf, d->storage_class); + buf->writestring("invariant"); + bodyToBuffer(d); + } + + void visit(UnitTestDeclaration *d) + { + if (hgs->hdrgen) + return; + StorageClassDeclaration::stcToCBuffer(buf, d->storage_class); + buf->writestring("unittest"); + bodyToBuffer(d); + } + + void visit(NewDeclaration *d) + { + StorageClassDeclaration::stcToCBuffer(buf, d->storage_class & ~STCstatic); + buf->writestring("new"); + parametersToBuffer(d->arguments, d->varargs); + bodyToBuffer(d); + } + + void visit(DeleteDeclaration *d) + { + StorageClassDeclaration::stcToCBuffer(buf, d->storage_class & ~STCstatic); + buf->writestring("delete"); + parametersToBuffer(d->arguments, 0); + bodyToBuffer(d); + } + + //////////////////////////////////////////////////////////////////////////// + + void visit(ErrorInitializer *iz) + { + buf->writestring("__error__"); + } + + void visit(VoidInitializer *iz) + { + buf->writestring("void"); + } + + void visit(StructInitializer *si) + { + //printf("StructInitializer::toCBuffer()\n"); + buf->writeByte('{'); + for (size_t i = 0; i < si->field.dim; i++) + { + if (i) + buf->writestring(", "); + if (Identifier *id = si->field[i]) + { + buf->writestring(id->toChars()); + buf->writeByte(':'); + } + if (Initializer *iz = si->value[i]) + iz->accept(this); + } + buf->writeByte('}'); + } + + void visit(ArrayInitializer *ai) + { + buf->writeByte('['); + for (size_t i = 0; i < ai->index.dim; i++) + { + if (i) + buf->writestring(", "); + if (Expression *ex = ai->index[i]) + { + ex->accept(this); + buf->writeByte(':'); + } + if (Initializer *iz = ai->value[i]) + iz->accept(this); + } + buf->writeByte(']'); + } + + void visit(ExpInitializer *ei) + { + ei->exp->accept(this); + } + + //////////////////////////////////////////////////////////////////////////// + + /************************************************** + * Write out argument list to buf. + */ + void argsToBuffer(Expressions *expressions) + { + if (!expressions || !expressions->dim) + return; + + for (size_t i = 0; i < expressions->dim; i++) + { + if (i) + buf->writestring(", "); + if (Expression *e = (*expressions)[i]) + expToBuffer(e, PREC_assign); + } + } + + void sizeToBuffer(Expression *e) + { + if (e->type == Type::tsize_t) + { + Expression *ex = (e->op == TOKcast ? ((CastExp *)e)->e1 : e); + ex = ex->optimize(WANTvalue); + + dinteger_t uval = ex->op == TOKint64 ? ex->toInteger() : (dinteger_t)-1; + if ((sinteger_t)uval >= 0) + { + dinteger_t sizemax; + if (Target::ptrsize == 4) + sizemax = 0xFFFFFFFFUL; + else if (Target::ptrsize == 8) + sizemax = 0xFFFFFFFFFFFFFFFFULL; + else + assert(0); + if (uval <= sizemax && uval <= 0x7FFFFFFFFFFFFFFFULL) + { + buf->printf("%llu", uval); + return; + } + } + } + expToBuffer(e, PREC_assign); + } + + /************************************************** + * Write expression out to buf, but wrap it + * in ( ) if its precedence is less than pr. + */ + void expToBuffer(Expression *e, PREC pr) + { + #ifdef DEBUG + if (precedence[e->op] == PREC_zero) + printf("precedence not defined for token '%s'\n", Token::tochars[e->op]); + #endif + assert(precedence[e->op] != PREC_zero); + assert(pr != PREC_zero); + + //if (precedence[e->op] == 0) e->print(); + /* Despite precedence, we don't allow aop] < pr || + (pr == PREC_rel && precedence[e->op] == pr)) + { + buf->writeByte('('); + e->accept(this); + buf->writeByte(')'); + } + else + e->accept(this); + } void visit(Expression *e) { @@ -1026,14 +2049,6 @@ public: goto L1; } - case Ttypedef: - { - TypeTypedef *tt = (TypeTypedef *)t; - buf->printf("cast(%s)", tt->sym->toChars()); - t = tt->sym->basetype; - goto L1; - } - case Twchar: // BUG: need to cast(wchar) case Tdchar: // BUG: need to cast(dchar) if ((uinteger_t)v > 0xFF) @@ -1091,7 +2106,7 @@ public: break; case Tbool: - buf->writestring((char *)(v ? "true" : "false")); + buf->writestring(v ? "true" : "false"); break; case Tpointer: @@ -1132,22 +2147,21 @@ public: void floatToBuffer(Type *type, real_t value) { - /* In order to get an exact representation, try converting it - * to decimal then back again. If it matches, use it. - * If it doesn't, fall back to hex, which is - * always exact. - * Longest string is for -real.max: - * "-1.18973e+4932\0".length == 17 - * "-0xf.fffffffffffffffp+16380\0".length == 28 - */ - const size_t BUFFER_LEN = 32; + /** sizeof(value)*3 is because each byte of mantissa is max + of 256 (3 characters). The string will be "-M.MMMMe-4932". + (ie, 8 chars more than mantissa). Plus one for trailing \0. + Plus one for rounding. */ + const size_t BUFFER_LEN = sizeof(value) * 3 + 8 + 1 + 1; char buffer[BUFFER_LEN]; ld_sprint(buffer, 'g', value); assert(strlen(buffer) < BUFFER_LEN); - real_t r = Port::strtold(buffer, NULL); - if (r != value) // if exact duplication - ld_sprint(buffer, 'a', value); + if (hgs->hdrgen) + { + real_t r = Port::strtold(buffer, NULL); + if (r != value) // if exact duplication + ld_sprint(buffer, 'a', value); + } buf->writestring(buffer); if (type) @@ -1231,12 +2245,11 @@ public: { case '"': case '\\': - if (!hgs->console) - buf->writeByte('\\'); + buf->writeByte('\\'); default: if (c <= 0xFF) { - if (c <= 0x7F && (isprint(c) || hgs->console)) + if (c <= 0x7F && isprint(c)) buf->writeByte(c); else buf->printf("\\x%02x", c); @@ -1259,7 +2272,7 @@ public: void visit(ArrayLiteralExp *e) { buf->writeByte('['); - argsToCBuffer(buf, e->elements, hgs); + argsToBuffer(e->elements); buf->writeByte(']'); } @@ -1273,9 +2286,9 @@ public: if (i) buf->writestring(", "); - expToCBuffer(buf, hgs, key, PREC_assign); + expToBuffer(key, PREC_assign); buf->writeByte(':'); - expToCBuffer(buf, hgs, value, PREC_assign); + expToBuffer(value, PREC_assign); } buf->writeByte(']'); } @@ -1295,7 +2308,7 @@ public: { int old = e->stageflags; e->stageflags |= stageToCBuffer; - argsToCBuffer(buf, e->elements, hgs); + argsToBuffer(e->elements); e->stageflags = old; } @@ -1304,28 +2317,28 @@ public: void visit(TypeExp *e) { - e->type->toCBuffer(buf, NULL, hgs); + typeToBuffer(e->type, NULL); } void visit(ScopeExp *e) { if (e->sds->isTemplateInstance()) { - e->sds->toCBuffer(buf, hgs); + e->sds->accept(this); } else if (hgs != NULL && hgs->ddoc) { // fixes bug 6491 - Module *module = e->sds->isModule(); - if (module) - buf->writestring(module->md->toChars()); + Module *m = e->sds->isModule(); + if (m) + buf->writestring(m->md->toChars()); else buf->writestring(e->sds->toChars()); } else { buf->writestring(e->sds->kind()); - buf->writestring(" "); + buf->writeByte(' '); buf->writestring(e->sds->toChars()); } } @@ -1339,21 +2352,21 @@ public: { if (e->thisexp) { - expToCBuffer(buf, hgs, e->thisexp, PREC_primary); + expToBuffer(e->thisexp, PREC_primary); buf->writeByte('.'); } buf->writestring("new "); if (e->newargs && e->newargs->dim) { buf->writeByte('('); - argsToCBuffer(buf, e->newargs, hgs); + argsToBuffer(e->newargs); buf->writeByte(')'); } - e->newtype->toCBuffer(buf, NULL, hgs); + typeToBuffer(e->newtype, NULL); if (e->arguments && e->arguments->dim) { buf->writeByte('('); - argsToCBuffer(buf, e->arguments, hgs); + argsToBuffer(e->arguments); buf->writeByte(')'); } } @@ -1362,28 +2375,25 @@ public: { if (e->thisexp) { - expToCBuffer(buf, hgs, e->thisexp, PREC_primary); + expToBuffer(e->thisexp, PREC_primary); buf->writeByte('.'); } buf->writestring("new"); if (e->newargs && e->newargs->dim) { buf->writeByte('('); - argsToCBuffer(buf, e->newargs, hgs); + argsToBuffer(e->newargs); buf->writeByte(')'); } buf->writestring(" class "); if (e->arguments && e->arguments->dim) { buf->writeByte('('); - argsToCBuffer(buf, e->arguments, hgs); + argsToBuffer(e->arguments); buf->writeByte(')'); } - //buf->writestring(" { }"); if (e->cd) - { - e->cd->toCBuffer(buf, hgs); - } + e->cd->accept(this); } void visit(SymOffExp *e) @@ -1411,34 +2421,34 @@ public: if (e->e0) { buf->writeByte('('); - e->e0->toCBuffer(buf, hgs); + e->e0->accept(this); buf->writestring(", tuple("); - argsToCBuffer(buf, e->exps, hgs); + argsToBuffer(e->exps); buf->writestring("))"); } else { buf->writestring("tuple("); - argsToCBuffer(buf, e->exps, hgs); + argsToBuffer(e->exps); buf->writeByte(')'); } } void visit(FuncExp *e) { - e->fd->toCBuffer(buf, hgs); + e->fd->accept(this); //buf->writestring(e->fd->toChars()); } void visit(DeclarationExp *e) { - e->declaration->toCBuffer(buf, hgs); + e->declaration->accept(this); } void visit(TypeidExp *e) { buf->writestring("typeid("); - ObjectToCBuffer(buf, hgs, e->obj); + objectToBuffer(e->obj); buf->writeByte(')'); } @@ -1451,8 +2461,7 @@ public: for (size_t i = 0; i < e->args->dim; i++) { buf->writestring(", ");; - RootObject *oarg = (*e->args)[i]; - ObjectToCBuffer(buf, hgs, oarg); + objectToBuffer((*e->args)[i]); } } buf->writeByte(')'); @@ -1466,7 +2475,7 @@ public: void visit(IsExp *e) { buf->writestring("is("); - e->targ->toCBuffer(buf, e->id, hgs); + typeToBuffer(e->targ, e->id); if (e->tok2 != TOKreserved) { buf->printf(" %s %s", Token::toChars(e->tok), Token::toChars(e->tok2)); @@ -1477,16 +2486,12 @@ public: buf->writestring(" : "); else buf->writestring(" == "); - e->tspec->toCBuffer(buf, NULL, hgs); + typeToBuffer(e->tspec, NULL); } - if (e->parameters) + if (e->parameters && e->parameters->dim) { - for (size_t i = 0; i < e->parameters->dim; i++) - { - buf->writestring(", "); - TemplateParameter *tp = (*e->parameters)[i]; - tp->toCBuffer(buf, hgs); - } + buf->writestring(", "); + visitTemplateParameters(e->parameters); } buf->writeByte(')'); } @@ -1494,71 +2499,70 @@ public: void visit(UnaExp *e) { buf->writestring(Token::toChars(e->op)); - expToCBuffer(buf, hgs, e->e1, precedence[e->op]); + expToBuffer(e->e1, precedence[e->op]); } void visit(BinExp *e) { - expToCBuffer(buf, hgs, e->e1, precedence[e->op]); + expToBuffer(e->e1, precedence[e->op]); buf->writeByte(' '); buf->writestring(Token::toChars(e->op)); buf->writeByte(' '); - expToCBuffer(buf, hgs, e->e2, (PREC)(precedence[e->op] + 1)); + expToBuffer(e->e2, (PREC)(precedence[e->op] + 1)); } void visit(CompileExp *e) { buf->writestring("mixin("); - expToCBuffer(buf, hgs, e->e1, PREC_assign); + expToBuffer(e->e1, PREC_assign); buf->writeByte(')'); } void visit(FileExp *e) { buf->writestring("import("); - expToCBuffer(buf, hgs, e->e1, PREC_assign); + expToBuffer(e->e1, PREC_assign); buf->writeByte(')'); } void visit(AssertExp *e) { buf->writestring("assert("); - expToCBuffer(buf, hgs, e->e1, PREC_assign); + expToBuffer(e->e1, PREC_assign); if (e->msg) { buf->writestring(", "); - expToCBuffer(buf, hgs, e->msg, PREC_assign); + expToBuffer(e->msg, PREC_assign); } buf->writeByte(')'); } void visit(DotIdExp *e) { - //printf("DotIdExp::toCBuffer()\n"); - expToCBuffer(buf, hgs, e->e1, PREC_primary); + expToBuffer(e->e1, PREC_primary); buf->writeByte('.'); buf->writestring(e->ident->toChars()); } void visit(DotTemplateExp *e) { - expToCBuffer(buf, hgs, e->e1, PREC_primary); + expToBuffer(e->e1, PREC_primary); buf->writeByte('.'); buf->writestring(e->td->toChars()); } void visit(DotVarExp *e) { - expToCBuffer(buf, hgs, e->e1, PREC_primary); + expToBuffer(e->e1, PREC_primary); buf->writeByte('.'); buf->writestring(e->var->toChars()); } void visit(DotTemplateInstanceExp *e) { - expToCBuffer(buf, hgs, e->e1, PREC_primary); + expToBuffer(e->e1, PREC_primary); buf->writeByte('.'); - e->ti->toCBuffer(buf, hgs); + e->ti->accept(this); } void visit(DelegateExp *e) @@ -1566,7 +2570,7 @@ public: buf->writeByte('&'); if (!e->func->isNested()) { - expToCBuffer(buf, hgs, e->e1, PREC_primary); + expToBuffer(e->e1, PREC_primary); buf->writeByte('.'); } buf->writestring(e->func->toChars()); @@ -1574,7 +2578,7 @@ public: void visit(DotTypeExp *e) { - expToCBuffer(buf, hgs, e->e1, PREC_primary); + expToBuffer(e->e1, PREC_primary); buf->writeByte('.'); buf->writestring(e->sym->toChars()); } @@ -1588,142 +2592,142 @@ public: * This is ok since types in constructor calls * can never depend on parens anyway */ - e->e1->toCBuffer(buf, hgs); + e->e1->accept(this); } else - expToCBuffer(buf, hgs, e->e1, precedence[e->op]); + expToBuffer(e->e1, precedence[e->op]); buf->writeByte('('); - argsToCBuffer(buf, e->arguments, hgs); + argsToBuffer(e->arguments); buf->writeByte(')'); } void visit(PtrExp *e) { buf->writeByte('*'); - expToCBuffer(buf, hgs, e->e1, precedence[e->op]); + expToBuffer(e->e1, precedence[e->op]); } void visit(DeleteExp *e) { buf->writestring("delete "); - expToCBuffer(buf, hgs, e->e1, precedence[e->op]); + expToBuffer(e->e1, precedence[e->op]); } void visit(CastExp *e) { buf->writestring("cast("); if (e->to) - e->to->toCBuffer(buf, NULL, hgs); + typeToBuffer(e->to, NULL); else { MODtoBuffer(buf, e->mod); } buf->writeByte(')'); - expToCBuffer(buf, hgs, e->e1, precedence[e->op]); + expToBuffer(e->e1, precedence[e->op]); } void visit(VectorExp *e) { buf->writestring("cast("); - e->to->toCBuffer(buf, NULL, hgs); + typeToBuffer(e->to, NULL); buf->writeByte(')'); - expToCBuffer(buf, hgs, e->e1, precedence[e->op]); + expToBuffer(e->e1, precedence[e->op]); } void visit(SliceExp *e) { - expToCBuffer(buf, hgs, e->e1, precedence[e->op]); + expToBuffer(e->e1, precedence[e->op]); buf->writeByte('['); if (e->upr || e->lwr) { if (e->lwr) - sizeToCBuffer(buf, hgs, e->lwr); + sizeToBuffer(e->lwr); else buf->writeByte('0'); buf->writestring(".."); if (e->upr) - sizeToCBuffer(buf, hgs, e->upr); + sizeToBuffer(e->upr); else - buf->writestring("$"); + buf->writeByte('$'); } buf->writeByte(']'); } void visit(ArrayLengthExp *e) { - expToCBuffer(buf, hgs, e->e1, PREC_primary); + expToBuffer(e->e1, PREC_primary); buf->writestring(".length"); } void visit(IntervalExp *e) { - expToCBuffer(buf, hgs, e->lwr, PREC_assign); + expToBuffer(e->lwr, PREC_assign); buf->writestring(".."); - expToCBuffer(buf, hgs, e->upr, PREC_assign); + expToBuffer(e->upr, PREC_assign); } void visit(DelegatePtrExp *e) { - expToCBuffer(buf, hgs, e->e1, PREC_primary); + expToBuffer(e->e1, PREC_primary); buf->writestring(".ptr"); } void visit(DelegateFuncptrExp *e) { - expToCBuffer(buf, hgs, e->e1, PREC_primary); + expToBuffer(e->e1, PREC_primary); buf->writestring(".funcptr"); } void visit(ArrayExp *e) { - expToCBuffer(buf, hgs, e->e1, PREC_primary); + expToBuffer(e->e1, PREC_primary); buf->writeByte('['); - argsToCBuffer(buf, e->arguments, hgs); + argsToBuffer(e->arguments); buf->writeByte(']'); } void visit(DotExp *e) { - expToCBuffer(buf, hgs, e->e1, PREC_primary); + expToBuffer(e->e1, PREC_primary); buf->writeByte('.'); - expToCBuffer(buf, hgs, e->e2, PREC_primary); + expToBuffer(e->e2, PREC_primary); } void visit(IndexExp *e) { - expToCBuffer(buf, hgs, e->e1, PREC_primary); + expToBuffer(e->e1, PREC_primary); buf->writeByte('['); - sizeToCBuffer(buf, hgs, e->e2); + sizeToBuffer(e->e2); buf->writeByte(']'); } void visit(PostExp *e) { - expToCBuffer(buf, hgs, e->e1, precedence[e->op]); + expToBuffer(e->e1, precedence[e->op]); buf->writestring(Token::toChars(e->op)); } void visit(PreExp *e) { buf->writestring(Token::toChars(e->op)); - expToCBuffer(buf, hgs, e->e1, precedence[e->op]); + expToBuffer(e->e1, precedence[e->op]); } void visit(RemoveExp *e) { - expToCBuffer(buf, hgs, e->e1, PREC_primary); + expToBuffer(e->e1, PREC_primary); buf->writestring(".remove("); - expToCBuffer(buf, hgs, e->e2, PREC_assign); - buf->writestring(")"); + expToBuffer(e->e2, PREC_assign); + buf->writeByte(')'); } void visit(CondExp *e) { - expToCBuffer(buf, hgs, e->econd, PREC_oror); + expToBuffer(e->econd, PREC_oror); buf->writestring(" ? "); - expToCBuffer(buf, hgs, e->e1, PREC_expr); + expToBuffer(e->e1, PREC_expr); buf->writestring(" : "); - expToCBuffer(buf, hgs, e->e2, PREC_cond); + expToBuffer(e->e2, PREC_cond); } void visit(DefaultInitExp *e) @@ -1735,6 +2739,198 @@ public: { buf->writestring(e->value->toChars()); } + + //////////////////////////////////////////////////////////////////////////// + + void visit(TemplateTypeParameter *tp) + { + buf->writestring(tp->ident->toChars()); + if (tp->specType) + { + buf->writestring(" : "); + typeToBuffer(tp->specType, NULL); + } + if (tp->defaultType) + { + buf->writestring(" = "); + typeToBuffer(tp->defaultType, NULL); + } + } + + void visit(TemplateThisParameter *tp) + { + buf->writestring("this "); + visit((TemplateTypeParameter *)tp); + } + + void visit(TemplateAliasParameter *tp) + { + buf->writestring("alias "); + if (tp->specType) + typeToBuffer(tp->specType, tp->ident); + else + buf->writestring(tp->ident->toChars()); + if (tp->specAlias) + { + buf->writestring(" : "); + objectToBuffer(tp->specAlias); + } + if (tp->defaultAlias) + { + buf->writestring(" = "); + objectToBuffer(tp->defaultAlias); + } + } + + void visit(TemplateValueParameter *tp) + { + typeToBuffer(tp->valType, tp->ident); + if (tp->specValue) + { + buf->writestring(" : "); + tp->specValue->accept(this); + } + if (tp->defaultValue) + { + buf->writestring(" = "); + tp->defaultValue->accept(this); + } + } + + void visit(TemplateTupleParameter *tp) + { + buf->writestring(tp->ident->toChars()); + buf->writestring("..."); + } + + //////////////////////////////////////////////////////////////////////////// + + void visit(DebugCondition *c) + { + if (c->ident) + buf->printf("debug (%s)", c->ident->toChars()); + else + buf->printf("debug (%u)", c->level); + } + + void visit(VersionCondition *c) + { + if (c->ident) + buf->printf("version (%s)", c->ident->toChars()); + else + buf->printf("version (%u)", c->level); + } + + void visit(StaticIfCondition *c) + { + buf->writestring("static if ("); + c->exp->accept(this); + buf->writeByte(')'); + } + + //////////////////////////////////////////////////////////////////////////// + + void visit(Parameter *p) + { + if (p->storageClass & STCauto) + buf->writestring("auto "); + + if (p->storageClass & STCout) + buf->writestring("out "); + else if (p->storageClass & STCref) + buf->writestring("ref "); + else if (p->storageClass & STCin) + buf->writestring("in "); + else if (p->storageClass & STClazy) + buf->writestring("lazy "); + else if (p->storageClass & STCalias) + buf->writestring("alias "); + + StorageClass stc = p->storageClass; + if (p->type && p->type->mod & MODshared) + stc &= ~STCshared; + + StorageClassDeclaration::stcToCBuffer(buf, + stc & (STCconst | STCimmutable | STCwild | STCshared | STCscope)); + + if (p->storageClass & STCalias) + { + if (p->ident) + buf->writestring(p->ident->toChars()); + } + else if (p->type->ty == Tident && + ((TypeIdentifier *)p->type)->ident->len > 3 && + strncmp(((TypeIdentifier *)p->type)->ident->string, "__T", 3) == 0) + { + // print parameter name, instead of undetermined type parameter + buf->writestring(p->ident->toChars()); + } + else + typeToBuffer(p->type, p->ident); + if (p->defaultArg) + { + buf->writestring(" = "); + p->defaultArg->accept(this); + } + } + + void parametersToBuffer(Parameters *parameters, int varargs) + { + buf->writeByte('('); + if (parameters) + { + size_t dim = Parameter::dim(parameters); + for (size_t i = 0; i < dim; i++) + { + if (i) + buf->writestring(", "); + Parameter *fparam = Parameter::getNth(parameters, i); + fparam->accept(this); + } + if (varargs) + { + if (parameters->dim && varargs == 1) + buf->writestring(", "); + buf->writestring("..."); + } + } + buf->writeByte(')'); + } + + void visit(Module *m) + { + if (m->md) + { + if (m->userAttribDecl) + { + buf->writestring("@("); + argsToBuffer(m->userAttribDecl->atts); + buf->writeByte(')'); + buf->writenl(); + } + if (m->md->isdeprecated) + { + if (m->md->msg) + { + buf->writestring("deprecated("); + m->md->msg->accept(this); + buf->writestring(") "); + } + else + buf->writestring("deprecated "); + } + + buf->writestring("module "); + buf->writestring(m->md->toChars()); + buf->writeByte(';'); + buf->writenl(); + } + for (size_t i = 0; i < m->members->dim; i++) + { + Dsymbol *s = (*m->members)[i]; + s->accept(this); + } + } }; void toCBuffer(Statement *s, OutBuffer *buf, HdrGenState *hgs) @@ -1745,30 +2941,29 @@ void toCBuffer(Statement *s, OutBuffer *buf, HdrGenState *hgs) void toCBuffer(Type *t, OutBuffer *buf, Identifier *ident, HdrGenState *hgs) { - if (t->ty == Tfunction) - { - functionToBufferFull((TypeFunction *)t, buf, ident, hgs, NULL); - return; - } - if (t->ty == Terror) - { - buf->writestring("_error_"); - return; - } - - toBufferShort(t, buf, hgs); - if (ident) - { - buf->writeByte(' '); - buf->writestring(ident->toChars()); - } + PrettyPrintVisitor v(buf, hgs); + v.typeToBuffer(t, ident); } -// Bypass the special printing of function and error types -void toBufferShort(Type *t, OutBuffer *buf, HdrGenState *hgs) +void toCBuffer(Dsymbol *s, OutBuffer *buf, HdrGenState *hgs) { PrettyPrintVisitor v(buf, hgs); - v.visitWithMask(t, 0); + s->accept(&v); +} + +// used from TemplateInstance::toChars() and TemplateMixin::toChars() +void toCBufferInstance(TemplateInstance *ti, OutBuffer *buf, bool qualifyTypes) +{ + HdrGenState hgs; + hgs.fullQual = qualifyTypes; + PrettyPrintVisitor v(buf, &hgs); + v.visit(ti); +} + +void toCBuffer(Initializer *iz, OutBuffer *buf, HdrGenState *hgs) +{ + PrettyPrintVisitor v(buf, hgs); + iz->accept(&v); } void trustToBuffer(OutBuffer *buf, TRUST trust) @@ -1817,16 +3012,25 @@ const char *linkageToChars(LINK linkage) return NULL; // never reached } -void protectionToBuffer(OutBuffer *buf, PROT prot) +void protectionToBuffer(OutBuffer *buf, Prot prot) { - const char *p = protectionToChars(prot); + const char *p = protectionToChars(prot.kind); if (p) buf->writestring(p); + + if (prot.kind == PROTpackage && prot.pkg) + { + Package *ppkg = prot.pkg; + + buf->writeByte('('); + buf->writestring(prot.pkg->toPrettyChars(true)); + buf->writeByte(')'); + } } -const char *protectionToChars(PROT prot) +const char *protectionToChars(PROTKIND kind) { - switch (prot) + switch (kind) { case PROTundefined: return NULL; case PROTnone: return "none"; @@ -1840,94 +3044,21 @@ const char *protectionToChars(PROT prot) return NULL; // never reached } -// callback for TypeFunction::attributesApply, avoids 'ref' in ctors and appends spaces -struct PostAppendStrings -{ - bool isCtor; - OutBuffer *buf; - - static int fp(void *param, const char *str) - { - PostAppendStrings *p = (PostAppendStrings *)param; - - // don't write 'ref' for ctors - if (p->isCtor && strcmp(str, "ref") == 0) - return 0; - - p->buf->writestring(str); - p->buf->writeByte(' '); - return 0; - } -}; - // Print the full function signature with correct ident, attributes and template args void functionToBufferFull(TypeFunction *tf, OutBuffer *buf, Identifier *ident, HdrGenState* hgs, TemplateDeclaration *td) { //printf("TypeFunction::toCBuffer() this = %p\n", this); - if (tf->inuse) - { - tf->inuse = 2; // flag error to caller - return; - } - tf->inuse++; - - /* Use 'storage class' style for attributes - */ - if (tf->mod) - { - MODtoBuffer(buf, tf->mod); - buf->writeByte(' '); - } - - PostAppendStrings pas; - pas.isCtor = (ident == Id::ctor); - pas.buf = buf; - tf->attributesApply(&pas, &PostAppendStrings::fp); - - if (tf->linkage > LINKd && hgs->ddoc != 1 && !hgs->hdrgen) - { - linkageToBuffer(buf, tf->linkage); - buf->writeByte(' '); - } - - if (ident && ident->toHChars2() != ident->toChars()) - { - } - else if (tf->next) - { - toBufferShort(tf->next, buf, hgs); - if (ident) - buf->writeByte(' '); - } - else if (hgs->ddoc) - buf->writestring("auto "); - - if (ident) - buf->writestring(ident->toHChars2()); - - if (td) - { - buf->writeByte('('); - for (size_t i = 0; i < td->origParameters->dim; i++) - { - TemplateParameter *tp = (*td->origParameters)[i]; - if (i) - buf->writestring(", "); - tp->toCBuffer(buf, hgs); - } - buf->writeByte(')'); - } - Parameter::argsToCBuffer(buf, hgs, tf->parameters, tf->varargs); - tf->inuse--; + PrettyPrintVisitor v(buf, hgs); + v.visitFuncIdentWithPrefix(tf, ident, td, true); } // ident is inserted before the argument list and will be "function" or "delegate" for a type -void functionToBufferWithIdent(TypeFunction *t, OutBuffer *buf, const char *ident) +void functionToBufferWithIdent(TypeFunction *tf, OutBuffer *buf, const char *ident) { HdrGenState hgs; PrettyPrintVisitor v(buf, &hgs); - v.visitFuncIdent(t, ident); + v.visitFuncIdentWithPostfix(tf, ident); } void toCBuffer(Expression *e, OutBuffer *buf, HdrGenState *hgs) @@ -1936,78 +3067,50 @@ void toCBuffer(Expression *e, OutBuffer *buf, HdrGenState *hgs) e->accept(&v); } -void sizeToCBuffer(OutBuffer *buf, HdrGenState *hgs, Expression *e) -{ - if (e->type == Type::tsize_t) - { - Expression *ex = (e->op == TOKcast ? ((CastExp *)e)->e1 : e); - ex = ex->optimize(WANTvalue); - - dinteger_t uval = ex->op == TOKint64 ? ex->toInteger() : (dinteger_t)-1; - if ((sinteger_t)uval >= 0) - { - dinteger_t sizemax; - if (Target::ptrsize == 4) - sizemax = 0xFFFFFFFFUL; - else if (Target::ptrsize == 8) - sizemax = 0xFFFFFFFFFFFFFFFFULL; - else - assert(0); - if (uval <= sizemax && uval <= 0x7FFFFFFFFFFFFFFFULL) - { - buf->printf("%llu", uval); - return; - } - } - } - expToCBuffer(buf, hgs, e, PREC_assign); -} - - /************************************************** - * Write expression out to buf, but wrap it - * in ( ) if its precedence is less than pr. + * Write out argument types to buf. */ - -void expToCBuffer(OutBuffer *buf, HdrGenState *hgs, Expression *e, PREC pr) +void argExpTypesToCBuffer(OutBuffer *buf, Expressions *arguments) { -#ifdef DEBUG - if (precedence[e->op] == PREC_zero) - printf("precedence not defined for token '%s'\n",Token::tochars[e->op]); -#endif - assert(precedence[e->op] != PREC_zero); - assert(pr != PREC_zero); + if (!arguments || !arguments->dim) + return; - //if (precedence[e->op] == 0) e->print(); - /* Despite precedence, we don't allow aop] < pr || - (pr == PREC_rel && precedence[e->op] == pr)) + HdrGenState hgs; + PrettyPrintVisitor v(buf, &hgs); + for (size_t i = 0; i < arguments->dim; i++) { - buf->writeByte('('); - e->toCBuffer(buf, hgs); - buf->writeByte(')'); - } - else - e->toCBuffer(buf, hgs); -} - -/************************************************** - * Write out argument list to buf. - */ - -void argsToCBuffer(OutBuffer *buf, Expressions *expressions, HdrGenState *hgs) -{ - if (expressions) - { - for (size_t i = 0; i < expressions->dim; i++) - { Expression *e = (*expressions)[i]; - - if (i) - buf->writestring(", "); - if (e) - expToCBuffer(buf, hgs, e, PREC_assign); - } + if (i) + buf->writestring(", "); + v.typeToBuffer((*arguments)[i]->type, NULL); } } + +void toCBuffer(TemplateParameter *tp, OutBuffer *buf, HdrGenState *hgs) +{ + PrettyPrintVisitor v(buf, hgs); + tp->accept(&v); +} + +void arrayObjectsToBuffer(OutBuffer *buf, Objects *objects) +{ + if (!objects || !objects->dim) + return; + + HdrGenState hgs; + PrettyPrintVisitor v(buf, &hgs); + for (size_t i = 0; i < objects->dim; i++) + { + if (i) + buf->writestring(", "); + v.objectToBuffer((*objects)[i]); + } +} + +const char *parametersTypeToChars(Parameters *parameters, int varargs) +{ + OutBuffer buf; + HdrGenState hgs; + PrettyPrintVisitor v(&buf, &hgs); + v.parametersToBuffer(parameters, varargs); + return buf.extractString(); +} diff --git a/dmd2/hdrgen.h b/dmd2/hdrgen.h index 67a34e0142..bea71d6208 100644 --- a/dmd2/hdrgen.h +++ b/dmd2/hdrgen.h @@ -15,28 +15,32 @@ void genhdrfile(Module *m); struct HdrGenState { - int hdrgen; // 1 if generating header file - int ddoc; // 1 if generating Ddoc file - int console; // 1 if writing to console + bool hdrgen; // true if generating header file + bool ddoc; // true if generating Ddoc file + bool fullQual; // fully qualify types when printing int tpltMember; - int inCallExp; - int inPtrExp; - int inSlcExp; - int inDotExp; - int inBinExp; - int inArrExp; - int emitInst; int autoMember; - bool fullQualification; // fully qualify types when printing - - struct - { - int init; - int decl; - } FLinit; - Scope* scope; // Scope when generating ddoc + int forStmtInit; HdrGenState() { memset(this, 0, sizeof(HdrGenState)); } }; +void toCBuffer(Statement *s, OutBuffer *buf, HdrGenState *hgs); +void toCBuffer(Type *t, OutBuffer *buf, Identifier *ident, HdrGenState *hgs); +void toCBuffer(Dsymbol *s, OutBuffer *buf, HdrGenState *hgs); +void toCBuffer(Initializer *iz, OutBuffer *buf, HdrGenState *hgs); +void toCBuffer(Expression *e, OutBuffer *buf, HdrGenState *hgs); +void toCBuffer(TemplateParameter *tp, OutBuffer *buf, HdrGenState *hgs); + +void toCBufferInstance(TemplateInstance *ti, OutBuffer *buf, bool qualifyTypes = false); + void functionToBufferFull(TypeFunction *tf, OutBuffer *buf, Identifier *ident, HdrGenState* hgs, TemplateDeclaration *td); +void functionToBufferWithIdent(TypeFunction *t, OutBuffer *buf, const char *ident); + +void argExpTypesToCBuffer(OutBuffer *buf, Expressions *arguments); + +void arrayObjectsToBuffer(OutBuffer *buf, Objects *objects); + +const char *parametersTypeToChars(Parameters *parameters, int varargs); + +const char *linkageToChars(LINK linkage); diff --git a/dmd2/idgen.c b/dmd2/idgen.c index 2240be67a0..5b312ce5e8 100644 --- a/dmd2/idgen.c +++ b/dmd2/idgen.c @@ -77,13 +77,15 @@ Msgtable msgtable[] = { "__vptr" }, { "__monitor" }, { "gate", "__gate" }, + { "__c_long" }, + { "__c_ulong" }, + { "__c_long_double" }, { "TypeInfo" }, { "TypeInfo_Class" }, { "TypeInfo_Interface" }, { "TypeInfo_Struct" }, { "TypeInfo_Enum" }, - { "TypeInfo_Typedef" }, { "TypeInfo_Pointer" }, { "TypeInfo_Vector" }, { "TypeInfo_Array" }, @@ -159,7 +161,7 @@ Msgtable msgtable[] = { "___out", "out" }, { "___in", "in" }, { "__int", "int" }, - { "__dollar", "$" }, + { "_dollar", "$" }, { "__LOCAL_SIZE" }, // For operator overloads @@ -334,6 +336,7 @@ Msgtable msgtable[] = { "isArithmetic" }, { "isAssociativeArray" }, { "isFinalClass" }, + { "isTemplate" }, { "isPOD" }, { "isNested" }, { "isFloating" }, @@ -368,7 +371,15 @@ Msgtable msgtable[] = { "getAttributes" }, { "getFunctionAttributes" }, { "getUnitTests" }, - { "getVirtualIndex" } + { "getVirtualIndex" }, + + // For C++ mangling + { "allocator" }, + { "basic_string" }, + { "basic_istream" }, + { "basic_ostream" }, + { "basic_iostream" }, + { "char_traits" }, }; diff --git a/dmd2/import.c b/dmd2/import.c index 3a5c8041d7..a357c5da4b 100644 --- a/dmd2/import.c +++ b/dmd2/import.c @@ -18,7 +18,6 @@ #include "identifier.h" #include "module.h" #include "scope.h" -#include "hdrgen.h" #include "mtype.h" #include "declaration.h" #include "id.h" @@ -87,9 +86,9 @@ const char *Import::kind() return isstatic ? (char *)"static import" : (char *)"import"; } -PROT Import::prot() +Prot Import::prot() { - return protection; + return Prot(protection); } Dsymbol *Import::syntaxCopy(Dsymbol *s) @@ -204,8 +203,8 @@ void Import::importAll(Scope *sc) if (!isstatic && !aliasId && !names.dim) { if (sc->explicitProtection) - protection = sc->protection; - sc->scopesym->importScope(mod, protection); + protection = sc->protection.kind; + sc->scopesym->importScope(mod, Prot(protection)); } } } @@ -238,12 +237,12 @@ void Import::semantic(Scope *sc) if (!isstatic && !aliasId && !names.dim) { if (sc->explicitProtection) - protection = sc->protection; + protection = sc->protection.kind; for (Scope *scd = sc; scd; scd = scd->enclosing) { if (scd->scopesym) { - scd->scopesym->importScope(mod, protection); + scd->scopesym->importScope(mod, Prot(protection)); break; } } @@ -264,7 +263,7 @@ void Import::semantic(Scope *sc) #if 0 sc->protection = protection; #else - sc->protection = PROTpublic; + sc->protection = Prot(PROTpublic); #endif for (size_t i = 0; i < aliasdecls.dim; i++) { @@ -318,7 +317,7 @@ void Import::semantic(Scope *sc) // use protection instead of sc->protection because it couldn't be // resolved yet, see the comment above - protectionToBuffer(ob, protection); + protectionToBuffer(ob, Prot(protection)); ob->writeByte(' '); if (isstatic) StorageClassDeclaration::stcToCBuffer(ob, STCstatic); @@ -453,46 +452,3 @@ bool Import::overloadInsert(Dsymbol *s) else return false; } - -void Import::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (hgs->hdrgen && id == Id::object) - return; // object is imported by default - - if (isstatic) - buf->writestring("static "); - buf->writestring("import "); - if (aliasId) - { - buf->printf("%s = ", aliasId->toChars()); - } - if (packages && packages->dim) - { - for (size_t i = 0; i < packages->dim; i++) - { Identifier *pid = (*packages)[i]; - - buf->printf("%s.", pid->toChars()); - } - } - buf->printf("%s", id->toChars()); - if (names.dim) - { - buf->writestring(" : "); - for (size_t i = 0; i < names.dim; i++) - { - Identifier *name = names[i]; - Identifier *alias = aliases[i]; - - if (alias) - buf->printf("%s = %s", alias->toChars(), name->toChars()); - else - buf->printf("%s", name->toChars()); - - if (i < names.dim - 1) - buf->writestring(", "); - } - } - buf->printf(";"); - buf->writenl(); -} - diff --git a/dmd2/import.h b/dmd2/import.h index 001450f870..c307b5fffc 100644 --- a/dmd2/import.h +++ b/dmd2/import.h @@ -21,11 +21,9 @@ class Identifier; struct Scope; -struct OutBuffer; class Module; class Package; class AliasDeclaration; -struct HdrGenState; class Import : public Dsymbol { @@ -37,7 +35,7 @@ public: Identifier *id; // module Identifier Identifier *aliasId; int isstatic; // !=0 if static import - PROT protection; + PROTKIND protection; // Pairs of alias=name to bind into current namespace Identifiers names; @@ -52,7 +50,7 @@ public: int isstatic); void addAlias(Identifier *name, Identifier *alias); const char *kind(); - PROT prot(); + Prot prot(); Dsymbol *syntaxCopy(Dsymbol *s); // copy only syntax trees void load(Scope *sc); void importAll(Scope *sc); @@ -62,7 +60,6 @@ public: int addMember(Scope *sc, ScopeDsymbol *sds, int memnum); Dsymbol *search(Loc loc, Identifier *ident, int flags = IgnoreNone); bool overloadInsert(Dsymbol *s); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); Import *isImport() { return this; } void accept(Visitor *v) { v->visit(this); } diff --git a/dmd2/init.c b/dmd2/init.c index 8652e4e6e9..89ad35c496 100644 --- a/dmd2/init.c +++ b/dmd2/init.c @@ -40,21 +40,16 @@ Initializers *Initializer::arraySyntaxCopy(Initializers *ai) a = new Initializers(); a->setDim(ai->dim); for (size_t i = 0; i < a->dim; i++) - { - Initializer *e = (*ai)[i]; - e = e->syntaxCopy(); - (*a)[i] = e; - } + (*a)[i] = (*ai)[i]->syntaxCopy(); } return a; } char *Initializer::toChars() { - HdrGenState hgs; - OutBuffer buf; - toCBuffer(&buf, &hgs); + HdrGenState hgs; + ::toCBuffer(this, &buf, &hgs); return buf.extractString(); } @@ -86,11 +81,6 @@ Expression *ErrorInitializer::toExpression(Type *t) return new ErrorExp(); } -void ErrorInitializer::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("__error__"); -} - /********************************** VoidInitializer ***************************/ VoidInitializer::VoidInitializer(Loc loc) @@ -122,11 +112,6 @@ Expression *VoidInitializer::toExpression(Type *t) return NULL; } -void VoidInitializer::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("void"); -} - /********************************** StructInitializer *************************/ StructInitializer::StructInitializer(Loc loc) @@ -137,17 +122,13 @@ StructInitializer::StructInitializer(Loc loc) Initializer *StructInitializer::syntaxCopy() { StructInitializer *ai = new StructInitializer(loc); - assert(field.dim == value.dim); ai->field.setDim(field.dim); ai->value.setDim(value.dim); for (size_t i = 0; i < field.dim; i++) { ai->field[i] = field[i]; - - Initializer *iz = value[i]; - iz = iz->syntaxCopy(); - ai->value[i] = iz; + ai->value[i] = value[i]->syntaxCopy(); } return ai; } @@ -306,27 +287,6 @@ Expression *StructInitializer::toExpression(Type *t) return NULL; } -void StructInitializer::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - //printf("StructInitializer::toCBuffer()\n"); - buf->writeByte('{'); - for (size_t i = 0; i < field.dim; i++) - { - if (i > 0) - buf->writestring(", "); - Identifier *id = field[i]; - if (id) - { - buf->writestring(id->toChars()); - buf->writeByte(':'); - } - Initializer *iz = value[i]; - if (iz) - iz->toCBuffer(buf, hgs); - } - buf->writeByte('}'); -} - /********************************** ArrayInitializer ************************************/ ArrayInitializer::ArrayInitializer(Loc loc) @@ -340,22 +300,14 @@ ArrayInitializer::ArrayInitializer(Loc loc) Initializer *ArrayInitializer::syntaxCopy() { //printf("ArrayInitializer::syntaxCopy()\n"); - ArrayInitializer *ai = new ArrayInitializer(loc); - assert(index.dim == value.dim); ai->index.setDim(index.dim); ai->value.setDim(value.dim); for (size_t i = 0; i < ai->value.dim; i++) { - Expression *e = index[i]; - if (e) - e = e->syntaxCopy(); - ai->index[i] = e; - - Initializer *iz = value[i]; - iz = iz->syntaxCopy(); - ai->value[i] = iz; + ai->index[i] = index[i] ? index[i]->syntaxCopy() : NULL; + ai->value[i] = value[i]->syntaxCopy(); } return ai; } @@ -719,26 +671,6 @@ Lno: return new ErrorExp(); } -void ArrayInitializer::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writeByte('['); - for (size_t i = 0; i < index.dim; i++) - { - if (i > 0) - buf->writestring(", "); - Expression *ex = index[i]; - if (ex) - { - ex->toCBuffer(buf, hgs); - buf->writeByte(':'); - } - Initializer *iz = value[i]; - if (iz) - iz->toCBuffer(buf, hgs); - } - buf->writeByte(']'); -} - /********************************** ExpInitializer ************************************/ ExpInitializer::ExpInitializer(Loc loc, Expression *exp) @@ -1051,8 +983,3 @@ Expression *ExpInitializer::toExpression(Type *t) } return exp; } - -void ExpInitializer::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - exp->toCBuffer(buf, hgs); -} diff --git a/dmd2/init.h b/dmd2/init.h index 7cb13ad625..1836d12ede 100644 --- a/dmd2/init.h +++ b/dmd2/init.h @@ -28,7 +28,6 @@ class VoidInitializer; class StructInitializer; class ArrayInitializer; class ExpInitializer; -struct HdrGenState; enum NeedInterpret { INITnointerpret, INITinterpret }; @@ -49,7 +48,6 @@ public: // needInterpret is INITinterpret if must be a manifest constant, 0 if not. virtual Initializer *semantic(Scope *sc, Type *t, NeedInterpret needInterpret) = 0; virtual Expression *toExpression(Type *t = NULL) = 0; - virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs) = 0; char *toChars(); virtual ErrorInitializer *isErrorInitializer() { return NULL; } @@ -70,7 +68,6 @@ public: Initializer *inferType(Scope *sc); Initializer *semantic(Scope *sc, Type *t, NeedInterpret needInterpret); Expression *toExpression(Type *t = NULL); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); virtual VoidInitializer *isVoidInitializer() { return this; } void accept(Visitor *v) { v->visit(this); } @@ -84,7 +81,6 @@ public: Initializer *inferType(Scope *sc); Initializer *semantic(Scope *sc, Type *t, NeedInterpret needInterpret); Expression *toExpression(Type *t = NULL); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); virtual ErrorInitializer *isErrorInitializer() { return this; } void accept(Visitor *v) { v->visit(this); } @@ -102,7 +98,6 @@ public: Initializer *inferType(Scope *sc); Initializer *semantic(Scope *sc, Type *t, NeedInterpret needInterpret); Expression *toExpression(Type *t = NULL); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); StructInitializer *isStructInitializer() { return this; } void accept(Visitor *v) { v->visit(this); } @@ -125,7 +120,6 @@ public: Initializer *semantic(Scope *sc, Type *t, NeedInterpret needInterpret); Expression *toExpression(Type *t = NULL); Expression *toAssocArrayLiteral(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); ArrayInitializer *isArrayInitializer() { return this; } void accept(Visitor *v) { v->visit(this); } @@ -142,7 +136,6 @@ public: Initializer *inferType(Scope *sc); Initializer *semantic(Scope *sc, Type *t, NeedInterpret needInterpret); Expression *toExpression(Type *t = NULL); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); virtual ExpInitializer *isExpInitializer() { return this; } void accept(Visitor *v) { v->visit(this); } diff --git a/dmd2/inline.c b/dmd2/inline.c index fbee2e6d43..e4078096ea 100644 --- a/dmd2/inline.c +++ b/dmd2/inline.c @@ -355,7 +355,6 @@ public: if (e->declaration->isStructDeclaration() || e->declaration->isClassDeclaration() || e->declaration->isFuncDeclaration() || - e->declaration->isTypedefDeclaration() || e->declaration->isAttribDeclaration() || e->declaration->isTemplateMixin()) { @@ -1364,7 +1363,7 @@ public: if (e->op == TOKconstruct && e->e2->op == TOKcall) { CallExp *ce = (CallExp *)e->e2; - if (ce->f && ce->f->nrvo_var) // NRVO + if (ce->f && ce->f->nrvo_can && ce->f->nrvo_var) // NRVO { if (e->e1->op == TOKvar) { @@ -1783,7 +1782,7 @@ static Expression *expandInline(FuncDeclaration *fd, FuncDeclaration *parent, TypeFunction *tf = (TypeFunction*)fd->type; #if LOG || CANINLINE_LOG - printf("FuncDeclaration::expandInline('%s')\n", toChars()); + printf("FuncDeclaration::expandInline('%s')\n", fd->toChars()); #endif memset(&ids, 0, sizeof(ids)); diff --git a/dmd2/interpret.c b/dmd2/interpret.c index b7823483e7..9ee8ead147 100644 --- a/dmd2/interpret.c +++ b/dmd2/interpret.c @@ -102,9 +102,9 @@ struct InterState InterState *caller; // calling function's InterState FuncDeclaration *fd; // function being interpreted Statement *start; // if !=NULL, start execution at this statement - /* target of EXP_GOTO_INTERPRET result; also - * target of labelled EXP_BREAK_INTERPRET or - * EXP_CONTINUE_INTERPRET. (NULL if no label). + /* target of CTFEExp result; also + * target of labelled CTFEExp or + * CTFEExp. (NULL if no label). */ Statement *gotoTarget; // Support for ref return values: @@ -184,9 +184,10 @@ void CtfeStack::setValue(VarDeclaration *v, Expression *e) void CtfeStack::push(VarDeclaration *v) { assert(!v->isDataseg() || v->isCTFE()); - if (v->ctfeAdrOnStack!= (size_t)-1 - && v->ctfeAdrOnStack >= framepointer) - { // Already exists in this frame, reuse it. + if (v->ctfeAdrOnStack != (size_t)-1 && + v->ctfeAdrOnStack >= framepointer) + { + // Already exists in this frame, reuse it. values[v->ctfeAdrOnStack] = NULL; return; } @@ -328,7 +329,7 @@ struct CompiledCtfeFunction { if (!td->objects) return; - for(size_t i= 0; i < td->objects->dim; ++i) + for (size_t i= 0; i < td->objects->dim; ++i) { RootObject *o = td->objects->tdata()[i]; Expression *ex = isExpression(o); @@ -808,7 +809,7 @@ Expression *ctfeInterpretForPragmaMsg(Expression *e) * thisarg 'this', if a needThis() function, NULL if not. * * Return result expression if successful, EXP_CANT_INTERPRET if not, - * or EXP_VOID_INTERPRET if function returned void. + * or CTFEExp if function returned void. */ Expression *interpret(FuncDeclaration *fd, InterState *istate, Expressions *arguments, Expression *thisarg) @@ -1022,7 +1023,7 @@ Expression *interpret(FuncDeclaration *fd, InterState *istate, Expressions *argu * statement, then go recursively down the AST looking * for that statement, then execute starting there. */ - if (e == EXP_GOTO_INTERPRET) + if (e && e->op == TOKgoto) { istatex.start = istatex.gotoTarget; // set starting statement istatex.gotoTarget = NULL; @@ -1030,7 +1031,7 @@ Expression *interpret(FuncDeclaration *fd, InterState *istate, Expressions *argu else break; } - assert(e != EXP_CONTINUE_INTERPRET && e != EXP_BREAK_INTERPRET); + assert(!(e && e->op == TOKcontinue) && !(e && e->op == TOKbreak)); /* Bugzilla 7887: If the returned reference is a ref parameter of fd, * peel off the local indirection. @@ -1060,10 +1061,10 @@ Expression *interpret(FuncDeclaration *fd, InterState *istate, Expressions *argu // If fell off the end of a void function, return void if (!e && tf->next->ty == Tvoid) - return EXP_VOID_INTERPRET; + return CTFEExp::voidexp; // If result is void, return void - if (e == EXP_VOID_INTERPRET) + if (e->op == TOKvoidexp) return e; // If it generated an exception, return it @@ -1131,7 +1132,7 @@ public: result = EXP_CANT_INTERPRET; return; } - if (e && e != EXP_VOID_INTERPRET && e->op == TOKthrownexception) + if (e && e->op == TOKthrownexception) { result = e; return; @@ -1183,7 +1184,7 @@ public: e = sx->interpret(istate); if (e == EXP_CANT_INTERPRET) break; - if (e == EXP_CONTINUE_INTERPRET) + if (e && e->op == TOKcontinue) { if (istate->gotoTarget && istate->gotoTarget != s) break; // continue at higher level @@ -1191,7 +1192,7 @@ public: e = NULL; continue; } - if (e == EXP_BREAK_INTERPRET) + if (e && e->op == TOKbreak) { if (!istate->gotoTarget || istate->gotoTarget == s) { @@ -1326,9 +1327,8 @@ public: Expression *m = (*elems)[i]; if (!m) continue; - if (m) - if ( !stopPointersEscaping(loc, m) ) - return false; + if (!stopPointersEscaping(loc, m)) + return false; } return true; } @@ -1347,7 +1347,7 @@ public: if (!s->exp) { - result = EXP_VOID_INTERPRET; + result = CTFEExp::voidexp; return; } assert(istate && istate->fd && istate->fd->type); @@ -1443,13 +1443,13 @@ public: target = target->isScopeStatement()->statement; } istate->gotoTarget = target; - result = EXP_BREAK_INTERPRET; + result = CTFEExp::breakexp; return; } else { istate->gotoTarget = NULL; - result = EXP_BREAK_INTERPRET; + result = CTFEExp::breakexp; return; } } @@ -1481,12 +1481,12 @@ public: target = target->isScopeStatement()->statement; } istate->gotoTarget = target; - result = EXP_CONTINUE_INTERPRET; + result = CTFEExp::continueexp; return; } else { - result = EXP_CONTINUE_INTERPRET; + result = CTFEExp::continueexp; return; } } @@ -1516,7 +1516,7 @@ public: break; if (wasGoto && istate->start) return; - if (e == EXP_BREAK_INTERPRET) + if (e && e->op == TOKbreak) { if (!istate->gotoTarget || istate->gotoTarget == s) { @@ -1525,7 +1525,7 @@ public: } // else break at a higher level break; } - if (e && e != EXP_CONTINUE_INTERPRET) + if (e && e->op != TOKcontinue) break; if (istate->gotoTarget && istate->gotoTarget != s) break; // continue at a higher level @@ -1594,7 +1594,7 @@ public: if (wasGoto && istate->start) return; - if (e == EXP_BREAK_INTERPRET) + if (e && e->op == TOKbreak) { if (!istate->gotoTarget || istate->gotoTarget == s) { @@ -1603,7 +1603,7 @@ public: } // else break at a higher level break; } - if (e && e != EXP_CONTINUE_INTERPRET) + if (e && e->op != TOKcontinue) break; if (istate->gotoTarget && istate->gotoTarget != s) @@ -1649,7 +1649,7 @@ public: result = e; return; } - if (e == EXP_BREAK_INTERPRET) + if (e && e->op == TOKbreak) { if (!istate->gotoTarget || istate->gotoTarget == s) { @@ -1701,7 +1701,7 @@ public: istate->start = scase; e = s->body ? s->body->interpret(istate) : NULL; assert(!istate->start); - if (e == EXP_BREAK_INTERPRET) + if (e && e->op == TOKbreak) { if (!istate->gotoTarget || istate->gotoTarget == s) { @@ -1749,7 +1749,7 @@ public: assert(s->label && s->label->statement); istate->gotoTarget = s->label->statement; - result = EXP_GOTO_INTERPRET; + result = CTFEExp::gotoexp; } void visit(GotoCaseStatement *s) @@ -1766,7 +1766,7 @@ public: assert(s->cs); istate->gotoTarget = s->cs; - result = EXP_GOTO_INTERPRET; + result = CTFEExp::gotoexp; } void visit(GotoDefaultStatement *s) @@ -1783,7 +1783,7 @@ public: assert(s->sw && s->sw->sdefault); istate->gotoTarget = s->sw->sdefault; - result = EXP_GOTO_INTERPRET; + result = CTFEExp::gotoexp; } void visit(LabelStatement *s) @@ -1849,7 +1849,7 @@ public: if (ca->handler) { e = ca->handler->interpret(istate); - if (e == EXP_GOTO_INTERPRET) + if (e && e->op == TOKgoto) { InterState istatex = *istate; istatex.start = istate->gotoTarget; // set starting statement @@ -1885,9 +1885,10 @@ public: ClassReferenceExp *boss = oldest->thrown; assert((*boss->value->elements)[4]->type->ty == Tclass); ClassReferenceExp *collateral = newest->thrown; - if (isAnErrorException(collateral->originalClass()) - && !isAnErrorException(boss->originalClass())) - { // The new exception bypass the existing chain + if ( isAnErrorException(collateral->originalClass()) && + !isAnErrorException(boss->originalClass())) + { + // The new exception bypass the existing chain assert((*collateral->value->elements)[5]->type->ty == Tclass); (*collateral->value->elements)[5] = boss; return newest; @@ -1977,7 +1978,7 @@ public: // If it is with(Enum) {...}, just execute the body. if (s->exp->op == TOKimport || s->exp->op == TOKtype) { - result = s->body ? s->body->interpret(istate) : EXP_VOID_INTERPRET; + result = s->body ? s->body->interpret(istate) : CTFEExp::voidexp; return; } @@ -2004,7 +2005,7 @@ public: if (s->body) { e = s->body->interpret(istate); - if (e == EXP_GOTO_INTERPRET) + if (e && e->op == TOKgoto) { InterState istatex = *istate; istatex.start = istate->gotoTarget; // set starting statement @@ -2018,7 +2019,7 @@ public: } } else - e = EXP_VOID_INTERPRET; + e = CTFEExp::voidexp; ctfeStack.pop(s->wthis); result = e; } @@ -2163,10 +2164,9 @@ public: { fromType = ((TypeArray *)(e->var->type))->next; } - if (e->var->isDataseg() && ( - (e->offset == 0 && isSafePointerCast(e->var->type, pointee)) || - (fromType && isSafePointerCast(fromType, pointee)) - )) + if (e->var->isDataseg() && + ((e->offset == 0 && isSafePointerCast(e->var->type, pointee)) || + (fromType && isSafePointerCast(fromType, pointee)))) { result = e; return; @@ -2183,17 +2183,17 @@ public: Type *elemtype = ((TypeArray *)(val->type))->next; // It's OK to cast from fixed length to dynamic array, eg &int[3] to int[]* - if (val->type->ty == Tsarray && pointee->ty == Tarray - && elemtype->size() == pointee->nextOf()->size()) + if (val->type->ty == Tsarray && pointee->ty == Tarray && + elemtype->size() == pointee->nextOf()->size()) { result = new AddrExp(e->loc, val); result->type = e->type; return; } - if (!isSafePointerCast(elemtype, pointee) ) + if (!isSafePointerCast(elemtype, pointee)) { // It's also OK to cast from &string to string*. - if (e->offset == 0 && isSafePointerCast(e->var->type, pointee) ) + if (e->offset == 0 && isSafePointerCast(e->var->type, pointee)) { result = new VarExp(e->loc, e->var); result->type = e->type; @@ -2210,7 +2210,9 @@ public: assert(sz * indx == e->offset); Expression *aggregate = NULL; if (val->op == TOKarrayliteral || val->op == TOKstring) + { aggregate = val; + } else if (val->op == TOKslice) { aggregate = ((SliceExp *)val)->e1; @@ -2225,7 +2227,7 @@ public: return; } } - else if (e->offset == 0 && isSafePointerCast(e->var->type, pointee) ) + else if (e->offset == 0 && isSafePointerCast(e->var->type, pointee)) { // Create a CTFE pointer &var VarExp *ve = new VarExp(e->loc, e->var); @@ -2304,7 +2306,7 @@ public: // after 'out', 'ref', and 'this' have been removed. static Expression *resolveReferences(Expression *e) { - for(;;) + for (;;) { if (e->op == TOKthis) { @@ -2332,8 +2334,8 @@ public: e = val; continue; } - else if (val && (val->op == TOKindex || val->op == TOKdotvar - || val->op == TOKthis || val->op == TOKvar)) + if (val && (val->op == TOKindex || val->op == TOKdotvar || + val->op == TOKthis || val->op == TOKvar)) { e = val; continue; @@ -2367,9 +2369,11 @@ public: !hasValue(v) && v->init && !v->isCTFE()) { - if(v->scope) + if (v->scope && !v->inuse) v->init = v->init->semantic(v->scope, v->type, INITinterpret); // might not be run on aggregate members - e = v->init->toExpression(v->type); + { + e = v->init->toExpression(v->type); + } if (v->inuse) { error(loc, "circular initialization of %s", v->toChars()); @@ -2405,7 +2409,7 @@ public: if (e && e != EXP_CANT_INTERPRET && e->op != TOKthrownexception) { e = copyLiteral(e); - if (v->isDataseg() || (v->storage_class & STCmanifest )) + if (v->isDataseg() || (v->storage_class & STCmanifest)) ctfeStack.saveGlobalConstant(v, e); } } @@ -2440,18 +2444,18 @@ public: if (!e && !v->isCTFE() && v->isDataseg()) { error(loc, "static variable %s cannot be read at compile time", v->toChars()); - e = EXP_CANT_INTERPRET; + return EXP_CANT_INTERPRET; } - else if (!e) + if (!e) { assert(!(v->init && v->init->isVoidInitializer())); // CTFE initiated from inside a function error(loc, "variable %s cannot be read at compile time", v->toChars()); return EXP_CANT_INTERPRET; } - else if (exceptionOrCantInterpret(e)) + if (exceptionOrCantInterpret(e)) return e; - else if (goal == ctfeNeedLvalue && v->isRef() && e->op == TOKindex) + if (goal == ctfeNeedLvalue && v->isRef() && e->op == TOKindex) { // If it is a foreach ref, resolve the index into a constant IndexExp *ie = (IndexExp *)e; @@ -2463,20 +2467,25 @@ public: } return e; } - else if ((goal == ctfeNeedLvalue) - || e->op == TOKstring || e->op == TOKstructliteral || e->op == TOKarrayliteral - || e->op == TOKassocarrayliteral || e->op == TOKslice - || e->type->toBasetype()->ty == Tpointer) + if (goal == ctfeNeedLvalue || + e->op == TOKstring || + e->op == TOKstructliteral || + e->op == TOKarrayliteral || + e->op == TOKassocarrayliteral || + e->op == TOKslice || + e->type->toBasetype()->ty == Tpointer) + { return e; // it's already an Lvalue - else if (e->op == TOKvoid) + } + if (e->op == TOKvoid) { VoidInitExp *ve = (VoidInitExp *)e; error(loc, "cannot read uninitialized variable %s in ctfe", v->toPrettyChars()); errorSupplemental(ve->var->loc, "%s was uninitialized and used before set", ve->var->toChars()); - e = EXP_CANT_INTERPRET; + return EXP_CANT_INTERPRET; } - else - e = e->interpret(istate, goal); + + e = e->interpret(istate, goal); } if (!e) e = EXP_CANT_INTERPRET; @@ -2490,7 +2499,7 @@ public: e = e->semantic(NULL); if (e->op == TOKerror) e = EXP_CANT_INTERPRET; - else // Convert NULL to VoidExp + else // Convert NULL to CTFEExp e = e->interpret(istate, goal); } else @@ -2512,7 +2521,7 @@ public: result = EXP_CANT_INTERPRET; return; } - else if (v && !hasValue(v)) + if (v && !hasValue(v)) { if (!v->isCTFE() && v->isDataseg()) e->error("static variable %s cannot be referenced at compile time", v->toChars()); @@ -2521,7 +2530,7 @@ public: result = EXP_CANT_INTERPRET; return; } - else if (v && hasValue(v) && getValue(v)->op == TOKvar) + if (v && hasValue(v) && getValue(v)->op == TOKvar) { // A ref of a reference, is the original reference result = getValue(v); @@ -2552,7 +2561,7 @@ public: TupleDeclaration *td = v->toAlias()->isTupleDeclaration(); if (!td->objects) return; - for(size_t i= 0; i < td->objects->dim; ++i) + for (size_t i= 0; i < td->objects->dim; ++i) { RootObject * o = (*td->objects)[i]; Expression *ex = isExpression(o); @@ -2687,7 +2696,7 @@ public: // A tuple of assignments can contain void (Bug 5676). if (goal == ctfeNeedNothing) continue; - if (ex == EXP_VOID_INTERPRET) + if (ex->op == TOKvoidexp) { e->error("ICE: void element %s in tuple", exp->toChars()); assert(0); @@ -2740,7 +2749,7 @@ public: Expression *exp = (*e->elements)[i]; if (exp->op == TOKindex) // segfault bug 6250 - assert(((IndexExp*)exp)->e1 != e); + assert(((IndexExp *)exp)->e1 != e); Expression *ex = exp->interpret(istate); if (exceptionOrCantInterpret(ex)) { @@ -2921,7 +2930,7 @@ public: if (!exp) { /* Ideally, we'd convert NULL members into void expressions. - * The problem is that the VoidExp will be removed when we + * The problem is that the CTFEExp will be removed when we * leave CTFE, causing another memory allocation if we use this * same struct literal again. * @@ -3016,6 +3025,21 @@ public: #if LOG printf("%s NewExp::interpret() %s\n", e->loc.toChars(), e->toChars()); #endif + + if (e->allocator) + { + e->error("member allocators not supported by CTFE"); + result = EXP_CANT_INTERPRET; + return; + } + + if (e->argprefix) + { + result = e->argprefix->interpret(istate, ctfeNeedNothing); + if (exceptionOrCantInterpret(result)) + return; + } + if (e->newtype->ty == Tarray && e->arguments) { result = recursivelyCreateArrayLiteral(e->loc, e->newtype, istate, e->arguments, 0); @@ -3190,14 +3214,14 @@ public: result = e1; return; } - switch(e->op) + switch (e->op) { - case TOKneg: result = Neg(e->type, e1); break; - case TOKtilde: result = Com(e->type, e1); break; - case TOKnot: result = Not(e->type, e1); break; - case TOKtobool: result = Bool(e->type, e1); break; - case TOKvector: result = e; break; // do nothing - default: assert(0); + case TOKneg: result = Neg(e->type, e1).copy(); break; + case TOKtilde: result = Com(e->type, e1); break; + case TOKnot: result = Not(e->type, e1); break; + case TOKtobool: result = Bool(e->type, e1); break; + case TOKvector: result = e; break; // do nothing + default: assert(0); } } @@ -3371,7 +3395,7 @@ public: void visit(BinExp *e) { - switch(e->op) + switch (e->op) { case TOKadd: interpretCommon(e, &Add); return; case TOKmin: interpretCommon(e, &Min); return; @@ -3427,13 +3451,13 @@ public: if (e->op == TOKvar) break; if (e->op == TOKindex) - e = ((IndexExp*)e)->e1; + e = ((IndexExp *)e)->e1; else if (e->op == TOKdotvar) e = ((DotVarExp *)e)->e1; else if (e->op == TOKdotti) e = ((DotTemplateInstanceExp *)e)->e1; else if (e->op == TOKslice) - e = ((SliceExp*)e)->e1; + e = ((SliceExp *)e)->e1; else return NULL; } @@ -3494,9 +3518,9 @@ public: // e = *x is never a reference, because *x is always a value if (!fp && e->e1->type->toBasetype()->equals(e->e2->type->toBasetype()) && - (e1->type->toBasetype()->ty == Tarray || isAssocArray(e1->type) - || e1->type->toBasetype()->ty == Tclass) - && e->e2->op != TOKstar) + (e1->type->toBasetype()->ty == Tarray || isAssocArray(e1->type) || + e1->type->toBasetype()->ty == Tclass) && + e->e2->op != TOKstar) { wantRef = true; // If it is assignment from a ref parameter, it's not a ref assignment @@ -3513,8 +3537,8 @@ public: } // If it is a construction of a ref variable, it is a ref assignment // (in fact, it is an lvalue reference assignment). - if (e->op == TOKconstruct && e->e1->op == TOKvar - && ((VarExp*)e->e1)->var->storage_class & STCref) + if (e->op == TOKconstruct && e->e1->op == TOKvar && + ((VarExp *)e->e1)->var->storage_class & STCref) { wantRef = true; wantLvalueRef = true; @@ -3568,8 +3592,8 @@ public: result = e1; return; } - if (!(e1->op == TOKvar || e1->op == TOKdotvar || e1->op == TOKindex - || e1->op == TOKslice || e1->op == TOKstructliteral)) + if (!(e1->op == TOKvar || e1->op == TOKdotvar || e1->op == TOKindex || + e1->op == TOKslice || e1->op == TOKstructliteral)) { e->error("cannot dereference invalid pointer %s", e->e1->toChars()); @@ -3578,8 +3602,8 @@ public: } } - if (!(e1->op == TOKarraylength || e1->op == TOKvar || e1->op == TOKdotvar - || e1->op == TOKindex || e1->op == TOKslice || e1->op == TOKstructliteral)) + if (!(e1->op == TOKarraylength || e1->op == TOKvar || e1->op == TOKdotvar || + e1->op == TOKindex || e1->op == TOKslice || e1->op == TOKstructliteral)) { e->error("CTFE internal error: unsupported assignment %s", e->toChars()); result = EXP_CANT_INTERPRET; @@ -3647,9 +3671,9 @@ public: } if (oldval->op == TOKslice) oldval = resolveSlice(oldval); - if (e->e1->type->ty == Tpointer && e->e2->type->isintegral() - && (e->op == TOKaddass || e->op == TOKminass || - e->op == TOKplusplus || e->op == TOKminusminus)) + if (e->e1->type->ty == Tpointer && e->e2->type->isintegral() && + (e->op == TOKaddass || e->op == TOKminass || + e->op == TOKplusplus || e->op == TOKminusminus)) { oldval = e->e1->interpret(istate, ctfeNeedLvalue); if (exceptionOrCantInterpret(oldval)) @@ -3863,7 +3887,8 @@ public: return; } if (aggregate->op == TOKassocarrayliteral) - { // Normal case, ultimate parent AA already exists + { + // Normal case, ultimate parent AA already exists // We need to walk from the deepest index up, checking that an AA literal // already exists on each level. Expression *index = ((IndexExp *)e1)->e2->interpret(istate); @@ -3965,8 +3990,8 @@ public: // pointer or reference // (in which case, we already have the lvalue). DotVarExp *dve = (DotVarExp *)e1; - bool isCtfePointer = (dve->e1->op == TOKstructliteral) - && ((StructLiteralExp *)(dve->e1))->ownedByCtfe; + bool isCtfePointer = (dve->e1->op == TOKstructliteral) && + ((StructLiteralExp *)(dve->e1))->ownedByCtfe; if (!isCtfePointer) { e1 = e1->interpret(istate, isPointer(e->type) ? ctfeNeedLvalueRef : ctfeNeedLvalue); @@ -4099,7 +4124,7 @@ public: assert(se->sd); int unionStart = se->sd->firstFieldInUnion(fieldi); int unionSize = se->sd->numFieldsInUnion(fieldi); - for(int i = unionStart; i < unionStart + unionSize; ++i) + for (int i = unionStart; i < unionStart + unionSize; ++i) { if (i == fieldi) continue; @@ -4174,8 +4199,9 @@ public: originalExp->error("cannot index null array %s", ie->e1->toChars()); return false; } - if (oldval->op != TOKarrayliteral && oldval->op != TOKstring - && oldval->op != TOKslice) + if (oldval->op != TOKarrayliteral && + oldval->op != TOKstring && + oldval->op != TOKslice) { originalExp->error("cannot determine length of %s at compile time", ie->e1->toChars()); @@ -4315,9 +4341,10 @@ public: assert(0); } } - if (wantRef && newval->op == TOKindex - && ((IndexExp *)newval)->e1 == aggregate) - { // It's a circular reference, resolve it now + if (wantRef && newval->op == TOKindex && + ((IndexExp *)newval)->e1 == aggregate) + { + // It's a circular reference, resolve it now newval = newval->interpret(istate); } @@ -4397,8 +4424,10 @@ public: else oldval = oldval->interpret(istate); - if (oldval->op != TOKarrayliteral && oldval->op != TOKstring - && oldval->op != TOKslice && oldval->op != TOKnull) + if (oldval->op != TOKarrayliteral && + oldval->op != TOKstring && + oldval->op != TOKslice && + oldval->op != TOKnull) { if (oldval->op == TOKsymoff) { @@ -4505,7 +4534,7 @@ public: } aggregate = sexpold->e1; } - if ( isPointer(aggregate->type) ) + if (isPointer(aggregate->type)) { // Slicing a pointer --> change the bounds aggregate = sexp->e1->interpret(istate, ctfeNeedLvalue); @@ -4545,8 +4574,8 @@ public: assert(0); } } - if (wantRef && newval->op == TOKindex - && ((IndexExp *)newval)->e1 == aggregate) + if (wantRef && newval->op == TOKindex && + ((IndexExp *)newval)->e1 == aggregate) { // It's a circular reference, resolve it now newval = newval->interpret(istate); @@ -4586,8 +4615,8 @@ public: sliceAssignStringFromString((StringExp *)existingSE, (StringExp *)newval, (size_t)firstIndex); return newval; } - else if (newval->op == TOKstring && existingAE - && existingAE->type->nextOf()->isintegral()) + else if (newval->op == TOKstring && existingAE && + existingAE->type->nextOf()->isintegral()) { /* Mixed slice: it was initialized as an array literal of chars/integers. * Now a slice of it is being set with a string. @@ -4640,8 +4669,9 @@ public: existingAE->type->ty == Tarray); Type *desttype = ((TypeArray *)existingAE->type)->next->toBasetype()->castMod(0); bool directblk = (e2->type->toBasetype()->castMod(0))->equals(desttype); - bool cow = !(newval->op == TOKstructliteral || newval->op == TOKarrayliteral - || newval->op == TOKstring); + bool cow = !(newval->op == TOKstructliteral || + newval->op == TOKarrayliteral || + newval->op == TOKstring); for (size_t j = 0; j < upperbound-lowerbound; j++) { if (!directblk) @@ -4685,7 +4715,7 @@ public: void visit(BinAssignExp *e) { - switch(e->op) + switch (e->op) { case TOKaddass: interpretAssignCommon(e, &Add); return; case TOKminass: interpretAssignCommon(e, &Min); return; @@ -4729,10 +4759,11 @@ public: { int ret = 1; while (e->op == TOKnot) - { ret *= -1; + { + ret *= -1; e = ((NotExp *)e)->e1; } - switch(e->op) + switch (e->op) { case TOKlt: case TOKle: @@ -4742,7 +4773,7 @@ public: case TOKge: *p1 = ((BinExp *)e)->e1; *p2 = ((BinExp *)e)->e2; - if ( !(isPointer((*p1)->type) && isPointer((*p2)->type)) ) + if (!(isPointer((*p1)->type) && isPointer((*p2)->type))) ret = 0; break; default: @@ -4756,7 +4787,7 @@ public: */ static TOK reverseRelation(TOK op) { - switch(op) + switch (op) { case TOKge: return TOKlt; case TOKgt: return TOKle; @@ -4781,7 +4812,7 @@ public: * the comparison operators can be any of >, <, <=, >=, provided that * both directions (p > q and p < q) are checked. Additionally the * relational sub-expressions can be negated, eg - * ( !(q1 < p1) && p2 <= q2 ) is valid. + * (!(q1 < p1) && p2 <= q2) is valid. */ void interpretFourPointerRelation(BinExp *e) { @@ -4824,8 +4855,9 @@ public: Expression *agg1 = getAggregateFromPointer(p1, &ofs1); Expression *agg2 = getAggregateFromPointer(p2, &ofs2); - if ( !pointToSameMemoryBlock(agg1, agg2) - && agg1->op != TOKnull && agg2->op != TOKnull) + if (!pointToSameMemoryBlock(agg1, agg2) && + agg1->op != TOKnull && + agg2->op != TOKnull) { // Here it is either CANT_INTERPRET, // or an IsInside comparison returning false. @@ -4866,11 +4898,10 @@ public: // p1 > p2 && p3 > p4 (same direction, also for < && <) // p1 > p2 && p3 < p4 (different direction, also < && >) // Changing any > into >= doesnt affect the result - if ( (dir1 == dir2 && pointToSameMemoryBlock(agg1, agg4) - && pointToSameMemoryBlock(agg2, agg3)) - || (dir1 != dir2 && pointToSameMemoryBlock(agg1, agg3) - && pointToSameMemoryBlock(agg2, agg4)) ) - { // it's a legal two-sided comparison + if ((dir1 == dir2 && pointToSameMemoryBlock(agg1, agg4) && pointToSameMemoryBlock(agg2, agg3)) || + (dir1 != dir2 && pointToSameMemoryBlock(agg1, agg3) && pointToSameMemoryBlock(agg2, agg4))) + { + // it's a legal two-sided comparison result = new IntegerExp(e->loc, (e->op == TOKandand) ? 0 : 1, e->type); return; } @@ -4936,7 +4967,7 @@ public: result = e->e2->interpret(istate); if (exceptionOrCantInterpret(result)) return; - if (result == EXP_VOID_INTERPRET) + if (result->op == TOKvoidexp) { assert(e->type->ty == Tvoid); result = NULL; @@ -4988,7 +5019,7 @@ public: if (exceptionOrCantInterpret(result)) return; - if (result == EXP_VOID_INTERPRET) + if (result->op == TOKvoidexp) { assert(e->type->ty == Tvoid); result = NULL; @@ -5087,10 +5118,10 @@ public: if (ecall->op == TOKstar) { // Calling a function pointer - Expression * pe = ((PtrExp*)ecall)->e1; + Expression * pe = ((PtrExp *)ecall)->e1; if (pe->op == TOKvar) { - VarDeclaration *vd = ((VarExp *)((PtrExp*)ecall)->e1)->var->isVarDeclaration(); + VarDeclaration *vd = ((VarExp *)((PtrExp *)ecall)->e1)->var->isVarDeclaration(); if (vd && hasValue(vd) && getValue(vd)->op == TOKsymoff) fd = ((SymOffExp *)getValue(vd))->var->isFuncDeclaration(); else @@ -5109,7 +5140,7 @@ public: else if (pe->op == TOKsymoff) fd = ((SymOffExp *)pe)->var->isFuncDeclaration(); else - ecall = ((PtrExp*)ecall)->e1->interpret(istate); + ecall = ((PtrExp *)ecall)->e1->interpret(istate); } if (exceptionOrCantInterpret(ecall)) @@ -5128,7 +5159,7 @@ public: } } - if (ecall->op == TOKdotvar && !((DotVarExp*)ecall)->var->isFuncDeclaration()) + if (ecall->op == TOKdotvar && !((DotVarExp *)ecall)->var->isFuncDeclaration()) { ecall = e->e1->interpret(istate); if (exceptionOrCantInterpret(ecall)) @@ -5141,8 +5172,8 @@ public: if (ecall->op == TOKdotvar) { // Calling a member function - pthis = ((DotVarExp*)e->e1)->e1; - fd = ((DotVarExp*)e->e1)->var->isFuncDeclaration(); + pthis = ((DotVarExp *)e->e1)->e1; + fd = ((DotVarExp *)e->e1)->var->isFuncDeclaration(); } else if (ecall->op == TOKvar) { @@ -5161,12 +5192,12 @@ public: else if (ecall->op == TOKfunction) { // Calling a delegate literal - fd = ((FuncExp*)ecall)->fd; + fd = ((FuncExp *)ecall)->fd; } - else if (ecall->op == TOKstar && ((PtrExp*)ecall)->e1->op == TOKfunction) + else if (ecall->op == TOKstar && ((PtrExp *)ecall)->e1->op == TOKfunction) { // Calling a function literal - fd = ((FuncExp*)((PtrExp*)ecall)->e1)->fd; + fd = ((FuncExp *)((PtrExp*)ecall)->e1)->fd; } else if (ecall->op == TOKdelegatefuncptr) { @@ -5293,7 +5324,7 @@ public: if (!global.gag) showCtfeBackTrace(e, fd); } - else if (result == EXP_VOID_INTERPRET) + else if (result->op == TOKvoidexp) ; else if (result->op != TOKthrownexception) { @@ -5325,11 +5356,11 @@ public: // If the comma returns a temporary variable, it needs to be an lvalue // (this is particularly important for struct constructors) - if (e->e1->op == TOKdeclaration && e->e2->op == TOKvar - && ((DeclarationExp *)e->e1)->declaration == ((VarExp*)e->e2)->var - && ((VarExp*)e->e2)->var->storage_class & STCctfe) // same as Expression::isTemp + if (e->e1->op == TOKdeclaration && e->e2->op == TOKvar && + ((DeclarationExp *)e->e1)->declaration == ((VarExp*)e->e2)->var && + ((VarExp*)e->e2)->var->storage_class & STCctfe) // same as Expression::isTemp { - VarExp* ve = (VarExp *)e->e2; + VarExp *ve = (VarExp *)e->e2; VarDeclaration *v = ve->var->isVarDeclaration(); ctfeStack.push(v); if (!v->init && !getValue(v)) @@ -5350,7 +5381,7 @@ public: result = newval; return; } - if (newval != EXP_VOID_INTERPRET) + if (newval->op != TOKvoidexp) { // v isn't necessarily null. setValueWithoutChecking(v, copyLiteral(newval)); @@ -5413,8 +5444,8 @@ public: result = e1; return; } - if (e1->op == TOKstring || e1->op == TOKarrayliteral || e1->op == TOKslice - || e1->op == TOKassocarrayliteral || e1->op == TOKnull) + if (e1->op == TOKstring || e1->op == TOKarrayliteral || e1->op == TOKslice || + e1->op == TOKassocarrayliteral || e1->op == TOKnull) { result = new IntegerExp(e->loc, resolveArrayLength(e1), e->type); } @@ -5560,8 +5591,8 @@ public: /* Set the $ variable. * Note that foreach uses indexing but doesn't need $ */ - if (e->lengthVar && (e1->op == TOKstring || e1->op == TOKarrayliteral - || e1->op == TOKslice)) + if (e->lengthVar && + (e1->op == TOKstring || e1->op == TOKarrayliteral || e1->op == TOKslice)) { uinteger_t dollar = resolveArrayLength(e1); Expression *dollarExp = new IntegerExp(e->loc, dollar, Type::tsize_t); @@ -5594,11 +5625,13 @@ public: e1 = ((SliceExp *)e1)->e1; e2 = new IntegerExp(e2->loc, indx, e2->type); } - if ((goal == ctfeNeedLvalue && e->type->ty != Taarray && e->type->ty != Tarray - && e->type->ty != Tsarray && e->type->ty != Tstruct && e->type->ty != Tclass) - || (goal == ctfeNeedLvalueRef && e->type->ty != Tsarray && e->type->ty != Tstruct) - ) - { // Pointer or reference of a scalar type + if ((goal == ctfeNeedLvalue && e->type->ty != Taarray && + e->type->ty != Tarray && e->type->ty != Tsarray && + e->type->ty != Tstruct && e->type->ty != Tclass) || + (goal == ctfeNeedLvalueRef && + e->type->ty != Tsarray && e->type->ty != Tstruct)) + { + // Pointer or reference of a scalar type result = new IndexExp(e->loc, e1, e2); result->type = e->type; return; @@ -5822,13 +5855,11 @@ public: result->type = e->type; return; } - if (e1->op == TOKarrayliteral - || e1->op == TOKstring) + if (e1->op == TOKarrayliteral || e1->op == TOKstring) { - if (iupr < ilwr || iupr > dollar) + if (iupr < ilwr || dollar < iupr) { - e->error("slice [%lld..%lld] exceeds array bounds [0..%lld]", - ilwr, iupr, dollar); + e->error("slice [%lld..%lld] exceeds array bounds [0..%lld]", ilwr, iupr, dollar); result = EXP_CANT_INTERPRET; return; } @@ -5964,8 +5995,8 @@ public: ultimatePointee = ultimatePointee->nextOf(); ultimateSrc = ultimateSrc->nextOf(); } - if (ultimatePointee->ty != Tvoid && ultimateSrc->ty != Tvoid - && !isSafePointerCast(elemtype, pointee)) + if (ultimatePointee->ty != Tvoid && ultimateSrc->ty != Tvoid && + !isSafePointerCast(elemtype, pointee)) { e->error("reinterpreting cast from %s* to %s* is not supported in CTFE", elemtype->toChars(), pointee->toChars()); @@ -5978,7 +6009,7 @@ public: if (e1->op == TOKslice) { - if ( ((SliceExp *)e1)->e1->op == TOKnull) + if (((SliceExp *)e1)->e1->op == TOKnull) { result = paintTypeOntoLiteral(e->type, ((SliceExp *)e1)->e1); return; @@ -6089,7 +6120,7 @@ public: // types of identical size. if ((e->to->ty == Tsarray || e->to->ty == Tarray) && (e1->type->ty == Tsarray || e1->type->ty == Tarray) && - !isSafePointerCast(e1->type->nextOf(), e->to->nextOf()) ) + !isSafePointerCast(e1->type->nextOf(), e->to->nextOf())) { e->error("array cast from %s to %s is not supported at compile time", e1->type->toChars(), e->to->toChars()); result = EXP_CANT_INTERPRET; @@ -6135,7 +6166,7 @@ public: } else { - e->error("%s is not a compile-time boolean expression", e1->toChars()); + e->error("%s is not a compile time boolean expression", e1->toChars()); result = EXP_CANT_INTERPRET; return; } @@ -6150,15 +6181,14 @@ public: #endif // Check for int<->float and long<->double casts. - if ( e->e1->op == TOKsymoff && ((SymOffExp *)e->e1)->offset == 0 - && isFloatIntPaint(e->type, ((SymOffExp *)e->e1)->var->type) ) + if (e->e1->op == TOKsymoff && ((SymOffExp *)e->e1)->offset == 0 && + isFloatIntPaint(e->type, ((SymOffExp *)e->e1)->var->type)) { // *(cast(int*)&v, where v is a float variable - result = paintFloatInt(getVarExp(e->loc, istate, ((SymOffExp *)e->e1)->var, ctfeNeedRvalue), - e->type); + result = paintFloatInt(getVarExp(e->loc, istate, ((SymOffExp *)e->e1)->var, ctfeNeedRvalue), e->type); return; } - else if (e->e1->op == TOKcast && ((CastExp *)e->e1)->e1->op == TOKaddress) + if (e->e1->op == TOKcast && ((CastExp *)e->e1)->e1->op == TOKaddress) { // *(cast(int *))&x where x is a float expression Expression *x = ((AddrExp *)(((CastExp *)e->e1)->e1))->e1; @@ -6176,8 +6206,7 @@ public: if (ae->e1->op == TOKaddress && ae->e2->op == TOKint64) { AddrExp *ade = (AddrExp *)ae->e1; - Expression *ex = ade->e1; - ex = ex->interpret(istate); + Expression *ex = ade->e1->interpret(istate); if (exceptionOrCantInterpret(ex)) { result = ex; @@ -6233,8 +6262,11 @@ public: if (exceptionOrCantInterpret(result)) return; - if (!(result->op == TOKvar || result->op == TOKdotvar || result->op == TOKindex - || result->op == TOKslice || result->op == TOKaddress)) + if (!(result->op == TOKvar || + result->op == TOKdotvar || + result->op == TOKindex || + result->op == TOKslice || + result->op == TOKaddress)) { if (result->op == TOKsymoff) e->error("cannot dereference pointer to static variable %s at compile time", ((SymOffExp *)result)->var->toChars()); @@ -6252,14 +6284,14 @@ public: // If the index has the same levels of indirection, it's an index int srcLevels = 0; int destLevels = 0; - for(Type *xx = ie->e1->type; xx->ty == Tpointer; xx = xx->nextOf()) + for (Type *xx = ie->e1->type; xx->ty == Tpointer; xx = xx->nextOf()) ++srcLevels; - for(Type *xx = result->type->nextOf(); xx->ty == Tpointer; xx = xx->nextOf()) + for (Type *xx = result->type->nextOf(); xx->ty == Tpointer; xx = xx->nextOf()) ++destLevels; bool isGenuineIndex = (srcLevels == destLevels); - if ((ie->e1->op == TOKarrayliteral || ie->e1->op == TOKstring) - && ie->e2->op == TOKint64) + if ((ie->e1->op == TOKarrayliteral || ie->e1->op == TOKstring) && + ie->e2->op == TOKint64) { Expression *dollar = ArrayLength(Type::tsize_t, ie->e1); dinteger_t len = dollar->toInteger(); @@ -6311,7 +6343,16 @@ public: } else if (result->op == TOKaddress) { - result = ((AddrExp*)result)->e1; // *(&x) ==> x + result = ((AddrExp *)result)->e1; // *(&x) ==> x + + // Bugzilla 13630, convert *(&[1,2,3]) to [1,2,3][0] + if (result->op == TOKarrayliteral && + result->type->toBasetype()->nextOf()->toBasetype()->equivalent(e->type)) + { + IntegerExp *ofs = new IntegerExp(result->loc, 0, Type::tsize_t); + result = new IndexExp(e->loc, result, ofs); + result->type = e->type; + } } else if (result->op == TOKnull) { @@ -6401,14 +6442,17 @@ public: result->op == TOKarrayliteral || result->op == TOKassocarrayliteral || result->op == TOKstring || result->op == TOKclassreference || result->op == TOKslice)) + { return; + } /* Element is an allocated pointer, which was created in * CastExp. */ if (goal == ctfeNeedLvalue && result->op == TOKindex && - result->type->equals(e->type) && - isPointer(e->type) ) + result->type->equals(e->type) && isPointer(e->type)) + { return; + } // ...Otherwise, just return the (simplified) dotvar expression result = new DotVarExp(e->loc, ex, v); result->type = e->type; @@ -6477,7 +6521,7 @@ public: } if (agg->op == TOKnull) { - result = EXP_VOID_INTERPRET; + result = CTFEExp::voidexp; return; } assert(agg->op == TOKassocarrayliteral); @@ -6649,8 +6693,7 @@ bool scrubArray(Loc loc, Expressions *elems, bool structlit) if (structlit && ((m->op == TOKvoid) || (m->op == TOKarrayliteral && m->type->ty == Tsarray && isEntirelyVoid(((ArrayLiteralExp *)m)->elements)) || - (m->op == TOKstructliteral && isEntirelyVoid(((StructLiteralExp *)m)->elements))) - ) + (m->op == TOKstructliteral && isEntirelyVoid(((StructLiteralExp *)m)->elements)))) { m = NULL; } @@ -6725,7 +6768,8 @@ Expression *interpret_values(InterState *istate, Expression *earg, Type *returnT // signature is int delegate(ref Value) OR int delegate(ref Key, ref Value) Expression *interpret_aaApply(InterState *istate, Expression *aa, Expression *deleg) -{ aa = aa->interpret(istate); +{ + aa = aa->interpret(istate); if (exceptionOrCantInterpret(aa)) return aa; if (aa->op != TOKassocarrayliteral) @@ -6762,7 +6806,8 @@ Expression *interpret_aaApply(InterState *istate, Expression *aa, Expression *de Expression *ekey = (*ae->keys)[i]; Expression *evalue = (*ae->values)[i]; if (wantRefValue) - { Type *t = evalue->type; + { + Type *t = evalue->type; evalue = new IndexExp(deleg->loc, ae, ekey); evalue->type = t; } @@ -6828,7 +6873,8 @@ Expression *foreachApplyUtf(InterState *istate, Expression *str, Expression *del else if (str->op == TOKarrayliteral) ale = (ArrayLiteralExp *)str; else - { str->error("CTFE internal error: cannot foreach %s", str->toChars()); + { + str->error("CTFE internal error: cannot foreach %s", str->toChars()); return EXP_CANT_INTERPRET; } Expressions args; @@ -6851,16 +6897,18 @@ Expression *foreachApplyUtf(InterState *istate, Expression *str, Expression *del size_t currentIndex = indx; // The index of the decoded character if (ale) - { // If it is an array literal, copy the code points into the buffer + { + // If it is an array literal, copy the code points into the buffer size_t buflen = 1; // #code points in the buffer size_t n = 1; // #code points in this char size_t sz = (size_t)ale->type->nextOf()->size(); - switch(sz) + switch (sz) { case 1: if (rvs) - { // find the start of the string + { + // find the start of the string --indx; buflen = 1; while (indx > 0 && buflen < 4) @@ -6868,7 +6916,7 @@ Expression *foreachApplyUtf(InterState *istate, Expression *str, Expression *del Expression * r = (*ale->elements)[indx]; assert(r->op == TOKint64); utf8_t x = (utf8_t)(((IntegerExp *)r)->getInteger()); - if ( (x & 0xC0) != 0x80) + if ((x & 0xC0) != 0x80) break; ++buflen; } @@ -6886,7 +6934,8 @@ Expression *foreachApplyUtf(InterState *istate, Expression *str, Expression *del break; case 2: if (rvs) - { // find the start of the string + { + // find the start of the string --indx; buflen = 1; Expression * r = (*ale->elements)[indx]; @@ -6927,14 +6976,16 @@ Expression *foreachApplyUtf(InterState *istate, Expression *str, Expression *del indx += n; } else - { // String literals + { + // String literals size_t saveindx; // used for reverse iteration switch (se->sz) { case 1: if (rvs) - { // find the start of the string + { + // find the start of the string utf8_t *s = (utf8_t *)se->string; --indx; while (indx > 0 && ((s[indx]&0xC0) == 0x80)) @@ -6947,7 +6998,8 @@ Expression *foreachApplyUtf(InterState *istate, Expression *str, Expression *del break; case 2: if (rvs) - { // find the start + { + // find the start unsigned short *s = (unsigned short *)se->string; --indx; if (s[indx] >= 0xDC00 && s[indx]<= 0xDFFF) @@ -6970,14 +7022,15 @@ Expression *foreachApplyUtf(InterState *istate, Expression *str, Expression *del } } if (errmsg) - { deleg->error("%s", errmsg); + { + deleg->error("%s", errmsg); return EXP_CANT_INTERPRET; } // Step 2: encode the dchar in the target encoding int charlen = 1; // How many codepoints are involved? - switch(charType->size()) + switch (charType->size()) { case 1: charlen = utf_codeLengthChar(rawvalue); @@ -7006,7 +7059,7 @@ Expression *foreachApplyUtf(InterState *istate, Expression *str, Expression *del for (int k= 0; k < charlen; ++k) { dchar_t codepoint; - switch(charType->size()) + switch (charType->size()) { case 1: codepoint = utf8buf[k]; @@ -7046,7 +7099,8 @@ Expression *evaluateIfBuiltin(InterState *istate, Loc loc, if (!pthis) { if (isBuiltin(fd) == BUILTINyes) - { Expressions args; + { + Expressions args; args.setDim(nargs); for (size_t i = 0; i < args.dim; i++) { @@ -7087,7 +7141,8 @@ Expression *evaluateIfBuiltin(InterState *istate, Loc loc, if (pthis && !fd->fbody && fd->isCtorDeclaration() && fd->parent && fd->parent->parent && fd->parent->parent->ident == Id::object) { if (pthis->op == TOKclassreference && fd->parent->ident == Id::Throwable) - { // At present, the constructors just copy their arguments into the struct. + { + // At present, the constructors just copy their arguments into the struct. // But we might need some magic if stack tracing gets added to druntime. StructLiteralExp *se = ((ClassReferenceExp *)pthis)->value; assert(arguments->dim <= se->elements->dim); @@ -7098,29 +7153,32 @@ Expression *evaluateIfBuiltin(InterState *istate, Loc loc, return e; (*se->elements)[i] = e; } - return EXP_VOID_INTERPRET; + return CTFEExp::voidexp; } } if (nargs == 1 && !pthis && (fd->ident == Id::criticalenter || fd->ident == Id::criticalexit)) - { // Support synchronized{} as a no-op - return EXP_VOID_INTERPRET; + { + // Support synchronized{} as a no-op + return CTFEExp::voidexp; } if (!pthis) { size_t idlen = strlen(fd->ident->string); - if (nargs == 2 && (idlen == 10 || idlen == 11) - && !strncmp(fd->ident->string, "_aApply", 7)) - { // Functions from aApply.d and aApplyR.d in the runtime + if (nargs == 2 && (idlen == 10 || idlen == 11) && + !strncmp(fd->ident->string, "_aApply", 7)) + { + // Functions from aApply.d and aApplyR.d in the runtime bool rvs = (idlen == 11); // true if foreach_reverse char c = fd->ident->string[idlen-3]; // char width: 'c', 'w', or 'd' char s = fd->ident->string[idlen-2]; // string width: 'c', 'w', or 'd' char n = fd->ident->string[idlen-1]; // numParams: 1 or 2. // There are 12 combinations - if ( (n == '1' || n == '2') && - (c == 'c' || c == 'w' || c == 'd') && - (s == 'c' || s == 'w' || s == 'd') && c != s) - { Expression *str = (*arguments)[0]; + if ((n == '1' || n == '2') && + (c == 'c' || c == 'w' || c == 'd') && + (s == 'c' || s == 'w' || s == 'd') && c != s) + { + Expression *str = (*arguments)[0]; str = str->interpret(istate); if (exceptionOrCantInterpret(str)) return str; diff --git a/dmd2/json.c b/dmd2/json.c index c6d182ec72..cb0c0c4468 100644 --- a/dmd2/json.c +++ b/dmd2/json.c @@ -450,8 +450,8 @@ public: property("kind", s->kind()); } - if (s->prot() != PROTpublic) - property("protection", protectionToChars(s->prot())); + if (s->prot().kind != PROTpublic) // TODO: How about package(names)? + property("protection", protectionToChars(s->prot().kind)); if (EnumMember *em = s->isEnumMember()) { @@ -556,8 +556,8 @@ public: property("kind", s->kind()); property("comment", (const char *)s->comment); property("line", "char", &s->loc); - if (s->prot() != PROTpublic) - property("protection", protectionToChars(s->prot())); + if (s->prot().kind != PROTpublic) + property("protection", protectionToChars(s->prot().kind)); if (s->aliasId) property("alias", s->aliasId->toChars()); @@ -641,17 +641,6 @@ public: objectEnd(); } - void visit(TypedefDeclaration *d) - { - objectStart(); - - jsonProperties(d); - - property("base", "baseDeco", d->basetype); - - objectEnd(); - } - void visit(AggregateDeclaration *d) { objectStart(); @@ -663,7 +652,7 @@ public: { if (cd->baseClass && cd->baseClass->ident != Id::Object) { - property("base", cd->baseClass->toChars()); + property("base", cd->baseClass->toPrettyChars(true)); } if (cd->interfaces_dim) { @@ -672,7 +661,7 @@ public: for (size_t i = 0; i < cd->interfaces_dim; i++) { BaseClass *b = cd->interfaces[i]; - item(b->base->toChars()); + item(b->base->toPrettyChars(true)); } arrayEnd(); } diff --git a/dmd2/lexer.c b/dmd2/lexer.c index 288a2fd104..a47f36d76a 100644 --- a/dmd2/lexer.c +++ b/dmd2/lexer.c @@ -68,7 +68,7 @@ static void cmtable_init() { if ('0' <= c && c <= '7') cmtable[c] |= CMoctal; - if (isdigit(c) || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F')) + if (isxdigit(c)) cmtable[c] |= CMhex; if (isalnum(c) || c == '_') cmtable[c] |= CMidchar; @@ -269,6 +269,7 @@ Lexer::Lexer(Module *mod, this->doDocComment = doDocComment; this->anyToken = 0; this->commentToken = commentToken; + this->errors = false; //initKeywords(); /* If first line starts with '#!', ignore the line @@ -329,6 +330,7 @@ void Lexer::error(const char *format, ...) va_start(ap, format); ::verror(token.loc, format, ap); va_end(ap); + errors = true; } void Lexer::error(Loc loc, const char *format, ...) @@ -337,6 +339,7 @@ void Lexer::error(Loc loc, const char *format, ...) va_start(ap, format); ::verror(loc, format, ap); va_end(ap); + errors = true; } void Lexer::deprecation(const char *format, ...) @@ -345,6 +348,8 @@ void Lexer::deprecation(const char *format, ...) va_start(ap, format); ::vdeprecation(token.loc, format, ap); va_end(ap); + if (global.params.useDeprecated == 0) + errors = true; } TOK Lexer::nextToken() @@ -569,39 +574,6 @@ void Lexer::scan(Token *t) t->value = escapeStringConstant(t,0); return; - case '\\': // escaped string literal - { unsigned c; - const utf8_t *pstart = p; - - stringbuffer.reset(); - do - { - p++; - switch (*p) - { - case 'u': - case 'U': - case '&': - c = escapeSequence(); - stringbuffer.writeUTF8(c); - break; - - default: - c = escapeSequence(); - stringbuffer.writeByte(c); - break; - } - } while (*p == '\\'); - t->len = (unsigned)stringbuffer.offset; - stringbuffer.writeByte(0); - t->ustring = (utf8_t *)mem.malloc(stringbuffer.offset); - memcpy(t->ustring, stringbuffer.data, stringbuffer.offset); - t->postfix = 0; - t->value = TOKstring; - error("Escape String literal %.*s is deprecated, use double quoted string literal \"%.*s\" instead", p - pstart, pstart, p - pstart, pstart); - return; - } - case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': @@ -1204,9 +1176,9 @@ void Lexer::scan(Token *t) } } if (c < 0x80 && isprint(c)) - error("unsupported char '%c'", c); + error("character '%c' is not a valid token", c); else - error("unsupported char 0x%02x", c); + error("character 0x%02x is not a valid token", c); p++; continue; } @@ -2085,7 +2057,7 @@ Ldone: } if (base == 8 && n >= 8) - deprecation("octal literals 0%llo%.*s are deprecated, use std.conv.octal!%llo%.*s instead", + error("octal literals 0%llo%.*s are no longer supported, use std.conv.octal!%llo%.*s instead", n, p - psuffix, psuffix, n, p - psuffix, psuffix); TOK result; @@ -2864,7 +2836,7 @@ int Token::isKeyword() void Lexer::initKeywords() { - stringtable._init(6151); + stringtable._init(28000); cmtable_init(); diff --git a/dmd2/lexer.h b/dmd2/lexer.h index feef131c0b..d27957e612 100644 --- a/dmd2/lexer.h +++ b/dmd2/lexer.h @@ -183,6 +183,7 @@ enum TOK TOKpound, TOKinterval, + TOKvoidexp, TOKMAX }; @@ -247,6 +248,7 @@ public: int doDocComment; // collect doc comment information int anyToken; // !=0 means seen at least one token int commentToken; // !=0 means comments are TOKcomment's + bool errors; // errors occurred during lexing or parsing Lexer(Module *mod, const utf8_t *base, size_t begoffset, size_t endoffset, diff --git a/dmd2/mangle.c b/dmd2/mangle.c index 438cb7259f..9cdce3418a 100644 --- a/dmd2/mangle.c +++ b/dmd2/mangle.c @@ -24,98 +24,377 @@ #include "template.h" #include "id.h" #include "module.h" +#include "enum.h" +#include "expression.h" +#include "utf.h" char *toCppMangle(Dsymbol *s); -void toBuffer(OutBuffer *buf, const char *id, Dsymbol *s); +void mangleToBuffer(Type *t, OutBuffer *buf); -void mangleFunc(OutBuffer *buf, FuncDeclaration *fd, bool inParent) +static unsigned char mangleChar[TMAX]; + +void initTypeMangle() { - //printf("deco = '%s'\n", fd->type->deco ? fd->type->deco : "null"); - //printf("fd->type = %s\n", fd->type->toChars()); - if (fd->needThis() || fd->isNested()) - buf->writeByte(Type::needThisPrefix()); - if (inParent) + mangleChar[Tarray] = 'A'; + mangleChar[Tsarray] = 'G'; + mangleChar[Taarray] = 'H'; + mangleChar[Tpointer] = 'P'; + mangleChar[Treference] = 'R'; + mangleChar[Tfunction] = 'F'; + mangleChar[Tident] = 'I'; + mangleChar[Tclass] = 'C'; + mangleChar[Tstruct] = 'S'; + mangleChar[Tenum] = 'E'; + mangleChar[Tdelegate] = 'D'; + + mangleChar[Tnone] = 'n'; + mangleChar[Tvoid] = 'v'; + mangleChar[Tint8] = 'g'; + mangleChar[Tuns8] = 'h'; + mangleChar[Tint16] = 's'; + mangleChar[Tuns16] = 't'; + mangleChar[Tint32] = 'i'; + mangleChar[Tuns32] = 'k'; + mangleChar[Tint64] = 'l'; + mangleChar[Tuns64] = 'm'; + mangleChar[Tfloat32] = 'f'; + mangleChar[Tfloat64] = 'd'; + mangleChar[Tfloat80] = 'e'; + + mangleChar[Timaginary32] = 'o'; + mangleChar[Timaginary64] = 'p'; + mangleChar[Timaginary80] = 'j'; + mangleChar[Tcomplex32] = 'q'; + mangleChar[Tcomplex64] = 'r'; + mangleChar[Tcomplex80] = 'c'; + + mangleChar[Tbool] = 'b'; + mangleChar[Tchar] = 'a'; + mangleChar[Twchar] = 'u'; + mangleChar[Tdchar] = 'w'; + + // '@' shouldn't appear anywhere in the deco'd names + mangleChar[Tinstance] = '@'; + mangleChar[Terror] = '@'; + mangleChar[Ttypeof] = '@'; + mangleChar[Ttuple] = 'B'; + mangleChar[Tslice] = '@'; + mangleChar[Treturn] = '@'; + mangleChar[Tvector] = '@'; + mangleChar[Tint128] = '@'; + mangleChar[Tuns128] = '@'; + + mangleChar[Tnull] = 'n'; // same as TypeNone + + for (size_t i = 0; i < TMAX; i++) { - TypeFunction *tfx = (TypeFunction *)fd->type; - TypeFunction *tf = (TypeFunction *)fd->originalType; - - // replace with the actual parameter types - Parameters *prms = tf->parameters; - tf->parameters = tfx->parameters; - - // do not mangle return type - Type *tret = tf->next; - tf->next = NULL; - - tf->toDecoBuffer(buf, 0); - - tf->parameters = prms; - tf->next = tret; - } - else if (fd->type->deco) - { - buf->writestring(fd->type->deco); - } - else - { - printf("[%s] %s %s\n", fd->loc.toChars(), fd->toChars(), fd->type->toChars()); - assert(0); // don't mangle function until semantic3 done. + if (!mangleChar[i]) + fprintf(stderr, "ty = %llu\n", (ulonglong)i); + assert(mangleChar[i]); } } -void mangleParent(OutBuffer *buf, Dsymbol *s) +/********************************* + * Mangling for mod. + */ +void MODtoDecoBuffer(OutBuffer *buf, MOD mod) { - Dsymbol *p; - if (TemplateInstance *ti = s->isTemplateInstance()) - p = ti->isTemplateMixin() ? ti->parent : ti->tempdecl->parent; - else - p = s->parent; - - if (p) + switch (mod) { - mangleParent(buf, p); - - if (p->getIdent()) - { - const char *id = p->ident->toChars(); - toBuffer(buf, id, s); - - if (FuncDeclaration *f = p->isFuncDeclaration()) - mangleFunc(buf, f, true); - } - else - buf->writeByte('0'); + case 0: + break; + case MODconst: + buf->writeByte('x'); + break; + case MODimmutable: + buf->writeByte('y'); + break; + case MODshared: + buf->writeByte('O'); + break; + case MODshared | MODconst: + buf->writestring("Ox"); + break; + case MODwild: + buf->writestring("Ng"); + break; + case MODwildconst: + buf->writestring("Ngx"); + break; + case MODshared | MODwild: + buf->writestring("ONg"); + break; + case MODshared | MODwildconst: + buf->writestring("ONgx"); + break; + default: + assert(0); } } -void mangleDecl(OutBuffer *buf, Declaration *sthis) -{ - mangleParent(buf, sthis); - - assert(sthis->ident); - const char *id = sthis->ident->toChars(); - toBuffer(buf, id, sthis); - - if (FuncDeclaration *fd = sthis->isFuncDeclaration()) - { - mangleFunc(buf, fd, false); - } - else if (sthis->type->deco) - { - buf->writestring(sthis->type->deco); - } - else - assert(0); -} - class Mangler : public Visitor { public: - const char *result; + OutBuffer *buf; - Mangler() + Mangler(OutBuffer *buf) { - result = NULL; + this->buf = buf; + } + + + //////////////////////////////////////////////////////////////////////////// + + /************************************************** + * Type mangling + */ + + void visitWithMask(Type *t, unsigned char modMask) + { + if (modMask != t->mod) + { + MODtoDecoBuffer(buf, t->mod); + } + t->accept(this); + } + + void visit(Type *t) + { + buf->writeByte(mangleChar[t->ty]); + } + + void visit(TypeNext *t) + { + visit((Type *)t); + visitWithMask(t->next, t->mod); + } + + void visit(TypeVector *t) + { + buf->writestring("Nh"); + visitWithMask(t->basetype, t->mod); + } + + void visit(TypeSArray *t) + { + visit((Type *)t); + if (t->dim) + buf->printf("%llu", t->dim->toInteger()); + if (t->next) + visitWithMask(t->next, t->mod); + } + + void visit(TypeDArray *t) + { + visit((Type *)t); + if (t->next) + visitWithMask(t->next, t->mod); + } + + void visit(TypeAArray *t) + { + visit((Type *)t); + visitWithMask(t->index, 0); + visitWithMask(t->next, t->mod); + } + + void visit(TypeFunction *t) + { + //printf("TypeFunction::toDecoBuffer() t = %p %s\n", t, t->toChars()); + //static int nest; if (++nest == 50) *(char*)0=0; + + mangleFuncType(t, t, t->mod, t->next); + } + + void mangleFuncType(TypeFunction *t, TypeFunction *ta, unsigned char modMask, Type *tret) + { + if (t->inuse) + { + t->inuse = 2; // flag error to caller + return; + } + t->inuse++; + + if (modMask != t->mod) + MODtoDecoBuffer(buf, t->mod); + + unsigned char mc; + switch (t->linkage) + { + case LINKd: mc = 'F'; break; + case LINKc: mc = 'U'; break; + case LINKwindows: mc = 'W'; break; + case LINKpascal: mc = 'V'; break; + case LINKcpp: mc = 'R'; break; + default: + assert(0); + } + buf->writeByte(mc); + + if (ta->purity || ta->isnothrow || ta->isnogc || ta->isproperty || ta->isref || ta->trust) + { + if (ta->purity) + buf->writestring("Na"); + if (ta->isnothrow) + buf->writestring("Nb"); + if (ta->isref) + buf->writestring("Nc"); + if (ta->isproperty) + buf->writestring("Nd"); + if (ta->isnogc) + buf->writestring("Ni"); + switch (ta->trust) + { + case TRUSTtrusted: + buf->writestring("Ne"); + break; + case TRUSTsafe: + buf->writestring("Nf"); + break; + default: + break; + } + } + + // Write argument types + argsToDecoBuffer(t->parameters); + //if (buf->data[buf->offset - 1] == '@') halt(); + buf->writeByte('Z' - t->varargs); // mark end of arg list + if (tret != NULL) + visitWithMask(tret, 0); + + t->inuse--; + } + + void visit(TypeIdentifier *t) + { + visit((Type *)t); + const char *name = t->ident->toChars(); + size_t len = strlen(name); + buf->printf("%u%s", (unsigned)len, name); + } + + void visit(TypeEnum *t) + { + visit((Type *)t); + t->sym->accept(this); + } + + void visit(TypeStruct *t) + { + //printf("TypeStruct::toDecoBuffer('%s') = '%s'\n", t->toChars(), name); + visit((Type *)t); + t->sym->accept(this); + } + + void visit(TypeClass *t) + { + //printf("TypeClass::toDecoBuffer('%s' mod=%x) = '%s'\n", t->toChars(), mod, name); + visit((Type *)t); + t->sym->accept(this); + } + + void visit(TypeTuple *t) + { + //printf("TypeTuple::toDecoBuffer() t = %p, %s\n", t, t->toChars()); + visit((Type *)t); + + OutBuffer buf2; + buf2.reserve(32); + Mangler v(&buf2); + v.argsToDecoBuffer(t->arguments); + int len = (int)buf2.offset; + buf->printf("%d%.*s", len, len, buf2.extractData()); + } + + void visit(TypeNull *t) + { + visit((Type *)t); + } + + //////////////////////////////////////////////////////////////////////////// + + void mangleDecl(Declaration *sthis) + { + mangleParent(sthis); + + assert(sthis->ident); + const char *id = sthis->ident->toChars(); + toBuffer(id, sthis); + + if (FuncDeclaration *fd = sthis->isFuncDeclaration()) + { + mangleFunc(fd, false); + } + else if (sthis->type->deco) + { + buf->writestring(sthis->type->deco); + } + else + assert(0); + } + + void mangleParent(Dsymbol *s) + { + Dsymbol *p; + if (TemplateInstance *ti = s->isTemplateInstance()) + p = ti->isTemplateMixin() ? ti->parent : ti->tempdecl->parent; + else + p = s->parent; + + if (p) + { + mangleParent(p); + + if (p->getIdent()) + { + const char *id = p->ident->toChars(); + toBuffer(id, s); + + if (FuncDeclaration *f = p->isFuncDeclaration()) + mangleFunc(f, true); + } + else + buf->writeByte('0'); + } + } + + void mangleFunc(FuncDeclaration *fd, bool inParent) + { + //printf("deco = '%s'\n", fd->type->deco ? fd->type->deco : "null"); + //printf("fd->type = %s\n", fd->type->toChars()); + if (fd->needThis() || fd->isNested()) + buf->writeByte(Type::needThisPrefix()); + if (inParent) + { + TypeFunction *tf = (TypeFunction *)fd->type; + TypeFunction *tfo = (TypeFunction *)fd->originalType; + mangleFuncType(tf, tfo, 0, NULL); + } + else if (fd->type->deco) + { + buf->writestring(fd->type->deco); + } + else + { + printf("[%s] %s %s\n", fd->loc.toChars(), fd->toChars(), fd->type->toChars()); + assert(0); // don't mangle function until semantic3 done. + } + } + + /************************************************************ + * Write length prefixed string to buf. + */ + void toBuffer(const char *id, Dsymbol *s) + { + size_t len = strlen(id); + if (len >= 8 * 1024 * 1024) // 8 megs ought be enough for anyone + s->error("excessive length %llu for symbol, possible recursive expansion?", len); + else + { + buf->printf("%llu", (ulonglong)len); + buf->write(id, len); + } } void visit(Declaration *d) @@ -132,43 +411,39 @@ public: case LINKc: case LINKwindows: case LINKpascal: - result = d->ident->toChars(); - break; + buf->writestring(d->ident->toChars()); + return; case LINKcpp: - result = toCppMangle(d); - break; + buf->writestring(toCppMangle(d)); + return; case LINKdefault: d->error("forward declaration"); - result = d->ident->toChars(); - break; + buf->writestring(d->ident->toChars()); + return; default: fprintf(stderr, "'%s', linkage = %d\n", d->toChars(), d->linkage); assert(0); + return; } } - if (!result) - { - OutBuffer buf; - buf.writestring("_D"); - mangleDecl(&buf, d); - result = buf.extractString(); - } + buf->writestring("_D"); + mangleDecl(d); #ifdef DEBUG - assert(result); - size_t len = strlen(result); + assert(buf->data); + size_t len = buf->offset; assert(len > 0); for (size_t i = 0; i < len; i++) { - assert(result[i] == '_' || - result[i] == '@' || - result[i] == '?' || - result[i] == '$' || - isalnum(result[i]) || result[i] & 0x80); + assert(buf->data[i] == '_' || + buf->data[i] == '@' || + buf->data[i] == '?' || + buf->data[i] == '$' || + isalnum(buf->data[i]) || buf->data[i] & 0x80); } #endif } @@ -255,19 +530,19 @@ public: if (fd->mangleOverride) { - result = fd->mangleOverride; + buf->writestring(fd->mangleOverride); return; } if (fd->isMain()) { - result = "_Dmain"; + buf->writestring("_Dmain"); return; } if (fd->isWinMain() || fd->isDllMain() || fd->ident == Id::tls_get_addr) { - result = fd->ident->toChars(); + buf->writestring(fd->ident->toChars()); return; } @@ -278,19 +553,13 @@ public: { if (vd->mangleOverride) { - result = vd->mangleOverride; + buf->writestring(vd->mangleOverride); return; } visit((Declaration *)vd); } - void visit(TypedefDeclaration *td) - { - //printf("TypedefDeclaration::mangle() '%s'\n", toChars()); - visit((Dsymbol *)td); - } - void visit(AggregateDeclaration *ad) { ClassDeclaration *cd = ad->isClassDeclaration(); @@ -304,7 +573,6 @@ public: cd->ident == Id::TypeInfo || cd->ident == Id::TypeInfo_Struct || cd->ident == Id::TypeInfo_Class || - cd->ident == Id::TypeInfo_Typedef || cd->ident == Id::TypeInfo_Tuple || cd == ClassDeclaration::object || cd == Type::typeinfoclass || @@ -330,19 +598,16 @@ public: printf("\n"); #endif - OutBuffer buf; if (!ti->tempdecl) ti->error("is not defined"); else - mangleParent(&buf, ti); + mangleParent(ti); ti->getIdent(); const char *id = ti->ident ? ti->ident->toChars() : ti->toChars(); - toBuffer(&buf, id, ti); - id = buf.extractString(); + toBuffer(id, ti); //printf("TemplateInstance::mangle() %s = %s\n", ti->toChars(), ti->id); - result = id; } void visit(Dsymbol *s) @@ -354,23 +619,244 @@ public: printf("\n"); #endif - OutBuffer buf; - mangleParent(&buf, s); + mangleParent(s); char *id = s->ident ? s->ident->toChars() : s->toChars(); - toBuffer(&buf, id, s); - id = buf.extractString(); + toBuffer(id, s); //printf("Dsymbol::mangle() %s = %s\n", s->toChars(), id); - result = id; + } + + //////////////////////////////////////////////////////////////////////////// + + void visit(Expression *e) + { + e->error("expression %s is not a valid template value argument", e->toChars()); + } + + void visit(IntegerExp *e) + { + if ((sinteger_t)e->value < 0) + buf->printf("N%lld", -e->value); + else + buf->printf("i%lld", e->value); + } + + void visit(RealExp *e) + { + buf->writeByte('e'); + realToMangleBuffer(e->value); + } + + void realToMangleBuffer(real_t value) + { + /* Rely on %A to get portable mangling. + * Must munge result to get only identifier characters. + * + * Possible values from %A => mangled result + * NAN => NAN + * -INF => NINF + * INF => INF + * -0X1.1BC18BA997B95P+79 => N11BC18BA997B95P79 + * 0X1.9P+2 => 19P2 + */ + + if (Port::isNan(value)) + buf->writestring("NAN"); // no -NAN bugs + else if (Port::isInfinity(value)) + buf->writestring(value < 0 ? "NINF" : "INF"); + else + { + const size_t BUFFER_LEN = 36; + char buffer[BUFFER_LEN]; + size_t n = ld_sprint(buffer, 'A', value); + assert(n < BUFFER_LEN); + for (size_t i = 0; i < n; i++) + { + char c = buffer[i]; + switch (c) + { + case '-': + buf->writeByte('N'); + break; + + case '+': + case 'X': + case '.': + break; + + case '0': + if (i < 2) + break; // skip leading 0X + default: + buf->writeByte(c); + break; + } + } + } + } + + void visit(ComplexExp *e) + { + buf->writeByte('c'); + realToMangleBuffer(e->toReal()); + buf->writeByte('c'); // separate the two + realToMangleBuffer(e->toImaginary()); + } + + void visit(NullExp *e) + { + buf->writeByte('n'); + } + + void visit(StringExp *e) + { + char m; + OutBuffer tmp; + utf8_t *q; + size_t qlen; + + /* Write string in UTF-8 format + */ + switch (e->sz) + { + case 1: + m = 'a'; + q = (utf8_t *)e->string; + qlen = e->len; + break; + + case 2: + m = 'w'; + for (size_t u = 0; u < e->len; ) + { + unsigned c; + const char *p = utf_decodeWchar((unsigned short *)e->string, e->len, &u, &c); + if (p) + e->error("%s", p); + else + tmp.writeUTF8(c); + } + q = (utf8_t *)tmp.data; + qlen = tmp.offset; + break; + + case 4: + m = 'd'; + for (size_t u = 0; u < e->len; u++) + { + unsigned c = ((unsigned *)e->string)[u]; + if (!utf_isValidDchar(c)) + e->error("invalid UCS-32 char \\U%08x", c); + else + tmp.writeUTF8(c); + } + q = (utf8_t *)tmp.data; + qlen = tmp.offset; + break; + + default: + assert(0); + } + buf->reserve(1 + 11 + 2 * qlen); + buf->writeByte(m); + buf->printf("%d_", (int)qlen); // nbytes <= 11 + + for (utf8_t *p = (utf8_t *)buf->data + buf->offset, *pend = p + 2 * qlen; + p < pend; p += 2, ++q) + { + utf8_t hi = *q >> 4 & 0xF; + p[0] = (utf8_t)(hi < 10 ? hi + '0' : hi - 10 + 'a'); + utf8_t lo = *q & 0xF; + p[1] = (utf8_t)(lo < 10 ? lo + '0' : lo - 10 + 'a'); + } + buf->offset += 2 * qlen; + } + + void visit(ArrayLiteralExp *e) + { + size_t dim = e->elements ? e->elements->dim : 0; + buf->printf("A%u", dim); + for (size_t i = 0; i < dim; i++) + { + (*e->elements)[i]->accept(this); + } + } + + void visit(AssocArrayLiteralExp *e) + { + size_t dim = e->keys->dim; + buf->printf("A%u", dim); + for (size_t i = 0; i < dim; i++) + { + (*e->keys)[i]->accept(this); + (*e->values)[i]->accept(this); + } + } + + void visit(StructLiteralExp *e) + { + size_t dim = e->elements ? e->elements->dim : 0; + buf->printf("S%u", dim); + for (size_t i = 0; i < dim; i++) + { + Expression *ex = (*e->elements)[i]; + if (ex) + ex->accept(this); + else + buf->writeByte('v'); // 'v' for void + } + } + + //////////////////////////////////////////////////////////////////////////// + + void argsToDecoBuffer(Parameters *arguments) + { + //printf("Parameter::argsToDecoBuffer()\n"); + Parameter::foreach(arguments, &argsToDecoBufferDg, (void *)this); + } + + static int argsToDecoBufferDg(void *ctx, size_t n, Parameter *arg) + { + arg->accept((Visitor *)ctx); + return 0; + } + + void visit(Parameter *p) + { + if (p->storageClass & STCscope) + buf->writeByte('M'); + switch (p->storageClass & (STCin | STCout | STCref | STClazy)) + { + case 0: + case STCin: + break; + case STCout: + buf->writeByte('J'); + break; + case STCref: + buf->writeByte('K'); + break; + case STClazy: + buf->writeByte('L'); + break; + default: + #ifdef DEBUG + printf("storageClass = x%llx\n", p->storageClass & (STCin | STCout | STCref | STClazy)); + halt(); + #endif + assert(0); + } + visitWithMask(p->type, 0); } }; const char *mangle(Dsymbol *s) { - Mangler v; + OutBuffer buf; + Mangler v(&buf); s->accept(&v); - return v.result; + return buf.extractString(); } /****************************************************************************** @@ -378,24 +864,34 @@ const char *mangle(Dsymbol *s) */ const char *mangleExact(FuncDeclaration *fd) { - Mangler v; + OutBuffer buf; + Mangler v(&buf); v.mangleExact(fd); - return v.result; + return buf.extractString(); } - -/************************************************************ - * Write length prefixed string to buf. - */ - -void toBuffer(OutBuffer *buf, const char *id, Dsymbol *s) +void mangleToBuffer(Type *t, OutBuffer *buf) { - size_t len = strlen(id); - if (len >= 8 * 1024 * 1024) // 8 megs ought be enough for anyone - s->error("excessive length %llu for symbol, possible recursive expansion?", len); - else - { - buf->printf("%llu", (ulonglong)len); - buf->write(id, len); - } + Mangler v(buf); + v.visitWithMask(t, 0); +} + +void mangleToBuffer(Type *t, OutBuffer *buf, bool internal) +{ + if (internal) + { + buf->writeByte(mangleChar[t->ty]); + if (t->ty == Tarray) + buf->writeByte(mangleChar[((TypeArray *)t)->next->ty]); + } + else if (t->deco) + buf->writestring(t->deco); + else + mangleToBuffer(t, buf); +} + +void mangleToBuffer(Expression *e, OutBuffer *buf) +{ + Mangler v(buf); + e->accept(&v); } diff --git a/dmd2/mars.c b/dmd2/mars.c index f137a68aaa..3037ffa86d 100644 --- a/dmd2/mars.c +++ b/dmd2/mars.c @@ -43,26 +43,28 @@ #include "declaration.h" #include "hdrgen.h" #include "doc.h" -#include "color.h" #if !IN_LLVM bool response_expand(size_t *pargc, const char ***pargv); + void browse(const char *url); void getenv_setargv(const char *envvar, size_t *pargc, const char** *pargv); - -void obj_start(char *srcfile); -void obj_end(Library *library, File *objfile); #endif void printCtfePerformanceStats(); -static bool parse_arch(size_t argc, const char** argv, bool is64bit); +static const char* parse_arch(size_t argc, const char** argv, const char* arch); void inlineScan(Module *m); // in traits.c void initTraitsStringTable(); +int runLINK(); +void deleteExeFile(); +int runProgram(); +const char *inifile(const char *argv0, const char *inifile, const char* envsectionname); + /** Normalize path by turning forward slashes into backslashes */ const char * toWinPath(const char *src) { @@ -84,8 +86,8 @@ Global global; void Global::init() { + inifilename = NULL; mars_ext = "d"; - sym_ext = "d"; hdr_ext = "di"; doc_ext = "html"; ddoc_ext = "ddoc"; @@ -204,133 +206,6 @@ bool Loc::equals(const Loc& loc) linnum == loc.linnum && FileName::equals(filename, loc.filename); } -/************************************** - * Print error message - */ - -void error(Loc loc, const char *format, ...) -{ - va_list ap; - va_start(ap, format); - verror(loc, format, ap); - va_end( ap ); -} - -void error(const char *filename, unsigned linnum, unsigned charnum, const char *format, ...) -{ Loc loc; - loc.filename = (char *)filename; - loc.linnum = linnum; - loc.charnum = charnum; - va_list ap; - va_start(ap, format); - verror(loc, format, ap); - va_end( ap ); -} - -void warning(Loc loc, const char *format, ...) -{ - va_list ap; - va_start(ap, format); - vwarning(loc, format, ap); - va_end( ap ); -} - -/************************************** - * Print supplementary message about the last error - * Used for backtraces, etc - */ -void errorSupplemental(Loc loc, const char *format, ...) -{ - va_list ap; - va_start(ap, format); - verrorSupplemental(loc, format, ap); - va_end( ap ); -} - -void deprecation(Loc loc, const char *format, ...) -{ - va_list ap; - va_start(ap, format); - vdeprecation(loc, format, ap); - - va_end( ap ); -} - -// Just print, doesn't care about gagging -void verrorPrint(Loc loc, const char *header, const char *format, va_list ap, - const char *p1, const char *p2) -{ - char *p = loc.toChars(); - - if (global.params.color) - setConsoleColorBright(); - if (*p) - fprintf(stderr, "%s: ", p); - mem.free(p); - - if (global.params.color) - setConsoleColorError(); - fputs(header, stderr); - if (global.params.color) - resetConsoleColor(); - if (p1) - fprintf(stderr, "%s ", p1); - if (p2) - fprintf(stderr, "%s ", p2); - OutBuffer tmp; - tmp.vprintf(format, ap); - fprintf(stderr, "%s\n", tmp.peekString()); - fflush(stderr); -} - -// header is "Error: " by default (see mars.h) -void verror(Loc loc, const char *format, va_list ap, - const char *p1, const char *p2, const char *header) -{ - if (!global.gag) - { - verrorPrint(loc, header, format, ap, p1, p2); - if (global.errors >= 20) // moderate blizzard of cascading messages - fatal(); -//halt(); - } - else - { - //fprintf(stderr, "(gag:%d) ", global.gag); - //verrorPrint(loc, header, format, ap, p1, p2); - global.gaggedErrors++; - } - global.errors++; -} - -// Doesn't increase error count, doesn't print "Error:". -void verrorSupplemental(Loc loc, const char *format, va_list ap) -{ - if (!global.gag) - verrorPrint(loc, " ", format, ap); -} - -void vwarning(Loc loc, const char *format, va_list ap) -{ - if (global.params.warnings && !global.gag) - { - verrorPrint(loc, "Warning: ", format, ap); -//halt(); - if (global.params.warnings == 1) - global.warnings++; // warnings don't count if gagged - } -} - -void vdeprecation(Loc loc, const char *format, va_list ap, - const char *p1, const char *p2) -{ - static const char *header = "Deprecation: "; - if (global.params.useDeprecated == 0) - verror(loc, format, ap, p1, p2, header); - else if (global.params.useDeprecated == 2 && !global.gag) - verrorPrint(loc, header, format, ap, p1, p2); -} - void readFile(Loc loc, File *f) { if (f->read()) @@ -363,29 +238,14 @@ void ensurePathToNameExists(Loc loc, const char *name) FileName::free(pt); } +extern void backend_init(); +extern void backend_term(); -/*************************************** - * Call this after printing out fatal error messages to clean up and exit - * the compiler. - */ - -void fatal() +static void logo() { -#if 0 - halt(); -#endif - exit(EXIT_FAILURE); -} - -/************************************** - * Try to stop forgetting to remove the breakpoints from - * release builds. - */ -void halt() -{ -#ifdef DEBUG - *(volatile char*)0=0; -#endif + printf("DMD%llu D Compiler %s\n%s %s\n", + (unsigned long long) sizeof(size_t) * 8, + global.version, global.copyright, global.written); } #if !IN_LLVM @@ -393,7 +253,7 @@ void halt() extern void backend_init(); extern void backend_term(); -void usage() +static void usage() { #if TARGET_LINUX const char fpic[] ="\ @@ -402,11 +262,10 @@ void usage() #else const char fpic[] = ""; #endif - printf("DMD%llu D Compiler %s\n%s %s\n", - (unsigned long long) sizeof(size_t) * 8, - global.version, global.copyright, global.written); + logo(); printf("\ Documentation: http://dlang.org/\n\ +Config file: %s\n\ Usage:\n\ dmd files.d ... { -switch }\n\ \n\ @@ -437,7 +296,7 @@ Usage:\n\ -H generate 'header' file\n\ -Hddirectory write 'header' file to directory\n\ -Hffilename write 'header' file to filename\n\ - --help print help\n\ + --help print help and exit\n\ -Ipath where to look for imports\n\ -ignore ignore unsupported pragmas\n\ -inline do function inlining\n\ @@ -466,6 +325,7 @@ Usage:\n\ -unittest compile in unit tests\n\ -v verbose\n\ -vcolumns print character (column) numbers in diagnostics\n\ + --version print compiler version and exit\n\ -version=level compile in version code >= level\n\ -version=ident compile in version code identified by ident\n\ -vtls list all variables going into thread local storage\n\ @@ -474,7 +334,7 @@ Usage:\n\ -wi warnings as messages (compilation will continue)\n\ -X generate JSON file\n\ -Xffilename write JSON file to filename\n\ -", fpic); +", FileName::canonicalName(global.inifilename), fpic); } extern signed char tyalignsize[]; @@ -513,6 +373,7 @@ void genCmain(Scope *sc) p.nextToken(); m->members = p.parseModule(); assert(p.token.value == TOKeof); + assert(!p.errors); // shouldn't have failed to parse it bool v = global.params.verbose; global.params.verbose = false; @@ -538,7 +399,6 @@ int tryMain(size_t argc, const char *argv[]) #if TARGET_WINDOS bool setdefaultlib = false; #endif - const char *inifilename = NULL; global.init(); #ifdef DEBUG @@ -589,6 +449,7 @@ int tryMain(size_t argc, const char *argv[]) global.params.is64bit = (sizeof(size_t) == 8); #if TARGET_WINDOS + global.params.mscoff = false; global.params.is64bit = false; global.params.defaultlibname = "phobos"; #elif TARGET_LINUX @@ -608,10 +469,12 @@ int tryMain(size_t argc, const char *argv[]) #elif TARGET_LINUX VersionCondition::addPredefinedGlobalIdent("Posix"); VersionCondition::addPredefinedGlobalIdent("linux"); + VersionCondition::addPredefinedGlobalIdent("ELFv1"); global.params.isLinux = true; #elif TARGET_OSX VersionCondition::addPredefinedGlobalIdent("Posix"); VersionCondition::addPredefinedGlobalIdent("OSX"); + VersionCondition::addPredefinedGlobalIdent("ELFv1"); global.params.isOSX = true; // For legacy compatibility @@ -619,14 +482,17 @@ int tryMain(size_t argc, const char *argv[]) #elif TARGET_FREEBSD VersionCondition::addPredefinedGlobalIdent("Posix"); VersionCondition::addPredefinedGlobalIdent("FreeBSD"); + VersionCondition::addPredefinedGlobalIdent("ELFv1"); global.params.isFreeBSD = true; #elif TARGET_OPENBSD VersionCondition::addPredefinedGlobalIdent("Posix"); VersionCondition::addPredefinedGlobalIdent("OpenBSD"); + VersionCondition::addPredefinedGlobalIdent("ELFv1"); global.params.isFreeBSD = true; #elif TARGET_SOLARIS VersionCondition::addPredefinedGlobalIdent("Posix"); VersionCondition::addPredefinedGlobalIdent("Solaris"); + VersionCondition::addPredefinedGlobalIdent("ELFv1"); global.params.isSolaris = true; #else #error "fix this" @@ -637,9 +503,9 @@ int tryMain(size_t argc, const char *argv[]) VersionCondition::addPredefinedGlobalIdent("all"); #if _WIN32 - inifilename = inifile(argv[0], "sc.ini", "Environment"); + global.inifilename = inifile(argv[0], "sc.ini", "Environment"); #elif __linux__ || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun - inifilename = inifile(argv[0], "dmd.conf", "Environment"); + global.inifilename = inifile(argv[0], "dmd.conf", "Environment"); #else #error "fix this" #endif @@ -648,13 +514,14 @@ int tryMain(size_t argc, const char *argv[]) const char** dflags_argv = NULL; getenv_setargv("DFLAGS", &dflags_argc, &dflags_argv); - bool is64bit = global.params.is64bit; // use default - is64bit = parse_arch(argc, argv, is64bit); - is64bit = parse_arch(dflags_argc, dflags_argv, is64bit); - global.params.is64bit = is64bit; + const char *arch = global.params.is64bit ? "64" : "32"; // use default + arch = parse_arch(argc, argv, arch); + arch = parse_arch(dflags_argc, dflags_argv, arch); + bool is64bit = arch[0] == '6'; - const char *envsec = is64bit ? "Environment64" : "Environment32"; - inifile(argv[0], inifilename, envsec); + char envsection[80]; + sprintf(envsection, "Environment%s", arch); + inifile(argv[0], global.inifilename, envsection); getenv_setargv("DFLAGS", &argc, &argv); @@ -755,9 +622,24 @@ int tryMain(size_t argc, const char *argv[]) global.params.trace = true; } else if (strcmp(p + 1, "m32") == 0) + { global.params.is64bit = false; + global.params.mscoff = false; + } else if (strcmp(p + 1, "m64") == 0) + { global.params.is64bit = true; + global.params.mscoff = true; + } + else if (strcmp(p + 1, "m32mscoff") == 0) + { + #if TARGET_WINDOS + global.params.is64bit = 0; + global.params.mscoff = true; + #else + error(Loc(), "-m32mscoff can only be used on windows"); + #endif + } else if (strcmp(p + 1, "profile") == 0) global.params.trace = true; else if (strcmp(p + 1, "v") == 0) @@ -778,7 +660,8 @@ int tryMain(size_t argc, const char *argv[]) { printf("\ Language changes listed by -transition=id:\n\ - =tls do list all variables going into thread local storage\n\ + =field,3449 list all non-mutable fields which occupy an object instance\n\ + =tls list all variables going into thread local storage\n\ "); return EXIT_FAILURE; } @@ -803,6 +686,8 @@ Language changes listed by -transition=id:\n\ { if (strcmp(p + 12, "tls") == 0) global.params.vtls = 1; + if (strcmp(p + 12, "field") == 0) + global.params.vfield = 1; } else goto Lerror; @@ -1051,6 +936,10 @@ Language changes listed by -transition=id:\n\ } else if (strcmp(p + 1, "-r") == 0) global.params.debugr = true; + else if (strcmp(p + 1, "-version") == 0) + { logo(); + exit(EXIT_SUCCESS); + } else if (strcmp(p + 1, "-x") == 0) global.params.debugx = true; else if (strcmp(p + 1, "-y") == 0) @@ -1166,7 +1055,7 @@ Language changes listed by -transition=id:\n\ if(global.params.is64bit != is64bit) error(Loc(), "the architecture must not be changed in the %s section of %s", - envsec, inifilename); + envsection, global.inifilename); // Target uses 64bit pointers. global.params.isLP64 = global.params.is64bit; @@ -1277,8 +1166,22 @@ Language changes listed by -transition=id:\n\ #endif #if TARGET_WINDOS VersionCondition::addPredefinedGlobalIdent("Win32"); + if (!setdefaultlib && global.params.mscoff) + { + global.params.defaultlibname = "phobos32mscoff"; + if (!setdebuglib) + global.params.debuglibname = global.params.defaultlibname; + } #endif } +#if TARGET_WINDOS + if (global.params.mscoff) + VersionCondition::addPredefinedGlobalIdent("CRuntime_Microsoft"); + else + VersionCondition::addPredefinedGlobalIdent("CRuntime_DigitalMars"); +#else + VersionCondition::addPredefinedGlobalIdent("CRuntime_GNU"); +#endif if (global.params.isLP64) VersionCondition::addPredefinedGlobalIdent("D_LP64"); if (global.params.doDocComments) @@ -1309,7 +1212,8 @@ Language changes listed by -transition=id:\n\ if (global.params.verbose) { fprintf(global.stdmsg, "binary %s\n", argv[0]); fprintf(global.stdmsg, "version %s\n", global.version); - fprintf(global.stdmsg, "config %s\n", inifilename ? inifilename : "(none)"); + fprintf(global.stdmsg, "config %s\n", global.inifilename ? global.inifilename + : "(none)"); } //printf("%d source files\n",files.dim); @@ -2005,21 +1909,19 @@ void escapePath(OutBuffer *buf, const char *fname) * to detect the desired architecture. */ -static bool parse_arch(size_t argc, const char** argv, bool is64bit) +static const char* parse_arch(size_t argc, const char** argv, const char* arch) { for (size_t i = 0; i < argc; ++i) { const char* p = argv[i]; if (p[0] == '-') { - if (strcmp(p + 1, "m32") == 0) - is64bit = false; - else if (strcmp(p + 1, "m64") == 0) - is64bit = true; + if (strcmp(p + 1, "m32") == 0 || strcmp(p + 1, "m32mscoff") == 0 || strcmp(p + 1, "m64") == 0) + arch = p + 2; else if (strcmp(p + 1, "run") == 0) break; } } - return is64bit; + return arch; } Dsymbols *Dsymbols_create() { return new Dsymbols(); } diff --git a/dmd2/mars.h b/dmd2/mars.h index aaecf257b5..9312d8c212 100644 --- a/dmd2/mars.h +++ b/dmd2/mars.h @@ -94,7 +94,6 @@ struct OutBuffer; // Can't include arraytypes.h here, need to declare these directly. template struct Array; -typedef Array Identifiers; typedef Array Strings; #if IN_LLVM @@ -139,7 +138,12 @@ struct Param bool isFreeBSD; // generate code for FreeBSD bool isOpenBSD; // generate code for OpenBSD bool isSolaris; // generate code for Solaris +#if !IN_LLVM + bool mscoff; // for Win32: write COFF object files instead of OMF + char useDeprecated; // 0: don't allow use of deprecated features +#else ubyte useDeprecated; // 0: don't allow use of deprecated features +#endif // 1: silently allow use of deprecated features // 2: warn about the use of deprecated features bool useAssert; // generate runtime code for assert()'s @@ -215,12 +219,10 @@ struct Param #if !IN_LLVM // Hidden debug switches - bool debuga; bool debugb; bool debugc; bool debugf; bool debugr; - bool debugw; bool debugx; bool debugy; #endif @@ -274,8 +276,8 @@ typedef unsigned structalign_t; struct Global { + const char *inifilename; const char *mars_ext; - const char *sym_ext; const char *obj_ext; #if IN_LLVM const char *obj_ext_alt; @@ -405,10 +407,6 @@ enum LINK LINKpascal, }; -// in hdrgen.c -void linkageToBuffer(OutBuffer *buf, LINK linkage); -const char *linkageToChars(LINK linkage); - enum DYNCAST { DYNCAST_OBJECT, @@ -428,40 +426,9 @@ enum MATCH MATCHexact // exact match }; -typedef uint64_t StorageClass; +typedef uinteger_t StorageClass; - -void warning(Loc loc, const char *format, ...); -void deprecation(Loc loc, const char *format, ...); -void error(Loc loc, const char *format, ...); -void errorSupplemental(Loc loc, const char *format, ...); -void verror(Loc loc, const char *format, va_list ap, const char *p1 = NULL, const char *p2 = NULL, const char *header = "Error: "); -void vwarning(Loc loc, const char *format, va_list); -void verrorSupplemental(Loc loc, const char *format, va_list ap); -void verrorPrint(Loc loc, const char *header, const char *format, va_list ap, const char *p1 = NULL, const char *p2 = NULL); -void vdeprecation(Loc loc, const char *format, va_list ap, const char *p1 = NULL, const char *p2 = NULL); - -#if defined(__GNUC__) || defined(__clang__) -__attribute__((noreturn)) -void fatal(); -#elif _MSC_VER -__declspec(noreturn) -void fatal(); -#else -void fatal(); -#endif - -void err_nomem(); -#if IN_LLVM -void error(const char *format, ...) IS_PRINTF(1); -void warning(const char *format, ...) IS_PRINTF(1); -#else -int runLINK(); -void deleteExeFile(); -int runProgram(); -const char *inifile(const char *argv0, const char *inifile, const char* envsectionname); -#endif -void halt(); +#include "errors.h" #if !IN_LLVM class Dsymbol; diff --git a/dmd2/module.c b/dmd2/module.c index c7dce9348b..bca4f74c96 100644 --- a/dmd2/module.c +++ b/dmd2/module.c @@ -21,9 +21,9 @@ #include "id.h" #include "import.h" #include "dsymbol.h" -#include "hdrgen.h" #include "expression.h" #include "lexer.h" +#include "attrib.h" #ifdef IN_GCC #include "d-dmd-gcc.h" @@ -50,9 +50,6 @@ Module::Module(const char *filename, Identifier *ident, int doDocComment, int do : Package(ident) { const char *srcfilename; -#if IN_DMD - const char *symfilename; -#endif // printf("Module::Module(filename = '%s', ident = '%s')\n", filename, ident->toChars()); this->arg = filename; @@ -64,6 +61,7 @@ Module::Module(const char *filename, Identifier *ident, int doDocComment, int do isPackageFile = false; needmoduleinfo = 0; selfimports = 0; + rootimports = 0; insearch = 0; searchCacheIdent = NULL; searchCacheSymbol = NULL; @@ -128,8 +126,6 @@ Module::Module(const char *filename, Identifier *ident, int doDocComment, int do #if IN_DMD objfile = setOutfile(global.params.objname, global.params.objdir, filename, global.obj_ext); - symfilename = FileName::forceExt(filename, global.sym_ext); - if (doDocComment) setDocfile(); @@ -137,7 +133,6 @@ Module::Module(const char *filename, Identifier *ident, int doDocComment, int do hdrfile = setOutfile(global.params.hdrname, global.params.hdrdir, arg, global.hdr_ext); //objfile = new File(objfilename); - symfile = new File(symfilename); #endif #if IN_LLVM // LDC @@ -296,7 +291,7 @@ bool Module::read(Loc loc) errorSupplemental(loc, "Please check your ldc2.conf configuration file."); errorSupplemental(loc, "Installation instructions can be found at http://wiki.dlang.org/LDC."); #else - errorSupplemental(loc, "dmd might not be correctly installed. Run 'dmd -man' for installation instructions."); + errorSupplemental(loc, "config file: %s", FileName::canonicalName(global.inifilename)); #endif } else @@ -606,6 +601,8 @@ void Module::parse() members = p.parseModule(); md = p.md; numlines = p.scanloc.linnum; + if (p.errors) + ++global.errors; } if (srcfile->ref == 0) @@ -686,12 +683,15 @@ void Module::parse() assert(prev); if (Module *mprev = prev->isModule()) { - if (strcmp(srcname, mprev->srcfile->toChars()) == 0) - error(loc, "from file %s must be imported with 'import %s;'", - srcname, toPrettyChars()); - else + if (FileName::compare(srcname, mprev->srcfile->toChars()) != 0) error(loc, "from file %s conflicts with another module %s from file %s", srcname, mprev->toChars(), mprev->srcfile->toChars()); + else if (isRoot() && mprev->isRoot()) + error(loc, "from file %s is specified twice on the command line", + srcname); + else + error(loc, "from file %s must be imported with 'import %s;'", + srcname, toPrettyChars()); } else if (Package *pkg = prev->isPackage()) { @@ -818,6 +818,11 @@ void Module::semantic() runDeferredSemantic(); } + if (userAttribDecl) + { + userAttribDecl->semantic(sc); + } + if (!scope) { sc = sc->pop(); @@ -847,6 +852,11 @@ void Module::semantic2() s->semantic2(sc); } + if (userAttribDecl) + { + userAttribDecl->semantic2(sc); + } + sc = sc->pop(); sc->pop(); semanticRun = PASSsemantic2done; @@ -874,39 +884,16 @@ void Module::semantic3() s->semantic3(sc); } + if (userAttribDecl) + { + userAttribDecl->semantic3(sc); + } + sc = sc->pop(); sc->pop(); semanticRun = PASSsemantic3done; } -/**************************************************** - */ - -#if IN_DMD -void Module::gensymfile() -{ - OutBuffer buf; - HdrGenState hgs; - - //printf("Module::gensymfile()\n"); - - buf.printf("// Sym file generated from '%s'", srcfile->toChars()); - buf.writenl(); - - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = (*members)[i]; - s->toCBuffer(&buf, &hgs); - } - - // Transfer image to file - symfile->setbuffer(buf.data, buf.offset); - buf.data = NULL; - - writeFile(loc, symfile); -} -#endif - /********************************** * Determine if we need to generate an instance of ModuleInfo * for this Module. @@ -1101,33 +1088,53 @@ int Module::imports(Module *m) } /************************************* - * Return !=0 if module imports itself. + * Return true if module imports itself. */ -int Module::selfImports() +bool Module::selfImports() { //printf("Module::selfImports() %s\n", toChars()); - if (!selfimports) + if (selfimports == 0) { for (size_t i = 0; i < amodules.dim; i++) - { - Module *mi = amodules[i]; - //printf("\t[%d] %s\n", i, mi->toChars()); - mi->insearch = 0; - } + amodules[i]->insearch = 0; selfimports = imports(this) + 1; for (size_t i = 0; i < amodules.dim; i++) - { - Module *mi = amodules[i]; - //printf("\t[%d] %s\n", i, mi->toChars()); - mi->insearch = 0; - } + amodules[i]->insearch = 0; } - return selfimports - 1; + return selfimports == 2; } +/************************************* + * Return true if module imports root module. + */ + +bool Module::rootImports() +{ + //printf("Module::rootImports() %s\n", toChars()); + if (rootimports == 0) + { + for (size_t i = 0; i < amodules.dim; i++) + amodules[i]->insearch = 0; + + rootimports = 1; + for (size_t i = 0; i < amodules.dim; ++i) + { + Module *m = amodules[i]; + if (m->isRoot() && imports(m)) + { + rootimports = 2; + break; + } + } + + for (size_t i = 0; i < amodules.dim; i++) + amodules[i]->insearch = 0; + } + return rootimports == 2; +} /* =========================== ModuleDeclaration ===================== */ @@ -1182,6 +1189,35 @@ Module *Package::isPackageMod() return NULL; } +/** + * Checks if pkg is a sub-package of this + * + * For example, if this qualifies to 'a1.a2' and pkg - to 'a1.a2.a3', + * this function returns 'true'. If it is other way around or qualified + * package paths conflict function returns 'false'. + * + * Params: + * pkg = possible subpackage + * + * Returns: + * see description + */ +bool Package::isAncestorPackageOf(Package* pkg) +{ + while (pkg) + { + if (this == pkg) + return true; + + if (!pkg->parent) + break; + + pkg = pkg->parent->isPackage(); + } + + return false; +} + /**************************************************** * Input: * packages[] the pkg1.pkg2 of pkg1.pkg2.mod @@ -1334,3 +1370,5 @@ const char *lookForSourceFile(const char *filename) } return NULL; } + + diff --git a/dmd2/module.h b/dmd2/module.h index 60f46fbb0e..a86ed8e64e 100644 --- a/dmd2/module.h +++ b/dmd2/module.h @@ -26,23 +26,14 @@ struct Escape; class VarDeclaration; class Library; -// Back end #if IN_LLVM class DValue; -typedef DValue elem; namespace llvm { class LLVMContext; class Module; class GlobalVariable; class StructType; } -#else - -#ifdef IN_GCC -typedef union tree_node elem; -#else -struct elem; -#endif #endif enum PKG @@ -65,6 +56,8 @@ public: Package *isPackage() { return this; } + bool isAncestorPackageOf(Package *pkg); + void semantic(Scope *sc) { } Dsymbol *search(Loc loc, Identifier *ident, int flags = IgnoreNone); void accept(Visitor *v) { v->visit(this); } @@ -91,7 +84,6 @@ public: File *srcfile; // input source file File *objfile; // output .obj file File *hdrfile; // 'header' file - File *symfile; // output symbol file File *docfile; // output documentation file unsigned errors; // if any errors in file unsigned numlines; // number of lines in source file @@ -100,7 +92,10 @@ public: int needmoduleinfo; int selfimports; // 0: don't know, 1: does not, 2: does - int selfImports(); // returns !=0 if module imports itself + bool selfImports(); // returns true if module imports itself + + int rootimports; // 0: don't know, 1: does not, 2: does + bool rootImports(); // returns true if module imports root module int insearch; Identifier *searchCacheIdent; @@ -156,9 +151,6 @@ public: void semantic3(); // pass 3 semantic analysis void genobjfile(bool multiobj); void genhelpers(bool iscomdat); -#if IN_DMD - void gensymfile(); -#endif int needModuleInfo(); Dsymbol *search(Loc loc, Identifier *ident, int flags = IgnoreNone); Dsymbol *symtabInsert(Dsymbol *s); diff --git a/dmd2/mtype.c b/dmd2/mtype.c index fb59030361..4b18ac973a 100644 --- a/dmd2/mtype.c +++ b/dmd2/mtype.c @@ -31,6 +31,7 @@ #include "rmem.h" #include "port.h" #include "target.h" +#include "checkedint.h" #include "dsymbol.h" #include "mtype.h" @@ -48,9 +49,6 @@ #include "aggregate.h" #include "hdrgen.h" -FuncDeclaration *hasThis(Scope *sc); -void toCBuffer(Type *t, OutBuffer *buf, Identifier *ident, HdrGenState *hgs); - #define LOGDOTEXP 0 // log ::dotExp() #define LOGDEFAULTINIT 0 // log ::defaultInit() @@ -66,7 +64,6 @@ ClassDeclaration *Type::dtypeinfo; ClassDeclaration *Type::typeinfoclass; ClassDeclaration *Type::typeinfointerface; ClassDeclaration *Type::typeinfostruct; -ClassDeclaration *Type::typeinfotypedef; ClassDeclaration *Type::typeinfopointer; ClassDeclaration *Type::typeinfoarray; ClassDeclaration *Type::typeinfostaticarray; @@ -125,10 +122,12 @@ Type *Type::tvoidptr; Type *Type::tstring; Type *Type::tvalist; Type *Type::basic[TMAX]; -unsigned char Type::mangleChar[TMAX]; -unsigned short Type::sizeTy[TMAX]; +unsigned char Type::sizeTy[TMAX]; StringTable Type::stringtable; +void initTypeMangle(); +void mangleToBuffer(Type *t, OutBuffer *buf); +void mangleToBuffer(Type *t, OutBuffer *buf, bool internal); Type::Type(TY ty) { @@ -186,6 +185,11 @@ bool Type::equals(RootObject *o) return false; } +bool Type::equivalent(Type *t) +{ + return immutableOf()->equals(t->immutableOf()); +} + char Type::needThisPrefix() { return 'M'; // name mangling prefix for functions needing 'this' @@ -193,7 +197,7 @@ char Type::needThisPrefix() void Type::init() { - stringtable._init(1543); + stringtable._init(14000); Lexer::initKeywords(); for (size_t i = 0; i < TMAX; i++) @@ -209,7 +213,6 @@ void Type::init() sizeTy[Tinstance] = sizeof(TypeInstance); sizeTy[Ttypeof] = sizeof(TypeTypeof); sizeTy[Tenum] = sizeof(TypeEnum); - sizeTy[Ttypedef] = sizeof(TypeTypedef); sizeTy[Tstruct] = sizeof(TypeStruct); sizeTy[Tclass] = sizeof(TypeClass); sizeTy[Ttuple] = sizeof(TypeTuple); @@ -218,63 +221,7 @@ void Type::init() sizeTy[Terror] = sizeof(TypeError); sizeTy[Tnull] = sizeof(TypeNull); - mangleChar[Tarray] = 'A'; - mangleChar[Tsarray] = 'G'; - mangleChar[Taarray] = 'H'; - mangleChar[Tpointer] = 'P'; - mangleChar[Treference] = 'R'; - mangleChar[Tfunction] = 'F'; - mangleChar[Tident] = 'I'; - mangleChar[Tclass] = 'C'; - mangleChar[Tstruct] = 'S'; - mangleChar[Tenum] = 'E'; - mangleChar[Ttypedef] = 'T'; - mangleChar[Tdelegate] = 'D'; - - mangleChar[Tnone] = 'n'; - mangleChar[Tvoid] = 'v'; - mangleChar[Tint8] = 'g'; - mangleChar[Tuns8] = 'h'; - mangleChar[Tint16] = 's'; - mangleChar[Tuns16] = 't'; - mangleChar[Tint32] = 'i'; - mangleChar[Tuns32] = 'k'; - mangleChar[Tint64] = 'l'; - mangleChar[Tuns64] = 'm'; - mangleChar[Tfloat32] = 'f'; - mangleChar[Tfloat64] = 'd'; - mangleChar[Tfloat80] = 'e'; - - mangleChar[Timaginary32] = 'o'; - mangleChar[Timaginary64] = 'p'; - mangleChar[Timaginary80] = 'j'; - mangleChar[Tcomplex32] = 'q'; - mangleChar[Tcomplex64] = 'r'; - mangleChar[Tcomplex80] = 'c'; - - mangleChar[Tbool] = 'b'; - mangleChar[Tchar] = 'a'; - mangleChar[Twchar] = 'u'; - mangleChar[Tdchar] = 'w'; - - // '@' shouldn't appear anywhere in the deco'd names - mangleChar[Tinstance] = '@'; - mangleChar[Terror] = '@'; - mangleChar[Ttypeof] = '@'; - mangleChar[Ttuple] = 'B'; - mangleChar[Tslice] = '@'; - mangleChar[Treturn] = '@'; - mangleChar[Tvector] = '@'; - mangleChar[Tint128] = '@'; - mangleChar[Tuns128] = '@'; - - mangleChar[Tnull] = 'n'; // same as TypeNone - - for (size_t i = 0; i < TMAX; i++) - { if (!mangleChar[i]) - fprintf(stderr, "ty = %llu\n", (ulonglong)i); - assert(mangleChar[i]); - } + initTypeMangle(); // Set basic types static TY basetab[] = @@ -287,7 +234,8 @@ void Type::init() Tchar, Twchar, Tdchar, Terror }; for (size_t i = 0; basetab[i] != Terror; i++) - { Type *t = new TypeBasic(basetab[i]); + { + Type *t = new TypeBasic(basetab[i]); t = t->merge(); basic[basetab[i]] = t; } @@ -1475,43 +1423,6 @@ MOD MODmerge(MOD mod1, MOD mod2) return result; } -/********************************* - * Mangling for mod. - */ -void MODtoDecoBuffer(OutBuffer *buf, MOD mod) -{ - switch (mod) - { case 0: - break; - case MODconst: - buf->writeByte('x'); - break; - case MODimmutable: - buf->writeByte('y'); - break; - case MODshared: - buf->writeByte('O'); - break; - case MODshared | MODconst: - buf->writestring("Ox"); - break; - case MODwild: - buf->writestring("Ng"); - break; - case MODwildconst: - buf->writestring("Ngx"); - break; - case MODshared | MODwild: - buf->writestring("ONg"); - break; - case MODshared | MODwildconst: - buf->writestring("ONgx"); - break; - default: - assert(0); - } -} - /********************************* * Store modifier name into buf. */ @@ -1573,21 +1484,6 @@ char *MODtoChars(MOD mod) return buf.extractString(); } -/******************************** - * Name mangling. - * Input: - * flag 0x100 do not do modifiers - */ - -void Type::toDecoBuffer(OutBuffer *buf, int flag) -{ - if (flag != mod && flag != 0x100) - { - MODtoDecoBuffer(buf, mod); - } - buf->writeByte(mangleChar[ty]); -} - /******************************** * For pretty-printing a type. */ @@ -1598,7 +1494,7 @@ char *Type::toChars() buf.reserve(16); HdrGenState hgs; - toCBuffer(&buf, NULL, &hgs); + ::toCBuffer(this, &buf, NULL, &hgs); return buf.extractString(); } @@ -1607,17 +1503,12 @@ char *Type::toPrettyChars(bool QualifyTypes) OutBuffer buf; buf.reserve(16); HdrGenState hgs; - hgs.fullQualification = QualifyTypes; + hgs.fullQual = QualifyTypes; - toCBuffer(&buf, NULL, &hgs); + ::toCBuffer(this, &buf, NULL, &hgs); return buf.extractString(); } -void Type::toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs) -{ - ::toCBuffer(this, buf, ident, hgs); -} - /********************************* * Store this type's modifier name into buf. */ @@ -1760,12 +1651,12 @@ Type *Type::merge() OutBuffer buf; buf.reserve(32); - //if (next) - //next = next->merge(); - toDecoBuffer(&buf); + mangleToBuffer(this, &buf); + StringValue *sv = stringtable.update((char *)buf.data, buf.offset); if (sv->ptrvalue) - { t = (Type *) sv->ptrvalue; + { + t = (Type *) sv->ptrvalue; #ifdef DEBUG if (!t->deco) printf("t = %s\n", t->toChars()); @@ -2188,11 +2079,6 @@ Expression *Type::getProperty(Loc loc, Identifier *ident, int flag) { e = new IntegerExp(loc, alignsize(), Type::tsize_t); } - else if (ident == Id::typeinfo) - { - error(loc, ".typeinfo deprecated, use typeid(type)"); - e = getTypeInfo(NULL); - } else if (ident == Id::init) { Type *tb = toBasetype(); @@ -2235,7 +2121,7 @@ Expression *Type::getProperty(Loc loc, Identifier *ident, int flag) else { Dsymbol *s = NULL; - if (ty == Tstruct || ty == Tclass || ty == Tenum || ty == Ttypedef) + if (ty == Tstruct || ty == Tclass || ty == Tenum) s = toDsymbol(NULL); if (s) s = s->search_correct(ident); @@ -2277,14 +2163,8 @@ Expression *Type::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag) } if (v) { - if (ident == Id::offset) + if (ident == Id::offsetof) { - error(e->loc, ".offset deprecated, use .offsetof"); - goto Loffset; - } - else if (ident == Id::offsetof) - { - Loffset: if (v->isField()) { e = new IntegerExp(e->loc, v->offset, Type::tsize_t); @@ -2314,12 +2194,7 @@ Expression *Type::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag) goto Lreturn; } } - if (ident == Id::typeinfo) - { - error(e->loc, ".typeinfo deprecated, use typeid(type)"); - e = getTypeInfo(sc); - } - else if (ident == Id::stringof) + if (ident == Id::stringof) { /* Bugzilla 3796: this should demangle e->type->deco rather than * pretty-printing the type. */ @@ -2445,16 +2320,7 @@ Identifier *Type::getTypeInfoIdent(int internal) // _init_10TypeInfo_%s OutBuffer buf; buf.reserve(32); - - if (internal) - { buf.writeByte(mangleChar[ty]); - if (ty == Tarray) - buf.writeByte(mangleChar[((TypeArray *)this)->next->ty]); - } - else if (deco) - buf.writestring(deco); - else - toDecoBuffer(&buf); + mangleToBuffer(this, &buf, internal != 0); size_t len = buf.offset; buf.writeByte(0); @@ -2602,14 +2468,6 @@ TypeNext::TypeNext(TY ty, Type *next) this->next = next; } -void TypeNext::toDecoBuffer(OutBuffer *buf, int flag) -{ - Type::toDecoBuffer(buf, flag); - assert(next != this); - //printf("this = %p, ty = %d, next = %p, ty = %d\n", this, this->ty, next, next->ty); - next->toDecoBuffer(buf, (flag & 0x100) ? 0 : mod); -} - void TypeNext::checkDeprecated(Loc loc, Scope *sc) { Type::checkDeprecated(loc, sc); @@ -2908,7 +2766,6 @@ void TypeNext::transitive() #define TFLAGSreal 8 #define TFLAGSimaginary 0x10 #define TFLAGScomplex 0x20 -#define TFLAGSvector 0x40 // valid for a SIMD vector type TypeBasic::TypeBasic(TY ty) : Type(ty) @@ -2919,43 +2776,42 @@ TypeBasic::TypeBasic(TY ty) switch (ty) { case Tvoid: d = Token::toChars(TOKvoid); - flags |= TFLAGSvector; break; case Tint8: d = Token::toChars(TOKint8); - flags |= TFLAGSintegral | TFLAGSvector; + flags |= TFLAGSintegral; break; case Tuns8: d = Token::toChars(TOKuns8); - flags |= TFLAGSintegral | TFLAGSunsigned | TFLAGSvector; + flags |= TFLAGSintegral | TFLAGSunsigned; break; case Tint16: d = Token::toChars(TOKint16); - flags |= TFLAGSintegral | TFLAGSvector; + flags |= TFLAGSintegral; break; case Tuns16: d = Token::toChars(TOKuns16); - flags |= TFLAGSintegral | TFLAGSunsigned | TFLAGSvector; + flags |= TFLAGSintegral | TFLAGSunsigned; break; case Tint32: d = Token::toChars(TOKint32); - flags |= TFLAGSintegral | TFLAGSvector; + flags |= TFLAGSintegral; break; case Tuns32: d = Token::toChars(TOKuns32); - flags |= TFLAGSintegral | TFLAGSunsigned | TFLAGSvector; + flags |= TFLAGSintegral | TFLAGSunsigned; break; case Tfloat32: d = Token::toChars(TOKfloat32); - flags |= TFLAGSfloating | TFLAGSreal | TFLAGSvector; + flags |= TFLAGSfloating | TFLAGSreal; break; case Tint64: d = Token::toChars(TOKint64); - flags |= TFLAGSintegral | TFLAGSvector; + flags |= TFLAGSintegral; break; case Tuns64: d = Token::toChars(TOKuns64); - flags |= TFLAGSintegral | TFLAGSunsigned | TFLAGSvector; + flags |= TFLAGSintegral | TFLAGSunsigned; break; case Tint128: d = Token::toChars(TOKint128); @@ -2967,7 +2823,7 @@ TypeBasic::TypeBasic(TY ty) break; case Tfloat64: d = Token::toChars(TOKfloat64); - flags |= TFLAGSfloating | TFLAGSreal | TFLAGSvector; + flags |= TFLAGSfloating | TFLAGSreal; break; case Tfloat80: d = Token::toChars(TOKfloat80); @@ -3032,7 +2888,6 @@ Type *TypeBasic::syntaxCopy() return this; } - char *TypeBasic::toChars() { return Type::toChars(); @@ -3166,7 +3021,7 @@ Expression *TypeBasic::getProperty(Loc loc, Identifier *ident, int flag) case Tcomplex80: case Timaginary80: case Tfloat80: - deprecation(loc, ".min property is deprecated, use .min_normal instead"); + error(loc, ".min property is deprecated, use .min_normal instead"); goto Lmin_normal; } } @@ -3654,15 +3509,22 @@ Type *TypeVector::semantic(Loc loc, Scope *sc) return terror; } TypeSArray *t = (TypeSArray *)basetype; - d_uns64 sz = t->size(loc); - if (sz != 16 && sz != 32) - { error(loc, "base type of __vector must be a 16 or 32 byte static array, not %s", t->toChars()); + int sz = (int)t->size(loc); + switch (Target::checkVectorType(sz, t->nextOf())) + { + case 0: // valid + break; + case 1: // no support at all + error(loc, "SIMD vector types not supported on this platform"); return terror; - } - TypeBasic *tb = t->nextOf()->isTypeBasic(); - if (!tb || !(tb->flags & TFLAGSvector)) - { error(loc, "base type of __vector must be a static array of an arithmetic type, not %s", t->toChars()); + case 2: // invalid size + error(loc, "%d byte vector type %s is not supported on this platform", sz, toChars()); return terror; + case 3: // invalid base type + error(loc, "vector type %s is not supported on this platform", toChars()); + return terror; + default: + assert(0); } return merge(); } @@ -3686,16 +3548,6 @@ char *TypeVector::toChars() return Type::toChars(); } -void TypeVector::toDecoBuffer(OutBuffer *buf, int flag) -{ - if (flag != mod && flag != 0x100) - { - MODtoDecoBuffer(buf, mod); - } - buf->writestring("Nh"); - basetype->toDecoBuffer(buf, (flag & 0x100) ? 0 : mod); -} - d_uns64 TypeVector::size(Loc loc) { return basetype->size(); @@ -3818,6 +3670,7 @@ Expression *TypeArray::dotExp(Scope *sc, Expression *e, Identifier *ident, int f static const char *reverseName[2] = { "_adReverseChar", "_adReverseWchar" }; static FuncDeclaration *reverseFd[2] = { NULL, NULL }; + warning(e->loc, "use std.algorithm.reverse instead of .reverse property"); int i = n->ty == Twchar; if (!reverseFd[i]) { Parameters *args = new Parameters; @@ -3839,6 +3692,7 @@ Expression *TypeArray::dotExp(Scope *sc, Expression *e, Identifier *ident, int f static const char *sortName[2] = { "_adSortChar", "_adSortWchar" }; static FuncDeclaration *sortFd[2] = { NULL, NULL }; + warning(e->loc, "use std.algorithm.sort instead of .sort property"); int i = n->ty == Twchar; if (!sortFd[i]) { Parameters *args = new Parameters; @@ -3862,6 +3716,7 @@ Expression *TypeArray::dotExp(Scope *sc, Expression *e, Identifier *ident, int f Expressions *arguments; dinteger_t size = next->size(e->loc); + warning(e->loc, "use std.algorithm.reverse instead of .reverse property"); assert(size); static FuncDeclaration *adReverse_fd = NULL; @@ -3887,6 +3742,7 @@ Expression *TypeArray::dotExp(Scope *sc, Expression *e, Identifier *ident, int f Expression *ec; Expressions *arguments; + warning(e->loc, "use std.algorithm.sort instead of .sort property"); if (!fd) { Parameters* args = new Parameters; args->push(new Parameter(0, Type::tvoid->arrayOf(), NULL, NULL)); @@ -3953,13 +3809,12 @@ d_uns64 TypeSArray::size(Loc loc) return Type::size(loc); sz = dim->toInteger(); - { dinteger_t n, n2; + { + bool overflow = false; - n = next->size(); - n2 = n * sz; - if (n && (n2 / n) != sz) + sz = mulu(next->size(), sz, overflow); + if (overflow) goto Loverflow; - sz = n2; } return sz; @@ -4167,6 +4022,7 @@ Type *TypeSArray::semantic(Loc loc, Scope *sc) if (dim->op == TOKerror) goto Lerror; + bool overflow = false; if (d1 != d2) goto Loverflow; @@ -4182,16 +4038,10 @@ Type *TypeSArray::semantic(Loc loc, Scope *sc) /* Only do this for types that don't need to have semantic() * run on them for the size, since they may be forward referenced. */ - n = tbn->size(loc); - n2 = n * d2; - if ((int)n2 < 0) - goto Loverflow; - if (n2 >= 0x1000000) // put a 'reasonable' limit on it - goto Loverflow; - if (n && n2 / n != d2) + if (mulu(tbn->size(loc), d2, overflow) >= 0x1000000 || overflow) // put a 'reasonable' limit on it { Loverflow: - error(loc, "index %lld overflow for static array", d1); + error(loc, "index %llu overflow for static array", (unsigned long long)d1); goto Lerror; } } @@ -4236,20 +4086,6 @@ Lerror: return Type::terror; } -void TypeSArray::toDecoBuffer(OutBuffer *buf, int flag) -{ - Type::toDecoBuffer(buf, flag); - if (dim) - buf->printf("%llu", dim->toInteger()); - if (next) - /* Note that static arrays are value types, so - * for a parameter, propagate the 0x100 to the next - * level, since for T[4][3], any const should apply to the T, - * not the [4]. - */ - next->toDecoBuffer(buf, (flag & 0x100) ? flag : mod); -} - Expression *TypeSArray::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag) { #if LOGDOTEXP @@ -4465,7 +4301,8 @@ Type *TypeDArray::syntaxCopy() if (t == next) t = this; else - { t = new TypeDArray(t); + { + t = new TypeDArray(t); t->mod = mod; } return t; @@ -4537,13 +4374,6 @@ void TypeDArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol } } -void TypeDArray::toDecoBuffer(OutBuffer *buf, int flag) -{ - Type::toDecoBuffer(buf, flag); - if (next) - next->toDecoBuffer(buf, (flag & 0x100) ? 0 : mod); -} - Expression *TypeDArray::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag) { #if LOGDOTEXP @@ -4684,7 +4514,8 @@ Type *TypeAArray::syntaxCopy() if (t == next && ti == index) t = this; else - { t = new TypeAArray(t, ti); + { + t = new TypeAArray(t, ti); t->mod = mod; } return t; @@ -4695,7 +4526,6 @@ d_uns64 TypeAArray::size(Loc loc) return Target::ptrsize; } - Type *TypeAArray::semantic(Loc loc, Scope *sc) { //printf("TypeAArray::semantic() %s index->ty = %d\n", toChars(), index->ty); @@ -4945,13 +4775,6 @@ Expression *TypeAArray::dotExp(Scope *sc, Expression *e, Identifier *ident, int return e; } -void TypeAArray::toDecoBuffer(OutBuffer *buf, int flag) -{ - Type::toDecoBuffer(buf, flag); - index->toDecoBuffer(buf); - next->toDecoBuffer(buf, (flag & 0x100) ? 0 : mod); -} - Expression *TypeAArray::defaultInit(Loc loc) { #if LOGDEFAULTINIT @@ -5047,7 +4870,8 @@ Type *TypePointer::syntaxCopy() if (t == next) t = this; else - { t = new TypePointer(t); + { + t = new TypePointer(t); t->mod = mod; } return t; @@ -5218,7 +5042,8 @@ Type *TypeReference::syntaxCopy() if (t == next) t = this; else - { t = new TypeReference(t); + { + t = new TypeReference(t); t->mod = mod; } return t; @@ -5508,65 +5333,6 @@ Lnotcovariant: return 2; } -void TypeFunction::toDecoBuffer(OutBuffer *buf, int flag) -{ - //printf("TypeFunction::toDecoBuffer() this = %p %s\n", this, toChars()); - //static int nest; if (++nest == 50) *(char*)0=0; - if (inuse) - { - inuse = 2; // flag error to caller - return; - } - inuse++; - - MODtoDecoBuffer(buf, mod); - - unsigned char mc; - switch (linkage) - { - case LINKd: mc = 'F'; break; - case LINKc: mc = 'U'; break; - case LINKwindows: mc = 'W'; break; - case LINKpascal: mc = 'V'; break; - case LINKcpp: mc = 'R'; break; - default: - assert(0); - } - buf->writeByte(mc); - - if (purity || isnothrow || isnogc || isproperty || isref || trust) - { - if (purity) - buf->writestring("Na"); - if (isnothrow) - buf->writestring("Nb"); - if (isref) - buf->writestring("Nc"); - if (isproperty) - buf->writestring("Nd"); - if (isnogc) - buf->writestring("Ni"); - switch (trust) - { - case TRUSTtrusted: - buf->writestring("Ne"); - break; - case TRUSTsafe: - buf->writestring("Nf"); - break; - default: break; - } - } - - // Write argument types - Parameter::argsToDecoBuffer(buf, parameters); - //if (buf->data[buf->offset - 1] == '@') halt(); - buf->writeByte('Z' - varargs); // mark end of arg list - if (next != NULL) - next->toDecoBuffer(buf); - inuse--; -} - Type *TypeFunction::semantic(Loc loc, Scope *sc) { if (deco) // if semantic() already run @@ -5680,7 +5446,7 @@ Type *TypeFunction::semantic(Loc loc, Scope *sc) */ Scope *argsc = sc->push(); argsc->stc = 0; // don't inherit storage class - argsc->protection = PROTpublic; + argsc->protection = Prot(PROTpublic); argsc->func = NULL; size_t dim = Parameter::dim(tf->parameters); @@ -6149,7 +5915,13 @@ MATCH TypeFunction::callMatch(Type *tthis, Expressions *args, int flag) goto Nomatch; } else if (p->storageClass & STCout) - { if (m && !arg->isLvalue()) + { + if (m && !arg->isLvalue()) + goto Nomatch; + + Type *targb = targ->toBasetype(); + Type *tprmb = tprm->toBasetype(); + if (!targb->constConv(tprmb)) goto Nomatch; } } @@ -6384,7 +6156,8 @@ Type *TypeDelegate::syntaxCopy() if (t == next) t = this; else - { t = new TypeDelegate(t); + { + t = new TypeDelegate(t); t->mod = mod; } return t; @@ -6530,7 +6303,6 @@ void TypeQualified::syntaxCopyHelper(TypeQualified *t) } } - void TypeQualified::addIdent(Identifier *ident) { idents.push(ident); @@ -6791,25 +6563,14 @@ const char *TypeIdentifier::kind() return "identifier"; } - Type *TypeIdentifier::syntaxCopy() { - TypeIdentifier *t; - - t = new TypeIdentifier(loc, ident); + TypeIdentifier *t = new TypeIdentifier(loc, ident); t->syntaxCopyHelper(this); t->mod = mod; return t; } -void TypeIdentifier::toDecoBuffer(OutBuffer *buf, int flag) -{ - Type::toDecoBuffer(buf, flag); - const char *name = ident->toChars(); - size_t len = strlen(name); - buf->printf("%u%s", (unsigned)len, name); -} - /************************************* * Takes an array of Identifiers and figures out if * it represents a Type or an Expression. @@ -6820,8 +6581,6 @@ void TypeIdentifier::toDecoBuffer(OutBuffer *buf, int flag) void TypeIdentifier::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid) { - Dsymbol *scopesym; - //printf("TypeIdentifier::resolve(sc = %p, idents = '%s')\n", sc, toChars()); if ((ident->equals(Id::super) || ident->equals(Id::This)) && !hasThis(sc)) @@ -6845,7 +6604,16 @@ void TypeIdentifier::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsy } } } + if (ident == Id::ctfe) + { + error(loc, "variable __ctfe cannot be read at compile time"); + *pe = NULL; + *ps = NULL; + *pt = Type::terror; + return; + } + Dsymbol *scopesym; Dsymbol *s = sc->search(loc, ident, &scopesym); resolveHelper(loc, sc, s, scopesym, pe, pt, ps, intypeid); if (*pt) @@ -6893,15 +6661,6 @@ Type *TypeIdentifier::semantic(Loc loc, Scope *sc) if (t) { //printf("\tit's a type %d, %s, %s\n", t->ty, t->toChars(), t->deco); - - if (t->ty == Ttypedef) - { - TypeTypedef *tt = (TypeTypedef *)t; - if (tt->sym->sem == SemanticIn) - { error(loc, "circular reference of typedef %s", tt->toChars()); - return terror; - } - } t = t->addMod(mod); } else @@ -6957,9 +6716,7 @@ const char *TypeInstance::kind() Type *TypeInstance::syntaxCopy() { //printf("TypeInstance::syntaxCopy() %s, %d\n", toChars(), idents.dim); - TypeInstance *t; - - t = new TypeInstance(loc, (TemplateInstance *)tempinst->syntaxCopy(NULL)); + TypeInstance *t = new TypeInstance(loc, (TemplateInstance *)tempinst->syntaxCopy(NULL)); t->syntaxCopyHelper(this); t->mod = mod; return t; @@ -7079,9 +6836,7 @@ const char *TypeTypeof::kind() Type *TypeTypeof::syntaxCopy() { //printf("TypeTypeof::syntaxCopy() %s\n", toChars()); - TypeTypeof *t; - - t = new TypeTypeof(loc, exp->syntaxCopy()); + TypeTypeof *t = new TypeTypeof(loc, exp->syntaxCopy()); t->syntaxCopyHelper(this); t->mod = mod; return t; @@ -7129,7 +6884,6 @@ void TypeTypeof::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol */ Scope *sc2 = sc->push(); sc2->intypeof = 1; - sc2->flags |= sc->flags & SCOPEstaticif; exp = exp->semantic(sc2); exp = resolvePropertiesOnly(sc2, exp); sc2->pop(); @@ -7405,13 +7159,6 @@ Type *TypeEnum::toBasetype() return sym->getMemtype(Loc())->toBasetype(); } -void TypeEnum::toDecoBuffer(OutBuffer *buf, int flag) -{ - const char *name = mangle(sym); - Type::toDecoBuffer(buf, flag); - buf->writestring(name); -} - Expression *TypeEnum::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag) { #if LOGDOTEXP @@ -7577,287 +7324,6 @@ Type *TypeEnum::nextOf() return sym->getMemtype(Loc())->nextOf(); } -/***************************** TypeTypedef *****************************/ - -TypeTypedef::TypeTypedef(TypedefDeclaration *sym) - : Type(Ttypedef) -{ - this->sym = sym; -} - -const char *TypeTypedef::kind() -{ - return "typedef"; -} - -Type *TypeTypedef::syntaxCopy() -{ - return this; -} - -char *TypeTypedef::toChars() -{ - return Type::toChars(); -} - -Type *TypeTypedef::semantic(Loc loc, Scope *sc) -{ - //printf("TypeTypedef::semantic(%s), sem = %d\n", toChars(), sym->sem); - unsigned int errors = global.errors; - sym->semantic(sc); - if (errors != global.errors || sym->errors || sym->basetype->ty == Terror) - return terror; - return merge(); -} - -d_uns64 TypeTypedef::size(Loc loc) -{ - return sym->basetype->size(loc); -} - -unsigned TypeTypedef::alignsize() -{ - return sym->basetype->alignsize(); -} - -Dsymbol *TypeTypedef::toDsymbol(Scope *sc) -{ - return sym; -} - -void TypeTypedef::toDecoBuffer(OutBuffer *buf, int flag) -{ - Type::toDecoBuffer(buf, flag); - const char *name = mangle(sym); - buf->writestring(name); -} - -Expression *TypeTypedef::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag) -{ -#if LOGDOTEXP - printf("TypeTypedef::dotExp(e = '%s', ident = '%s') '%s'\n", e->toChars(), ident->toChars(), toChars()); -#endif - if (ident == Id::init) - { - return Type::dotExp(sc, e, ident, flag); - } - return sym->basetype->dotExp(sc, e, ident, flag); -} - -structalign_t TypeTypedef::alignment() -{ - if (sym->inuse) - { - sym->error("circular definition"); - sym->basetype = Type::terror; - return STRUCTALIGN_DEFAULT; - } - sym->inuse = 1; - structalign_t a = sym->basetype->alignment(); - sym->inuse = 0; - return a; -} - -Expression *TypeTypedef::getProperty(Loc loc, Identifier *ident, int flag) -{ -#if LOGDOTEXP - printf("TypeTypedef::getProperty(ident = '%s') '%s'\n", ident->toChars(), toChars()); -#endif - if (ident == Id::init) - { - return Type::getProperty(loc, ident, flag); - } - return sym->basetype->getProperty(loc, ident, flag); -} - -bool TypeTypedef::isintegral() -{ - //printf("TypeTypedef::isintegral()\n"); - //printf("sym = '%s'\n", sym->toChars()); - //printf("basetype = '%s'\n", sym->basetype->toChars()); - return sym->basetype->isintegral(); -} - -bool TypeTypedef::isfloating() -{ - return sym->basetype->isfloating(); -} - -bool TypeTypedef::isreal() -{ - return sym->basetype->isreal(); -} - -bool TypeTypedef::isimaginary() -{ - return sym->basetype->isimaginary(); -} - -bool TypeTypedef::iscomplex() -{ - return sym->basetype->iscomplex(); -} - -bool TypeTypedef::isunsigned() -{ - return sym->basetype->isunsigned(); -} - -bool TypeTypedef::isscalar() -{ - return sym->basetype->isscalar(); -} - -bool TypeTypedef::isAssignable() -{ - return sym->basetype->isAssignable(); -} - -bool TypeTypedef::checkBoolean() -{ - return sym->basetype->checkBoolean(); -} - -bool TypeTypedef::needsDestruction() -{ - return sym->basetype->needsDestruction(); -} - -bool TypeTypedef::needsNested() -{ - return sym->basetype->needsNested(); -} - -Type *TypeTypedef::toBasetype() -{ - if (sym->inuse) - { - sym->error("circular definition"); - sym->basetype = Type::terror; - return Type::terror; - } - sym->inuse = 1; - Type *t = sym->basetype->toBasetype(); - sym->inuse = 0; - t = t->addMod(mod); - return t; -} - -MATCH TypeTypedef::implicitConvTo(Type *to) -{ MATCH m; - - //printf("TypeTypedef::implicitConvTo(to = %s) %s\n", to->toChars(), toChars()); - if (equals(to)) - m = MATCHexact; // exact match - else if (sym->basetype->implicitConvTo(to)) - m = MATCHconvert; // match with conversions - else if (ty == to->ty && sym == ((TypeTypedef *)to)->sym) - { - m = constConv(to); - } - else - m = MATCHnomatch; // no match - return m; -} - -MATCH TypeTypedef::constConv(Type *to) -{ - if (equals(to)) - return MATCHexact; - if (ty == to->ty && sym == ((TypeTypedef *)to)->sym) - return sym->basetype->implicitConvTo(((TypeTypedef *)to)->sym->basetype); - return MATCHnomatch; -} - -Type *TypeTypedef::toHeadMutable() -{ - if (!mod) - return this; - - Type *tb = toBasetype(); - Type *t = tb->toHeadMutable(); - if (t->equals(tb)) - return this; - else - return mutableOf(); -} - -Expression *TypeTypedef::defaultInit(Loc loc) -{ -#if LOGDEFAULTINIT - printf("TypeTypedef::defaultInit() '%s'\n", toChars()); -#endif - if (sym->init) - { - //sym->init->toExpression()->print(); - return sym->init->toExpression(); - } - Type *bt = sym->basetype; - Expression *e = bt->defaultInit(loc); - e->type = this; - while (bt->ty == Tsarray) - { TypeSArray *tsa = (TypeSArray *)bt; - e->type = tsa->next; - bt = tsa->next->toBasetype(); - } - return e; -} - -Expression *TypeTypedef::defaultInitLiteral(Loc loc) -{ -#if LOGDEFAULTINIT - printf("TypeTypedef::defaultInitLiteral() '%s'\n", toChars()); -#endif - if (sym->init) - { - //sym->init->toExpression()->print(); - Expression *e = sym->init->toExpression(); - if (!e) - { - error(loc, "void initializer has no value"); - e = new ErrorExp(); - } - return e; - } - Type *bt = sym->basetype; - Expression *e = bt->defaultInitLiteral(loc); - e->type = this; - return e; -} - -bool TypeTypedef::isZeroInit(Loc loc) -{ - if (sym->init) - { - if (sym->init->isVoidInitializer()) - return true; // initialize voids to 0 - Expression *e = sym->init->toExpression(); - if (e && e->isBool(false)) - return true; - return false; // assume not - } - if (sym->inuse) - { - sym->error("circular definition"); - sym->basetype = Type::terror; - } - sym->inuse = 1; - bool result = sym->basetype->isZeroInit(loc); - sym->inuse = 0; - return result; -} - -int TypeTypedef::hasPointers() -{ - return toBasetype()->hasPointers(); -} - -int TypeTypedef::hasWild() -{ - assert(toBasetype()); - return mod & MODwild || toBasetype()->hasWild(); -} - /***************************** TypeStruct *****************************/ TypeStruct::TypeStruct(StructDeclaration *sym) @@ -7923,14 +7389,6 @@ Dsymbol *TypeStruct::toDsymbol(Scope *sc) return sym; } -void TypeStruct::toDecoBuffer(OutBuffer *buf, int flag) -{ - const char *name = mangle(sym); - //printf("TypeStruct::toDecoBuffer('%s') = '%s'\n", toChars(), name); - Type::toDecoBuffer(buf, flag); - buf->writestring(name); -} - Expression *TypeStruct::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag) { Dsymbol *s; @@ -8020,13 +7478,23 @@ L1: s = s->toAlias(); VarDeclaration *v = s->isVarDeclaration(); - if (v && v->inuse && (!v->type || !v->type->deco)) // Bugzilla 9494 + if (v && (!v->type || !v->type->deco)) { - e->error("circular reference to '%s'", v->toPrettyChars()); - return new ErrorExp(); + if (v->inuse) // Bugzilla 9494 + { + e->error("circular reference to '%s'", v->toPrettyChars()); + return new ErrorExp(); + } + if (v->scope) + { + v->semantic(v->scope); + s = v->toAlias(); // Need this if 'v' is a tuple variable + v = s->isVarDeclaration(); + } } if (v && !v->isDataseg() && (v->storage_class & STCmanifest)) { + accessCheck(e->loc, sc, NULL, v); Expression *ve = new VarExp(e->loc, v); ve = ve->semantic(sc); return ve; @@ -8127,6 +7595,8 @@ L1: return e; } } + if (d->semanticRun == PASSinit && d->scope) + d->semantic(d->scope); accessCheck(e->loc, sc, e, d); VarExp *ve = new VarExp(e->loc, d, 1); if (d->isVarDeclaration() && d->needThis()) @@ -8468,14 +7938,6 @@ Dsymbol *TypeClass::toDsymbol(Scope *sc) return sym; } -void TypeClass::toDecoBuffer(OutBuffer *buf, int flag) -{ - const char *name = mangle(sym); - //printf("TypeClass::toDecoBuffer('%s' flag=%d mod=%x) = '%s'\n", toChars(), flag, mod, name); - Type::toDecoBuffer(buf, flag); - buf->writestring(name); -} - Expression *TypeClass::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag) { Dsymbol *s; @@ -8650,11 +8112,6 @@ L1: return e; } - if (ident == Id::typeinfo) - { - error(e->loc, ".typeinfo deprecated, use typeid(type)"); - return getTypeInfo(sc); - } if (ident == Id::outer && sym->vthis) { if (sym->vthis->scope) @@ -8671,13 +8128,23 @@ L1: s = s->toAlias(); VarDeclaration *v = s->isVarDeclaration(); - if (v && v->inuse && (!v->type || !v->type->deco)) // Bugzilla 9494 + if (v && (!v->type || !v->type->deco)) { - e->error("circular reference to '%s'", v->toPrettyChars()); - return new ErrorExp(); + if (v->inuse) // Bugzilla 9494 + { + e->error("circular reference to '%s'", v->toPrettyChars()); + return new ErrorExp(); + } + if (v->scope) + { + v->semantic(v->scope); + s = v->toAlias(); // Need this if 'v' is a tuple variable + v = s->isVarDeclaration(); + } } if (v && !v->isDataseg() && (v->storage_class & STCmanifest)) { + accessCheck(e->loc, sc, NULL, v); Expression *ve = new VarExp(e->loc, v); ve = ve->semantic(sc); return ve; @@ -8836,6 +8303,8 @@ L1: } } //printf("e = %s, d = %s\n", e->toChars(), d->toChars()); + if (d->semanticRun == PASSinit && d->scope) + d->semantic(d->scope); accessCheck(e->loc, sc, e, d); VarExp *ve = new VarExp(e->loc, d, 1); if (d->isVarDeclaration() && d->needThis()) @@ -9132,17 +8601,6 @@ Type *TypeTuple::makeConst() } #endif -void TypeTuple::toDecoBuffer(OutBuffer *buf, int flag) -{ - //printf("TypeTuple::toDecoBuffer() this = %p, %s\n", this, toChars()); - Type::toDecoBuffer(buf, flag); - OutBuffer buf2; - buf2.reserve(32); - Parameter::argsToDecoBuffer(&buf2, arguments); - int len = (int)buf2.offset; - buf->printf("%d%.*s", len, len, (char *)buf2.extractData()); -} - Expression *TypeTuple::getProperty(Loc loc, Identifier *ident, int flag) { Expression *e; @@ -9364,12 +8822,6 @@ bool TypeNull::checkBoolean() return true; } -void TypeNull::toDecoBuffer(OutBuffer *buf, int flag) -{ - //tvoidptr->toDecoBuffer(buf, flag); - Type::toDecoBuffer(buf, flag); -} - d_uns64 TypeNull::size(Loc loc) { return tvoidptr->size(loc); } Expression *TypeNull::defaultInit(Loc loc) { return new NullExp(Loc(), Type::tnull); } @@ -9390,122 +8842,25 @@ Parameter *Parameter::create(StorageClass storageClass, Type *type, Identifier * Parameter *Parameter::syntaxCopy() { - Parameter *a = new Parameter(storageClass, - type ? type->syntaxCopy() : NULL, - ident, - defaultArg ? defaultArg->syntaxCopy() : NULL); - return a; + return new Parameter(storageClass, + type ? type->syntaxCopy() : NULL, + ident, + defaultArg ? defaultArg->syntaxCopy() : NULL); } Parameters *Parameter::arraySyntaxCopy(Parameters *args) -{ Parameters *a = NULL; - +{ + Parameters *a = NULL; if (args) { a = new Parameters(); a->setDim(args->dim); for (size_t i = 0; i < a->dim; i++) - { Parameter *arg = (*args)[i]; - - arg = arg->syntaxCopy(); - (*a)[i] = arg; - } + (*a)[i] = (*args)[i]->syntaxCopy(); } return a; } -char *Parameter::argsTypesToChars(Parameters *args, int varargs) -{ - OutBuffer buf; - buf.reserve(16); - - HdrGenState hgs; - argsToCBuffer(&buf, &hgs, args, varargs); - - buf.writeByte(0); - return buf.extractData(); -} - -void Parameter::argsToCBuffer(OutBuffer *buf, HdrGenState *hgs, Parameters *arguments, int varargs) -{ - buf->writeByte('('); - if (arguments) - { - OutBuffer argbuf; - argbuf.reserve(32); - - size_t dim = Parameter::dim(arguments); - for (size_t i = 0; i < dim; i++) - { - if (i) - buf->writestring(", "); - Parameter *arg = Parameter::getNth(arguments, i); - - if (arg->storageClass & STCauto) - buf->writestring("auto "); - - if (arg->storageClass & STCout) - buf->writestring("out "); - else if (arg->storageClass & STCref) - buf->writestring("ref "); - else if (arg->storageClass & STCin) - buf->writestring("in "); - else if (arg->storageClass & STClazy) - buf->writestring("lazy "); - else if (arg->storageClass & STCalias) - buf->writestring("alias "); - - StorageClass stc = arg->storageClass; - if (arg->type && arg->type->mod & MODshared) - stc &= ~STCshared; - - StorageClassDeclaration::stcToCBuffer(buf, - stc & (STCconst | STCimmutable | STCwild | STCshared | STCscope)); - - argbuf.reset(); - if (arg->storageClass & STCalias) - { 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) - { - argbuf.writestring(" = "); - arg->defaultArg->toCBuffer(&argbuf, hgs); - } - buf->write(&argbuf); - } - if (varargs) - { - if (arguments->dim && varargs == 1) - buf->writestring(", "); - buf->writestring("..."); - } - } - buf->writeByte(')'); -} - -static int argsToDecoBufferDg(void *ctx, size_t n, Parameter *arg) -{ - arg->toDecoBuffer((OutBuffer *)ctx); - return 0; -} - -void Parameter::argsToDecoBuffer(OutBuffer *buf, Parameters *arguments) -{ - //printf("Parameter::argsToDecoBuffer()\n"); - // Write argument types - foreach(arguments, &argsToDecoBufferDg, buf); -} - /**************************************** * Determine if parameter list is really a template parameter list * (i.e. it has auto or alias parameters) @@ -9528,66 +8883,32 @@ int Parameter::isTPL(Parameters *arguments) * Determine if parameter is a lazy array of delegates. * If so, return the return type of those delegates. * If not, return NULL. + * + * Returns T if the type is one of the following forms: + * T delegate()[] + * T delegate()[dim] */ Type *Parameter::isLazyArray() { -// if (inout == Lazy) + Type *tb = type->toBasetype(); + if (tb->ty == Tsarray || tb->ty == Tarray) { - Type *tb = type->toBasetype(); - if (tb->ty == Tsarray || tb->ty == Tarray) + Type *tel = ((TypeArray *)tb)->next->toBasetype(); + if (tel->ty == Tdelegate) { - Type *tel = ((TypeArray *)tb)->next->toBasetype(); - if (tel->ty == Tdelegate) - { - TypeDelegate *td = (TypeDelegate *)tel; - TypeFunction *tf = (TypeFunction *)td->next; + TypeDelegate *td = (TypeDelegate *)tel; + TypeFunction *tf = (TypeFunction *)td->next; - if (!tf->varargs && Parameter::dim(tf->parameters) == 0) - { - return tf->next; // return type of delegate - } + if (!tf->varargs && Parameter::dim(tf->parameters) == 0) + { + return tf->next; // return type of delegate } } } return NULL; } -void Parameter::toDecoBuffer(OutBuffer *buf) -{ - if (storageClass & STCscope) - buf->writeByte('M'); - switch (storageClass & (STCin | STCout | STCref | STClazy)) - { case 0: - case STCin: - break; - case STCout: - buf->writeByte('J'); - break; - case STCref: - buf->writeByte('K'); - break; - case STClazy: - buf->writeByte('L'); - break; - default: -#ifdef DEBUG - printf("storageClass = x%llx\n", storageClass & (STCin | STCout | STCref | STClazy)); - halt(); -#endif - assert(0); - } -#if 0 - int mod = 0x100; - if (type->toBasetype()->ty == Tclass) - mod = 0; - type->toDecoBuffer(buf, mod); -#else - //type->toHeadMutable()->toDecoBuffer(buf, 0); - type->toDecoBuffer(buf, 0); -#endif -} - /*************************************** * Determine number of arguments, folding in tuples. */ diff --git a/dmd2/mtype.h b/dmd2/mtype.h index e0350b2aa6..c7492572ea 100644 --- a/dmd2/mtype.h +++ b/dmd2/mtype.h @@ -28,18 +28,14 @@ class Identifier; class Expression; class StructDeclaration; class ClassDeclaration; -class VarDeclaration; class EnumDeclaration; -class TypedefDeclaration; class TypeInfoDeclaration; class Dsymbol; class TemplateInstance; -struct CppMangleState; class TemplateDeclaration; enum LINK; class TypeBasic; -struct HdrGenState; class Parameter; // Back end @@ -55,8 +51,6 @@ typedef struct TYPE type; struct Symbol; #endif -class TypeTuple; - void semanticTypeInfo(Scope *sc, Type *t); MATCH deduceType(RootObject *o, Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wm = NULL, size_t inferStart = 0); Type *reliesOnTident(Type *t, TemplateParameters *tparams = NULL, size_t iStart = 0); @@ -75,7 +69,6 @@ enum ENUMTY Tstruct, Tenum, - Ttypedef, Tdelegate, Tnone, Tvoid, @@ -85,8 +78,8 @@ enum ENUMTY Tuns16, Tint32, Tuns32, - Tint64, + Tuns64, Tfloat32, Tfloat64, @@ -96,8 +89,8 @@ enum ENUMTY Timaginary80, Tcomplex32, Tcomplex64, - Tcomplex80, + Tbool, Tchar, Twchar, @@ -107,8 +100,8 @@ enum ENUMTY Ttypeof, Ttuple, Tslice, - Treturn, + Tnull, Tvector, Tint128, @@ -212,7 +205,6 @@ public: static ClassDeclaration *typeinfoclass; static ClassDeclaration *typeinfointerface; static ClassDeclaration *typeinfostruct; - static ClassDeclaration *typeinfotypedef; static ClassDeclaration *typeinfopointer; static ClassDeclaration *typeinfoarray; static ClassDeclaration *typeinfostaticarray; @@ -230,8 +222,7 @@ public: static TemplateDeclaration *rtinfo; static Type *basic[TMAX]; - static unsigned char mangleChar[TMAX]; - static unsigned short sizeTy[TMAX]; + static unsigned char sizeTy[TMAX]; static StringTable stringtable; // These tables are for implicit conversion of binary ops; @@ -248,6 +239,7 @@ public: Type *copy(); virtual Type *syntaxCopy(); bool equals(RootObject *o); + bool equivalent(Type *t); // kludge for template.isType() int dyncast() { return DYNCAST_TYPE; } int covariant(Type *t, StorageClass *pstc = NULL); @@ -262,10 +254,8 @@ public: virtual unsigned alignsize(); virtual Type *semantic(Loc loc, Scope *sc); Type *trySemantic(Loc loc, Scope *sc); - virtual void toDecoBuffer(OutBuffer *buf, int flag = 0); Type *merge(); Type *merge2(); - void toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs); void modToBuffer(OutBuffer *buf); char *modToChars(); @@ -389,7 +379,6 @@ public: Type *next; TypeNext(TY ty, Type *next); - void toDecoBuffer(OutBuffer *buf, int flag); void checkDeprecated(Loc loc, Scope *sc); int hasWild(); Type *nextOf(); @@ -456,7 +445,6 @@ public: Expression *getProperty(Loc loc, Identifier *ident, int flag); Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag); char *toChars(); - void toDecoBuffer(OutBuffer *buf, int flag); bool isintegral(); bool isfloating(); bool isscalar(); @@ -492,7 +480,6 @@ public: unsigned alignsize(); Type *semantic(Loc loc, Scope *sc); void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false); - void toDecoBuffer(OutBuffer *buf, int flag); Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag); bool isString(); bool isZeroInit(Loc loc); @@ -521,7 +508,6 @@ public: unsigned alignsize(); Type *semantic(Loc loc, Scope *sc); void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false); - void toDecoBuffer(OutBuffer *buf, int flag); Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag); bool isString(); bool isZeroInit(Loc loc); @@ -549,7 +535,6 @@ public: d_uns64 size(Loc loc); Type *semantic(Loc loc, Scope *sc); void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false); - void toDecoBuffer(OutBuffer *buf, int flag); Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag); Expression *defaultInit(Loc loc); bool isZeroInit(Loc loc); @@ -661,7 +646,6 @@ public: Type *syntaxCopy(); Type *semantic(Loc loc, Scope *sc); void purityLevel(); - void toDecoBuffer(OutBuffer *buf, int flag); TypeInfoDeclaration *getTypeInfoDeclaration(); bool hasLazyParameters(); bool parameterEscapes(Parameter *p); @@ -728,7 +712,6 @@ public: const char *kind(); Type *syntaxCopy(); //char *toChars(); - void toDecoBuffer(OutBuffer *buf, int flag); void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false); Dsymbol *toDsymbol(Scope *sc); Type *semantic(Loc loc, Scope *sc); @@ -747,7 +730,6 @@ public: const char *kind(); Type *syntaxCopy(); //char *toChars(); - //void toDecoBuffer(OutBuffer *buf, int flag); void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false); Type *semantic(Loc loc, Scope *sc); Dsymbol *toDsymbol(Scope *sc); @@ -809,7 +791,6 @@ public: Type *syntaxCopy(); Type *semantic(Loc loc, Scope *sc); Dsymbol *toDsymbol(Scope *sc); - void toDecoBuffer(OutBuffer *buf, int flag); Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag); structalign_t alignment(); Expression *defaultInit(Loc loc); @@ -849,7 +830,6 @@ public: char *toChars(); Type *semantic(Loc loc, Scope *sc); Dsymbol *toDsymbol(Scope *sc); - void toDecoBuffer(OutBuffer *buf, int flag); Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag); Expression *getProperty(Loc loc, Identifier *ident, int flag); bool isintegral(); @@ -876,48 +856,6 @@ public: void accept(Visitor *v) { v->visit(this); } }; -class TypeTypedef : public Type -{ -public: - TypedefDeclaration *sym; - - TypeTypedef(TypedefDeclaration *sym); - const char *kind(); - Type *syntaxCopy(); - d_uns64 size(Loc loc); - unsigned alignsize(); - char *toChars(); - Type *semantic(Loc loc, Scope *sc); - Dsymbol *toDsymbol(Scope *sc); - void toDecoBuffer(OutBuffer *buf, int flag); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag); - structalign_t alignment(); - Expression *getProperty(Loc loc, Identifier *ident, int flag); - bool isintegral(); - bool isfloating(); - bool isreal(); - bool isimaginary(); - bool iscomplex(); - bool isscalar(); - bool isunsigned(); - bool checkBoolean(); - bool isAssignable(); - bool needsDestruction(); - bool needsNested(); - Type *toBasetype(); - MATCH implicitConvTo(Type *to); - MATCH constConv(Type *to); - Type *toHeadMutable(); - Expression *defaultInit(Loc loc); - Expression *defaultInitLiteral(Loc loc); - bool isZeroInit(Loc loc); - TypeInfoDeclaration *getTypeInfoDeclaration(); - int hasPointers(); - int hasWild(); - - void accept(Visitor *v) { v->visit(this); } -}; - class TypeClass : public Type { public: @@ -931,7 +869,6 @@ public: Type *syntaxCopy(); Type *semantic(Loc loc, Scope *sc); Dsymbol *toDsymbol(Scope *sc); - void toDecoBuffer(OutBuffer *buf, int flag); Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag); ClassDeclaration *isClassHandle(); int isBaseOf(Type *t, int *poffset); @@ -965,7 +902,6 @@ public: Type *syntaxCopy(); Type *semantic(Loc loc, Scope *sc); bool equals(RootObject *o); - void toDecoBuffer(OutBuffer *buf, int flag); Expression *getProperty(Loc loc, Identifier *ident, int flag); Expression *defaultInit(Loc loc); TypeInfoDeclaration *getTypeInfoDeclaration(); @@ -993,7 +929,6 @@ public: const char *kind(); Type *syntaxCopy(); - void toDecoBuffer(OutBuffer *buf, int flag); MATCH implicitConvTo(Type *to); bool checkBoolean(); @@ -1019,13 +954,11 @@ public: static Parameter *create(StorageClass storageClass, Type *type, Identifier *ident, Expression *defaultArg); Parameter *syntaxCopy(); Type *isLazyArray(); - void toDecoBuffer(OutBuffer *buf); // kludge for template.isType() int dyncast() { return DYNCAST_PARAMETER; } + virtual void accept(Visitor *v) { v->visit(this); } + static Parameters *arraySyntaxCopy(Parameters *args); - static char *argsTypesToChars(Parameters *args, int varargs); - static void argsToCBuffer(OutBuffer *buf, HdrGenState *hgs, Parameters *arguments, int varargs); - static void argsToDecoBuffer(OutBuffer *buf, Parameters *arguments); static int isTPL(Parameters *arguments); static size_t dim(Parameters *arguments); static Parameter *getNth(Parameters *arguments, size_t nth, size_t *pn = NULL); @@ -1041,6 +974,5 @@ char *MODtoChars(MOD mod); bool MODimplicitConv(MOD modfrom, MOD modto); bool MODmethodConv(MOD modfrom, MOD modto); MOD MODmerge(MOD mod1, MOD mod2); -void identifierToDocBuffer(Identifier* ident, OutBuffer *buf, HdrGenState *hgs); #endif /* DMD_MTYPE_H */ diff --git a/dmd2/nspace.c b/dmd2/nspace.c index 5b5e334085..cbc72f43fc 100644 --- a/dmd2/nspace.c +++ b/dmd2/nspace.c @@ -14,7 +14,6 @@ #include "dsymbol.h" #include "nspace.h" #include "identifier.h" -#include "hdrgen.h" #include "scope.h" /* This implements namespaces. @@ -31,8 +30,7 @@ Nspace::Nspace(Loc loc, Identifier *ident, Dsymbols *members) Dsymbol *Nspace::syntaxCopy(Dsymbol *s) { Nspace *ns = new Nspace(loc, ident, NULL); - ScopeDsymbol::syntaxCopy(ns); - return ns; + return ScopeDsymbol::syntaxCopy(ns); } void Nspace::semantic(Scope *sc) @@ -60,7 +58,7 @@ void Nspace::semantic(Scope *sc) ScopeDsymbol *sds = (ScopeDsymbol *)sce->scopesym; if (sds) { - sds->importScope(this, PROTpublic); + sds->importScope(this, Prot(PROTpublic)); break; } } @@ -214,23 +212,3 @@ void Nspace::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool is } } } - - -void Nspace::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("extern (C++, "); - buf->writestring(ident->string); - buf->writeByte(')'); - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - buf->level++; - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = (*members)[i]; - s->toCBuffer(buf, hgs); - } - buf->level--; - buf->writeByte('}'); - buf->writenl(); -} diff --git a/dmd2/nspace.h b/dmd2/nspace.h index 7e5cdccdab..ec3e6577e0 100644 --- a/dmd2/nspace.h +++ b/dmd2/nspace.h @@ -31,9 +31,9 @@ class Nspace : public ScopeDsymbol bool hasPointers(); void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion); const char *kind(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); void toObjFile(bool multiobj); Nspace *isNspace() { return this; } + void accept(Visitor *v) { v->visit(this); } }; #endif /* DMD_NSPACE_H */ diff --git a/dmd2/opover.c b/dmd2/opover.c index bee9f089c0..8d9f455236 100644 --- a/dmd2/opover.c +++ b/dmd2/opover.c @@ -921,7 +921,15 @@ Expression *op_overload(Expression *e, Scope *sc) } } - result = compare_overload(e, sc, Id::eq); + // Comparing a class with typeof(null) should not call opEquals + if (t1->ty == Tclass && t2->ty == Tnull || + t1->ty == Tnull && t2->ty == Tclass) + { + } + else + { + result = compare_overload(e, sc, Id::eq); + } } void visit(CmpExp *e) diff --git a/dmd2/optimize.c b/dmd2/optimize.c index ba7918f272..c9c84a50a8 100644 --- a/dmd2/optimize.c +++ b/dmd2/optimize.c @@ -260,7 +260,7 @@ Expression *Expression_optimize(Expression *e, int result, bool keepLvalue) e->e1 = e->e1->optimize(result); if (e->e1->isConst() == 1) { - ret = Neg(e->type, e->e1); + ret = Neg(e->type, e->e1).copy(); } } @@ -322,7 +322,7 @@ Expression *Expression_optimize(Expression *e, int result, bool keepLvalue) Expression *ex = ((PtrExp *)e->e1)->e1; if (e->type->equals(ex->type)) ret = ex; - else if (e->type->toBasetype()->immutableOf()->equals(ex->type->toBasetype()->immutableOf())) + else if (e->type->toBasetype()->equivalent(ex->type->toBasetype())) { ret = ex->copy(); ret->type = e->type; @@ -379,7 +379,7 @@ Expression *Expression_optimize(Expression *e, int result, bool keepLvalue) Expression *ex = ((AddrExp *)e->e1)->e1; if (e->type->equals(ex->type)) ret = ex; - else if (e->type->toBasetype()->immutableOf()->equals(ex->type->toBasetype()->immutableOf())) + else if (e->type->toBasetype()->equivalent(ex->type->toBasetype())) { ret = ex->copy(); ret->type = e->type; diff --git a/dmd2/parse.c b/dmd2/parse.c index cdfeb8c842..21907dd144 100644 --- a/dmd2/parse.c +++ b/dmd2/parse.c @@ -36,6 +36,7 @@ #include "version.h" #include "aliasthis.h" #include "nspace.h" +#include "hdrgen.h" // How multiple declarations are parsed. // If 1, treat as C. @@ -97,32 +98,78 @@ Parser::Parser(Loc loc, Module *module, const utf8_t *base, size_t length, int d Dsymbols *Parser::parseModule() { - Dsymbols *decldefs; + const utf8_t *comment = token.blockComment; bool isdeprecated = false; Expression *msg = NULL; + Expressions *udas = NULL; + Dsymbols *decldefs; - if (token.value == TOKdeprecated) + Token *tk; + if (skipAttributes(&token, &tk) && tk->value == TOKmodule) { - Token *tk; - if (skipParensIf(peek(&token), &tk) && tk->value == TOKmodule) + while (token.value != TOKmodule) { - // deprecated (...) module ... - isdeprecated = true; - nextToken(); - if (token.value == TOKlparen) + switch (token.value) { - check(TOKlparen); - msg = parseAssignExp(); - check(TOKrparen); + case TOKdeprecated: + { + // deprecated (...) module ... + if (isdeprecated) + { + error("there is only one deprecation attribute allowed for module declaration"); + } + else + { + isdeprecated = true; + } + nextToken(); + if (token.value == TOKlparen) + { + check(TOKlparen); + msg = parseAssignExp(); + check(TOKrparen); + } + break; + } + case TOKat: + { + Expressions *exps = NULL; + StorageClass stc = parseAttribute(&exps); + + if (stc == STCproperty || stc == STCnogc || stc == STCdisable || + stc == STCsafe || stc == STCtrusted || stc == STCsystem) + { + error("@%s attribute for module declaration is not supported", token.toChars()); + } + else + { + udas = UserAttributeDeclaration::concat(udas, exps); + } + if (stc) + nextToken(); + break; + } + default: + { + error("'module' expected instead of %s", token.toChars()); + nextToken(); + break; + } } } } + if (udas) + { + Dsymbols *a = new Dsymbols(); + UserAttributeDeclaration *udad = new UserAttributeDeclaration(udas, a); + mod->userAttribDecl = udad; + } + // ModuleDeclation leads off if (token.value == TOKmodule) { Loc loc = token.loc; - const utf8_t *comment = token.blockComment; bool safe = false; nextToken(); @@ -202,7 +249,7 @@ struct PrefixAttributes StorageClass storageClass; Expression *depmsg; LINK link; - PROT protection; + Prot protection; unsigned alignment; Expressions *udas; const utf8_t *comment; @@ -241,7 +288,7 @@ Dsymbols *Parser::parseDeclDefs(int once, Dsymbol **pLastDecl, PrefixAttributes pAttrs = &attrs; pAttrs->comment = token.blockComment; } - PROT prot; + PROTKIND prot; StorageClass stc; Condition *condition; @@ -341,11 +388,11 @@ Dsymbols *Parser::parseDeclDefs(int once, Dsymbol **pLastDecl, PrefixAttributes if (peekNext() == TOKdot) goto Ldeclaration; else - s = parseCtor(); + s = parseCtor(pAttrs); break; case TOKtilde: - s = parseDtor(); + s = parseDtor(pAttrs); break; case TOKinvariant: @@ -356,7 +403,7 @@ Dsymbols *Parser::parseDeclDefs(int once, Dsymbol **pLastDecl, PrefixAttributes { // invariant {} // invariant() {} - s = parseInvariant(); + s = parseInvariant(pAttrs); } else { @@ -367,17 +414,17 @@ Dsymbols *Parser::parseDeclDefs(int once, Dsymbol **pLastDecl, PrefixAttributes } case TOKunittest: - s = parseUnitTest(); + s = parseUnitTest(pAttrs); if (*pLastDecl) (*pLastDecl)->ddocUnittest = (UnitTestDeclaration *)s; break; case TOKnew: - s = parseNew(); + s = parseNew(pAttrs); break; case TOKdelete: - s = parseDelete(); + s = parseDelete(pAttrs); break; case TOKcolon: @@ -395,9 +442,9 @@ Dsymbols *Parser::parseDeclDefs(int once, Dsymbol **pLastDecl, PrefixAttributes { TOK next = peekNext(); if (next == TOKthis) - s = parseStaticCtor(); + s = parseStaticCtor(pAttrs); else if (next == TOKtilde) - s = parseStaticDtor(); + s = parseStaticDtor(pAttrs); else if (next == TOKassert) s = parseStaticAssert(); else if (next == TOKif) @@ -458,12 +505,12 @@ Dsymbols *Parser::parseDeclDefs(int once, Dsymbol **pLastDecl, PrefixAttributes TOK next2 = peekNext2(); if (next2 == TOKthis) { - s = parseSharedStaticCtor(); + s = parseSharedStaticCtor(pAttrs); break; } if (next2 == TOKtilde) { - s = parseSharedStaticDtor(); + s = parseSharedStaticDtor(pAttrs); break; } } @@ -499,15 +546,7 @@ Dsymbols *Parser::parseDeclDefs(int once, Dsymbol **pLastDecl, PrefixAttributes goto Lautodecl; } Lstc: - if (pAttrs->storageClass & stc) - { - if (token.value == TOKidentifier) - error("redundant storage class '@%s'", token.ident->toChars()); - else - error("redundant storage class '%s'", Token::toChars(token.value)); - } - composeStorageClass(pAttrs->storageClass | stc); - pAttrs->storageClass |= stc; + pAttrs->storageClass = appendStorageClass(pAttrs->storageClass, stc); nextToken(); Lautodecl: @@ -599,7 +638,9 @@ Dsymbols *Parser::parseDeclDefs(int once, Dsymbol **pLastDecl, PrefixAttributes case TOKlbracket: { - warning(token.loc, "use @(attributes) instead of [attributes]"); + if (peekNext() == TOKrbracket) + error("empty attribute list is not allowed"); + deprecation("use @(attributes) instead of [attributes]"); Expressions *exps = parseArguments(); // no redundant/conflicting check for UDAs @@ -672,23 +713,50 @@ Dsymbols *Parser::parseDeclDefs(int once, Dsymbol **pLastDecl, PrefixAttributes case TOKpublic: prot = PROTpublic; goto Lprot; case TOKexport: prot = PROTexport; goto Lprot; Lprot: - nextToken(); - if (pAttrs->protection != PROTundefined) + { + if (pAttrs->protection.kind != PROTundefined) { - if (pAttrs->protection != prot) + if (pAttrs->protection.kind != prot) error("conflicting protection attribute '%s' and '%s'", - protectionToChars(pAttrs->protection), protectionToChars(prot)); + protectionToChars(pAttrs->protection.kind), protectionToChars(prot)); else error("redundant protection attribute '%s'", protectionToChars(prot)); } - pAttrs->protection = prot; - a = parseBlock(pLastDecl, pAttrs); - if (pAttrs->protection != PROTundefined) + pAttrs->protection.kind = prot; + + nextToken(); + + // optional qualified package identifier to bind + // protection to + Identifiers *pkg_prot_idents = NULL; + if (pAttrs->protection.kind == PROTpackage && token.value == TOKlparen) { - s = new ProtDeclaration(pAttrs->protection, a); - pAttrs->protection = PROTundefined; + pkg_prot_idents = parseQualifiedIdentifier("protection package"); + + if (pkg_prot_idents) + check(TOKrparen); + else + { + while (token.value != TOKsemicolon && token.value != TOKeof) + nextToken(); + nextToken(); + break; + } + } + + Loc attrloc = token.loc; + a = parseBlock(pLastDecl, pAttrs); + if (pAttrs->protection.kind != PROTundefined) + { + if (pAttrs->protection.kind == PROTpackage && pkg_prot_idents) + s = new ProtDeclaration(attrloc, pkg_prot_idents, a); + else + s = new ProtDeclaration(attrloc, pAttrs->protection, a); + + pAttrs->protection = Prot(PROTundefined); } break; + } case TOKalign: { @@ -880,23 +948,45 @@ Dsymbols *Parser::parseDeclDefs(int once, Dsymbol **pLastDecl, PrefixAttributes } /********************************************* - * Give error on conflicting storage classes. + * Give error on redundant/conflicting storage class. */ -void Parser::composeStorageClass(StorageClass stc) +StorageClass Parser::appendStorageClass(StorageClass storageClass, StorageClass stc) { - StorageClass u = stc; - u &= STCconst | STCimmutable | STCmanifest; - if (u & (u - 1)) - error("conflicting storage class %s", Token::toChars(token.value)); - u = stc; - u &= STCgshared | STCshared | STCtls; - if (u & (u - 1)) - error("conflicting storage class %s", Token::toChars(token.value)); - u = stc; - u &= STCsafe | STCsystem | STCtrusted; - if (u & (u - 1)) - error("conflicting attribute @%s", token.toChars()); + if ((storageClass & stc) || + (storageClass & STCin && stc & (STCconst | STCscope)) || + (stc & STCin && storageClass & (STCconst | STCscope))) + { + OutBuffer buf; + StorageClassDeclaration::stcToCBuffer(&buf, stc); + if (buf.data[buf.offset - 1] == ' ') + buf.data[buf.offset - 1] = '\0'; + error("redundant attribute '%s'", buf.peekString()); + return storageClass | stc; + } + + storageClass |= stc; + + if (stc & (STCconst | STCimmutable | STCmanifest)) + { + StorageClass u = storageClass & (STCconst | STCimmutable | STCmanifest); + if (u & (u - 1)) + error("conflicting attribute '%s'", Token::toChars(token.value)); + } + if (stc & (STCgshared | STCshared | STCtls)) + { + StorageClass u = storageClass & (STCgshared | STCshared | STCtls); + if (u & (u - 1)) + error("conflicting attribute '%s'", Token::toChars(token.value)); + } + if (stc & (STCsafe | STCsystem | STCtrusted)) + { + StorageClass u = storageClass & (STCsafe | STCsystem | STCtrusted); + if (u & (u - 1)) + error("conflicting attribute '@%s'", token.toChars()); + } + + return storageClass; } /*********************************************** @@ -947,6 +1037,8 @@ StorageClass Parser::parseAttribute(Expressions **pudas) { // @( ArgumentList ) // Concatenate with existing + if (peekNext() == TOKrparen) + error("empty attribute list is not allowed"); udas = parseArguments(); } else @@ -970,24 +1062,23 @@ StorageClass Parser::parseAttribute(Expressions **pudas) * Parse const/immutable/shared/inout/nothrow/pure postfix */ -StorageClass Parser::parsePostfix(Expressions **pudas) +StorageClass Parser::parsePostfix(StorageClass storageClass, Expressions **pudas) { - StorageClass stc = STCundefined; - while (1) { + StorageClass stc; switch (token.value) { - case TOKconst: stc |= STCconst; break; - case TOKimmutable: stc |= STCimmutable; break; - case TOKshared: stc |= STCshared; break; - case TOKwild: stc |= STCwild; break; - case TOKnothrow: stc |= STCnothrow; break; - case TOKpure: stc |= STCpure; break; + case TOKconst: stc = STCconst; break; + case TOKimmutable: stc = STCimmutable; break; + case TOKshared: stc = STCshared; break; + case TOKwild: stc = STCwild; break; + case TOKnothrow: stc = STCnothrow; break; + case TOKpure: stc = STCpure; break; case TOKat: { Expressions *udas = NULL; - stc |= parseAttribute(&udas); + stc = parseAttribute(&udas); if (udas) { if (pudas) @@ -1004,31 +1095,35 @@ StorageClass Parser::parsePostfix(Expressions **pudas) break; } - default: return stc; + default: + return storageClass; } - composeStorageClass(stc); + storageClass = appendStorageClass(storageClass, stc); nextToken(); } } StorageClass Parser::parseTypeCtor() { - StorageClass stc = 0; + StorageClass storageClass = STCundefined; while (1) { if (peek(&token)->value == TOKlparen) - return stc; + return storageClass; + + StorageClass stc; switch (token.value) { - case TOKconst: stc |= STCconst; break; - case TOKimmutable: stc |= STCimmutable; break; - case TOKshared: stc |= STCshared; break; - case TOKwild: stc |= STCwild; break; + case TOKconst: stc = STCconst; break; + case TOKimmutable: stc = STCimmutable; break; + case TOKshared: stc = STCshared; break; + case TOKwild: stc = STCwild; break; - default: return stc; + default: + return storageClass; } - composeStorageClass(stc); + storageClass = appendStorageClass(storageClass, stc); nextToken(); } } @@ -1223,6 +1318,41 @@ LINK Parser::parseLinkage(Identifiers **pidents) return link; } +/*********************************** + * Parse ident1.ident2.ident3 + * + * Params: + * entity = what qualified identifier is expected to resolve into. + * Used only for better error message + * + * Returns: + * array of identifiers with actual qualified one stored last + */ +Identifiers *Parser::parseQualifiedIdentifier(const char *entity) +{ + Identifiers *qualified = NULL; + + do + { + nextToken(); + if (token.value != TOKidentifier) + { + error("%s expected as dot-separated identifiers, got '%s'", + entity, token.toChars()); + return NULL; + } + + Identifier *id = token.ident; + if (!qualified) + qualified = new Identifiers(); + qualified->push(id); + + nextToken(); + } while (token.value == TOKdot); + + return qualified; +} + /************************************** * Parse a debug conditional */ @@ -1334,10 +1464,11 @@ Condition *Parser::parseStaticIfCondition() * Current token is 'this'. */ -Dsymbol *Parser::parseCtor() +Dsymbol *Parser::parseCtor(PrefixAttributes *pAttrs) { Expressions *udas = NULL; Loc loc = token.loc; + StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined; nextToken(); if (token.value == TOKlparen && peekNext() == TOKthis && peekNext2() == TOKrparen) @@ -1347,8 +1478,13 @@ Dsymbol *Parser::parseCtor() nextToken(); check(TOKrparen); - StorageClass stc = parsePostfix(&udas); + stc = parsePostfix(stc, &udas); + if (stc & STCstatic) + error(loc, "postblit cannot be static"); + PostBlitDeclaration *f = new PostBlitDeclaration(loc, Loc(), stc, Id::_postblit); + if (pAttrs) + pAttrs->storageClass = STCundefined; Dsymbol *s = parseContracts(f); if (udas) { @@ -1367,42 +1503,34 @@ Dsymbol *Parser::parseCtor() if (token.value == TOKlparen && peekPastParen(&token)->value == TOKlparen) { tpl = parseTemplateParameterList(); - - int varargs; - Parameters *parameters = parseParameters(&varargs); - StorageClass stc = parsePostfix(&udas); - - Expression *constraint = tpl ? parseConstraint() : NULL; - - Type *tf = new TypeFunction(parameters, NULL, varargs, linkage, stc); // RetrunType -> auto - tf = tf->addSTC(stc); - - CtorDeclaration *f = new CtorDeclaration(loc, Loc(), stc, tf); - Dsymbol *s = parseContracts(f); - if (udas) - { - Dsymbols *a = new Dsymbols(); - a->push(f); - s = new UserAttributeDeclaration(udas, a); - } - - // Wrap a template around it - Dsymbols *decldefs = new Dsymbols(); - decldefs->push(s); - TemplateDeclaration *tempdecl = - new TemplateDeclaration(loc, f->ident, tpl, constraint, decldefs); - return tempdecl; } /* Just a regular constructor */ int varargs; Parameters *parameters = parseParameters(&varargs); - StorageClass stc = parsePostfix(&udas); + stc = parsePostfix(stc, &udas); + if (varargs != 0 || Parameter::dim(parameters) != 0) + { + if (stc & STCstatic) + error(loc, "constructor cannot be static"); + } + else if (StorageClass ss = stc & (STCshared | STCstatic)) // this() + { + if (ss == STCstatic) + error(loc, "use 'static this()' to declare a static constructor"); + else if (ss == (STCshared | STCstatic)) + error(loc, "use 'shared static this()' to declare a shared static constructor"); + } + + Expression *constraint = tpl ? parseConstraint() : NULL; + Type *tf = new TypeFunction(parameters, NULL, varargs, linkage, stc); // RetrunType -> auto tf = tf->addSTC(stc); CtorDeclaration *f = new CtorDeclaration(loc, Loc(), stc, tf); + if (pAttrs) + pAttrs->storageClass = STCundefined; Dsymbol *s = parseContracts(f); if (udas) { @@ -1410,6 +1538,15 @@ Dsymbol *Parser::parseCtor() a->push(f); s = new UserAttributeDeclaration(udas, a); } + + if (tpl) + { + // Wrap a template around it + Dsymbols *decldefs = new Dsymbols(); + decldefs->push(s); + s = new TemplateDeclaration(loc, f->ident, tpl, constraint, decldefs); + } + return s; } @@ -1419,18 +1556,29 @@ Dsymbol *Parser::parseCtor() * Current token is '~'. */ -Dsymbol *Parser::parseDtor() +Dsymbol *Parser::parseDtor(PrefixAttributes *pAttrs) { Expressions *udas = NULL; Loc loc = token.loc; + StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined; nextToken(); check(TOKthis); check(TOKlparen); check(TOKrparen); - StorageClass stc = parsePostfix(&udas); + stc = parsePostfix(stc, &udas); + if (StorageClass ss = stc & (STCshared | STCstatic)) + { + if (ss == STCstatic) + error(loc, "use 'static ~this()' to declare a static destructor"); + else if (ss == (STCshared | STCstatic)) + error(loc, "use 'shared static ~this()' to declare a shared static destructor"); + } + DtorDeclaration *f = new DtorDeclaration(loc, Loc(), stc, Id::dtor); + if (pAttrs) + pAttrs->storageClass = STCundefined; Dsymbol *s = parseContracts(f); if (udas) { @@ -1447,41 +1595,35 @@ Dsymbol *Parser::parseDtor() * Current token is 'static'. */ -Dsymbol *Parser::parseStaticCtor() +Dsymbol *Parser::parseStaticCtor(PrefixAttributes *pAttrs) { //Expressions *udas = NULL; Loc loc = token.loc; + StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined; nextToken(); nextToken(); check(TOKlparen); check(TOKrparen); - StorageClass stc = parsePostfix(NULL); + + stc = parsePostfix(stc & ~STC_TYPECTOR, NULL) | stc; + if (stc & STCshared) + error(loc, "use 'shared static this()' to declare a shared static constructor"); + else if (stc & STCstatic) + appendStorageClass(stc, STCstatic); // complaint for the redundancy + else if (StorageClass modStc = stc & STC_TYPECTOR) + { + OutBuffer buf; + StorageClassDeclaration::stcToCBuffer(&buf, modStc); + if (buf.data[buf.offset - 1] == ' ') + buf.data[buf.offset - 1] = '\0'; + error(loc, "static constructor cannot be %s", buf.peekString()); + } + stc &= ~(STCstatic | STC_TYPECTOR); StaticCtorDeclaration *f = new StaticCtorDeclaration(loc, Loc(), stc); - Dsymbol *s = parseContracts(f); - return s; -} - -/***************************************** - * Parse a shared static constructor definition: - * shared static this() { body } - * Current token is 'shared'. - */ - -Dsymbol *Parser::parseSharedStaticCtor() -{ - //Expressions *udas = NULL; - Loc loc = token.loc; - - nextToken(); - nextToken(); - nextToken(); - check(TOKlparen); - check(TOKrparen); - StorageClass stc = parsePostfix(NULL); - - SharedStaticCtorDeclaration *f = new SharedStaticCtorDeclaration(loc, Loc(), stc); + if (pAttrs) + pAttrs->storageClass = STCundefined; Dsymbol *s = parseContracts(f); return s; } @@ -1492,10 +1634,11 @@ Dsymbol *Parser::parseSharedStaticCtor() * Current token is 'static'. */ -Dsymbol *Parser::parseStaticDtor() +Dsymbol *Parser::parseStaticDtor(PrefixAttributes *pAttrs) { Expressions *udas = NULL; Loc loc = token.loc; + StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined; nextToken(); nextToken(); @@ -1503,11 +1646,24 @@ Dsymbol *Parser::parseStaticDtor() check(TOKlparen); check(TOKrparen); - StorageClass stc = parsePostfix(&udas); + stc = parsePostfix(stc & ~STC_TYPECTOR, &udas) | stc; if (stc & STCshared) - error("to create a 'shared' static destructor, move 'shared' in front of the declaration"); + error(loc, "use 'shared static ~this()' to declare a shared static destructor"); + else if (stc & STCstatic) + appendStorageClass(stc, STCstatic); // complaint for the redundancy + else if (StorageClass modStc = stc & STC_TYPECTOR) + { + OutBuffer buf; + StorageClassDeclaration::stcToCBuffer(&buf, modStc); + if (buf.data[buf.offset - 1] == ' ') + buf.data[buf.offset - 1] = '\0'; + error(loc, "static destructor cannot be %s", buf.peekString()); + } + stc &= ~(STCstatic | STC_TYPECTOR); StaticDtorDeclaration *f = new StaticDtorDeclaration(loc, Loc(), stc); + if (pAttrs) + pAttrs->storageClass = STCundefined; Dsymbol *s = parseContracts(f); if (udas) { @@ -1518,16 +1674,55 @@ Dsymbol *Parser::parseStaticDtor() return s; } +/***************************************** + * Parse a shared static constructor definition: + * shared static this() { body } + * Current token is 'shared'. + */ + +Dsymbol *Parser::parseSharedStaticCtor(PrefixAttributes *pAttrs) +{ + //Expressions *udas = NULL; + Loc loc = token.loc; + StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined; + + nextToken(); + nextToken(); + nextToken(); + check(TOKlparen); + check(TOKrparen); + + stc = parsePostfix(stc & ~STC_TYPECTOR, NULL) | stc; + if (StorageClass ss = stc & (STCshared | STCstatic)) + appendStorageClass(stc, ss); // complaint for the redundancy + else if (StorageClass modStc = stc & STC_TYPECTOR) + { + OutBuffer buf; + StorageClassDeclaration::stcToCBuffer(&buf, modStc); + if (buf.data[buf.offset - 1] == ' ') + buf.data[buf.offset - 1] = '\0'; + error(loc, "shared static constructor cannot be %s", buf.peekString()); + } + stc &= ~(STCstatic | STC_TYPECTOR); + + SharedStaticCtorDeclaration *f = new SharedStaticCtorDeclaration(loc, Loc(), stc); + if (pAttrs) + pAttrs->storageClass = STCundefined; + Dsymbol *s = parseContracts(f); + return s; +} + /***************************************** * Parse a shared static destructor definition: * shared static ~this() { body } * Current token is 'shared'. */ -Dsymbol *Parser::parseSharedStaticDtor() +Dsymbol *Parser::parseSharedStaticDtor(PrefixAttributes *pAttrs) { Expressions *udas = NULL; Loc loc = token.loc; + StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined; nextToken(); nextToken(); @@ -1536,11 +1731,22 @@ Dsymbol *Parser::parseSharedStaticDtor() check(TOKlparen); check(TOKrparen); - StorageClass stc = parsePostfix(&udas); - if (stc & STCshared) - error("static destructor is 'shared' already"); + stc = parsePostfix(stc & ~STC_TYPECTOR, &udas) | stc; + if (StorageClass ss = stc & (STCshared | STCstatic)) + appendStorageClass(stc, ss); // complaint for the redundancy + else if (StorageClass modStc = stc & STC_TYPECTOR) + { + OutBuffer buf; + StorageClassDeclaration::stcToCBuffer(&buf, modStc); + if (buf.data[buf.offset - 1] == ' ') + buf.data[buf.offset - 1] = '\0'; + error(loc, "shared static destructor cannot be %s", buf.peekString()); + } + stc &= ~(STCstatic | STC_TYPECTOR); SharedStaticDtorDeclaration *f = new SharedStaticDtorDeclaration(loc, Loc(), stc); + if (pAttrs) + pAttrs->storageClass = STCundefined; Dsymbol *s = parseContracts(f); if (udas) { @@ -1557,10 +1763,10 @@ Dsymbol *Parser::parseSharedStaticDtor() * Current token is 'invariant'. */ -InvariantDeclaration *Parser::parseInvariant() +Dsymbol *Parser::parseInvariant(PrefixAttributes *pAttrs) { - InvariantDeclaration *f; Loc loc = token.loc; + StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined; nextToken(); if (token.value == TOKlparen) // optional () @@ -1569,7 +1775,9 @@ InvariantDeclaration *Parser::parseInvariant() check(TOKrparen); } - f = new InvariantDeclaration(loc, Loc(), STCundefined); + InvariantDeclaration *f = new InvariantDeclaration(loc, Loc(), stc); + if (pAttrs) + pAttrs->storageClass = STCundefined; f->fbody = parseStatement(PScurly); return f; } @@ -1580,16 +1788,16 @@ InvariantDeclaration *Parser::parseInvariant() * Current token is 'unittest'. */ -UnitTestDeclaration *Parser::parseUnitTest() +Dsymbol *Parser::parseUnitTest(PrefixAttributes *pAttrs) { - UnitTestDeclaration *f; - Statement *body; Loc loc = token.loc; + StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined; nextToken(); + const utf8_t *begPtr = token.ptr + 1; // skip '{' const utf8_t *endPtr = NULL; - body = parseStatement(PScurly, &endPtr); + Statement *sbody = parseStatement(PScurly, &endPtr); /** Extract unittest body as a string. Must be done eagerly since memory will be released by the lexer before doc gen. */ @@ -1598,7 +1806,7 @@ UnitTestDeclaration *Parser::parseUnitTest() { /* Remove trailing whitespaces */ for (const utf8_t *p = endPtr - 1; - begPtr <= p && (*p == ' ' || *p == '\n' || *p == '\t'); --p) + begPtr <= p && (*p == ' ' || *p == '\r' || *p == '\n' || *p == '\t'); --p) { endPtr = p; } @@ -1613,8 +1821,10 @@ UnitTestDeclaration *Parser::parseUnitTest() } } - f = new UnitTestDeclaration(loc, token.loc, docline); - f->fbody = body; + UnitTestDeclaration *f = new UnitTestDeclaration(loc, token.loc, stc, docline); + if (pAttrs) + pAttrs->storageClass = STCundefined; + f->fbody = sbody; return f; } @@ -1624,18 +1834,20 @@ UnitTestDeclaration *Parser::parseUnitTest() * Current token is 'new'. */ -NewDeclaration *Parser::parseNew() +Dsymbol *Parser::parseNew(PrefixAttributes *pAttrs) { - NewDeclaration *f; - Parameters *arguments; - int varargs; Loc loc = token.loc; + StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined; nextToken(); - arguments = parseParameters(&varargs); - f = new NewDeclaration(loc, Loc(), arguments, varargs); - parseContracts(f); - return f; + + int varargs; + Parameters *arguments = parseParameters(&varargs); + NewDeclaration *f = new NewDeclaration(loc, Loc(), stc, arguments, varargs); + if (pAttrs) + pAttrs->storageClass = STCundefined; + Dsymbol *s = parseContracts(f); + return s; } /***************************************** @@ -1644,20 +1856,22 @@ NewDeclaration *Parser::parseNew() * Current token is 'delete'. */ -DeleteDeclaration *Parser::parseDelete() +Dsymbol *Parser::parseDelete(PrefixAttributes *pAttrs) { - DeleteDeclaration *f; - Parameters *arguments; - int varargs; Loc loc = token.loc; + StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined; nextToken(); - arguments = parseParameters(&varargs); + + int varargs; + Parameters *arguments = parseParameters(&varargs); if (varargs) error("... not allowed in delete function parameter list"); - f = new DeleteDeclaration(loc, Loc(), arguments); - parseContracts(f); - return f; + DeleteDeclaration *f = new DeleteDeclaration(loc, Loc(), stc, arguments); + if (pAttrs) + pAttrs->storageClass = STCundefined; + Dsymbol *s = parseContracts(f); + return s; } /********************************************** @@ -1724,13 +1938,7 @@ Parameters *Parser::parseParameters(int *pvarargs, TemplateParameters **tpl) case TOKfinal: stc = STCfinal; goto L2; case TOKauto: stc = STCauto; goto L2; L2: - if (storageClass & stc || - (storageClass & STCin && stc & (STCconst | STCscope)) || - (stc & STCin && storageClass & (STCconst | STCscope)) - ) - error("redundant storage class '%s'", Token::toChars(token.value)); - storageClass |= stc; - composeStorageClass(storageClass); + storageClass = appendStorageClass(storageClass, stc); continue; #if 0 @@ -1858,8 +2066,12 @@ EnumDeclaration *Parser::parseEnum() if (token.value == TOKcolon) { nextToken(); + + int alt = 0; + Loc typeLoc = token.loc; memtype = parseBasicType(); - memtype = parseDeclarator(memtype, NULL, NULL); + memtype = parseDeclarator(memtype, &alt, NULL); + checkCstyleTypeSyntax(typeLoc, memtype, alt, NULL); } else memtype = NULL; @@ -1961,15 +2173,17 @@ Dsymbol *Parser::parseAggregate() //printf("Parser::parseAggregate()\n"); nextToken(); if (token.value != TOKidentifier) - { id = NULL; + { + id = NULL; } else - { id = token.ident; + { + id = token.ident; nextToken(); if (token.value == TOKlparen) - { // Class template declaration. - + { + // Class template declaration. // Gather template parameter list tpl = parseTemplateParameterList(); constraint = parseConstraint(); @@ -2036,7 +2250,8 @@ Dsymbol *Parser::parseAggregate() break; } if (a && token.value == TOKsemicolon) - { nextToken(); + { + nextToken(); } else if (token.value == TOKlcurly) { @@ -2044,7 +2259,7 @@ Dsymbol *Parser::parseAggregate() nextToken(); Dsymbols *decl = parseDeclDefs(0); if (token.value != TOKrcurly) - error("} expected following member declarations in aggregate"); + error("} expected following members in %s declaration at %s", Token::toChars(tok), loc.toChars()); nextToken(); if (anon) { @@ -2057,7 +2272,7 @@ Dsymbol *Parser::parseAggregate() } else { - error("{ } expected following aggregate declaration"); + error("{ } expected following %s declaration", Token::toChars(tok)); a = new StructDeclaration(loc, NULL); } @@ -2084,33 +2299,33 @@ BaseClasses *Parser::parseBaseClasses() for (; 1; nextToken()) { bool prot = false; - PROT protection = PROTpublic; + Prot protection = Prot(PROTpublic); switch (token.value) { case TOKprivate: prot = true; - protection = PROTprivate; + protection = Prot(PROTprivate); nextToken(); break; case TOKpackage: prot = true; - protection = PROTpackage; + protection = Prot(PROTpackage); nextToken(); break; case TOKprotected: prot = true; - protection = PROTprotected; + protection = Prot(PROTprotected); nextToken(); break; case TOKpublic: prot = true; - protection = PROTpublic; + protection = Prot(PROTpublic); nextToken(); break; default: break; } if (prot) - deprecation("use of base class protection is deprecated"); + error("use of base class protection is no longer supported"); BaseClass *b = new BaseClass(parseBasicType(), protection); baseclasses->push(b); if (token.value != TOKcomma) @@ -2719,7 +2934,7 @@ Dsymbols *Parser::parseImport() return decldefs; } -Type *Parser::parseType(Identifier **pident, TemplateParameters **tpl) +Type *Parser::parseType(Identifier **pident, TemplateParameters **ptpl) { /* Take care of the storage class prefixes that * serve as type attributes: @@ -2771,9 +2986,15 @@ Type *Parser::parseType(Identifier **pident, TemplateParameters **tpl) break; } + Loc typeLoc = token.loc; + Type *t; t = parseBasicType(); - t = parseDeclarator(t, pident, tpl); + + int alt = 0; + t = parseDeclarator(t, &alt, pident, ptpl); + checkCstyleTypeSyntax(typeLoc, t, alt, pident ? *pident : NULL); + t = t->addSTC(stc); return t; } @@ -2983,7 +3204,7 @@ Type *Parser::parseBasicType2(Type *t) nextToken(); arguments = parseParameters(&varargs); - StorageClass stc = parsePostfix(NULL); + StorageClass stc = parsePostfix(STCundefined, NULL); TypeFunction *tf = new TypeFunction(arguments, t, varargs, linkage, stc); if (stc & (STCconst | STCimmutable | STCshared | STCwild)) { @@ -3009,8 +3230,8 @@ Type *Parser::parseBasicType2(Type *t) return NULL; } -Type *Parser::parseDeclarator(Type *t, Identifier **pident, - TemplateParameters **tpl, StorageClass storage_class, int* pdisable, Expressions **pudas) +Type *Parser::parseDeclarator(Type *t, int *palt, Identifier **pident, + TemplateParameters **tpl, StorageClass storageClass, int* pdisable, Expressions **pudas) { //printf("parseDeclarator(tpl = %p)\n", tpl); t = parseBasicType2(t); @@ -3028,6 +3249,7 @@ Type *Parser::parseDeclarator(Type *t, Identifier **pident, break; case TOKlparen: + { // like: T (*fp)(); // like: T ((*fp))(); if (peekNext() == TOKmul || @@ -3038,14 +3260,14 @@ Type *Parser::parseDeclarator(Type *t, Identifier **pident, * although the D style would be: * int[]*[3] ident */ - deprecation("C-style function pointer and pointer to array syntax is deprecated. Use 'function' to declare function pointers"); + *palt |= 1; nextToken(); - ts = parseDeclarator(t, pident); + ts = parseDeclarator(t, palt, pident); check(TOKrparen); break; } ts = t; - { + Token *peekt = &token; /* Completely disallow C-style things like: * T (a); @@ -3054,13 +3276,12 @@ Type *Parser::parseDeclarator(Type *t, Identifier **pident, */ if (isParameters(&peekt)) { - error("function declaration without return type. " - "(Note that constructors are always named 'this')"); + error("function declaration without return type. (Note that constructors are always named 'this')"); } else error("unexpected ( in declarator"); - } break; + } default: ts = t; @@ -3079,21 +3300,26 @@ Type *Parser::parseDeclarator(Type *t, Identifier **pident, * int[] ident */ case TOKlbracket: - { // This is the old C-style post [] syntax. + { + // This is the old C-style post [] syntax. + Loc loc = token.loc; TypeNext *ta; nextToken(); if (token.value == TOKrbracket) - { // It's a dynamic array + { + // It's a dynamic array ta = new TypeDArray(t); // [] nextToken(); + *palt |= 2; } else if (isDeclaration(&token, 0, TOKrbracket, NULL)) - { // It's an associative array - + { + // It's an associative array //printf("it's an associative array\n"); Type *index = parseType(); // [ type ] check(TOKrbracket); ta = new TypeAArray(t, index); + *palt |= 2; } else { @@ -3101,6 +3327,7 @@ Type *Parser::parseDeclarator(Type *t, Identifier **pident, Expression *e = parseAssignExp(); // [ expression ] ta = new TypeSArray(t, e); check(TOKrbracket); + *palt |= 2; } /* Insert ta into @@ -3146,8 +3373,8 @@ Type *Parser::parseDeclarator(Type *t, Identifier **pident, /* Parse const/immutable/shared/inout/nothrow/pure postfix */ - StorageClass stc = parsePostfix(pudas); - stc |= storage_class; // merge prefix storage classes + StorageClass stc = parsePostfix(storageClass, pudas); + // merge prefix storage classes Type *tf = new TypeFunction(arguments, t, varargs, linkage, stc); tf = tf->addSTC(stc); if (pdisable) @@ -3226,10 +3453,7 @@ void Parser::parseStorageClasses(StorageClass &storage_class, LINK &link, unsign continue; } L1: - if (storage_class & stc) - error("redundant storage class '%s'", token.toChars()); - storage_class = storage_class | stc; - composeStorageClass(storage_class); + storage_class = appendStorageClass(storage_class, stc); nextToken(); continue; @@ -3378,14 +3602,10 @@ Dsymbols *Parser::parseDeclarations(bool autodecl, PrefixAttributes *pAttrs, con error("user defined attributes not allowed for %s declarations", Token::toChars(tok)); t = parseType(); - Dsymbol *s = new AliasDeclaration(loc, ident, t); - ((Declaration *)s)->storage_class = storage_class; - if (link != linkage) - { - Dsymbols *a2 = new Dsymbols(); - a2->push(s); - s = new LinkDeclaration(link, a2); - } + Declaration *v = new AliasDeclaration(loc, ident, t); + v->storage_class = storage_class; + + Dsymbol *s = v; if (tpl) { Dsymbols *a2 = new Dsymbols(); @@ -3394,6 +3614,12 @@ Dsymbols *Parser::parseDeclarations(bool autodecl, PrefixAttributes *pAttrs, con new TemplateDeclaration(loc, ident, tpl, NULL, a2); s = tempdecl; } + if (link != linkage) + { + Dsymbols *a2 = new Dsymbols(); + a2->push(s); + s = new LinkDeclaration(link, a2); + } a->push(s); switch (token.value) { @@ -3427,7 +3653,7 @@ Dsymbols *Parser::parseDeclarations(bool autodecl, PrefixAttributes *pAttrs, con break; } case TOKtypedef: - deprecation("use of typedef is deprecated; use alias instead"); + error("use alias instead of typedef"); tok = token.value; nextToken(); break; @@ -3518,14 +3744,21 @@ L2: tfirst = NULL; Dsymbols *a = new Dsymbols(); + if (pAttrs) + { + storage_class |= pAttrs->storageClass; + //pAttrs->storageClass = STCundefined; + } + while (1) { - loc = token.loc; TemplateParameters *tpl = NULL; int disable; + int alt = 0; + loc = token.loc; ident = NULL; - t = parseDeclarator(ts, &ident, &tpl, storage_class, &disable, &udas); + t = parseDeclarator(ts, &alt, &ident, &tpl, storage_class, &disable, &udas); assert(t); if (!tfirst) tfirst = t; @@ -3533,7 +3766,9 @@ L2: error("multiple declarations must have the same type, not %s and %s", tfirst->toChars(), t->toChars()); bool isThis = (t->ty == Tident && ((TypeIdentifier *)t)->ident == Id::This); - if (!isThis && !ident) + if (ident) + checkCstyleTypeSyntax(loc, t, alt, ident); + else if (!isThis) error("no identifier for declarator %s", t->toChars()); if (tok == TOKtypedef || tok == TOKalias) @@ -3558,7 +3793,7 @@ L2: } if (tok == TOKtypedef) { - v = new TypedefDeclaration(loc, ident, t, init); + v = new AliasDeclaration(loc, ident, t); // dummy } else { @@ -3574,25 +3809,35 @@ L2: v = new AliasDeclaration(loc, ident, t); } v->storage_class = storage_class; - if (link == linkage) - a->push(v); - else + if (pAttrs) + { + /* AliasDeclaration distinguish @safe, @system, @trusted atttributes + * on prefix and postfix. + * @safe alias void function() FP1; + * alias @safe void function() FP2; // FP2 is not @safe + * alias void function() @safe FP3; + */ + pAttrs->storageClass &= (STCsafe | STCsystem | STCtrusted); + } + Dsymbol *s = v; + + if (link != linkage) { Dsymbols *ax = new Dsymbols(); ax->push(v); - Dsymbol *s = new LinkDeclaration(link, ax); - a->push(s); + s = new LinkDeclaration(link, ax); } + a->push(s); switch (token.value) { case TOKsemicolon: nextToken(); - addComment(v, comment); + addComment(s, comment); break; case TOKcomma: nextToken(); - addComment(v, comment); + addComment(s, comment); continue; default: @@ -3613,78 +3858,13 @@ L2: #endif //printf("%s funcdecl t = %s, storage_class = x%lx\n", loc.toChars(), t->toChars(), storage_class); - if (pAttrs) - { - StorageClass prefixStc = pAttrs->storageClass; - t = t->addSTC(prefixStc); - - TypeFunction *tf = (TypeFunction *)t; - if (prefixStc & STCpure) - { - if (tf->purity == PUREfwdref) - error("redundant storage class 'pure'"); - tf->purity = PUREfwdref; - } - if (prefixStc & STCnothrow) - { - if (tf->isnothrow) - error("redundant storage class 'nothrow'"); - tf->isnothrow = true; - } - if (prefixStc & STCnogc) - { - if (tf->isnogc) - error("redundant storage class '@nogc'"); - tf->isnogc = true; - } - if (prefixStc & STCproperty) - { - if (tf->isproperty) - error("redundant storage class '@property'"); - tf->isproperty = true; - } - - if (prefixStc & STCref) - { - if (tf->isref) - error("redundant storage class 'ref'"); - tf->isref = true; - } - - StorageClass postfixTrustStc; - switch (tf->trust) - { - case TRUSTdefault: - if (prefixStc & STCsafe) tf->trust = TRUSTsafe; - if (prefixStc & STCsystem) tf->trust = TRUSTsystem; - if (prefixStc & STCtrusted) tf->trust = TRUSTtrusted; - break; - case TRUSTsafe: postfixTrustStc = STCsafe; goto Ltrust; - case TRUSTsystem: postfixTrustStc = STCsystem; goto Ltrust; - case TRUSTtrusted: postfixTrustStc = STCtrusted; goto Ltrust; - Ltrust: - { - if (prefixStc & postfixTrustStc) - error("redundant storage class '%s'", trustToChars(tf->trust)); - else if (prefixStc & (STCsafe | STCsystem | STCtrusted)) - error("conflicting storage class '%s'", trustToChars(tf->trust)); - break; - } - default: - assert(0); - } - - storage_class |= prefixStc & ~(STC_TYPECTOR | STC_FUNCATTR); - pAttrs->storageClass = STCundefined; - } - FuncDeclaration *f = new FuncDeclaration(loc, Loc(), ident, storage_class | (disable ? STCdisable : 0), t); - addComment(f, comment); + if (pAttrs) + pAttrs->storageClass = STCundefined; if (tpl) constraint = parseConstraint(); Dsymbol *s = parseContracts(f); - addComment(s, NULL); /* A template parameter list means it's a function template */ @@ -3719,8 +3899,8 @@ L2: ax->push(s); s = new UserAttributeDeclaration(udas, ax); } - addComment(s, comment); a->push(s); + addComment(s, comment); } else if (ident) { @@ -3733,6 +3913,9 @@ L2: VarDeclaration *v = new VarDeclaration(loc, t, ident, init); v->storage_class = storage_class; + if (pAttrs) + pAttrs->storageClass = STCundefined; + Dsymbol *s = v; if (tpl && init) @@ -3743,7 +3926,6 @@ L2: new TemplateDeclaration(loc, ident, tpl, NULL, a2, 0); s = tempdecl; } - if (link != linkage) { Dsymbols *ax = new Dsymbols(); @@ -3761,12 +3943,12 @@ L2: { case TOKsemicolon: nextToken(); - addComment(v, comment); + addComment(s, comment); break; case TOKcomma: nextToken(); - addComment(v, comment); + addComment(s, comment); continue; default: @@ -3817,28 +3999,30 @@ Dsymbols *Parser::parseAutoDeclarations(StorageClass storageClass, const utf8_t new TemplateDeclaration(loc, ident, tpl, NULL, a2, 0); s = tempdecl; } - a->push(s); - if (token.value == TOKsemicolon) + switch (token.value) { - nextToken(); - addComment(v, comment); - } - else if (token.value == TOKcomma) - { - nextToken(); - if (token.value == TOKidentifier && - skipParensIf(peek(&token), &tk) && - tk->value == TOKassign) - { - addComment(v, comment); + case TOKsemicolon: + nextToken(); + addComment(s, comment); + break; + + case TOKcomma: + nextToken(); + if (!(token.value == TOKidentifier && + skipParensIf(peek(&token), &tk) && + tk->value == TOKassign)) + { + error("Identifier expected following comma"); + break; + } + addComment(s, comment); continue; - } - else - error("Identifier expected following comma"); + + default: + error("semicolon expected following auto declaration, not '%s'", token.toChars()); + break; } - else - error("semicolon expected following auto declaration, not '%s'", token.toChars()); break; } return a; @@ -4233,6 +4417,20 @@ void Parser::checkDanglingElse(Loc elseloc) } } +void Parser::checkCstyleTypeSyntax(Loc loc, Type *t, int alt, Identifier *ident) +{ + if (!alt) + return; + + const char *sp = !ident ? "" : " "; + const char *s = !ident ? "" : ident->toChars(); + if (alt & 1) // contains C-style function pointer syntax + error(loc, "instead of C-style syntax, use D-style '%s%s%s'", t->toChars(), sp, s); + else + ::warning(loc, "instead of C-style syntax, use D-style syntax '%s%s%s'", t->toChars(), sp, s); + +} + /***************************************** * Input: * flags PSxxxx @@ -4546,7 +4744,7 @@ Statement *Parser::parseStatement(int flags, const utf8_t** endPtr) if (token.value == TOKsemicolon) nextToken(); else - deprecation("do-while statement without terminating ; is deprecated"); + error("terminating ';' required after do-while statement"); s = new DoStatement(loc, body, condition); break; } @@ -4614,10 +4812,7 @@ Statement *Parser::parseStatement(int flags, const utf8_t** endPtr) Lagain: if (stc) { - if (storageClass & stc) - error("redundant storage class '%s'", Token::toChars(token.value)); - storageClass |= stc; - composeStorageClass(storageClass); + storageClass = appendStorageClass(storageClass, stc); nextToken(); } switch (token.value) @@ -4714,10 +4909,7 @@ Statement *Parser::parseStatement(int flags, const utf8_t** endPtr) LagainStc: if (stc) { - if (storageClass & stc) - error("redundant storage class '%s'", Token::toChars(token.value)); - storageClass |= stc; - composeStorageClass(storageClass); + storageClass = appendStorageClass(storageClass, stc); nextToken(); } switch (token.value) @@ -5193,7 +5385,7 @@ Statement *Parser::parseStatement(int flags, const utf8_t** endPtr) case TOKvolatile: nextToken(); s = parseStatement(PSsemi | PScurlyscope); - deprecation("volatile statements deprecated; use synchronized statements instead"); + error("volatile statements no longer allowed; use synchronized statements instead"); s = new SynchronizedStatement(loc, (Expression *)NULL, s); break; @@ -5207,6 +5399,10 @@ Statement *Parser::parseStatement(int flags, const utf8_t** endPtr) Loc labelloc; nextToken(); + StorageClass stc = parsePostfix(STCundefined, NULL); + if (stc & (STCconst | STCimmutable | STCshared | STCwild)) + error("const/immutable/shared/inout attributes are not allowed on asm blocks"); + check(TOKlcurly); Token *toklist = NULL; Token **ptoklist = &toklist; @@ -5287,7 +5483,7 @@ Statement *Parser::parseStatement(int flags, const utf8_t** endPtr) } break; } - s = new AsmBlockStatement(loc, statements); + s = new CompoundAsmStatement(loc, statements, stc); nextToken(); break; } @@ -5998,7 +6194,17 @@ int Parser::skipAttributes(Token *t, Token **pt) case TOKoverride: case TOKabstract: case TOKsynchronized: + break; case TOKdeprecated: + if (peek(t)->value == TOKlparen) + { + t = peek(t); + if (!skipParens(t, &t)) + goto Lerror; + // t is on the next of closing parenthesis + continue; + } + break; case TOKnothrow: case TOKpure: case TOKref: @@ -6412,6 +6618,9 @@ Expression *Parser::parsePrimaryExp() { tok2 = token.value; nextToken(); + + if (tok2 == TOKtypedef) + deprecation("typedef is removed"); } else { @@ -6423,7 +6632,8 @@ Expression *Parser::parsePrimaryExp() if (token.value == TOKcomma) tpl = parseTemplateParameterList(1); else - { tpl = new TemplateParameters(); + { + tpl = new TemplateParameters(); check(TOKrparen); } } @@ -6431,7 +6641,8 @@ Expression *Parser::parsePrimaryExp() check(TOKrparen); } else - { error("(type identifier : specialization) expected following is"); + { + error("(type identifier : specialization) expected following is"); goto Lerr; } e = new IsExp(loc, targ, ident, tok, tspec, tok2, tpl); @@ -6581,7 +6792,7 @@ Expression *Parser::parsePrimaryExp() // (parameters) => expression // (parameters) { statements... } parameters = parseParameters(&varargs, &tpl); - stc = parsePostfix(NULL); + stc = parsePostfix(STCundefined, NULL); if (stc & (STCconst | STCimmutable | STCshared | STCwild)) error("const/immutable/shared/inout attributes are only valid for non-static member functions"); break; diff --git a/dmd2/parse.h b/dmd2/parse.h index 8e4a04d2b2..4edb92117a 100644 --- a/dmd2/parse.h +++ b/dmd2/parse.h @@ -78,9 +78,9 @@ public: Dsymbols *parseDeclDefs(int once, Dsymbol **pLastDecl = NULL, PrefixAttributes *pAttrs = NULL); Dsymbols *parseAutoDeclarations(StorageClass storageClass, const utf8_t *comment); Dsymbols *parseBlock(Dsymbol **pLastDecl, PrefixAttributes *pAttrs = NULL); - void composeStorageClass(StorageClass stc); + StorageClass appendStorageClass(StorageClass storageClass, StorageClass stc); StorageClass parseAttribute(Expressions **pexps); - StorageClass parsePostfix(Expressions **pudas); + StorageClass parsePostfix(StorageClass storageClass, Expressions **pudas); StorageClass parseTypeCtor(); Expression *parseConstraint(); TemplateDeclaration *parseTemplateDeclaration(bool ismixin = false); @@ -93,33 +93,35 @@ public: TypeQualified *parseTypeof(); Type *parseVector(); LINK parseLinkage(Identifiers **); + Identifiers *parseQualifiedIdentifier(const char *entity); Condition *parseDebugCondition(); Condition *parseVersionCondition(); Condition *parseStaticIfCondition(); - Dsymbol *parseCtor(); - Dsymbol *parseDtor(); - Dsymbol *parseStaticCtor(); - Dsymbol *parseStaticDtor(); - Dsymbol *parseSharedStaticCtor(); - Dsymbol *parseSharedStaticDtor(); - InvariantDeclaration *parseInvariant(); - UnitTestDeclaration *parseUnitTest(); - NewDeclaration *parseNew(); - DeleteDeclaration *parseDelete(); + Dsymbol *parseCtor(PrefixAttributes *pAttrs); + Dsymbol *parseDtor(PrefixAttributes *pAttrs); + Dsymbol *parseStaticCtor(PrefixAttributes *pAttrs); + Dsymbol *parseStaticDtor(PrefixAttributes *pAttrs); + Dsymbol *parseSharedStaticCtor(PrefixAttributes *pAttrs); + Dsymbol *parseSharedStaticDtor(PrefixAttributes *pAttrs); + Dsymbol *parseInvariant(PrefixAttributes *pAttrs); + Dsymbol *parseUnitTest(PrefixAttributes *pAttrs); + Dsymbol *parseNew(PrefixAttributes *pAttrs); + Dsymbol *parseDelete(PrefixAttributes *pAttrs); Parameters *parseParameters(int *pvarargs, TemplateParameters **tpl = NULL); EnumDeclaration *parseEnum(); Dsymbol *parseAggregate(); BaseClasses *parseBaseClasses(); Dsymbols *parseImport(); - Type *parseType(Identifier **pident = NULL, TemplateParameters **tpl = NULL); + Type *parseType(Identifier **pident = NULL, TemplateParameters **ptpl = NULL); Type *parseBasicType(); Type *parseBasicType2(Type *t); - Type *parseDeclarator(Type *t, Identifier **pident, - TemplateParameters **tpl = NULL, StorageClass storage_class = 0, int* pdisable = NULL, Expressions **pudas = NULL); + Type *parseDeclarator(Type *t, int *alt, Identifier **pident, + TemplateParameters **tpl = NULL, StorageClass storage_class = 0, int *pdisable = NULL, Expressions **pudas = NULL); void parseStorageClasses(StorageClass &storage_class, LINK &link, unsigned &structalign, Expressions *&udas); Dsymbols *parseDeclarations(bool autodecl, PrefixAttributes *pAttrs, const utf8_t *comment); FuncDeclaration *parseContracts(FuncDeclaration *f); void checkDanglingElse(Loc elseloc); + void checkCstyleTypeSyntax(Loc loc, Type *t, int alt, Identifier *ident); /** endPtr used for documented unittests */ Statement *parseStatement(int flags, const utf8_t** endPtr = NULL); Initializer *parseInitializer(); diff --git a/dmd2/readme.txt b/dmd2/readme.txt index 2b79949ddb..87229c86b5 100644 --- a/dmd2/readme.txt +++ b/dmd2/readme.txt @@ -1,7 +1,7 @@ The D Programming Language Compiler Front End Source - Copyright (c) 1999-2013, by Digital Mars + Copyright (c) 1999-2014, by Digital Mars http://www.digitalmars.com/ All Rights Reserved @@ -12,10 +12,9 @@ of the D Programming Language defined in the documents at http://dlang.org/ These sources are free, they are redistributable and modifiable -under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 1, or (at your option) -any later version (attached as gpl.txt), -or the Artistic License (attached as artistic.txt). +under the terms of the Boost Software License, Version 1.0. +The terms of this license are in the file boostlicense.txt, +or see http://www.boost.org/LICENSE_1_0.txt. The optimizer and code generator sources are covered under a separate license, backendlicense.txt. diff --git a/dmd2/root/aav.c b/dmd2/root/aav.c index 08748525ea..570301a8c7 100644 --- a/dmd2/root/aav.c +++ b/dmd2/root/aav.c @@ -18,6 +18,7 @@ #include #include "aav.h" +#include "rmem.h" inline size_t hash(size_t a) @@ -55,7 +56,8 @@ size_t dmd_aaLen(AA* aa) /************************************************* * Get pointer to value in associative array indexed by key. - * Add entry for key if it is not already there. + * Add entry for key if it is not already there, returning a pointer to a null Value. + * Create the associative array if it does not already exist. */ Value* dmd_aaGet(AA** paa, Key key) @@ -63,9 +65,9 @@ Value* dmd_aaGet(AA** paa, Key key) //printf("paa = %p\n", paa); if (!*paa) - { AA *a = new AA(); - a->b = a->binit; - a->b_length = sizeof(a->binit) / sizeof(a->binit[0]); + { AA *a = (AA *)mem.malloc(sizeof(AA)); + a->b = (aaA**)a->binit; + a->b_length = 4; a->nodes = 0; a->binit[0] = NULL; a->binit[1] = NULL; @@ -91,7 +93,7 @@ Value* dmd_aaGet(AA** paa, Key key) //printf("create new one\n"); size_t nodes = ++(*paa)->nodes; - e = (nodes != 1) ? new aaA() : &(*paa)->aafirst; + e = (nodes != 1) ? (aaA *)mem.malloc(sizeof(aaA)) : &(*paa)->aafirst; //e = new aaA(); e->next = NULL; e->key = key; @@ -151,7 +153,7 @@ void dmd_aaRehash(AA** paa) len = 32; else len *= 4; - aaA** newb = new aaA*[len]; + aaA** newb = (aaA**)mem.malloc(sizeof(aaA)*len); memset(newb, 0, len * sizeof(aaA*)); for (size_t k = 0; k < aa->b_length; k++) @@ -164,8 +166,8 @@ void dmd_aaRehash(AA** paa) e = enext; } } - if (aa->b != aa->binit) - delete[] aa->b; + if (aa->b != (aaA**)aa->binit) + mem.free(aa->b); aa->b = newb; aa->b_length = len; diff --git a/dmd2/root/checkedint.c b/dmd2/root/checkedint.c new file mode 100644 index 0000000000..e4ecfff0a8 --- /dev/null +++ b/dmd2/root/checkedint.c @@ -0,0 +1,559 @@ + +/********************************************** + * This module implements integral arithmetic primitives that check + * for out-of-range results. + * This is a translation to C++ of D's core.checkedint + * + * Integral arithmetic operators operate on fixed width types. + * Results that are not representable in those fixed widths are silently + * truncated to fit. + * This module offers integral arithmetic primitives that produce the + * same results, but set an 'overflow' flag when such truncation occurs. + * The setting is sticky, meaning that numerous operations can be cascaded + * and then the flag need only be checked at the end. + * Whether the operation is signed or unsigned is indicated by an 's' or 'u' + * suffix, respectively. While this could be achieved without such suffixes by + * using overloading on the signedness of the types, the suffix makes it clear + * which is happening without needing to examine the types. + * + * While the generic versions of these functions are computationally expensive + * relative to the cost of the operation itself, compiler implementations are free + * to recognize them and generate equivalent and faster code. + * + * References: $(LINK2 http://blog.regehr.org/archives/1139, Fast Integer Overflow Checks) + * Copyright: Copyright (c) Walter Bright 2014. + * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) + * Authors: Walter Bright + * Source: https://github.com/D-Programming-Language/dmd/blob/master/src/root/port.c + */ + +#include + +#include "checkedint.h" + +#ifdef __DMC__ +#undef UINT64_MAX +#define UINT64_MAX 18446744073709551615ULL +#undef UINT32_MAX +#define UINT32_MAX 4294967295U +#endif + + + +/******************************* + * Add two signed integers, checking for overflow. + * + * The overflow is sticky, meaning a sequence of operations can + * be done and overflow need only be checked at the end. + * Params: + * x = left operand + * y = right operand + * overflow = set if an overflow occurs, is not affected otherwise + * Returns: + * the sum + */ + +int adds(int x, int y, bool& overflow) +{ + int64_t r = (int64_t)x + (int64_t)y; + if (r < INT32_MIN || r > INT32_MAX) + overflow = true; + return (int)r; +} + +#ifdef DEBUG +void unittest1() +{ + bool overflow = false; + assert(adds(2, 3, overflow) == 5); + assert(!overflow); + assert(adds(1, INT32_MAX - 1, overflow) == INT32_MAX); + assert(!overflow); + assert(adds(INT32_MIN + 1, -1, overflow) == INT32_MIN); + assert(!overflow); + assert(adds(INT32_MAX, 1, overflow) == INT32_MIN); + assert(overflow); + overflow = false; + assert(adds(INT32_MIN, -1, overflow) == INT32_MAX); + assert(overflow); + assert(adds(0, 0, overflow) == 0); + assert(overflow); // sticky +} +#endif + +/// ditto +int64_t adds(int64_t x, int64_t y, bool& overflow) +{ + int64_t r = (uint64_t)x + (uint64_t)y; + if (x < 0 && y < 0 && r >= 0 || + x >= 0 && y >= 0 && r < 0) + overflow = true; + return r; +} + +#ifdef DEBUG +void unittest2() +{ + bool overflow = false; + assert(adds((int64_t)2, (int64_t)3, overflow) == 5); + assert(!overflow); + assert(adds((int64_t)1, INT64_MAX - 1, overflow) == INT64_MAX); + assert(!overflow); + assert(adds(INT64_MIN + 1, (int64_t)-1, overflow) == INT64_MIN); + assert(!overflow); + assert(adds(INT64_MAX, (int64_t)1, overflow) == INT64_MIN); + assert(overflow); + overflow = false; + assert(adds(INT64_MIN, (int64_t)-1, overflow) == INT64_MAX); + assert(overflow); + assert(adds((int64_t)0, (int64_t)0, overflow) == 0); + assert(overflow); // sticky +} +#endif + + +/******************************* + * Add two unsigned integers, checking for overflow (aka carry). + * + * The overflow is sticky, meaning a sequence of operations can + * be done and overflow need only be checked at the end. + * Params: + * x = left operand + * y = right operand + * overflow = set if an overflow occurs, is not affected otherwise + * Returns: + * the sum + */ + +unsigned addu(unsigned x, unsigned y, bool& overflow) +{ + unsigned r = x + y; + if (r < x || r < y) + overflow = true; + return r; +} + +#ifdef DEBUG +void unittest3() +{ + bool overflow = false; + assert(addu(2U, 3U, overflow) == 5); + assert(!overflow); + assert(addu(1U, UINT32_MAX - 1U, overflow) == UINT32_MAX); + assert(!overflow); + assert(addu(0U, -1U, overflow) == UINT32_MAX); + assert(!overflow); + assert(addu(UINT32_MAX, 1U, overflow) == 0); + assert(overflow); + overflow = false; + assert(addu(0U + 1U, -1U, overflow) == 0); + assert(overflow); + assert(addu(0U, 0U, overflow) == 0); + assert(overflow); // sticky +} +#endif + +/// ditto +uint64_t addu(uint64_t x, uint64_t y, bool& overflow) +{ + uint64_t r = x + y; + if (r < x || r < y) + overflow = true; + return r; +} + +#ifdef DEBUG +void unittest4() +{ + bool overflow = false; + assert(addu((uint64_t)2, (uint64_t)3, overflow) == 5); + assert(!overflow); + assert(addu((uint64_t)1, UINT64_MAX - 1, overflow) == UINT64_MAX); + assert(!overflow); + assert(addu((uint64_t)0, (uint64_t)-1, overflow) == UINT64_MAX); + assert(!overflow); + assert(addu(UINT64_MAX, (uint64_t)1, overflow) == 0); + assert(overflow); + overflow = false; + assert(addu((uint64_t)0 + 1, (uint64_t)-1, overflow) == 0); + assert(overflow); + assert(addu((uint64_t)0, (uint64_t)0, overflow) == 0); + assert(overflow); // sticky +} +#endif + + +/******************************* + * Subtract two signed integers, checking for overflow. + * + * The overflow is sticky, meaning a sequence of operations can + * be done and overflow need only be checked at the end. + * Params: + * x = left operand + * y = right operand + * overflow = set if an overflow occurs, is not affected otherwise + * Returns: + * the sum + */ + +int subs(int x, int y, bool& overflow) +{ + int64_t r = (int64_t)x - (int64_t)y; + if (r < INT32_MIN || r > INT32_MAX) + overflow = true; + return (int)r; +} + +#ifdef DEBUG +void unittest5() +{ + bool overflow = false; + assert(subs(2, -3, overflow) == 5); + assert(!overflow); + assert(subs(1, -INT32_MAX + 1, overflow) == INT32_MAX); + assert(!overflow); + assert(subs(INT32_MIN + 1, 1, overflow) == INT32_MIN); + assert(!overflow); + assert(subs(INT32_MAX, -1, overflow) == INT32_MIN); + assert(overflow); + overflow = false; + assert(subs(INT32_MIN, 1, overflow) == INT32_MAX); + assert(overflow); + assert(subs(0, 0, overflow) == 0); + assert(overflow); // sticky +} +#endif + +/// ditto +int64_t subs(int64_t x, int64_t y, bool& overflow) +{ + int64_t r = (uint64_t)x - (uint64_t)y; + if (x < 0 && y >= 0 && r >= 0 || + x >= 0 && y < 0 && r < 0 || + y == INT64_MIN) + overflow = true; + return r; +} + +#ifdef DEBUG +void unittest6() +{ + bool overflow = false; + assert(subs((int64_t)2, (int64_t)-3, overflow) == 5); + assert(!overflow); + assert(subs((int64_t)1, -INT64_MAX + (int64_t)1, overflow) == INT64_MAX); + assert(!overflow); + assert(subs(INT64_MIN + 1, (int64_t)1, overflow) == INT64_MIN); + assert(!overflow); + assert(subs(INT64_MAX, (int64_t)-1, overflow) == INT64_MIN); + assert(overflow); + overflow = false; + assert(subs(INT64_MIN, (int64_t)1, overflow) == INT64_MAX); + assert(overflow); + assert(subs((int64_t)0, (int64_t)0, overflow) == 0); + assert(overflow); // sticky +} +#endif + +/******************************* + * Subtract two unsigned integers, checking for overflow (aka borrow). + * + * The overflow is sticky, meaning a sequence of operations can + * be done and overflow need only be checked at the end. + * Params: + * x = left operand + * y = right operand + * overflow = set if an overflow occurs, is not affected otherwise + * Returns: + * the sum + */ + +unsigned subu(unsigned x, unsigned y, bool& overflow) +{ + if (x < y) + overflow = true; + return x - y; +} + +#ifdef DEBUG +void unittest7() +{ + bool overflow = false; + assert(subu(3U, 2U, overflow) == 1); + assert(!overflow); + assert(subu(UINT32_MAX, 1U, overflow) == UINT32_MAX - 1); + assert(!overflow); + assert(subu(1U, 1U, overflow) == 0); + assert(!overflow); + assert(subu(0U, 1U, overflow) == UINT32_MAX); + assert(overflow); + overflow = false; + assert(subu(UINT32_MAX - 1U, UINT32_MAX, overflow) == UINT32_MAX); + assert(overflow); + assert(subu(0U, 0U, overflow) == 0); + assert(overflow); // sticky +} +#endif + + +/// ditto +uint64_t subu(uint64_t x, uint64_t y, bool& overflow) +{ + if (x < y) + overflow = true; + return x - y; +} + +#ifdef DEBUG +void unittest8() +{ + bool overflow = false; + assert(subu((uint64_t)3, (uint64_t)2, overflow) == 1); + assert(!overflow); + assert(subu(UINT64_MAX, (uint64_t)1, overflow) == UINT64_MAX - 1); + assert(!overflow); + assert(subu((uint64_t)1, (uint64_t)1, overflow) == 0); + assert(!overflow); + assert(subu((uint64_t)0, (uint64_t)1, overflow) == UINT64_MAX); + assert(overflow); + overflow = false; + assert(subu(UINT64_MAX - 1, UINT64_MAX, overflow) == UINT64_MAX); + assert(overflow); + assert(subu((uint64_t)0, (uint64_t)0, overflow) == 0); + assert(overflow); // sticky +} +#endif + + +/*********************************************** + * Negate an integer. + * + * Params: + * x = operand + * overflow = set if x cannot be negated, is not affected otherwise + * Returns: + * the negation of x + */ + +int negs(int x, bool& overflow) +{ + if (x == (int)INT32_MIN) + overflow = true; + return -x; +} + +#ifdef DEBUG +void unittest9() +{ + bool overflow = false; + assert(negs(0, overflow) == -0); + assert(!overflow); + assert(negs(1234, overflow) == -1234); + assert(!overflow); + assert(negs(-5678, overflow) == 5678); + assert(!overflow); + assert(negs((int)INT32_MIN, overflow) == -INT32_MIN); + assert(overflow); + assert(negs(0, overflow) == -0); + assert(overflow); // sticky +} +#endif + +/// ditto +int64_t negs(int64_t x, bool& overflow) +{ + if (x == INT64_MIN) + overflow = true; + return -x; +} + +#ifdef DEBUG +void unittest10() +{ + bool overflow = false; + assert(negs((int64_t)0, overflow) == -0); + assert(!overflow); + assert(negs((int64_t)1234, overflow) == -1234); + assert(!overflow); + assert(negs((int64_t)-5678, overflow) == 5678); + assert(!overflow); + assert(negs(INT64_MIN, overflow) == -INT64_MIN); + assert(overflow); + assert(negs((int64_t)0, overflow) == -0); + assert(overflow); // sticky +} +#endif + + +/******************************* + * Multiply two signed integers, checking for overflow. + * + * The overflow is sticky, meaning a sequence of operations can + * be done and overflow need only be checked at the end. + * Params: + * x = left operand + * y = right operand + * overflow = set if an overflow occurs, is not affected otherwise + * Returns: + * the sum + */ + +int muls(int x, int y, bool& overflow) +{ + int64_t r = (int64_t)x * (int64_t)y; + if (r < INT32_MIN || r > INT32_MAX) + overflow = true; + return (int)r; +} + +#ifdef DEBUG +void unittest11() +{ + bool overflow = false; + assert(muls(2, 3, overflow) == 6); + assert(!overflow); + assert(muls(-200, 300, overflow) == -60000); + assert(!overflow); + assert(muls(1, INT32_MAX, overflow) == INT32_MAX); + assert(!overflow); + assert(muls(INT32_MIN, 1, overflow) == INT32_MIN); + assert(!overflow); + assert(muls(INT32_MAX, 2, overflow) == (INT32_MAX * 2)); + assert(overflow); + overflow = false; + assert(muls(INT32_MIN, -1, overflow) == INT32_MIN); + assert(overflow); + assert(muls(0, 0, overflow) == 0); + assert(overflow); // sticky +} +#endif + +/// ditto +int64_t muls(int64_t x, int64_t y, bool& overflow) +{ + int64_t r = (uint64_t)x * (uint64_t)y; + if (x && (r / x) != y) + overflow = true; + return r; +} + +#ifdef DEBUG +void unittest12() +{ + bool overflow = false; + assert(muls((int64_t)2, (int64_t)3, overflow) == 6); + assert(!overflow); + assert(muls((int64_t)-200, (int64_t)300, overflow) == -60000); + assert(!overflow); + assert(muls((int64_t)1, INT64_MAX, overflow) == INT64_MAX); + assert(!overflow); + assert(muls(INT64_MIN, (int64_t)1, overflow) == INT64_MIN); + assert(!overflow); + assert(muls(INT64_MAX, (int64_t)2, overflow) == (INT64_MAX * 2)); + assert(overflow); + overflow = false; + assert(muls(INT64_MIN, (int64_t)-1, overflow) == INT64_MIN); + assert(overflow); + assert(muls((int64_t)0, (int64_t)0, overflow) == 0); + assert(overflow); // sticky +} +#endif + + +/******************************* + * Multiply two unsigned integers, checking for overflow (aka carry). + * + * The overflow is sticky, meaning a sequence of operations can + * be done and overflow need only be checked at the end. + * Params: + * x = left operand + * y = right operand + * overflow = set if an overflow occurs, is not affected otherwise + * Returns: + * the sum + */ + +unsigned mulu(unsigned x, unsigned y, bool& overflow) +{ + unsigned r = x * y; + if (r && (r < x || r < y)) + overflow = true; + return r; +} + +#ifdef DEBUG +void unittest13() +{ + bool overflow = false; + assert(mulu(2U, 3U, overflow) == 6); + assert(!overflow); + assert(mulu(1U, UINT32_MAX, overflow) == UINT32_MAX); + assert(!overflow); + assert(mulu(0U, 1U, overflow) == 0); + assert(!overflow); + assert(mulu(UINT32_MAX, 2U, overflow) == (unsigned)(UINT32_MAX * 2)); + assert(overflow); + overflow = false; + assert(mulu(0U, -1U, overflow) == 0); + assert(!overflow); + overflow = true; + assert(mulu(0U, 0U, overflow) == 0); + assert(overflow); // sticky +} +#endif + +/// ditto +uint64_t mulu(uint64_t x, uint64_t y, bool& overflow) +{ + uint64_t r = x * y; + if (r && (r < x || r < y)) + overflow = true; + return r; +} + +#ifdef DEBUG +void unittest14() +{ + bool overflow = false; + assert(mulu((uint64_t)2, (uint64_t)3, overflow) == 6); + assert(!overflow); + assert(mulu(1, UINT64_MAX, overflow) == UINT64_MAX); + assert(!overflow); + assert(mulu((uint64_t)0, 1, overflow) == 0); + assert(!overflow); + assert(mulu(UINT64_MAX, 2, overflow) == (UINT64_MAX * 2)); + assert(overflow); + overflow = false; + assert(mulu((uint64_t)0, -1, overflow) == 0); + assert(!overflow); + overflow = true; + assert(mulu((uint64_t)0, (uint64_t)0, overflow) == 0); + assert(overflow); // sticky +} +#endif + +#ifdef DEBUG +struct CheckedintUnittest +{ + CheckedintUnittest() + { + unittest1(); + unittest2(); + unittest3(); + unittest4(); + unittest5(); + unittest6(); + unittest7(); + unittest8(); + unittest9(); + unittest10(); + unittest11(); + unittest12(); + unittest13(); + } +}; + +static CheckedintUnittest unittest; +#endif + +//void main() { } diff --git a/dmd2/root/checkedint.h b/dmd2/root/checkedint.h new file mode 100644 index 0000000000..17ee3418ee --- /dev/null +++ b/dmd2/root/checkedint.h @@ -0,0 +1,24 @@ + +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif +#include + + +int adds(int x, int y, bool& overflow); +int64_t adds(int64_t x, int64_t y, bool& overflow); +unsigned addu(unsigned x, unsigned y, bool& overflow); +uint64_t addu(uint64_t x, uint64_t y, bool& overflow); + +int subs(int x, int y, bool& overflow); +int64_t subs(int64_t x, int64_t y, bool& overflow); +unsigned subu(unsigned x, unsigned y, bool& overflow); +uint64_t subu(uint64_t x, uint64_t y, bool& overflow); + +int negs(int x, bool& overflow); +int64_t negs(int64_t x, bool& overflow); + +int muls(int x, int y, bool& overflow); +int64_t muls(int64_t x, int64_t y, bool& overflow); +unsigned mulu(unsigned x, unsigned y, bool& overflow); +uint64_t mulu(uint64_t x, uint64_t y, bool& overflow); diff --git a/dmd2/root/file.c b/dmd2/root/file.c index 369698f31c..d124418534 100644 --- a/dmd2/root/file.c +++ b/dmd2/root/file.c @@ -279,7 +279,7 @@ int File::write() char *name; name = this->name->toChars(); - fd = open(name, O_CREAT | O_WRONLY | O_TRUNC, 0644); + fd = open(name, O_CREAT | O_WRONLY | O_TRUNC, (6 << 6) | (4 << 3) | 4); if (fd == -1) goto err; diff --git a/dmd2/root/filename.c b/dmd2/root/filename.c index 75ecd78842..c5cc39ff42 100644 --- a/dmd2/root/filename.c +++ b/dmd2/root/filename.c @@ -127,8 +127,14 @@ Strings *FileName::splitPath(const char *path) #if POSIX case '~': - buf.writestring(getenv("HOME")); + { + char *home = getenv("HOME"); + if (home) + buf.writestring(home); + else + buf.writestring("~"); continue; + } #endif #if 0 @@ -600,7 +606,7 @@ int FileName::ensurePathExists(const char *path) int r = _mkdir(path); #endif #if POSIX - int r = mkdir(path, 0777); + int r = mkdir(path, (7 << 6) | (7 << 3) | 7); #endif if (r) { diff --git a/dmd2/root/port.c b/dmd2/root/port.c index 836d5184f5..381f5e1e7e 100644 --- a/dmd2/root/port.c +++ b/dmd2/root/port.c @@ -29,6 +29,9 @@ double Port::dbl_max = DBL_MAX; double Port::dbl_min = DBL_MIN; longdouble Port::ldbl_max = LDBL_MAX; +bool Port::yl2x_supported = true; +bool Port::yl2xp1_supported = true; + struct PortInitializer { PortInitializer(); @@ -95,6 +98,16 @@ int Port::fequal(longdouble x, longdouble y) return memcmp(&x, &y, 10) == 0; } +void Port::yl2x_impl(longdouble* x, longdouble* y, longdouble* res) +{ + *res = _inline_yl2x(*x, *y); +} + +void Port::yl2xp1_impl(longdouble* x, longdouble* y, longdouble* res) +{ + *res = _inline_yl2xp1(*x, *y); +} + char *Port::strupr(char *s) { return ::strupr(s); @@ -158,6 +171,10 @@ longdouble Port::strtold(const char *buffer, char **endp) #include // for std::numeric_limits #include "target.h" +#if IN_LLVM +#include "llvm/Support/ErrorHandling.h" +#endif + double Port::nan; longdouble Port::ldbl_nan; longdouble Port::snan; @@ -169,6 +186,19 @@ double Port::dbl_max = DBL_MAX; double Port::dbl_min = DBL_MIN; longdouble Port::ldbl_max = LDBL_MAX; +#if IN_LLVM +bool Port::yl2x_supported = false; +bool Port::yl2xp1_supported = false; +#else +#if _M_IX86 || _M_X64 +bool Port::yl2x_supported = true; +bool Port::yl2xp1_supported = true; +#else +bool Port::yl2x_supported = false; +bool Port::yl2xp1_supported = false; +#endif +#endif + struct PortInitializer { PortInitializer(); @@ -254,6 +284,78 @@ int Port::fequal(longdouble x, longdouble y) return memcmp(&x, &y, Target::realsize - Target::realpad) == 0; } +#if IN_LLVM +void Port::yl2x_impl(longdouble* x, longdouble* y, longdouble* res) +{ + llvm_unreachable("Port::yl2x_impl"); +} + +void Port::yl2xp1_impl(longdouble* x, longdouble* y, longdouble* res) +{ + llvm_unreachable("Port::yl2xp1_impl"); +} +#else +#if _M_IX86 +void Port::yl2x_impl(longdouble* x, longdouble* y, longdouble* res) +{ + __asm + { + mov eax, y + mov ebx, x + mov ecx, res + fld tbyte ptr [eax] + fld tbyte ptr [ebx] + fyl2x + fstp tbyte ptr [ecx] + } +} + +void Port::yl2xp1_impl(longdouble* x, longdouble* y, longdouble* res) +{ + __asm + { + mov eax, y + mov ebx, x + mov ecx, res + fld tbyte ptr [eax] + fld tbyte ptr [ebx] + fyl2xp1 + fstp tbyte ptr [ecx] + } +} +#elif _M_X64 + +//defined in ldfpu.asm +extern "C" +{ + void ld_yl2x(longdouble *x, longdouble *y, longdouble *r); + void ld_yl2xp1(longdouble *x, longdouble *y, longdouble *r); +} + +void Port::yl2x_impl(longdouble* x, longdouble* y, longdouble* res) +{ + ld_yl2x(x, y, res); +} + +void Port::yl2xp1_impl(longdouble* x, longdouble* y, longdouble* res) +{ + ld_yl2xp1(x, y, res); +} +#else + +void Port::yl2x_impl(longdouble* x, longdouble* y, longdouble* res) +{ + assert(0); +} + +void Port::yl2xp1_impl(longdouble* x, longdouble* y, longdouble* res) +{ + assert(0); +} + +#endif +#endif + char *Port::strupr(char *s) { return ::strupr(s); @@ -319,6 +421,14 @@ double Port::dbl_max = 1.7976931348623157e308; double Port::dbl_min = 5e-324; longdouble Port::ldbl_max = LDBL_MAX; +#if _X86_ || __x86_64__ +bool Port::yl2x_supported = true; +bool Port::yl2xp1_supported = true; +#else +bool Port::yl2x_supported = false; +bool Port::yl2xp1_supported = false; +#endif + struct PortInitializer { PortInitializer(); @@ -401,6 +511,28 @@ int Port::fequal(longdouble x, longdouble y) return memcmp(&x, &y, 10) == 0; } +#if _X86_ || __x86_64__ +void Port::yl2x_impl(longdouble* x, longdouble* y, longdouble* res) +{ + __asm__ volatile("fyl2x": "=t" (*res): "u" (*y), "0" (*x) : "st(1)" ); +} + +void Port::yl2xp1_impl(longdouble* x, longdouble* y, longdouble* res) +{ + __asm__ volatile("fyl2xp1": "=t" (*res): "u" (*y), "0" (*x) : "st(1)" ); +} +#else +void Port::yl2x_impl(longdouble* x, longdouble* y, longdouble* res) +{ + assert(0); +} + +void Port::yl2xp1_impl(longdouble* x, longdouble* y, longdouble* res) +{ + assert(0); +} +#endif + char *Port::strupr(char *s) { char *t = s; @@ -507,6 +639,14 @@ double Port::dbl_max = 1.7976931348623157e308; double Port::dbl_min = 5e-324; longdouble Port::ldbl_max = LDBL_MAX; +#if __i386 || __x86_64__ +bool Port::yl2x_supported = true; +bool Port::yl2xp1_supported = true; +#else +bool Port::yl2x_supported = false; +bool Port::yl2xp1_supported = false; +#endif + struct PortInitializer { PortInitializer(); @@ -694,6 +834,28 @@ int Port::fequal(longdouble x, longdouble y) return memcmp(&x, &y, Target::realsize - Target::realpad) == 0; } +#if __i386 || __x86_64__ +void Port::yl2x_impl(longdouble* x, longdouble* y, longdouble* res) +{ + __asm__ volatile("fyl2x": "=t" (*res): "u" (*y), "0" (*x) : "st(1)" ); +} + +void Port::yl2xp1_impl(longdouble* x, longdouble* y, longdouble* res) +{ + __asm__ volatile("fyl2xp1": "=t" (*res): "u" (*y), "0" (*x) : "st(1)" ); +} +#else +void Port::yl2x_impl(longdouble* x, longdouble* y, longdouble* res) +{ + assert(0); +} + +void Port::yl2xp1_impl(longdouble* x, longdouble* y, longdouble* res) +{ + assert(0); +} +#endif + char *Port::strupr(char *s) { char *t = s; @@ -794,6 +956,14 @@ double Port::dbl_max = 1.7976931348623157e308; double Port::dbl_min = 5e-324; longdouble Port::ldbl_max = LDBL_MAX; +#if __i386 || __x86_64__ +bool Port::yl2x_supported = true; +bool Port::yl2xp1_supported = true; +#else +bool Port::yl2x_supported = false; +bool Port::yl2xp1_supported = false; +#endif + struct PortInitializer { PortInitializer(); @@ -875,6 +1045,72 @@ int Port::fequal(longdouble x, longdouble y) */ return memcmp(&x, &y, 10) == 0; } +#if __i386 +void Port::yl2x_impl(long double* x, long double* y, long double* res) +{ + __asm__ volatile("movl %0, %%eax;" // move x, y, res to registers + "movl %1, %%ebx;" + "movl %2, %%ecx;" + "fldt (%%ebx);" // push *y and *x to the FPU stack + "fldt (%%eax);" // "t" suffix means tbyte + "fyl2x;" // do operation and wait + "fstpt (%%ecx)" // pop result to a *res + : // output: empty + :"r"(x), "r"(y), "r"(res) // input: x => %0, y => %1, res => %2 + :"%eax", "%ebx", "%ecx"); // clobbered register: eax, ebc, ecx +} + +void Port::yl2xp1_impl(long double* x, long double* y, long double* res) +{ + __asm__ volatile("movl %0, %%eax;" // move x, y, res to registers + "movl %1, %%ebx;" + "movl %2, %%ecx;" + "fldt (%%ebx);" // push *y and *x to the FPU stack + "fldt (%%eax);" // "t" suffix means tbyte + "yl2xp1;" // do operation and wait + "fstpt (%%ecx)" // pop result to a *res + : // output: empty + :"r"(x), "r"(y), "r"(res) // input: x => %0, y => %1, res => %2 + :"%eax", "%ebx", "%ecx"); // clobbered register: eax, ebc, ecx +#elif __x86_64__ +void Port::yl2x_impl(long double* x, long double* y, long double* res) +{ + __asm__ volatile("movq %0, %%rcx;" // move x, y, res to registers + "movq %1, %%rdx;" + "movq %2, %%r8;" + "fldt (%%rdx);" // push *y and *x to the FPU stack + "fldt (%%rcx);" // "t" suffix means tbyte + "fyl2x;" // do operation and wait + "fstpt (%%r8)" // pop result to a *res + : // output: empty + :"r"(x), "r"(y), "r"(res) // input: x => %0, y => %1, res => %2 + :"%rcx", "%rdx", "%r8"); // clobbered register: rcx, rdx, r8 +} + +void Port::yl2xp1_impl(long double* x, long double* y, long double* res) +{ + __asm__ volatile("movq %0, %%rcx;" // move x, y, res to registers + "movq %1, %%rdx;" + "movq %2, %%r8;" + "fldt (%%rdx);" // push *y and *x to the FPU stack + "fldt (%%rcx);" // "t" suffix means tbyte + "yl2xp1;" // do operation and wait + "fstpt (%%r8)" // pop result to a *res + : // output: empty + :"r"(x), "r"(y), "r"(res) // input: x => %0, y => %1, res => %2 + :"%rcx", "%rdx", "%r8"); // clobbered register: rcx, rdx, r8 +} +#else +void Port::yl2x_impl(longdouble* x, longdouble* y, longdouble* res) +{ + assert(0); +} + +void Port::yl2xp1_impl(longdouble* x, longdouble* y, longdouble* res) +{ + assert(0); +} +#endif char *Port::strupr(char *s) { diff --git a/dmd2/root/port.h b/dmd2/root/port.h index 12da99f44b..1631c0b01f 100644 --- a/dmd2/root/port.h +++ b/dmd2/root/port.h @@ -46,6 +46,9 @@ struct Port static double dbl_min; static longdouble ldbl_max; + static bool yl2x_supported; + static bool yl2xp1_supported; + static int isNan(double); static int isNan(longdouble); @@ -58,6 +61,9 @@ struct Port static longdouble sqrt(longdouble x); static int fequal(longdouble x, longdouble y); + static void yl2x_impl(longdouble* x, longdouble* y, longdouble* res); + static void yl2xp1_impl(longdouble* x, longdouble* y, longdouble* res); + static char *strupr(char *); static int memicmp(const char *s1, const char *s2, int n); diff --git a/dmd2/root/rmem.h b/dmd2/root/rmem.h index c4f784a044..5f5b83f8ba 100644 --- a/dmd2/root/rmem.h +++ b/dmd2/root/rmem.h @@ -1,11 +1,11 @@ - +// Compiler implementation of the D programming language // Copyright (c) 2000-2012 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. +// Distributed under the Boost Software License, Version 1.0. +// http://www.boost.org/LICENSE_1_0.txt +// https://github.com/D-Programming-Language/dmd/blob/master/src/root/rmem.h #ifndef ROOT_MEM_H #define ROOT_MEM_H diff --git a/dmd2/root/stringtable.c b/dmd2/root/stringtable.c index 8777cd281a..61377eb309 100644 --- a/dmd2/root/stringtable.c +++ b/dmd2/root/stringtable.c @@ -16,184 +16,208 @@ #include "rmem.h" // mem #include "stringtable.h" +#define POOL_BITS 12 +#define POOL_SIZE (1U << POOL_BITS) + // TODO: Merge with root.String -hash_t calcHash(const char *str, size_t len) +// MurmurHash2 was written by Austin Appleby, and is placed in the public +// domain. The author hereby disclaims copyright to this source code. +// https://sites.google.com/site/murmurhash/ +static uint32_t calcHash(const char *key, size_t len) { - hash_t hash = 0; + // 'm' and 'r' are mixing constants generated offline. + // They're not really 'magic', they just happen to work well. - union + const uint32_t m = 0x5bd1e995; + const int r = 24; + + // Initialize the hash to a 'random' value + + uint32_t h = len; + + // Mix 4 bytes at a time into the hash + + const uint8_t *data = (const uint8_t *)key; + + while(len >= 4) { - uint8_t scratchB[4]; - uint16_t scratchS[2]; - uint32_t scratchI; - }; - - while (1) - { - switch (len) - { - case 0: - return hash; +#if defined _M_I86 || defined _M_AMD64 || defined __i386 || defined __x86_64 + uint32_t k = *(uint32_t *)data; // possibly unaligned load +#else + uint32_t k = data[3] << 24 | data[2] << 16 | data[1] << 8 | data[0]; +#endif - case 1: - hash *= 37; - hash += *(const uint8_t *)str; - return hash; + k *= m; + k ^= k >> r; + k *= m; - case 2: - hash *= 37; - scratchB[0] = str[0]; - scratchB[1] = str[1]; - hash += scratchS[0]; - return hash; + h *= m; + h ^= k; - case 3: - hash *= 37; - scratchB[0] = str[0]; - scratchB[1] = str[1]; - hash += (scratchS[0] << 8) + - ((const uint8_t *)str)[2]; - return hash; - - default: - hash *= 37; - scratchB[0] = str[0]; - scratchB[1] = str[1]; - scratchB[2] = str[2]; - scratchB[3] = str[3]; - hash += scratchI; - str += 4; - len -= 4; - break; - } + data += 4; + len -= 4; } + + // Handle the last few bytes of the input array + + switch(len & 3) + { + case 3: h ^= data[2] << 16; + case 2: h ^= data[1] << 8; + case 1: h ^= data[0]; + h *= m; + }; + + // Do a few final mixes of the hash to ensure the last few + // bytes are well-incorporated. + + h ^= h >> 13; + h *= m; + h ^= h >> 15; + + return h; } -static int hashCmp(hash_t lhs, hash_t rhs) +struct StringEntry { - if (lhs == rhs) - return 0; - else if (lhs < rhs) - return -1; - return 1; + uint32_t hash, vptr; +}; + +uint32_t StringTable::allocValue(const char *s, size_t length) +{ + const size_t nbytes = sizeof(StringValue) + length + 1; + + if (!npools || nfill + nbytes > POOL_SIZE) + { + pools = (uint8_t **)mem.realloc(pools, ++npools * sizeof(pools[0])); + pools[npools - 1] = (uint8_t *)mem.malloc(nbytes > POOL_SIZE ? nbytes : POOL_SIZE); + nfill = 0; + } + + StringValue *sv = (StringValue *)&pools[npools - 1][nfill]; + sv->ptrvalue = NULL; + sv->length = length; + ::memcpy(sv->lstring, s, length); + sv->lstring[length] = 0; + + const uint32_t vptr = npools << POOL_BITS | nfill; + nfill += nbytes + (-nbytes & 7); // align to 8 bytes + return vptr; } -void StringValue::ctor(const char *p, size_t length) +StringValue *StringTable::getValue(uint32_t vptr) { - this->length = length; - this->lstring[length] = 0; - memcpy(this->lstring, p, length * sizeof(char)); + if (!vptr) return NULL; + + const size_t idx = (vptr >> POOL_BITS) - 1; + const size_t off = vptr & POOL_SIZE - 1; + return (StringValue *)&pools[idx][off]; } +static size_t nextpow2(size_t val) +{ + size_t res = 1; + while (res < val) + res <<= 1; + return res; +} + +static const double loadFactor = 0.8; + void StringTable::_init(size_t size) { - table = (void **)mem.calloc(size, sizeof(void *)); + size = nextpow2((size_t)(size / loadFactor)); + if (size < 32) size = 32; + table = (StringEntry *)mem.calloc(size, sizeof(table[0])); tabledim = size; + pools = NULL; + npools = nfill = 0; count = 0; } StringTable::~StringTable() { - // Zero out dangling pointers to help garbage collector. - // Should zero out StringEntry's too. - for (size_t i = 0; i < count; i++) - table[i] = NULL; + for (size_t i = 0; i < npools; ++i) + mem.free(pools[i]); mem.free(table); + mem.free(pools); table = NULL; + pools = NULL; } -struct StringEntry +size_t StringTable::findSlot(hash_t hash, const char *s, size_t length) { - StringEntry *left; - StringEntry *right; - hash_t hash; - - StringValue value; - - static StringEntry *alloc(const char *s, size_t len); -}; - -StringEntry *StringEntry::alloc(const char *s, size_t len) -{ - StringEntry *se; - - se = (StringEntry *) mem.calloc(1,sizeof(StringEntry) + len + 1); - se->value.ctor(s, len); - se->hash = calcHash(s,len); - return se; -} - -void **StringTable::search(const char *s, size_t len) -{ - hash_t hash; - unsigned u; - int cmp; - StringEntry **se; - - //printf("StringTable::search(%p,%d)\n",s,len); - hash = calcHash(s,len); - u = hash % tabledim; - se = (StringEntry **)&table[u]; - //printf("\thash = %d, u = %d\n",hash,u); - while (*se) + // quadratic probing using triangular numbers + // http://stackoverflow.com/questions/2348187/moving-from-linear-probing-to-quadratic-probing-hash-collisons/2349774#2349774 + for (size_t i = hash & (tabledim - 1), j = 1; ;++j) { - cmp = hashCmp((*se)->hash, hash); - if (cmp == 0) + StringValue *sv; + if (!table[i].vptr || + table[i].hash == hash && + (sv = getValue(table[i].vptr))->length == length && + ::memcmp(s, sv->lstring, length) == 0) + return i; + i = (i + j) & (tabledim - 1); + } +} + +StringValue *StringTable::lookup(const char *s, size_t length) +{ + const hash_t hash = calcHash(s, length); + const size_t i = findSlot(hash, s, length); + // printf("lookup %.*s %p\n", (int)length, s, table[i].value ?: NULL); + return getValue(table[i].vptr); +} + +StringValue *StringTable::update(const char *s, size_t length) +{ + const hash_t hash = calcHash(s, length); + size_t i = findSlot(hash, s, length); + if (!table[i].vptr) + { + if (++count > tabledim * loadFactor) { - cmp = (*se)->value.len() - len; - if (cmp == 0) - { - cmp = ::memcmp(s,(*se)->value.toDchars(),len); - if (cmp == 0) - break; - } + grow(); + i = findSlot(hash, s, length); } - if (cmp < 0) - se = &(*se)->left; - else - se = &(*se)->right; + table[i].hash = hash; + table[i].vptr = allocValue(s, length); } - //printf("\treturn %p, %p\n",se, (*se)); - return (void **)se; + // printf("update %.*s %p\n", (int)length, s, table[i].value ?: NULL); + return getValue(table[i].vptr); } -StringValue *StringTable::lookup(const char *s, size_t len) -{ StringEntry *se; - - se = *(StringEntry **)search(s,len); - if (se) - return &se->value; - else - return NULL; -} - -StringValue *StringTable::update(const char *s, size_t len) -{ StringEntry **pse; - StringEntry *se; - - pse = (StringEntry **)search(s,len); - se = *pse; - if (!se) // not in table: so create new entry +StringValue *StringTable::insert(const char *s, size_t length) +{ + const hash_t hash = calcHash(s, length); + size_t i = findSlot(hash, s, length); + if (table[i].vptr) + return NULL; // already in table + if (++count > tabledim * loadFactor) { - se = StringEntry::alloc(s, len); - *pse = se; + grow(); + i = findSlot(hash, s, length); } - return &se->value; + table[i].hash = hash; + table[i].vptr = allocValue(s, length); + // printf("insert %.*s %p\n", (int)length, s, table[i].value ?: NULL); + return getValue(table[i].vptr); } -StringValue *StringTable::insert(const char *s, size_t len) -{ StringEntry **pse; - StringEntry *se; +void StringTable::grow() +{ + const size_t odim = tabledim; + StringEntry *otab = table; + tabledim *= 2; + table = (StringEntry *)mem.calloc(tabledim, sizeof(table[0])); - pse = (StringEntry **)search(s,len); - se = *pse; - if (se) - return NULL; // error: already in table - else + for (size_t i = 0; i < odim; ++i) { - se = StringEntry::alloc(s, len); - *pse = se; + StringEntry &se = otab[i]; + if (!se.vptr) continue; + StringValue *sv = getValue(se.vptr); + table[findSlot(se.hash, sv->lstring, sv->length)] = se; } - return &se->value; + mem.free(otab); } diff --git a/dmd2/root/stringtable.h b/dmd2/root/stringtable.h index 92ce68926f..9aa4c88659 100644 --- a/dmd2/root/stringtable.h +++ b/dmd2/root/stringtable.h @@ -40,21 +40,23 @@ public: const char *toDchars() const { return lstring; } private: - friend struct StringEntry; + friend struct StringTable; StringValue(); // not constructible - // This is more like a placement new c'tor - void ctor(const char *p, size_t length); }; struct StringTable { private: - void **table; - size_t count; + StringEntry *table; size_t tabledim; + uint8_t **pools; + size_t npools, nfill; + + size_t count; + public: - void _init(size_t size = 37); + void _init(size_t size = 0); ~StringTable(); StringValue *lookup(const char *s, size_t len); @@ -62,7 +64,10 @@ public: StringValue *update(const char *s, size_t len); private: - void **search(const char *s, size_t len); + uint32_t allocValue(const char *p, size_t length); + StringValue *getValue(uint32_t validx); + size_t findSlot(hash_t hash, const char *s, size_t len); + void grow(); }; #endif diff --git a/dmd2/scope.c b/dmd2/scope.c index 1267dc9d8f..d15528cba8 100644 --- a/dmd2/scope.c +++ b/dmd2/scope.c @@ -62,6 +62,7 @@ Scope::Scope() this->tf = NULL; this->os = NULL; this->tinst = NULL; + this->minst = NULL; this->sbreak = NULL; this->scontinue = NULL; this->fes = NULL; @@ -70,7 +71,7 @@ Scope::Scope() this->func = NULL; this->slabel = NULL; this->linkage = LINKd; - this->protection = PROTpublic; + this->protection = Prot(PROTpublic); this->explicitProtection = 0; this->stc = 0; this->depmsg = NULL; @@ -78,7 +79,6 @@ Scope::Scope() this->nofree = 0; this->noctor = 0; this->intypeof = 0; - this->speculative = false; this->lastVar = NULL; this->callSuper = 0; this->fieldinit = NULL; @@ -87,6 +87,8 @@ Scope::Scope() this->lastdc = NULL; this->lastoffset = 0; this->docbuf = NULL; + this->anchorCounts = NULL; + this->prevAnchor = NULL; this->userAttribDecl = NULL; } @@ -104,15 +106,18 @@ Scope *Scope::copy() Scope *Scope::createGlobal(Module *module) { - Scope *sc; - - sc = Scope::alloc(); + Scope *sc = Scope::alloc(); memset(sc, 0, sizeof(Scope)); + sc->structalign = STRUCTALIGN_DEFAULT; sc->linkage = LINKd; - sc->protection = PROTpublic; + sc->protection = Prot(PROTpublic); sc->module = module; + + sc->tinst = NULL; + sc->minst = module; + sc->scopesym = new ScopeDsymbol(); sc->scopesym->symtab = new DsymbolTable(); @@ -150,7 +155,7 @@ Scope *Scope::push() s->slabel = NULL; s->nofree = 0; s->fieldinit = saveFieldInit(); - s->flags = (flags & (SCOPEcontract | SCOPEdebug | SCOPEctfe | SCOPEcompile)); + s->flags = (flags & (SCOPEcontract | SCOPEdebug | SCOPEctfe | SCOPEcompile | SCOPEconstraint)); s->lastdc = NULL; s->lastoffset = 0; @@ -187,7 +192,8 @@ Scope *Scope::pop() } if (!nofree) - { enclosing = freelist; + { + enclosing = freelist; freelist = this; flags |= SCOPEfree; } @@ -216,7 +222,8 @@ Scope *Scope::startCTFE() // If a template is instantiated from CT evaluated expression, // compiler can elide its code generation. - sc->speculative = true; + sc->tinst = NULL; + sc->minst = NULL; #endif return sc; } @@ -235,7 +242,8 @@ void Scope::mergeCallSuper(Loc loc, unsigned cs) // The two paths are callSuper and cs; the result is merged into callSuper. if (cs != callSuper) - { // Have ALL branches called a constructor? + { + // Have ALL branches called a constructor? int aAll = (cs & (CSXthis_ctor | CSXsuper_ctor)) != 0; int bAll = (callSuper & (CSXthis_ctor | CSXsuper_ctor)) != 0; @@ -268,7 +276,8 @@ void Scope::mergeCallSuper(Loc loc, unsigned cs) callSuper = cs | (callSuper & (CSXany_ctor | CSXlabel)); } else - { // Both branches must have called ctors, or both not. + { + // Both branches must have called ctors, or both not. ok = (aAll == bAll); // If one returned without a ctor, we must remember that // (Don't bother if we've already found an error) @@ -302,7 +311,6 @@ bool mergeFieldInit(Loc loc, unsigned &fieldInit, unsigned fi, bool mustInit) { if (fi != fieldInit) { - // Have any branches returned? bool aRet = (fi & CSXreturn) != 0; bool bRet = (fieldInit & CSXreturn) != 0; @@ -355,59 +363,54 @@ void Scope::mergeFieldInit(Loc loc, unsigned *fies) Module *Scope::instantiatingModule() { - if (tinst && tinst->instantiatingModule) - return tinst->instantiatingModule; - return module; + // TODO: in speculative context, returning 'module' is correct? + return minst ? minst : module; } Dsymbol *Scope::search(Loc loc, Identifier *ident, Dsymbol **pscopesym) -{ Dsymbol *s; - Scope *sc; - +{ //printf("Scope::search(%p, '%s')\n", this, ident->toChars()); if (ident == Id::empty) { // Look for module scope - for (sc = this; sc; sc = sc->enclosing) + for (Scope *sc = this; sc; sc = sc->enclosing) { assert(sc != sc->enclosing); - if (sc->scopesym) + if (!sc->scopesym) + continue; + + if (Dsymbol *s = sc->scopesym->isModule()) { - s = sc->scopesym->isModule(); - if (s) - { - //printf("\tfound %s.%s\n", s->parent ? s->parent->toChars() : "", s->toChars()); - if (pscopesym) - *pscopesym = sc->scopesym; - return s; - } + //printf("\tfound %s.%s\n", s->parent ? s->parent->toChars() : "", s->toChars()); + if (pscopesym) + *pscopesym = sc->scopesym; + return s; } } return NULL; } - for (sc = this; sc; sc = sc->enclosing) + for (Scope *sc = this; sc; sc = sc->enclosing) { assert(sc != sc->enclosing); - if (sc->scopesym) - { - //printf("\tlooking in scopesym '%s', kind = '%s'\n", sc->scopesym->toChars(), sc->scopesym->kind()); - s = sc->scopesym->search(loc, ident); - if (s) - { - if (ident == Id::length && - sc->scopesym->isArrayScopeSymbol() && - sc->enclosing && - sc->enclosing->search(loc, ident, NULL)) - { - warning(s->loc, "array 'length' hides other 'length' name in outer scope"); - } + if (!sc->scopesym) + continue; - //printf("\tfound %s.%s, kind = '%s'\n", s->parent ? s->parent->toChars() : "", s->toChars(), s->kind()); - if (pscopesym) - *pscopesym = sc->scopesym; - return s; + //printf("\tlooking in scopesym '%s', kind = '%s'\n", sc->scopesym->toChars(), sc->scopesym->kind()); + if (Dsymbol *s = sc->scopesym->search(loc, ident)) + { + if (ident == Id::length && + sc->scopesym->isArrayScopeSymbol() && + sc->enclosing && + sc->enclosing->search(loc, ident, NULL)) + { + warning(s->loc, "array 'length' hides other 'length' name in outer scope"); } + + //printf("\tfound %s.%s, kind = '%s'\n", s->parent ? s->parent->toChars() : "", s->toChars(), s->kind()); + if (pscopesym) + *pscopesym = sc->scopesym; + return s; } } @@ -452,18 +455,15 @@ Dsymbol *Scope::insert(Dsymbol *s) */ ClassDeclaration *Scope::getClassScope() -{ Scope *sc; - - for (sc = this; sc; sc = sc->enclosing) +{ + for (Scope *sc = this; sc; sc = sc->enclosing) { - ClassDeclaration *cd; + if (!sc->scopesym) + continue; - if (sc->scopesym) - { - cd = sc->scopesym->isClassDeclaration(); - if (cd) - return cd; - } + ClassDeclaration *cd = sc->scopesym->isClassDeclaration(); + if (cd) + return cd; } return NULL; } @@ -473,23 +473,18 @@ ClassDeclaration *Scope::getClassScope() */ AggregateDeclaration *Scope::getStructClassScope() -{ Scope *sc; - - for (sc = this; sc; sc = sc->enclosing) +{ + for (Scope *sc = this; sc; sc = sc->enclosing) { - AggregateDeclaration *ad; + if (!sc->scopesym) + continue; - if (sc->scopesym) - { - ad = sc->scopesym->isClassDeclaration(); - if (ad) - return ad; - else - { ad = sc->scopesym->isStructDeclaration(); - if (ad) - return ad; - } - } + AggregateDeclaration *ad = sc->scopesym->isClassDeclaration(); + if (ad) + return ad; + ad = sc->scopesym->isStructDeclaration(); + if (ad) + return ad; } return NULL; } @@ -501,11 +496,11 @@ AggregateDeclaration *Scope::getStructClassScope() */ void Scope::setNoFree() -{ Scope *sc; +{ //int i = 0; //printf("Scope::setNoFree(this = %p)\n", this); - for (sc = this; sc; sc = sc->enclosing) + for (Scope *sc = this; sc; sc = sc->enclosing) { //printf("\tsc = %p\n", sc); sc->nofree = 1; @@ -518,7 +513,6 @@ void Scope::setNoFree() } } - /************************************************ * Given the failed search attempt, try to find * one with a close spelling. diff --git a/dmd2/scope.h b/dmd2/scope.h index 73f470b787..9b70fdb1e6 100644 --- a/dmd2/scope.h +++ b/dmd2/scope.h @@ -30,20 +30,21 @@ class AggregateDeclaration; class FuncDeclaration; class UserAttributeDeclaration; struct DocComment; +struct AA; class TemplateInstance; +#include "dsymbol.h" + #if IN_LLVM struct EnclosingHandler; class AnonDeclaration; #endif #if __GNUC__ -// Requires a full definition for PROT and LINK -#include "dsymbol.h" +// Requires a full definition for LINK #include "mars.h" #else enum LINK; -enum PROT; #endif #define CSXthis_ctor 1 // called this() @@ -54,20 +55,22 @@ enum PROT; #define CSXreturn 0x20 // seen a return statement #define CSXany_ctor 0x40 // either this() or super() was called +// Flags that would not be inherited beyond scope nesting #define SCOPEctor 0x0001 // constructor type -#define SCOPEstaticif 0x0002 // inside static if -#define SCOPEfree 0x0004 // is on free list -#define SCOPEstaticassert 0x0008 // inside static assert -#define SCOPEdebug 0x0010 // inside debug conditional +#define SCOPEnoaccesscheck 0x0002 // don't do access checks +#define SCOPEcondition 0x0004 // inside static if/assert condition +#define SCOPEdebug 0x0008 // inside debug conditional +// Flags that would be inherited beyond scope nesting +#define SCOPEconstraint 0x0010 // inside template constraint #define SCOPEinvariant 0x0020 // inside invariant code #define SCOPErequire 0x0040 // inside in contract code #define SCOPEensure 0x0060 // inside out contract code #define SCOPEcontract 0x0060 // [mask] we're inside contract code - #define SCOPEctfe 0x0080 // inside a ctfe-only expression -#define SCOPEnoaccesscheck 0x0100 // don't do access checks -#define SCOPEcompile 0x0200 // inside __traits(compile) +#define SCOPEcompile 0x0100 // inside __traits(compile) + +#define SCOPEfree 0x8000 // is on free list struct Scope { @@ -83,7 +86,6 @@ struct Scope SwitchStatement *sw; // enclosing switch statement TryFinallyStatement *tf; // enclosing try finally statement OnScopeStatement *os; // enclosing scope(xxx) statement - TemplateInstance *tinst; // enclosing template instance Statement *sbreak; // enclosing statement that supports "break" Statement *scontinue; // enclosing statement that supports "continue" ForeachStatement *fes; // if nested function for ForeachStatement, this is it @@ -92,9 +94,16 @@ struct Scope int nofree; // set if shouldn't free it int noctor; // set if constructor calls aren't allowed int intypeof; // in typeof(exp) - bool speculative; // in __traits(compiles) and so on VarDeclaration *lastVar; // Previous symbol used to prevent goto-skips-init + /* If minst && !tinst, it's in definitely non-speculative scope (eg. module member scope). + * If !minst && !tinst, it's in definitely speculative scope (eg. template constraint). + * If minst && tinst, it's in instantiated code scope without speculation. + * If !minst && tinst, it's in instantiated code scope with speculation. + */ + Module *minst; // root module where the instantiated templates should belong to + TemplateInstance *tinst; // enclosing template instance + unsigned callSuper; // primitive flow analysis for constructors unsigned *fieldinit; size_t fieldinit_dim; @@ -102,7 +111,7 @@ struct Scope structalign_t structalign; // alignment for struct members LINK linkage; // linkage for external functions - PROT protection; // protection for class members + Prot protection; // protection for class members int explicitProtection; // set if in an explicit protection attribute StorageClass stc; // storage class @@ -116,6 +125,8 @@ struct Scope size_t lastoffset; // offset in docbuf of where to insert next dec (for ditto) size_t lastoffset2; // offset in docbuf of where to insert next dec (for unittest) OutBuffer *docbuf; // buffer for documentation output + AA *anchorCounts; // lookup duplicate anchor name count + Identifier *prevAnchor; // qualified symbol name of last doc anchor static Scope *freelist; static Scope *alloc(); diff --git a/dmd2/statement.c b/dmd2/statement.c index b9810f73c9..b525424f9b 100644 --- a/dmd2/statement.c +++ b/dmd2/statement.c @@ -33,7 +33,7 @@ #include "import.h" bool walkPostorder(Statement *s, StoppableVisitor *v); -bool isNonAssignmentArrayOp(Expression *e); +StorageClass mergeFuncAttrs(StorageClass s1, FuncDeclaration *f); Identifier *fixupLabelName(Scope *sc, Identifier *ident) { @@ -696,12 +696,14 @@ int Statement::blockExit(FuncDeclaration *func, bool mustNotThrow) result = s->statement ? s->statement->blockExit(func, mustNotThrow) : BEfallthru; } - void visit(AsmStatement *s) + void visit(CompoundAsmStatement *s) { - if (mustNotThrow) - s->error("asm statements are assumed to throw", s->toChars()); + if (mustNotThrow && !(s->stc & STCnothrow)) + s->deprecation("asm statement is assumed to throw - mark it with 'nothrow' if it does not"); + // Assume the worst - result = BEfallthru | BEthrow | BEreturn | BEgoto | BEhalt; + result = BEfallthru | BEreturn | BEgoto | BEhalt; + if (!(s->stc & STCnothrow)) result |= BEthrow; } #if IN_LLVM @@ -815,9 +817,7 @@ ExpStatement *ExpStatement::create(Loc loc, Expression *exp) Statement *ExpStatement::syntaxCopy() { - Expression *e = exp ? exp->syntaxCopy() : NULL; - ExpStatement *es = new ExpStatement(loc, e); - return es; + return new ExpStatement(loc, exp ? exp->syntaxCopy() : NULL); } Statement *ExpStatement::semantic(Scope *sc) @@ -914,9 +914,7 @@ DtorExpStatement::DtorExpStatement(Loc loc, Expression *exp, VarDeclaration *v) Statement *DtorExpStatement::syntaxCopy() { - Expression *e = exp ? exp->syntaxCopy() : NULL; - DtorExpStatement *es = new DtorExpStatement(loc, e, var); - return es; + return new DtorExpStatement(loc, exp ? exp->syntaxCopy() : NULL, var); } /******************************** CompileStatement ***************************/ @@ -929,9 +927,7 @@ CompileStatement::CompileStatement(Loc loc, Expression *exp) Statement *CompileStatement::syntaxCopy() { - Expression *e = exp->syntaxCopy(); - CompileStatement *es = new CompileStatement(loc, e); - return es; + return new CompileStatement(loc, exp->syntaxCopy()); } Statements *CompileStatement::flatten(Scope *sc) @@ -952,15 +948,18 @@ Statements *CompileStatement::flatten(Scope *sc) else { se = se->toUTF8(sc); + unsigned errors = global.errors; Parser p(loc, sc->module, (utf8_t *)se->string, se->len, 0); p.nextToken(); while (p.token.value != TOKeof) { - unsigned errors = global.errors; Statement *s = p.parseStatement(PSsemi | PScurlyscope); - if (!s || global.errors != errors) + if (!s || p.errors) + { + assert(!p.errors || global.errors != errors); // make sure we caught all the cases goto Lerror; + } a->push(s); } return a; @@ -1015,16 +1014,13 @@ Statement *CompoundStatement::syntaxCopy() Statements *a = new Statements(); a->setDim(statements->dim); for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (*statements)[i]; - if (s) - s = s->syntaxCopy(); - (*a)[i] = s; + { + Statement *s = (*statements)[i]; + (*a)[i] = s ? s->syntaxCopy() : NULL; } - CompoundStatement *cs = new CompoundStatement(loc, a); - return cs; + return new CompoundStatement(loc, a); } - Statement *CompoundStatement::semantic(Scope *sc) { //printf("CompoundStatement::semantic(this = %p, sc = %p)\n", this, sc); @@ -1238,13 +1234,11 @@ Statement *CompoundDeclarationStatement::syntaxCopy() Statements *a = new Statements(); a->setDim(statements->dim); for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (*statements)[i]; - if (s) - s = s->syntaxCopy(); - (*a)[i] = s; + { + Statement *s = (*statements)[i]; + (*a)[i] = s ? s->syntaxCopy() : NULL; } - CompoundDeclarationStatement *cs = new CompoundDeclarationStatement(loc, a); - return cs; + return new CompoundDeclarationStatement(loc, a); } /**************************** UnrolledLoopStatement ***************************/ @@ -1260,16 +1254,13 @@ Statement *UnrolledLoopStatement::syntaxCopy() Statements *a = new Statements(); a->setDim(statements->dim); for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (*statements)[i]; - if (s) - s = s->syntaxCopy(); - (*a)[i] = s; + { + Statement *s = (*statements)[i]; + (*a)[i] = s ? s->syntaxCopy() : NULL; } - UnrolledLoopStatement *cs = new UnrolledLoopStatement(loc, a); - return cs; + return new UnrolledLoopStatement(loc, a); } - Statement *UnrolledLoopStatement::semantic(Scope *sc) { //printf("UnrolledLoopStatement::semantic(this = %p, sc = %p)\n", this, sc); @@ -1316,11 +1307,7 @@ ScopeStatement::ScopeStatement(Loc loc, Statement *s) Statement *ScopeStatement::syntaxCopy() { - Statement *s; - - s = statement ? statement->syntaxCopy() : NULL; - s = new ScopeStatement(loc, s); - return s; + return new ScopeStatement(loc, statement ? statement->syntaxCopy() : NULL); } ReturnStatement *ScopeStatement::isReturnStatement() @@ -1397,11 +1384,11 @@ WhileStatement::WhileStatement(Loc loc, Expression *c, Statement *b) Statement *WhileStatement::syntaxCopy() { - WhileStatement *s = new WhileStatement(loc, condition->syntaxCopy(), body ? body->syntaxCopy() : NULL); - return s; + return new WhileStatement(loc, + condition->syntaxCopy(), + body ? body->syntaxCopy() : NULL); } - Statement *WhileStatement::semantic(Scope *sc) { /* Rewrite as a for(;condition;) loop @@ -1433,11 +1420,11 @@ DoStatement::DoStatement(Loc loc, Statement *b, Expression *c) Statement *DoStatement::syntaxCopy() { - DoStatement *s = new DoStatement(loc, body ? body->syntaxCopy() : NULL, condition->syntaxCopy()); - return s; + return new DoStatement(loc, + body ? body->syntaxCopy() : NULL, + condition->syntaxCopy()); } - Statement *DoStatement::semantic(Scope *sc) { sc->noctor++; @@ -1484,17 +1471,11 @@ ForStatement::ForStatement(Loc loc, Statement *init, Expression *condition, Expr Statement *ForStatement::syntaxCopy() { - Statement *i = NULL; - if (init) - i = init->syntaxCopy(); - Expression *c = NULL; - if (condition) - c = condition->syntaxCopy(); - Expression *inc = NULL; - if (increment) - inc = increment->syntaxCopy(); - ForStatement *s = new ForStatement(loc, i, c, inc, body->syntaxCopy()); - return s; + return new ForStatement(loc, + init ? init->syntaxCopy() : NULL, + condition ? condition->syntaxCopy() : NULL, + increment ? increment->syntaxCopy() : NULL, + body->syntaxCopy()); } Statement *ForStatement::semantic(Scope *sc) @@ -1609,11 +1590,10 @@ ForeachStatement::ForeachStatement(Loc loc, TOK op, Parameters *arguments, Statement *ForeachStatement::syntaxCopy() { - Parameters *args = Parameter::arraySyntaxCopy(arguments); - Expression *exp = aggr->syntaxCopy(); - ForeachStatement *s = new ForeachStatement(loc, op, args, exp, + return new ForeachStatement(loc, op, + Parameter::arraySyntaxCopy(arguments), + aggr->syntaxCopy(), body ? body->syntaxCopy() : NULL); - return s; } Statement *ForeachStatement::semantic(Scope *sc) @@ -1634,8 +1614,12 @@ Statement *ForeachStatement::semantic(Scope *sc) if (!inferAggregate(this, sc, sapply)) { - error("invalid foreach aggregate %s", aggr->toChars()); - Lerror: + const char *msg = ""; + if (aggr->type && isAggregate(aggr->type)) + { + msg = ", define opApply(), range primitives, or use .tupleof"; + } + error("invalid foreach aggregate %s%s", aggr->toChars(), msg); return new ErrorStatement(); } @@ -1683,7 +1667,7 @@ Statement *ForeachStatement::semantic(Scope *sc) else error("cannot uniquely infer foreach argument types"); - goto Lerror; + return new ErrorStatement(); } Type *tab = aggr->type->toBasetype(); @@ -1693,7 +1677,7 @@ Statement *ForeachStatement::semantic(Scope *sc) if (dim < 1 || dim > 2) { error("only one (value) or two (key,value) arguments for tuple foreach"); - goto Lerror; + return new ErrorStatement(); } Type *argtype = (*arguments)[dim-1]->type; @@ -1701,7 +1685,7 @@ Statement *ForeachStatement::semantic(Scope *sc) { argtype = argtype->semantic(loc, sc); if (argtype->ty == Terror) - goto Lerror; + return new ErrorStatement(); } TypeTuple *tuple = (TypeTuple *)tab; @@ -1738,7 +1722,7 @@ Statement *ForeachStatement::semantic(Scope *sc) if (arg->storageClass & (STCout | STCref | STClazy)) { error("no storage class for key %s", arg->ident->toChars()); - goto Lerror; + return new ErrorStatement(); } arg->type = arg->type->semantic(loc, sc); TY keyty = arg->type->ty; @@ -1749,13 +1733,13 @@ Statement *ForeachStatement::semantic(Scope *sc) if (keyty != Tint64 && keyty != Tuns64) { error("foreach: key type must be int or uint, long or ulong, not %s", arg->type->toChars()); - goto Lerror; + return new ErrorStatement(); } } else { error("foreach: key type must be int or uint, not %s", arg->type->toChars()); - goto Lerror; + return new ErrorStatement(); } } Initializer *ie = new ExpInitializer(Loc(), new IntegerExp(k)); @@ -1770,7 +1754,7 @@ Statement *ForeachStatement::semantic(Scope *sc) arg->storageClass & STCref && !te) { error("no storage class for value %s", arg->ident->toChars()); - goto Lerror; + return new ErrorStatement(); } Dsymbol *var; if (te) @@ -1795,12 +1779,12 @@ Statement *ForeachStatement::semantic(Scope *sc) if (arg->storageClass & STCref) { error("symbol %s cannot be ref", s->toChars()); - goto Lerror; + return new ErrorStatement(); } if (argtype) { error("cannot specify element type for symbol %s", ds->toChars()); - goto Lerror; + return new ErrorStatement(); } } else if (e->op == TOKtype) @@ -1809,7 +1793,7 @@ Statement *ForeachStatement::semantic(Scope *sc) if (argtype) { error("cannot specify element type for type %s", e->type->toChars()); - goto Lerror; + return new ErrorStatement(); } } else @@ -1827,7 +1811,7 @@ Statement *ForeachStatement::semantic(Scope *sc) if (v->storage_class & STCref) { error("constant value %s cannot be ref", ie->toChars()); - goto Lerror; + return new ErrorStatement(); } else v->storage_class |= STCmanifest; @@ -1841,7 +1825,7 @@ Statement *ForeachStatement::semantic(Scope *sc) if (argtype) { error("cannot specify element type for symbol %s", s->toChars()); - goto Lerror; + return new ErrorStatement(); } } DeclarationExp *de = new DeclarationExp(loc, var); @@ -1933,8 +1917,7 @@ Statement *ForeachStatement::semantic(Scope *sc) key = var; if (arg->storageClass & STCref) { - if (!var->type->immutableOf()->equals(arg->type->immutableOf()) || - !MODimplicitConv(var->type->mod, arg->type->mod)) + if (var->type->constConv(arg->type) <= MATCHnomatch) { error("key type mismatch, %s to ref %s", var->type->toChars(), arg->type->toChars()); @@ -1948,6 +1931,7 @@ Statement *ForeachStatement::semantic(Scope *sc) if (!IntRange::fromType(var->type).contains(dimrange)) { error("index type '%s' cannot cover index range 0..%llu", arg->type->toChars(), ta->dim->toInteger()); + goto Lerror2; } key->range = new IntRange(SignExtendedNumber(0), dimrange.imax); } @@ -1967,8 +1951,7 @@ Statement *ForeachStatement::semantic(Scope *sc) var->storage_class |= STCctorinit; Type *t = tab->nextOf(); - if (!t->immutableOf()->equals(arg->type->immutableOf()) || - !MODimplicitConv(t->mod, arg->type->mod)) + if (t->constConv(arg->type) <= MATCHnomatch) { error("argument type mismatch, %s to ref %s", t->toChars(), arg->type->toChars()); @@ -1992,7 +1975,7 @@ Statement *ForeachStatement::semantic(Scope *sc) VarDeclaration *tmp; if (aggr->op == TOKarrayliteral && !((*arguments)[dim - 1]->storageClass & STCref)) - { + { ArrayLiteralExp *ale = (ArrayLiteralExp *)aggr; size_t edim = ale->elements ? ale->elements->dim : 0; aggr->type = tab->nextOf()->sarrayOf(edim); @@ -2078,6 +2061,8 @@ Statement *ForeachStatement::semantic(Scope *sc) } case Taarray: + if (op == TOKforeach_reverse) + warning("cannot use foreach_reverse with an associative array"); if (!checkForArgTypes()) return this; @@ -2243,7 +2228,7 @@ Statement *ForeachStatement::semantic(Scope *sc) } case Tdelegate: if (op == TOKforeach_reverse) - warning("cannot use foreach_reverse with a delegate"); + deprecation("cannot use foreach_reverse with a delegate"); Lapply: { Expression *ec; @@ -2360,7 +2345,8 @@ Statement *ForeachStatement::semantic(Scope *sc) args->push(new Parameter(stc, arg->type, id, NULL)); #endif } - tfld = new TypeFunction(args, Type::tint32, 0, LINKd); + StorageClass stc = mergeFuncAttrs(STCsafe | STCpure | STCnothrow | STCnogc, func); + tfld = new TypeFunction(args, Type::tint32, 0, LINKd, stc); cases = new Statements(); gotos = new ScopeStatements(); FuncLiteralDeclaration *fld = new FuncLiteralDeclaration(loc, Loc(), tfld, TOKdelegate, this); @@ -2634,12 +2620,11 @@ ForeachRangeStatement::ForeachRangeStatement(Loc loc, TOK op, Parameter *arg, Statement *ForeachRangeStatement::syntaxCopy() { - ForeachRangeStatement *s = new ForeachRangeStatement(loc, op, + return new ForeachRangeStatement(loc, op, arg->syntaxCopy(), lwr->syntaxCopy(), upr->syntaxCopy(), body ? body->syntaxCopy() : NULL); - return s; } Statement *ForeachRangeStatement::semantic(Scope *sc) @@ -2811,11 +2796,11 @@ Statement *ForeachRangeStatement::semantic(Scope *sc) } if (arg->storageClass & STCref) { - if (!key->type->immutableOf()->equals(arg->type->immutableOf()) || - !MODimplicitConv(key->type->mod, arg->type->mod)) + if (key->type->constConv(arg->type) <= MATCHnomatch) { error("argument type mismatch, %s to ref %s", key->type->toChars(), arg->type->toChars()); + goto Lerror; } } @@ -2849,17 +2834,11 @@ IfStatement::IfStatement(Loc loc, Parameter *arg, Expression *condition, Stateme Statement *IfStatement::syntaxCopy() { - Statement *i = NULL; - if (ifbody) - i = ifbody->syntaxCopy(); - - Statement *e = NULL; - if (elsebody) - e = elsebody->syntaxCopy(); - - Parameter *a = arg ? arg->syntaxCopy() : NULL; - IfStatement *s = new IfStatement(loc, a, condition->syntaxCopy(), i, e); - return s; + return new IfStatement(loc, + arg ? arg->syntaxCopy() : NULL, + condition->syntaxCopy(), + ifbody ? ifbody->syntaxCopy() : NULL, + elsebody ? elsebody->syntaxCopy() : NULL); } Statement *IfStatement::semantic(Scope *sc) @@ -2946,12 +2925,10 @@ ConditionalStatement::ConditionalStatement(Loc loc, Condition *condition, Statem Statement *ConditionalStatement::syntaxCopy() { - Statement *e = NULL; - if (elsebody) - e = elsebody->syntaxCopy(); - ConditionalStatement *s = new ConditionalStatement(loc, - condition->syntaxCopy(), ifbody->syntaxCopy(), e); - return s; + return new ConditionalStatement(loc, + condition->syntaxCopy(), + ifbody->syntaxCopy(), + elsebody ? elsebody->syntaxCopy() : NULL); } Statement *ConditionalStatement::semantic(Scope *sc) @@ -3016,16 +2993,14 @@ PragmaStatement::PragmaStatement(Loc loc, Identifier *ident, Expressions *args, Statement *PragmaStatement::syntaxCopy() { - Statement *b = NULL; - if (body) - b = body->syntaxCopy(); - PragmaStatement *s = new PragmaStatement(loc, - ident, Expression::arraySyntaxCopy(args), b); - return s; + return new PragmaStatement(loc, ident, + Expression::arraySyntaxCopy(args), + body ? body->syntaxCopy() : NULL); } Statement *PragmaStatement::semantic(Scope *sc) -{ // Should be merged with PragmaDeclaration +{ + // Should be merged with PragmaDeclaration //printf("PragmaStatement::semantic() %s\n", toChars()); //printf("body = %p\n", body); if (ident == Id::msg) @@ -3064,9 +3039,13 @@ Statement *PragmaStatement::semantic(Scope *sc) /* Should this be allowed? */ error("pragma(lib) not allowed as statement"); + goto Lerror; #else if (!args || args->dim != 1) + { error("string expected for library name"); + goto Lerror; + } else { Expression *e = (*args)[0]; @@ -3080,7 +3059,10 @@ Statement *PragmaStatement::semantic(Scope *sc) (*args)[0] = e; StringExp *se = e->toStringExp(); if (!se) + { error("string expected for library name, not '%s'", e->toChars()); + goto Lerror; + } else if (global.params.verbose) { char *name = (char *)mem.malloc(se->len + 1); @@ -3120,22 +3102,33 @@ Statement *PragmaStatement::semantic(Scope *sc) (*args)[0] = e; Dsymbol *sa = getDsymbol(e); if (!sa || !sa->isFuncDeclaration()) + { error("function name expected for start address, not '%s'", e->toChars()); + goto Lerror; + } if (body) { body = body->semantic(sc); + if (body->isErrorStatement()) + return body; } return this; } } else + { error("unrecognized pragma(%s)", ident->toChars()); -Lerror: + goto Lerror; + } + if (body) { body = body->semantic(sc); } return body; + +Lerror: + return new ErrorStatement(); } /******************************** StaticAssertStatement ***************************/ @@ -3148,8 +3141,7 @@ StaticAssertStatement::StaticAssertStatement(StaticAssert *sa) Statement *StaticAssertStatement::syntaxCopy() { - StaticAssertStatement *s = new StaticAssertStatement((StaticAssert *)sa->syntaxCopy(NULL)); - return s; + return new StaticAssertStatement((StaticAssert *)sa->syntaxCopy(NULL)); } Statement *StaticAssertStatement::semantic(Scope *sc) @@ -3178,10 +3170,10 @@ SwitchStatement::SwitchStatement(Loc loc, Expression *c, Statement *b, bool isFi Statement *SwitchStatement::syntaxCopy() { - //printf("SwitchStatement::syntaxCopy(%p)\n", this); - SwitchStatement *s = new SwitchStatement(loc, - condition->syntaxCopy(), body->syntaxCopy(), isFinal); - return s; + return new SwitchStatement(loc, + condition->syntaxCopy(), + body->syntaxCopy(), + isFinal); } Statement *SwitchStatement::semantic(Scope *sc) @@ -3190,6 +3182,7 @@ Statement *SwitchStatement::semantic(Scope *sc) tf = sc->tf; if (cases) return this; // already run + bool conditionError = false; condition = condition->semantic(sc); condition = resolveProperties(sc, condition); TypeEnum *te = NULL; @@ -3209,10 +3202,17 @@ Statement *SwitchStatement::semantic(Scope *sc) { condition = integralPromotions(condition, sc); if (condition->op != TOKerror && !condition->type->isintegral()) + { error("'%s' must be of integral or string type, it is a %s", condition->toChars(), condition->type->toChars()); + conditionError = true;; + } } condition = condition->optimize(WANTvalue); condition = checkGC(sc, condition); + if (condition->op == TOKerror) + conditionError = true; + + bool needswitcherror = false; sc = sc->push(); sc->sbreak = this; @@ -3223,6 +3223,9 @@ Statement *SwitchStatement::semantic(Scope *sc) body = body->semantic(sc); sc->noctor--; + if (conditionError || body->isErrorStatement()) + goto Lerror; + // Resolve any goto case's with exp for (size_t i = 0; i < gotoCases.dim; i++) { @@ -3231,7 +3234,7 @@ Statement *SwitchStatement::semantic(Scope *sc) if (!gcs->exp) { gcs->error("no case statement following goto case;"); - break; + goto Lerror; } for (Scope *scx = sc; scx; scx = scx->enclosing) @@ -3250,18 +3253,15 @@ Statement *SwitchStatement::semantic(Scope *sc) } } gcs->error("case %s not found", gcs->exp->toChars()); + goto Lerror; Lfoundcase: ; } - bool needswitcherror = false; if (isFinal) - { Type *t = condition->type; - while (t && t->ty == Ttypedef) - { // Don't use toBasetype() because that will skip past enums - t = ((TypeTypedef *)t)->sym->basetype; - } + { + Type *t = condition->type; Dsymbol *ds; EnumDeclaration *ed = NULL; if (t && ((ds = t->toDsymbol(sc)) != NULL)) @@ -3285,6 +3285,7 @@ Statement *SwitchStatement::semantic(Scope *sc) goto L1; } error("enum member %s not represented in final switch", em->toChars()); + goto Lerror; } L1: ; @@ -3324,6 +3325,10 @@ Statement *SwitchStatement::semantic(Scope *sc) sc->pop(); return this; + + Lerror: + sc->pop(); + return new ErrorStatement(); } bool SwitchStatement::hasBreak() @@ -3349,13 +3354,15 @@ CaseStatement::CaseStatement(Loc loc, Expression *exp, Statement *s) Statement *CaseStatement::syntaxCopy() { - CaseStatement *s = new CaseStatement(loc, exp->syntaxCopy(), statement->syntaxCopy()); - return s; + return new CaseStatement(loc, + exp->syntaxCopy(), + statement->syntaxCopy()); } Statement *CaseStatement::semantic(Scope *sc) { SwitchStatement *sw = sc->sw; + bool errors = false; //printf("CaseStatement::semantic() %s\n", toChars()); sc = sc->startCTFE(); @@ -3379,7 +3386,10 @@ Statement *CaseStatement::semantic(Scope *sc) */ sw->hasVars = 1; if (sw->isFinal) + { error("case variables not allowed in final switch statements"); + errors = true; + } goto L1; } } @@ -3391,7 +3401,7 @@ Statement *CaseStatement::semantic(Scope *sc) else if (exp->op != TOKint64 && exp->op != TOKerror) { error("case must be a string or an integral constant, not %s", exp->toChars()); - exp = new ErrorExp(); + errors = true; } L1: @@ -3401,7 +3411,9 @@ Statement *CaseStatement::semantic(Scope *sc) //printf("comparing '%s' with '%s'\n", exp->toChars(), cs->exp->toChars()); if (cs->exp->equals(exp)) - { error("duplicate case %s in switch statement", exp->toChars()); + { + error("duplicate case %s in switch statement", exp->toChars()); + errors = true; break; } } @@ -3421,11 +3433,21 @@ Statement *CaseStatement::semantic(Scope *sc) } if (sc->sw->tf != sc->tf) + { error("switch and case are in different finally blocks"); + errors = true; + } } else + { error("case not in switch statement"); + errors = true; + } statement = statement->semantic(sc); + if (statement->isErrorStatement()) + return statement; + if (errors || exp->op == TOKerror) + return new ErrorStatement(); return this; } @@ -3451,9 +3473,10 @@ CaseRangeStatement::CaseRangeStatement(Loc loc, Expression *first, Statement *CaseRangeStatement::syntaxCopy() { - CaseRangeStatement *s = new CaseRangeStatement(loc, - first->syntaxCopy(), last->syntaxCopy(), statement->syntaxCopy()); - return s; + return new CaseRangeStatement(loc, + first->syntaxCopy(), + last->syntaxCopy(), + statement->syntaxCopy()); } Statement *CaseRangeStatement::semantic(Scope *sc) @@ -3462,12 +3485,16 @@ Statement *CaseRangeStatement::semantic(Scope *sc) if (sw == NULL) { error("case range not in switch statement"); - return NULL; + return new ErrorStatement(); } //printf("CaseRangeStatement::semantic() %s\n", toChars()); + bool errors = false; if (sw->isFinal) + { error("case ranges not allowed in final switch"); + errors = true; + } sc = sc->startCTFE(); first = first->semantic(sc); @@ -3483,8 +3510,12 @@ Statement *CaseRangeStatement::semantic(Scope *sc) last = last->implicitCastTo(sc, sw->condition->type); last = last->ctfeInterpret(); - if (first->op == TOKerror || last->op == TOKerror) - return statement ? statement->semantic(sc) : NULL; + if (first->op == TOKerror || last->op == TOKerror || errors) + { + if (statement) + statement->semantic(sc); + return new ErrorStatement(); + } uinteger_t fval = first->toInteger(); uinteger_t lval = last->toInteger(); @@ -3495,14 +3526,20 @@ Statement *CaseRangeStatement::semantic(Scope *sc) { error("first case %s is greater than last case %s", first->toChars(), last->toChars()); + errors = true; lval = fval; } if (lval - fval > 256) - { error("had %llu cases which is more than 256 cases in case range", lval - fval); + { + error("had %llu cases which is more than 256 cases in case range", lval - fval); + errors = true; lval = fval + 256; } + if (errors) + return new ErrorStatement(); + /* This works by replacing the CaseRange with an array of Case's. * * case a: .. case b: s; @@ -3544,30 +3581,41 @@ DefaultStatement::DefaultStatement(Loc loc, Statement *s) Statement *DefaultStatement::syntaxCopy() { - DefaultStatement *s = new DefaultStatement(loc, statement->syntaxCopy()); - return s; + return new DefaultStatement(loc, statement->syntaxCopy()); } Statement *DefaultStatement::semantic(Scope *sc) { //printf("DefaultStatement::semantic()\n"); + bool errors = false; if (sc->sw) { if (sc->sw->sdefault) { error("switch statement already has a default"); + errors = true; } sc->sw->sdefault = this; if (sc->sw->tf != sc->tf) + { error("switch and default are in different finally blocks"); - + errors = true; + } if (sc->sw->isFinal) + { error("default statement not allowed in final switch statement"); + errors = true; + } } else + { error("default not in switch statement"); + errors = true; + } statement = statement->semantic(sc); + if (errors || statement->isErrorStatement()) + return new ErrorStatement(); return this; } @@ -3581,15 +3629,17 @@ GotoDefaultStatement::GotoDefaultStatement(Loc loc) Statement *GotoDefaultStatement::syntaxCopy() { - GotoDefaultStatement *s = new GotoDefaultStatement(loc); - return s; + return new GotoDefaultStatement(loc); } Statement *GotoDefaultStatement::semantic(Scope *sc) { sw = sc->sw; if (!sw) + { error("goto default not in switch statement"); + return new ErrorStatement(); + } return this; } @@ -3607,30 +3657,30 @@ GotoCaseStatement::GotoCaseStatement(Loc loc, Expression *exp) Statement *GotoCaseStatement::syntaxCopy() { - Expression *e = exp ? exp->syntaxCopy() : NULL; - GotoCaseStatement *s = new GotoCaseStatement(loc, e); - return s; + return new GotoCaseStatement(loc, exp ? exp->syntaxCopy() : NULL); } Statement *GotoCaseStatement::semantic(Scope *sc) { - if (exp) - exp = exp->semantic(sc); - if (!sc->sw) + { error("goto case not in switch statement"); - else + return new ErrorStatement(); + } + + if (exp) { #if IN_LLVM sw = sc->sw; #endif - sc->sw->gotoCases.push(this); - if (exp) - { - exp = exp->implicitCastTo(sc, sc->sw->condition->type); - exp = exp->optimize(WANTvalue); - } + exp = exp->semantic(sc); + exp = exp->implicitCastTo(sc, sc->sw->condition->type); + exp = exp->optimize(WANTvalue); + if (exp->op == TOKerror) + return new ErrorStatement(); } + + sc->sw->gotoCases.push(this); return this; } @@ -3647,16 +3697,12 @@ ReturnStatement::ReturnStatement(Loc loc, Expression *exp) : Statement(loc) { this->exp = exp; - this->implicit0 = 0; + this->caseDim = 0; } Statement *ReturnStatement::syntaxCopy() { - Expression *e = NULL; - if (exp) - e = exp->syntaxCopy(); - ReturnStatement *s = new ReturnStatement(loc, e); - return s; + return new ReturnStatement(loc, exp ? exp->syntaxCopy() : NULL); } Statement *ReturnStatement::semantic(Scope *sc) @@ -3673,50 +3719,71 @@ Statement *ReturnStatement::semantic(Scope *sc) TypeFunction *tf = (TypeFunction *)fd->type; assert(tf->ty == Tfunction); - Type *tret = tf->next; - if (fd->tintro) - /* We'll be implicitly casting the return expression to tintro - */ - tret = fd->tintro->nextOf(); - Type *tbret = NULL; - - if (tret) - tbret = tret->toBasetype(); - - // main() returns 0, even if it returns void - if (!exp && (!tbret || tbret->ty == Tvoid) && fd->isMain()) + if (exp && exp->op == TOKvar && ((VarExp *)exp)->var == fd->vresult) { - implicit0 = 1; - exp = new IntegerExp(0); + // return vresult; + if (sc->fes) + { + assert(caseDim == 0); + sc->fes->cases->push(this); + return new ReturnStatement(Loc(), new IntegerExp(sc->fes->cases->dim + 1)); + } + if (fd->returnLabel) + { + GotoStatement *gs = new GotoStatement(loc, Id::returnLabel); + gs->label = fd->returnLabel; + return gs; + } + + if (!fd->returns) + fd->returns = new ReturnStatements(); + fd->returns->push(this); + return this; } + Type *tret = tf->next; + Type *tbret = tret ? tret->toBasetype() : NULL; + + bool inferRef = (tf->isref && (fd->storage_class & STCauto)); + Expression *e0 = NULL; + + bool errors = false; if (sc->flags & SCOPEcontract) + { error("return statements cannot be in contracts"); + errors = true; + } if (sc->os && sc->os->tok != TOKon_scope_failure) + { error("return statements cannot be in %s bodies", Token::toChars(sc->os->tok)); + errors = true; + } if (sc->tf) + { error("return statements cannot be in finally bodies"); + errors = true; + } if (fd->isCtorDeclaration()) { + if (exp) + { + error("cannot return expression from constructor"); + errors = true; + } + // Constructors implicitly do: // return this; - if (exp && exp->op != TOKthis) - error("cannot return expression from constructor"); exp = new ThisExp(Loc()); exp->type = tret; } - - if (!exp) - fd->nrvo_can = 0; - - if (exp) + else if (exp) { fd->hasReturnExp |= 1; FuncLiteralDeclaration *fld = fd->isFuncLiteralDeclaration(); if (tret) - exp = inferType(exp, tbret); + exp = inferType(exp, tret); else if (fld && fld->treq) exp = inferType(exp, fld->treq->nextOf()->nextOf()); exp = exp->semantic(sc); @@ -3727,37 +3794,97 @@ Statement *ReturnStatement::semantic(Scope *sc) if (!exp->rvalue()) // don't make error for void expression exp = new ErrorExp(); } - if (isNonAssignmentArrayOp(exp)) - { - exp->error("array operation %s without assignment not implemented", exp->toChars()); + if (checkNonAssignmentArrayOp(exp)) exp = new ErrorExp(); - } if (exp->op == TOKcall) exp = valueNoDtor(exp); - // deduce 'auto ref' - if (tf->isref && (fd->storage_class & STCauto)) + // Extract side-effect part + exp = Expression::extractLast(exp, &e0); + + /* Void-return function can have void typed expression + * on return statement. + */ + if (tbret && tbret->ty == Tvoid || exp->type->ty == Tvoid) + { + if (exp->type->ty != Tvoid) + { + error("cannot return non-void from void function"); + errors = true; + + exp = new CastExp(loc, exp, Type::tvoid); + exp = exp->semantic(sc); + } + + /* Replace: + * return exp; + * with: + * exp; return; + */ + e0 = Expression::combine(e0, exp); + exp = NULL; + } + if (e0) + e0 = checkGC(sc, e0); + } + + if (exp) + { + if (fd->inferRetType) // infer return type + { + if (!tret) + { + tf->next = exp->type; + } + else if (tret->ty != Terror && !exp->type->equals(tret)) + { + int m1 = exp->type->implicitConvTo(tret); + int m2 = tret->implicitConvTo(exp->type); + //printf("exp->type = %s m2<-->m1 tret %s\n", exp->type->toChars(), tret->toChars()); + //printf("m1 = %d, m2 = %d\n", m1, m2); + + if (m1 && m2) + ; + else if (!m1 && m2) + tf->next = exp->type; + else if (m1 && !m2) + ; + else if (exp->op != TOKerror) + { + error("mismatched function return type inference of %s and %s", + exp->type->toChars(), tret->toChars()); + errors = true; + tf->next = Type::terror; + } + } + + tret = tf->next; + tbret = tret->toBasetype(); + } + + if (inferRef) // deduce 'auto ref' { /* Determine "refness" of function return: * if it's an lvalue, return by ref, else return by value */ if (exp->isLvalue()) { - /* Return by ref - * (but first ensure it doesn't fail the "check for - * escaping reference" test) + /* May return by ref */ - unsigned errors = global.startGagging(); + unsigned olderrors = global.startGagging(); exp->checkEscapeRef(); - if (global.endGagging(errors)) + if (global.endGagging(olderrors)) tf->isref = false; // return by value } else tf->isref = false; // return by value - fd->storage_class &= ~STCauto; + + /* The "refness" is determined by all of return statements. + * This means: + * return 3; return x; // ok, x can be a value + * return x; return 3; // ok, x can be a value + */ } - if (!tf->isref) - exp = exp->optimize(WANTvalue); // handle NRVO if (fd->nrvo_can && exp->op == TOKvar) @@ -3768,7 +3895,8 @@ Statement *ReturnStatement::semantic(Scope *sc) if (tf->isref) { // Function returns a reference - fd->nrvo_can = 0; + if (!inferRef) + fd->nrvo_can = 0; } else if (!v || v->isOut() || v->isRef()) fd->nrvo_can = 0; @@ -3785,194 +3913,51 @@ Statement *ReturnStatement::semantic(Scope *sc) else if (fd->nrvo_var != v) fd->nrvo_can = 0; } - else + else //if (!exp->isLvalue()) // keep NRVO-ability fd->nrvo_can = 0; + } + else + { + // handle NRVO + fd->nrvo_can = 0; // infer return type if (fd->inferRetType) { - Type *tfret = tf->nextOf(); - if (tfret) + if (tf->next && tf->next->ty != Tvoid) { - if (tfret != Type::terror) - { - if (!exp->type->equals(tfret)) - { - int m1 = exp->type->implicitConvTo(tfret); - int m2 = tfret->implicitConvTo(exp->type); - //printf("exp->type = %s m2<-->m1 tret %s\n", exp->type->toChars(), tfret->toChars()); - //printf("m1 = %d, m2 = %d\n", m1, m2); - - if (m1 && m2) - #if IN_LLVM - exp = exp->implicitCastTo(sc, tret); - #else - ; - #endif - else if (!m1 && m2) - tf->next = exp->type; - else if (m1 && !m2) - ; - else if (exp->op != TOKerror) - error("mismatched function return type inference of %s and %s", - exp->type->toChars(), tfret->toChars()); - } - } - - /* The "refness" is determined by the first return statement, - * not all of them. This means: - * return 3; return x; // ok, x can be a value - * return x; return 3; // error, 3 is not an lvalue - */ - } - else - tf->next = exp->type; - - if (!fd->tintro) - { - tret = tf->next; - tbret = tret->toBasetype(); - } - } - - if (tbret->ty != Tvoid) - { - if (!exp->type->implicitConvTo(tret) && - fd->parametersIntersect(exp->type)) - { - if (exp->type->immutableOf()->implicitConvTo(tret)) - exp = exp->castTo(sc, exp->type->immutableOf()); - else if (exp->type->wildOf()->implicitConvTo(tret)) - exp = exp->castTo(sc, exp->type->wildOf()); - } - if (fd->tintro) - exp = exp->implicitCastTo(sc, tf->next); - - // eorg isn't casted to tret (== fd->tintro->nextOf()) - if (fd->returnLabel) - eorg = exp->copy(); - exp = exp->implicitCastTo(sc, tret); - - if (!tf->isref) - exp = exp->optimize(WANTvalue); - } - } - else if (fd->inferRetType) - { - if (tf->next) - { - if (tf->next->ty != Tvoid) error("mismatched function return type inference of void and %s", tf->next->toChars()); - } - tf->next = Type::tvoid; - - tret = Type::tvoid; - tbret = tret; - } - else if (tbret->ty != Tvoid) // if non-void return - error("return expression expected"); - - if (sc->fes) - { - Statement *s; - - if (exp && !implicit0) - { - exp = exp->implicitCastTo(sc, tret); - } - if (!exp || exp->op == TOKint64 || exp->op == TOKfloat64 || - exp->op == TOKimaginary80 || exp->op == TOKcomplex80 || - exp->op == TOKthis || exp->op == TOKsuper || exp->op == TOKnull || - exp->op == TOKstring) - { - sc->fes->cases->push(this); - // Construct: return cases->dim+1; - s = new ReturnStatement(Loc(), new IntegerExp(sc->fes->cases->dim + 1)); - } - else if (tf->next->toBasetype() == Type::tvoid) - { - s = new ReturnStatement(Loc(), NULL); - sc->fes->cases->push(s); - - // Construct: { exp; return cases->dim + 1; } - Statement *s1 = new ExpStatement(loc, exp); - Statement *s2 = new ReturnStatement(Loc(), new IntegerExp(sc->fes->cases->dim + 1)); - s = new CompoundStatement(loc, s1, s2); - } - else - { - // Construct: return vresult; - if (!fd->vresult) - { - // Declare vresult - Scope *sco = fd->scout ? fd->scout : scx; - if (!fd->outId) - fd->outId = Id::result; - VarDeclaration *v = new VarDeclaration(loc, tret, fd->outId, NULL); - if (fd->outId == Id::result) - v->storage_class |= STCtemp; - v->noscope = 1; - v->storage_class |= STCresult; - if (tf->isref) - v->storage_class |= STCref | STCforeach; - v->semantic(sco); - if (!sco->insert(v)) - assert(0); - v->parent = fd; - fd->vresult = v; + errors = true; } + tf->next = Type::tvoid; - s = new ReturnStatement(Loc(), new VarExp(Loc(), fd->vresult)); - sc->fes->cases->push(s); - - // Construct: { vresult = exp; return cases->dim + 1; } - if (tf->isref) - exp = new ConstructExp(loc, new VarExp(Loc(), fd->vresult), exp); - else - exp = new BlitExp(loc, new VarExp(Loc(), fd->vresult), exp); - exp = exp->semantic(sc); - Statement *s1 = new ExpStatement(loc, exp); - Statement *s2 = new ReturnStatement(Loc(), new IntegerExp(sc->fes->cases->dim + 1)); - s = new CompoundStatement(loc, s1, s2); - } - return s; - } - - if (exp) - { - exp = checkGC(sc, exp); - - if (tf->isref && !fd->isCtorDeclaration()) - { - // Function returns a reference - exp = exp->toLvalue(sc, exp); - exp->checkEscapeRef(); - } - else - { - //exp->print(); - exp->checkEscape(); + tret = tf->next; + tbret = tret->toBasetype(); } - if (fd->returnLabel && tbret->ty != Tvoid) - { - fd->buildResultVar(); - VarExp *v = new VarExp(Loc(), fd->vresult); + if (inferRef) // deduce 'auto ref' + tf->isref = false; - assert(eorg); - if (tf->isref) - exp = new ConstructExp(loc, v, eorg); - else - exp = new BlitExp(loc, v, eorg); - exp = exp->semantic(sc); + if (tbret->ty != Tvoid) // if non-void return + { + error("return expression expected"); + errors = true; + } + else if (fd->isMain()) + { + // main() returns 0, even if it returns void + exp = new IntegerExp(0); } } // If any branches have called a ctor, but this branch hasn't, it's an error if (sc->callSuper & CSXany_ctor && !(sc->callSuper & (CSXthis_ctor | CSXsuper_ctor))) + { error("return without calling constructor"); + errors = true; + } sc->callSuper |= CSXreturn; if (sc->fieldinit) { @@ -3985,49 +3970,58 @@ Statement *ReturnStatement::semantic(Scope *sc) bool mustInit = (v->storage_class & STCnodefaultctor || v->type->needsNested()); if (mustInit && !(sc->fieldinit[i] & CSXthis_ctor)) + { error("an earlier return statement skips field %s initialization", v->toChars()); - + errors = true; + } sc->fieldinit[i] |= CSXreturn; } } - // See if all returns are instead to be replaced with a goto returnLabel; - if (fd->returnLabel) + if (errors) + return new ErrorStatement(); + + if (sc->fes) { - GotoStatement *gs = new GotoStatement(loc, Id::returnLabel); - - gs->label = fd->returnLabel; - if (exp) + if (!exp) { - /* Replace: return exp; - * with: exp; goto returnLabel; - */ - Statement *s = new ExpStatement(Loc(), exp); - return new CompoundStatement(loc, s, gs); - } - return gs; - } + // Send out "case receiver" statement to the foreach. + // return exp; + Statement *s = new ReturnStatement(Loc(), exp); + sc->fes->cases->push(s); - if (exp && tbret->ty == Tvoid && !implicit0) + // Immediately rewrite "this" return statement as: + // return cases->dim+1; + this->exp = new IntegerExp(sc->fes->cases->dim + 1); + if (e0) + return new CompoundStatement(loc, new ExpStatement(loc, e0), this); + return this; + } + else + { + fd->buildResultVar(NULL, exp->type); + fd->vresult->checkNestedReference(sc, Loc()); + + // Send out "case receiver" statement to the foreach. + // return vresult; + Statement *s = new ReturnStatement(Loc(), new VarExp(Loc(), fd->vresult)); + sc->fes->cases->push(s); + + // Save receiver index for the later rewriting from: + // return exp; + // to: + // vresult = exp; retrun caseDim; + caseDim = sc->fes->cases->dim + 1; + } + } + if (exp) { - if (exp->type->ty != Tvoid) - { - error("cannot return non-void from void function"); - } - - /* Replace: - * return exp; - * with: - * cast(void)exp; return; - */ - Expression *ce = new CastExp(loc, exp, Type::tvoid); - Statement *s = new ExpStatement(loc, ce); - s = s->semantic(sc); - - exp = NULL; - return new CompoundStatement(loc, s, this); + if (!fd->returns) + fd->returns = new ReturnStatements(); + fd->returns->push(this); } - + if (e0) + return new CompoundStatement(loc, new ExpStatement(loc, e0), this); return this; } @@ -4041,8 +4035,7 @@ BreakStatement::BreakStatement(Loc loc, Identifier *ident) Statement *BreakStatement::syntaxCopy() { - BreakStatement *s = new BreakStatement(loc, ident); - return s; + return new BreakStatement(loc, ident); } Statement *BreakStatement::semantic(Scope *sc) @@ -4130,8 +4123,7 @@ ContinueStatement::ContinueStatement(Loc loc, Identifier *ident) Statement *ContinueStatement::syntaxCopy() { - ContinueStatement *s = new ContinueStatement(loc, ident); - return s; + return new ContinueStatement(loc, ident); } Statement *ContinueStatement::semantic(Scope *sc) @@ -4230,9 +4222,9 @@ SynchronizedStatement::SynchronizedStatement(Loc loc, Expression *exp, Statement Statement *SynchronizedStatement::syntaxCopy() { - Expression *e = exp ? exp->syntaxCopy() : NULL; - SynchronizedStatement *s = new SynchronizedStatement(loc, e, body ? body->syntaxCopy() : NULL); - return s; + return new SynchronizedStatement(loc, + exp ? exp->syntaxCopy() : NULL, + body ? body->syntaxCopy() : NULL); } Statement *SynchronizedStatement::semantic(Scope *sc) @@ -4286,12 +4278,12 @@ Statement *SynchronizedStatement::semantic(Scope *sc) Parameters* args = new Parameters; args->push(new Parameter(0, ClassDeclaration::object->type, NULL, NULL)); - FuncDeclaration *fdenter = FuncDeclaration::genCfunc(args, Type::tvoid, Id::monitorenter); + FuncDeclaration *fdenter = FuncDeclaration::genCfunc(args, Type::tvoid, Id::monitorenter, STCnothrow); Expression *e = new CallExp(loc, new VarExp(loc, fdenter), new VarExp(loc, tmp)); e->type = Type::tvoid; // do not run semantic on e cs->push(new ExpStatement(loc, e)); - FuncDeclaration *fdexit = FuncDeclaration::genCfunc(args, Type::tvoid, Id::monitorexit); + FuncDeclaration *fdexit = FuncDeclaration::genCfunc(args, Type::tvoid, Id::monitorexit, STCnothrow); e = new CallExp(loc, new VarExp(loc, fdexit), new VarExp(loc, tmp)); e->type = Type::tvoid; // do not run semantic on e Statement *s = new ExpStatement(loc, e); @@ -4376,12 +4368,14 @@ WithStatement::WithStatement(Loc loc, Expression *exp, Statement *body) Statement *WithStatement::syntaxCopy() { - WithStatement *s = new WithStatement(loc, exp->syntaxCopy(), body ? body->syntaxCopy() : NULL); - return s; + return new WithStatement(loc, + exp->syntaxCopy(), + body ? body->syntaxCopy() : NULL); } Statement *WithStatement::semantic(Scope *sc) -{ ScopeDsymbol *sym; +{ + ScopeDsymbol *sym; Initializer *init; //printf("WithStatement::semantic()\n"); @@ -4434,11 +4428,22 @@ Statement *WithStatement::semantic(Scope *sc) { if (!exp->isLvalue()) { + /* Re-write to + * { + * auto __withtmp = exp + * with(__withtmp) + * { + * ... + * } + * } + */ init = new ExpInitializer(loc, exp); wthis = new VarDeclaration(loc, exp->type, Lexer::uniqueId("__withtmp"), init); wthis->storage_class |= STCtemp; - exp = new CommaExp(loc, new DeclarationExp(loc, wthis), new VarExp(loc, wthis)); - exp = exp->semantic(sc); + ExpStatement *es = new ExpStatement(loc, new DeclarationExp(loc, wthis)); + exp = new VarExp(loc, wthis); + Statement *ss = new ScopeStatement(loc, new CompoundStatement(loc, es, this)); + return ss->semantic(sc); } Expression *e = exp->addressOf(); init = new ExpInitializer(loc, e); @@ -4486,11 +4491,9 @@ Statement *TryCatchStatement::syntaxCopy() for (size_t i = 0; i < a->dim; i++) { Catch *c = (*catches)[i]; - c = c->syntaxCopy(); - (*a)[i] = c; + (*a)[i] = c->syntaxCopy(); } - TryCatchStatement *s = new TryCatchStatement(loc, body->syntaxCopy(), a); - return s; + return new TryCatchStatement(loc, body->syntaxCopy(), a); } Statement *TryCatchStatement::semantic(Scope *sc) @@ -4575,7 +4578,7 @@ Catch::Catch(Loc loc, Type *t, Identifier *id, Statement *handler) Catch *Catch::syntaxCopy() { Catch *c = new Catch(loc, - (type ? type->syntaxCopy() : NULL), + type ? type->syntaxCopy() : NULL, ident, (handler ? handler->syntaxCopy() : NULL)); c->internalCatch = internalCatch; @@ -4663,9 +4666,8 @@ TryFinallyStatement *TryFinallyStatement::create(Loc loc, Statement *body, State Statement *TryFinallyStatement::syntaxCopy() { - TryFinallyStatement *s = new TryFinallyStatement(loc, + return new TryFinallyStatement(loc, body->syntaxCopy(), finalbody->syntaxCopy()); - return s; } Statement *TryFinallyStatement::semantic(Scope *sc) @@ -4711,9 +4713,7 @@ OnScopeStatement::OnScopeStatement(Loc loc, TOK tok, Statement *statement) Statement *OnScopeStatement::syntaxCopy() { - OnScopeStatement *s = new OnScopeStatement(loc, - tok, statement->syntaxCopy()); - return s; + return new OnScopeStatement(loc, tok, statement->syntaxCopy()); } Statement *OnScopeStatement::semantic(Scope *sc) @@ -4854,9 +4854,8 @@ DebugStatement::DebugStatement(Loc loc, Statement *statement) Statement *DebugStatement::syntaxCopy() { - DebugStatement *s = new DebugStatement(loc, - statement ? statement->syntaxCopy() : NULL); - return s; + return new DebugStatement(loc, + statement ? statement->syntaxCopy() : NULL); } Statement *DebugStatement::semantic(Scope *sc) @@ -4900,26 +4899,24 @@ GotoStatement::GotoStatement(Loc loc, Identifier *ident) this->enclosingScopeExit = NULL; #endif this->lastVar = NULL; - this->fd = NULL; } Statement *GotoStatement::syntaxCopy() { - GotoStatement *s = new GotoStatement(loc, ident); - return s; + return new GotoStatement(loc, ident); } Statement *GotoStatement::semantic(Scope *sc) { - FuncDeclaration *fd = sc->func; //printf("GotoStatement::semantic()\n"); - ident = fixupLabelName(sc, ident); + FuncDeclaration *fd = sc->func; - this->lastVar = sc->lastVar; - this->fd = sc->func; + ident = fixupLabelName(sc, ident); + label = fd->searchLabel(ident); tf = sc->tf; os = sc->os; - label = fd->searchLabel(ident); + lastVar = sc->lastVar; + if (!label->statement && sc->fes) { /* Either the goto label is forward referenced or it @@ -5017,25 +5014,26 @@ LabelStatement::LabelStatement(Loc loc, Identifier *ident, Statement *statement) #if IN_LLVM this->enclosingScopeExit = NULL; #endif - this->gotoTarget = NULL; this->lastVar = NULL; + this->gotoTarget = NULL; this->lblock = NULL; this->fwdrefs = NULL; } Statement *LabelStatement::syntaxCopy() { - LabelStatement *s = new LabelStatement(loc, ident, statement ? statement->syntaxCopy() : NULL); - return s; + return new LabelStatement(loc, ident, statement ? statement->syntaxCopy() : NULL); } Statement *LabelStatement::semantic(Scope *sc) { + //printf("LabelStatement::semantic()\n"); FuncDeclaration *fd = sc->parent->isFuncDeclaration(); - this->lastVar = sc->lastVar; - //printf("LabelStatement::semantic()\n"); ident = fixupLabelName(sc, ident); + tf = sc->tf; + os = sc->os; + lastVar = sc->lastVar; LabelDsymbol *ls = fd->searchLabel(ident); if (ls->statement) @@ -5045,8 +5043,7 @@ Statement *LabelStatement::semantic(Scope *sc) } else ls->statement = this; - tf = sc->tf; - os = sc->os; + sc = sc->push(); sc->scopesym = sc->enclosing->scopesym; sc->callSuper |= CSXlabel; @@ -5060,6 +5057,7 @@ Statement *LabelStatement::semantic(Scope *sc) if (statement) statement = statement->semantic(sc); sc->pop(); + return this; } @@ -5138,8 +5136,54 @@ Statement *AsmStatement::syntaxCopy() return new AsmStatement(loc, tokens); } - #endif + +/************************ CompoundAsmStatement ***************************************/ + +CompoundAsmStatement::CompoundAsmStatement(Loc loc, Statements *s, StorageClass stc) + : CompoundStatement(loc, s) +{ + this->stc = stc; +} + +CompoundAsmStatement *CompoundAsmStatement::syntaxCopy() +{ + Statements *a = new Statements(); + a->setDim(statements->dim); + for (size_t i = 0; i < statements->dim; i++) + { + Statement *s = (*statements)[i]; + (*a)[i] = s ? s->syntaxCopy() : NULL; + } + return new CompoundAsmStatement(loc, a, stc); +} + +Statements *CompoundAsmStatement::flatten(Scope *sc) +{ + return NULL; +} + +CompoundAsmStatement *CompoundAsmStatement::semantic(Scope *sc) +{ + for (size_t i = 0; i < statements->dim; i++) + { + Statement *s = (*statements)[i]; + (*statements)[i] = s ? s->semantic(sc) : NULL; + } + + assert(sc->func); + // use setImpure/setGC when the deprecation cycle is over + PURE purity; + if (!(stc & STCpure) && (purity = sc->func->isPureBypassingInference()) != PUREimpure && purity != PUREfwdref) + deprecation("asm statement is assumed to be impure - mark it with 'pure' if it is not"); + if (!(stc & STCnogc) && sc->func->isNogcBypassingInference()) + deprecation("asm statement is assumed to use the GC - mark it with '@nogc' if it does not"); + if (!(stc & (STCtrusted|STCsafe)) && sc->func->setUnsafe()) + error("asm statement is assumed to be @system - mark it with '@trusted' if it is not"); + + return this; +} + /************************ ImportStatement ***************************************/ ImportStatement::ImportStatement(Loc loc, Dsymbols *imports) diff --git a/dmd2/statement.h b/dmd2/statement.h index 76704a2c70..35476d1a02 100644 --- a/dmd2/statement.h +++ b/dmd2/statement.h @@ -51,7 +51,6 @@ class TryFinallyStatement; class CaseStatement; class DefaultStatement; class LabelStatement; -struct HdrGenState; struct InterState; struct CompiledCtfeFunction; #if IN_LLVM @@ -105,8 +104,6 @@ enum BE BEany = (BEfallthru | BEthrow | BEreturn | BEgoto | BEhalt), }; -void toCBuffer(Statement *s, OutBuffer *buf, HdrGenState *hgs); - class Statement : public RootObject { public: @@ -580,7 +577,7 @@ class ReturnStatement : public Statement { public: Expression *exp; - bool implicit0; // this is an implicit "return 0;" + size_t caseDim; ReturnStatement(Loc loc, Expression *exp); Statement *syntaxCopy(); @@ -752,7 +749,6 @@ public: Statement* enclosingScopeExit; #endif VarDeclaration *lastVar; - FuncDeclaration *fd; GotoStatement(Loc loc, Identifier *ident); Statement *syntaxCopy(); @@ -772,10 +768,10 @@ public: #if IN_LLVM Statement* enclosingScopeExit; #endif - Statement *gotoTarget; // interpret VarDeclaration *lastVar; - block *lblock; // back end + Statement *gotoTarget; // interpret + block *lblock; // back end Blocks *fwdrefs; // forward references to this LabelStatement LabelStatement(Loc loc, Identifier *ident, Statement *statement); @@ -827,6 +823,20 @@ public: #endif }; +// a complete asm {} block +class CompoundAsmStatement : public CompoundStatement +{ +public: + StorageClass stc; // postfix attributes like nothrow/pure/@trusted + + CompoundAsmStatement(Loc loc, Statements *s, StorageClass stc); + CompoundAsmStatement *syntaxCopy(); + CompoundAsmStatement *semantic(Scope *sc); + Statements *flatten(Scope *sc); + + void accept(Visitor *v) { v->visit(this); } +}; + class ImportStatement : public Statement { public: diff --git a/dmd2/staticassert.c b/dmd2/staticassert.c index c3542f1ffd..d0ea66f619 100644 --- a/dmd2/staticassert.c +++ b/dmd2/staticassert.c @@ -17,7 +17,6 @@ #include "staticassert.h" #include "expression.h" #include "id.h" -#include "hdrgen.h" #include "scope.h" #include "template.h" #include "declaration.h" @@ -35,11 +34,8 @@ StaticAssert::StaticAssert(Loc loc, Expression *exp, Expression *msg) Dsymbol *StaticAssert::syntaxCopy(Dsymbol *s) { - StaticAssert *sa; - assert(!s); - sa = new StaticAssert(loc, exp->syntaxCopy(), msg ? msg->syntaxCopy() : NULL); - return sa; + return new StaticAssert(loc, exp->syntaxCopy(), msg ? msg->syntaxCopy() : NULL); } int StaticAssert::addMember(Scope *sc, ScopeDsymbol *sds, int memnum) @@ -56,8 +52,9 @@ void StaticAssert::semantic2(Scope *sc) //printf("StaticAssert::semantic2() %s\n", toChars()); ScopeDsymbol *sds = new ScopeDsymbol(); sc = sc->push(sds); - sc->speculative = true; - sc->flags |= SCOPEstaticassert; + sc->tinst = NULL; + sc->minst = NULL; + sc->flags |= SCOPEcondition; sc = sc->startCTFE(); Expression *e = exp->semantic(sc); @@ -84,22 +81,19 @@ void StaticAssert::semantic2(Scope *sc) { if (msg) { - HdrGenState hgs; - OutBuffer buf; - sc = sc->startCTFE(); msg = msg->semantic(sc); msg = resolveProperties(sc, msg); sc = sc->endCTFE(); msg = msg->ctfeInterpret(); - hgs.console = 1; - StringExp * s = msg->toStringExp(); - if (s) - { s->postfix = 0; // Don't display a trailing 'c' - msg = s; + if (StringExp * se = msg->toStringExp()) + { + // same with pragma(msg) + se = se->toUTF8(sc); + error("\"%.*s\"", (int)se->len, (char *)se->string); } - msg->toCBuffer(&buf, &hgs); - error("%s", buf.peekString()); + else + error("%s", msg->toChars()); } else error("(%s) is false", exp->toChars()); @@ -129,17 +123,3 @@ const char *StaticAssert::kind() { return "static assert"; } - -void StaticAssert::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(kind()); - buf->writeByte('('); - exp->toCBuffer(buf, hgs); - if (msg) - { - buf->writestring(", "); - msg->toCBuffer(buf, hgs); - } - buf->writestring(");"); - buf->writenl(); -} diff --git a/dmd2/staticassert.h b/dmd2/staticassert.h index 4762fb75f0..a38da09052 100644 --- a/dmd2/staticassert.h +++ b/dmd2/staticassert.h @@ -19,7 +19,6 @@ #include "dsymbol.h" class Expression; -struct HdrGenState; class StaticAssert : public Dsymbol { @@ -36,7 +35,6 @@ public: bool oneMember(Dsymbol **ps, Identifier *ident); void toObjFile(bool multiobj); const char *kind(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); void accept(Visitor *v) { v->visit(this); } }; diff --git a/dmd2/struct.c b/dmd2/struct.c index d6f269e76b..bcc4046a0e 100644 --- a/dmd2/struct.c +++ b/dmd2/struct.c @@ -130,7 +130,7 @@ AggregateDeclaration::AggregateDeclaration(Loc loc, Identifier *id) this->loc = loc; storage_class = 0; - protection = PROTpublic; + protection = Prot(PROTpublic); type = NULL; structsize = 0; // size of struct alignsize = 0; // size of struct for alignment purposes @@ -156,7 +156,7 @@ AggregateDeclaration::AggregateDeclaration(Loc loc, Identifier *id) getRTInfo = NULL; } -PROT AggregateDeclaration::prot() +Prot AggregateDeclaration::prot() { return protection; } @@ -174,6 +174,8 @@ void AggregateDeclaration::semantic2(Scope *sc) if (!members) return; + if (scope && sizeok == SIZEOKfwd) // Bugzilla 12531 + semantic(NULL); if (scope) { error("has forward references"); @@ -185,7 +187,7 @@ void AggregateDeclaration::semantic2(Scope *sc) sc2->parent = this; //if (isUnionDeclaration()) // TODO // sc2->inunion = 1; - sc2->protection = PROTpublic; + sc2->protection = Prot(PROTpublic); sc2->explicitProtection = 0; sc2->structalign = STRUCTALIGN_DEFAULT; sc2->userAttribDecl = NULL; @@ -219,7 +221,7 @@ void AggregateDeclaration::semantic3(Scope *sc) sc2->parent = this; if (isUnionDeclaration()) sc2->inunion = 1; - sc2->protection = PROTpublic; + sc2->protection = Prot(PROTpublic); sc2->explicitProtection = 0; sc2->structalign = STRUCTALIGN_DEFAULT; sc2->userAttribDecl = NULL; @@ -386,7 +388,7 @@ bool AggregateDeclaration::isDeprecated() bool AggregateDeclaration::isExport() { - return protection == PROTexport; + return protection.kind == PROTexport; } /**************************** @@ -642,14 +644,10 @@ StructDeclaration::StructDeclaration(Loc loc, Identifier *id) Dsymbol *StructDeclaration::syntaxCopy(Dsymbol *s) { - StructDeclaration *sd; - - if (s) - sd = (StructDeclaration *)s; - else - sd = new StructDeclaration(loc, ident); - ScopeDsymbol::syntaxCopy(sd); - return sd; + StructDeclaration *sd = + s ? (StructDeclaration *)s + : new StructDeclaration(loc, ident); + return ScopeDsymbol::syntaxCopy(sd); } void StructDeclaration::semantic(Scope *sc) @@ -736,7 +734,7 @@ void StructDeclaration::semantic(Scope *sc) sc2->parent = this; if (isUnionDeclaration()) sc2->inunion = 1; - sc2->protection = PROTpublic; + sc2->protection = Prot(PROTpublic); sc2->explicitProtection = 0; sc2->structalign = STRUCTALIGN_DEFAULT; sc2->userAttribDecl = NULL; @@ -863,7 +861,8 @@ void StructDeclaration::semantic(Scope *sc) { unsigned xerrors = global.startGagging(); sc = sc->push(); - sc->speculative = true; + sc->tinst = NULL; + sc->minst = NULL; FuncDeclaration *fcall = resolveFuncCall(loc, sc, scall, NULL, NULL, NULL, 1); sc = sc->pop(); global.endGagging(xerrors); @@ -1222,32 +1221,6 @@ bool StructDeclaration::isPOD() return (ispod == ISPODyes); } -void StructDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->printf("%s ", kind()); - if (!isAnonymous()) - buf->writestring(toChars()); - if (!members) - { - buf->writeByte(';'); - buf->writenl(); - return; - } - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - buf->level++; - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = (*members)[i]; - s->toCBuffer(buf, hgs); - } - buf->level--; - buf->writeByte('}'); - buf->writenl(); -} - - const char *StructDeclaration::kind() { return "struct"; @@ -1262,17 +1235,11 @@ UnionDeclaration::UnionDeclaration(Loc loc, Identifier *id) Dsymbol *UnionDeclaration::syntaxCopy(Dsymbol *s) { - UnionDeclaration *ud; - - if (s) - ud = (UnionDeclaration *)s; - else - ud = new UnionDeclaration(loc, ident); - StructDeclaration::syntaxCopy(ud); - return ud; + assert(!s); + UnionDeclaration *ud = new UnionDeclaration(loc, ident); + return StructDeclaration::syntaxCopy(ud); } - const char *UnionDeclaration::kind() { return "union"; diff --git a/dmd2/target.h b/dmd2/target.h index a662ec6b01..d36f663b8a 100644 --- a/dmd2/target.h +++ b/dmd2/target.h @@ -26,7 +26,8 @@ struct Target static int realpad; // 'padding' added to the CPU real size to bring it up to realsize static int realalignsize; // alignment for reals static bool reverseCppOverloads; // with dmc, overloaded functions are grouped and in reverse order - static int longsize; // size of a C 'long' or 'unsigned long' type + static int c_longsize; // size of a C 'long' or 'unsigned long' type + static int c_long_doublesize; // size of a C 'long double' static void init(); static unsigned alignsize(Type* type); @@ -34,6 +35,7 @@ struct Target static unsigned critsecsize(); static Type *va_listType(); // get type of va_list static Expression *paintAsType(Expression *e, Type *type); + static int checkVectorType(int sz, Type *type); }; #endif diff --git a/dmd2/template.c b/dmd2/template.c index 111e077988..9e44d1d25a 100644 --- a/dmd2/template.c +++ b/dmd2/template.c @@ -46,9 +46,9 @@ void DtoOverloadedIntrinsicName(TemplateInstance* ti, TemplateDeclaration* td, s size_t templateParameterLookup(Type *tparam, TemplateParameters *parameters); int arrayObjectMatch(Objects *oa1, Objects *oa2); -hash_t arrayObjectHash(Objects *oa1); unsigned char deduceWildHelper(Type *t, Type **at, Type *tparam); MATCH deduceTypeHelper(Type *t, Type **at, Type *tparam); +void mangleToBuffer(Expression *e, OutBuffer *buf); /******************************************** * These functions substitute for dynamic_cast. dynamic_cast does not work @@ -228,11 +228,11 @@ bool definitelyValueParameter(Expression *e) if (e->op != TOKdotvar) return true; - /* Template instantiations involving a DotVar expression are difficult. - * In most cases, they should be treated as a value parameter, and interpreted. - * But they might also just be a fully qualified name, which should be treated - * as an alias. - */ + /* Template instantiations involving a DotVar expression are difficult. + * In most cases, they should be treated as a value parameter, and interpreted. + * But they might also just be a fully qualified name, which should be treated + * as an alias. + */ // x.y.f cannot be a value FuncDeclaration *f = ((DotVarExp *)e)->var->isFuncDeclaration(); @@ -407,73 +407,13 @@ hash_t arrayObjectHash(Objects *oa1) return hash; } - -/**************************************** - * This makes a 'pretty' version of the template arguments. - * It's analogous to genIdent() which makes a mangled version. - */ - -void ObjectToCBuffer(OutBuffer *buf, HdrGenState *hgs, RootObject *oarg) -{ - //printf("ObjectToCBuffer()\n"); - Type *t = isType(oarg); - Expression *e = isExpression(oarg); - Dsymbol *s = isDsymbol(oarg); - Tuple *v = isTuple(oarg); - /* The logic of this should match what genIdent() does. The _dynamic_cast() - * function relies on all the pretty strings to be unique for different classes - * (see Bugzilla 7375). - * Perhaps it would be better to demangle what genIdent() does. - */ - if (t) - { - //printf("\tt: %s ty = %d\n", t->toChars(), t->ty); - t->toCBuffer(buf, NULL, hgs); - } - else if (e) - { - if (e->op == TOKvar) - e = e->optimize(WANTvalue); // added to fix Bugzilla 7375 - e->toCBuffer(buf, hgs); - } - else if (s) - { - char *p = s->ident ? s->ident->toChars() : s->toChars(); - buf->writestring(p); - } - else if (v) - { - Objects *args = &v->objects; - for (size_t i = 0; i < args->dim; i++) - { - if (i) - buf->writestring(", "); - RootObject *o = (*args)[i]; - ObjectToCBuffer(buf, hgs, o); - } - } - else if (!oarg) - { - buf->writestring("NULL"); - } - else - { -#ifdef DEBUG - printf("bad Object = %p\n", oarg); -#endif - assert(0); - } -} - RootObject *objectSyntaxCopy(RootObject *o) { if (!o) return NULL; - Type *t = isType(o); - if (t) + if (Type *t = isType(o)) return t->syntaxCopy(); - Expression *e = isExpression(o); - if (e) + if (Expression *e = isExpression(o)) return e->syntaxCopy(); return o; } @@ -515,7 +455,7 @@ TemplateDeclaration::TemplateDeclaration(Loc loc, Identifier *id, this->ismixin = ismixin; this->isstatic = true; this->previous = NULL; - this->protection = PROTundefined; + this->protection = Prot(PROTundefined); this->numinstances = 0; // Compute in advance for Ddoc's use @@ -534,29 +474,25 @@ TemplateDeclaration::TemplateDeclaration(Loc loc, Identifier *id, Dsymbol *TemplateDeclaration::syntaxCopy(Dsymbol *) { //printf("TemplateDeclaration::syntaxCopy()\n"); - TemplateDeclaration *td; - TemplateParameters *p; - - p = NULL; + TemplateParameters *p = NULL; if (parameters) { p = new TemplateParameters(); p->setDim(parameters->dim); for (size_t i = 0; i < p->dim; i++) - { - TemplateParameter *tp = (*parameters)[i]; - (*p)[i] = tp->syntaxCopy(); - } + (*p)[i] = (*parameters)[i]->syntaxCopy(); } - Expression *e = NULL; - if (constraint) - e = constraint->syntaxCopy(); - Dsymbols *d = Dsymbol::arraySyntaxCopy(members); - td = new TemplateDeclaration(loc, ident, p, e, d, ismixin, literal); #if IN_LLVM + TemplateDeclaration *td = new TemplateDeclaration(loc, ident, p, + constraint ? constraint->syntaxCopy() : NULL, + Dsymbol::arraySyntaxCopy(members), ismixin, literal); td->intrinsicName = intrinsicName; -#endif return td; +#else + return new TemplateDeclaration(loc, ident, p, + constraint ? constraint->syntaxCopy() : NULL, + Dsymbol::arraySyntaxCopy(members), ismixin, literal); +#endif } void TemplateDeclaration::semantic(Scope *sc) @@ -808,8 +744,8 @@ bool TemplateDeclaration::evaluateConstraint( Scope *scx = paramscope->push(ti); scx->parent = ti; - scx->tinst = ti; - scx->speculative = true; + scx->tinst = NULL; + scx->minst = NULL; assert(!ti->symtab); if (fd) @@ -858,7 +794,7 @@ bool TemplateDeclaration::evaluateConstraint( Expression *e = constraint->syntaxCopy(); scx = scx->startCTFE(); - scx->flags |= SCOPEstaticif; + scx->flags |= SCOPEcondition | SCOPEconstraint; assert(ti->inst == NULL); ti->inst = ti; // temporary instantiation to enable genIdent() @@ -946,6 +882,7 @@ MATCH TemplateDeclaration::matchWithInstance(Scope *sc, TemplateInstance *ti, paramsym->parent = scope->parent; Scope *paramscope = scope->push(paramsym); paramscope->tinst = ti; + paramscope->minst = sc->minst; paramscope->callsc = sc; paramscope->stc = 0; @@ -1026,10 +963,15 @@ MATCH TemplateDeclaration::matchWithInstance(Scope *sc, TemplateInstance *ti, // Resolve parameter types and 'auto ref's. tf->fargs = fargs; + unsigned olderrors = global.startGagging(); fd->type = tf->semantic(loc, paramscope); - fd->originalType = fd->type; // for mangling - if (fd->type->ty != Tfunction) + if (global.endGagging(olderrors)) + { + assert(fd->type->ty != Tfunction); goto Lnomatch; + } + assert(fd->type->ty == Tfunction); + fd->originalType = fd->type; // for mangling } // TODO: dedtypes => ti->tiargs ? @@ -1104,11 +1046,6 @@ MATCH TemplateDeclaration::leastAsSpecialized(Scope *sc, TemplateDeclaration *td */ TemplateInstance ti(Loc(), ident); // create dummy template instance - ti.tinst = this->getInstantiating(sc); - if (ti.tinst) - ti.instantiatingModule = ti.tinst->instantiatingModule; - else - ti.instantiatingModule = sc->instantiatingModule(); // Set type arguments to dummy template instance to be types // generated from the parameters to this template declaration ti.tiargs = new Objects(); @@ -1246,6 +1183,7 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch( paramsym->parent = scope->parent; // should use hasnestedArgs and enclosing? Scope *paramscope = scope->push(paramsym); paramscope->tinst = ti; + paramscope->minst = sc->minst; paramscope->callsc = sc; paramscope->stc = 0; @@ -1383,13 +1321,8 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch( } } -#if BUGZILLA_11946 - if (isstatic) - tthis = NULL; -#else if (toParent()->isModule() || (scope->stc & STCstatic)) tthis = NULL; -#endif if (tthis) { bool hasttp = false; @@ -1654,39 +1587,20 @@ Lretry: if (m == MATCHnomatch && prmtype->deco) m = farg->implicitConvTo(prmtype); - /* If no match, see if there's a conversion to a delegate - */ if (m == MATCHnomatch) { - Type *tbp = prmtype->toBasetype(); - Type *tba = farg->type->toBasetype(); - if (tbp->ty == Tdelegate) + AggregateDeclaration *ad = isAggregate(farg->type); + if (ad && ad->aliasthis) { - TypeDelegate *td = (TypeDelegate *)prmtype->toBasetype(); - TypeFunction *tf = (TypeFunction *)td->next; - - if (!tf->varargs && Parameter::dim(tf->parameters) == 0) + /* If a semantic error occurs while doing alias this, + * eg purity(bug 7295), just regard it as not a match. + */ + unsigned olderrors = global.startGagging(); + Expression *e = resolveAliasThis(sc, farg); + if (!global.endGagging(olderrors)) { - m = deduceType(farg->type, paramscope, tf->next, parameters, dedtypes); - if (m == MATCHnomatch && tf->next->toBasetype()->ty == Tvoid) - m = MATCHconvert; - } - //printf("\tm2 = %d\n", m); - } - else if (AggregateDeclaration *ad = isAggregate(tba)) - { - if (ad->aliasthis) - { - /* If a semantic error occurs while doing alias this, - * eg purity(bug 7295), just regard it as not a match. - */ - unsigned olderrors = global.startGagging(); - Expression *e = resolveAliasThis(sc, farg); - if (!global.endGagging(olderrors)) - { - farg = e; - goto Lretry; - } + farg = e; + goto Lretry; } } } @@ -1935,17 +1849,17 @@ Lmatch: // Partially instantiate function for constraint and fd->leastAsSpecialized() { assert(paramsym); - Scope *sc1 = scope->push(paramsym); - sc1->tinst = ti; - - Scope *sc2 = sc1->push(ti); + Scope *sc2 = scope; + sc2 = sc2->push(paramsym); + sc2 = sc2->push(ti); sc2->parent = ti; sc2->tinst = ti; + sc2->minst = sc->minst; fd = doHeaderInstantiation(ti, sc2, fd, tthis, fargs); - sc2->pop(); - sc1->pop(); + sc2 = sc2->pop(); + sc2 = sc2->pop(); if (!fd) goto Lnomatch; @@ -1958,10 +1872,10 @@ Lmatch: } #if 0 - for (i = 0; i < dedargs->dim; i++) + for (size_t i = 0; i < dedargs->dim; i++) { - Type *t = (*dedargs)[i]; - printf("\tdedargs[%d] = %d, %s\n", i, t->dyncast(), t->toChars()); + RootObject *o = (*dedargs)[i]; + printf("\tdedargs[%d] = %d, %s\n", i, o->dyncast(), o->toChars()); } #endif @@ -2154,7 +2068,7 @@ void functionResolve(Match *m, Dsymbol *dstart, Loc loc, Scope *sc, if (tiargs && tiargs->dim > 0) return 0; - //printf("fd = %s %s\n", fd->toChars(), fd->type->toChars()); + //printf("fd = %s %s, fargs = %s\n", fd->toChars(), fd->type->toChars(), fargs->toChars()); m->anyf = fd; TypeFunction *tf = (TypeFunction *)fd->type; @@ -2282,12 +2196,6 @@ void functionResolve(Match *m, Dsymbol *dstart, Loc loc, Scope *sc, if (!tiargs) tiargs = new Objects(); TemplateInstance *ti = new TemplateInstance(loc, td, tiargs); - ti->tinst = td->getInstantiating(sc); - if (ti->tinst) - ti->instantiatingModule = ti->tinst->instantiatingModule; - else - ti->instantiatingModule = sc->instantiatingModule(); - Objects dedtypes; dedtypes.setDim(td->parameters->dim); assert(td->semanticRun != PASSinit); @@ -2398,11 +2306,6 @@ void functionResolve(Match *m, Dsymbol *dstart, Loc loc, Scope *sc, /* This is a 'dummy' instance to evaluate constraint properly. */ TemplateInstance *ti = new TemplateInstance(loc, td, tiargs); - ti->tinst = td->getInstantiating(sc); - if (ti->tinst) - ti->instantiatingModule = ti->tinst->instantiatingModule; - else - ti->instantiatingModule = sc->instantiatingModule(); ti->parent = td->parent; // Maybe calculating valid 'enclosing' is unnecessary. FuncDeclaration *fd = f; @@ -2410,9 +2313,7 @@ void functionResolve(Match *m, Dsymbol *dstart, Loc loc, Scope *sc, MATCH mta = (MATCH)(x >> 4); MATCH mfa = (MATCH)(x & 0xF); //printf("match:t/f = %d/%d\n", mta, mfa); - if (!fd) - goto Lerror; - if (mfa == MATCHnomatch) + if (!fd || mfa == MATCHnomatch) continue; Type *tthis_fd = fd->needThis() ? tthis : NULL; @@ -2583,7 +2484,7 @@ void functionResolve(Match *m, Dsymbol *dstart, Loc loc, Scope *sc, if (FuncLiteralDeclaration *fld = m->lastf->isFuncLiteralDeclaration()) { - if ((sc->flags & SCOPEstaticif) || sc->intypeof) + if ((sc->flags & SCOPEconstraint) || sc->intypeof) { // Inside template constraint, or inside typeof, // nested reference check doesn't work correctly. @@ -2692,14 +2593,23 @@ FuncDeclaration *TemplateDeclaration::doHeaderInstantiation( tf->next = NULL; fd->type = tf; fd->type = fd->type->addSTC(scx->stc); + + unsigned olderrors = global.startGagging(); fd->type = fd->type->semantic(fd->loc, scx); + scx = scx->pop(); + + if (global.endGagging(olderrors)) + { + assert(fd->type->ty != Tfunction); + return NULL; + } + assert(fd->type->ty == Tfunction); + fd->originalType = fd->type; // for mangling //printf("\t[%s] fd->type = %s, mod = %x, ", loc.toChars(), fd->type->toChars(), fd->type->mod); //printf("fd->needThis() = %d\n", fd->needThis()); - scx = scx->pop(); - - return fd->type->ty == Tfunction ? fd : NULL; + return fd; } bool TemplateDeclaration::hasStaticCtorOrDtor() @@ -2707,138 +2617,6 @@ bool TemplateDeclaration::hasStaticCtorOrDtor() return false; // don't scan uninstantiated templates } -void TemplateDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ -#if 0 // Should handle template functions for doc generation - if (onemember && onemember->isFuncDeclaration()) - buf->writestring("foo "); -#endif - if (hgs->hdrgen && members && members->dim == 1) - { - FuncDeclaration *fd = (*members)[0]->isFuncDeclaration(); - if (fd && fd->type && fd->type->ty == Tfunction && fd->ident == ident) - { - StorageClassDeclaration::stcToCBuffer(buf, fd->storage_class); - functionToBufferFull((TypeFunction *)fd->type, buf, ident, hgs, this); - - if (constraint) - { - buf->writestring(" if ("); - constraint->toCBuffer(buf, hgs); - buf->writeByte(')'); - } - - hgs->tpltMember++; - fd->bodyToCBuffer(buf, hgs); - hgs->tpltMember--; - return; - } - - AggregateDeclaration *ad = (*members)[0]->isAggregateDeclaration(); - if (ad) - { - buf->writestring(ad->kind()); - buf->writeByte(' '); - buf->writestring(ident->toChars()); - buf->writeByte('('); - for (size_t i = 0; i < parameters->dim; i++) - { - TemplateParameter *tp = (*parameters)[i]; - if (hgs->ddoc) - tp = (*origParameters)[i]; - if (i) - buf->writestring(", "); - tp->toCBuffer(buf, hgs); - } - buf->writeByte(')'); - - if (constraint) - { - buf->writestring(" if ("); - constraint->toCBuffer(buf, hgs); - buf->writeByte(')'); - } - - ClassDeclaration *cd = ad->isClassDeclaration(); - if (cd && cd->baseclasses->dim) - { - buf->writestring(" : "); - for (size_t i = 0; i < cd->baseclasses->dim; i++) - { - BaseClass *b = (*cd->baseclasses)[i]; - if (i) - buf->writestring(", "); - b->type->toCBuffer(buf, NULL, hgs); - } - } - - hgs->tpltMember++; - if (ad->members) - { - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - buf->level++; - for (size_t i = 0; i < ad->members->dim; i++) - { - Dsymbol *s = (*ad->members)[i]; - s->toCBuffer(buf, hgs); - } - buf->level--; - buf->writestring("}"); - } - else - buf->writeByte(';'); - buf->writenl(); - hgs->tpltMember--; - return; - } - } - - if (hgs->ddoc) - buf->writestring(kind()); - else - buf->writestring("template"); - buf->writeByte(' '); - buf->writestring(ident->toChars()); - buf->writeByte('('); - for (size_t i = 0; i < parameters->dim; i++) - { - TemplateParameter *tp = (*parameters)[i]; - if (hgs->ddoc) - tp = (*origParameters)[i]; - if (i) - buf->writestring(", "); - tp->toCBuffer(buf, hgs); - } - buf->writeByte(')'); - if (constraint) - { - buf->writestring(" if ("); - constraint->toCBuffer(buf, hgs); - buf->writeByte(')'); - } - - if (hgs->hdrgen) - { - hgs->tpltMember++; - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - buf->level++; - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = (*members)[i]; - s->toCBuffer(buf, hgs); - } - buf->level--; - buf->writeByte('}'); - buf->writenl(); - hgs->tpltMember--; - } -} - - char *TemplateDeclaration::toChars() { if (literal) @@ -2847,7 +2625,6 @@ char *TemplateDeclaration::toChars() OutBuffer buf; HdrGenState hgs; - memset(&hgs, 0, sizeof(hgs)); buf.writestring(ident->toChars()); buf.writeByte('('); for (size_t i = 0; i < parameters->dim; i++) @@ -2855,7 +2632,7 @@ char *TemplateDeclaration::toChars() TemplateParameter *tp = (*parameters)[i]; if (i) buf.writestring(", "); - tp->toCBuffer(&buf, &hgs); + ::toCBuffer(tp, &buf, &hgs); } buf.writeByte(')'); @@ -2865,21 +2642,20 @@ char *TemplateDeclaration::toChars() if (fd && fd->type) { TypeFunction *tf = (TypeFunction *)fd->type; - char const* args = Parameter::argsTypesToChars(tf->parameters, tf->varargs); - buf.writestring(args); + buf.writestring(parametersTypeToChars(tf->parameters, tf->varargs)); } } if (constraint) { buf.writestring(" if ("); - constraint->toCBuffer(&buf, &hgs); + ::toCBuffer(constraint, &buf, &hgs); buf.writeByte(')'); } return buf.extractString(); } -PROT TemplateDeclaration::prot() +Prot TemplateDeclaration::prot() { return protection; } @@ -2992,21 +2768,6 @@ void TemplateDeclaration::removeInstance(TemplateInstance *handle) --numinstances; } -/******************************************* - * Returns template instance which instantiating this template declaration. - */ - -TemplateInstance *TemplateDeclaration::getInstantiating(Scope *sc) -{ - /* If this is instantiated declaration in root module, Return it. - */ - TemplateInstance *tinst = isInstantiated(); - if (tinst && (!tinst->instantiatingModule || tinst->instantiatingModule->isRoot())) - return tinst; - - return sc->tinst; -} - /* ======================== Type ============================================ */ /**** @@ -3759,7 +3520,7 @@ MATCH deduceType(RootObject *o, Scope *sc, Type *tparam, TemplateParameters *par fparam->type = fparam->type->addStorageClass(fparam->storageClass); fparam->storageClass &= ~(STC_TYPECTOR | STCin); } - //printf("\t-> this = %d, ", ty); print(); + //printf("\t-> this = %d, ", t->ty); t->print(); //printf("\t-> tparam = %d, ", tparam->ty); tparam->print(); /* See if tuple match @@ -4211,22 +3972,6 @@ MATCH deduceType(RootObject *o, Scope *sc, Type *tparam, TemplateParameters *par visit((Type *)t); } - void visit(TypeTypedef *t) - { - // Extra check - if (tparam && tparam->ty == Ttypedef) - { - TypeTypedef *tp = (TypeTypedef *)tparam; - - if (t->sym != tp->sym) - { - result = MATCHnomatch; - return; - } - } - visit((Type *)t); - } - /* Helper for TypeClass::deduceType(). * Classes can match with implicit conversion to a base class or interface. * This is complicated, because there may be more than one base class which @@ -4462,13 +4207,13 @@ MATCH deduceType(RootObject *o, Scope *sc, Type *tparam, TemplateParameters *par match1 = MATCHexact; for (size_t j = 0; j < xt->argexps.dim; j++) { - Expression *e = xt->argexps[j]; - if (e == emptyArrayElement) + Expression *ex = xt->argexps[j]; + if (ex == emptyArrayElement) continue; Type *pt = tt->addMod(xt->tparams[j]->mod); if (wm && *wm) pt = pt->substWildTo(*wm); - MATCH m = e->implicitConvTo(pt); + MATCH m = ex->implicitConvTo(pt); if (match1 > m) match1 = m; if (match1 <= MATCHnomatch) @@ -4573,7 +4318,7 @@ MATCH deduceType(RootObject *o, Scope *sc, Type *tparam, TemplateParameters *par { if ((!e->elements || !e->elements->dim) && e->type->toBasetype()->nextOf()->ty == Tvoid && - (tparam->ty == Tarray/* || tparam->ty == Tsarray || tparam->ty == Taarray*/)) + tparam->ty == Tarray) { // tparam:T[] <- e:[] (void[]) result = deduceEmptyArrayElement(); @@ -4979,12 +4724,9 @@ TemplateTypeParameter *TemplateTypeParameter::isTemplateTypeParameter() TemplateParameter *TemplateTypeParameter::syntaxCopy() { - TemplateTypeParameter *tp = new TemplateTypeParameter(loc, ident, specType, defaultType); - if (tp->specType) - tp->specType = specType->syntaxCopy(); - if (defaultType) - tp->defaultType = defaultType->syntaxCopy(); - return tp; + return new TemplateTypeParameter(loc, ident, + specType ? specType->syntaxCopy() : NULL, + defaultType ? defaultType->syntaxCopy() : NULL); } void TemplateTypeParameter::declareParameter(Scope *sc) @@ -5121,23 +4863,6 @@ void TemplateTypeParameter::print(RootObject *oarg, RootObject *oded) printf("\tDeduced Type: %s\n", ta->toChars()); } - -void TemplateTypeParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(ident->toChars()); - if (specType) - { - buf->writestring(" : "); - specType->toCBuffer(buf, NULL, hgs); - } - if (defaultType) - { - buf->writestring(" = "); - defaultType->toCBuffer(buf, NULL, hgs); - } -} - - void *TemplateTypeParameter::dummyArg() { Type *t = specType; @@ -5192,18 +4917,9 @@ TemplateThisParameter *TemplateThisParameter::isTemplateThisParameter() TemplateParameter *TemplateThisParameter::syntaxCopy() { - TemplateThisParameter *tp = new TemplateThisParameter(loc, ident, specType, defaultType); - if (tp->specType) - tp->specType = specType->syntaxCopy(); - if (defaultType) - tp->defaultType = defaultType->syntaxCopy(); - return tp; -} - -void TemplateThisParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("this "); - TemplateTypeParameter::toCBuffer(buf, hgs); + return new TemplateThisParameter(loc, ident, + specType ? specType->syntaxCopy() : NULL, + defaultType ? defaultType->syntaxCopy() : NULL); } /* ======================== TemplateAliasParameter ========================== */ @@ -5229,12 +4945,10 @@ TemplateAliasParameter *TemplateAliasParameter::isTemplateAliasParameter() TemplateParameter *TemplateAliasParameter::syntaxCopy() { - TemplateAliasParameter *tp = new TemplateAliasParameter(loc, ident, specType, specAlias, defaultAlias); - if (tp->specType) - tp->specType = specType->syntaxCopy(); - tp->specAlias = objectSyntaxCopy(specAlias); - tp->defaultAlias = objectSyntaxCopy(defaultAlias); - return tp; + return new TemplateAliasParameter(loc, ident, + specType ? specType->syntaxCopy() : NULL, + objectSyntaxCopy(specAlias), + objectSyntaxCopy(defaultAlias)); } void TemplateAliasParameter::declareParameter(Scope *sc) @@ -5438,29 +5152,6 @@ void TemplateAliasParameter::print(RootObject *oarg, RootObject *oded) printf("\tParameter alias: %s\n", sa->toChars()); } -void TemplateAliasParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("alias "); - if (specType) - { - HdrGenState hgs1; - specType->toCBuffer(buf, ident, &hgs1); - } - else - buf->writestring(ident->toChars()); - if (specAlias) - { - buf->writestring(" : "); - ObjectToCBuffer(buf, hgs, specAlias); - } - if (defaultAlias) - { - buf->writestring(" = "); - ObjectToCBuffer(buf, hgs, defaultAlias); - } -} - - void *TemplateAliasParameter::dummyArg() { RootObject *s = specAlias; @@ -5525,14 +5216,10 @@ TemplateValueParameter *TemplateValueParameter::isTemplateValueParameter() TemplateParameter *TemplateValueParameter::syntaxCopy() { - TemplateValueParameter *tp = - new TemplateValueParameter(loc, ident, valType, specValue, defaultValue); - tp->valType = valType->syntaxCopy(); - if (specValue) - tp->specValue = specValue->syntaxCopy(); - if (defaultValue) - tp->defaultValue = defaultValue->syntaxCopy(); - return tp; + return new TemplateValueParameter(loc, ident, + valType->syntaxCopy(), + specValue ? specValue->syntaxCopy() : NULL, + defaultValue ? defaultValue->syntaxCopy() : NULL); } void TemplateValueParameter::declareParameter(Scope *sc) @@ -5730,23 +5417,6 @@ void TemplateValueParameter::print(RootObject *oarg, RootObject *oded) printf("\tParameter Value: %s\n", ea ? ea->toChars() : "NULL"); } - -void TemplateValueParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - valType->toCBuffer(buf, ident, hgs); - if (specValue) - { - buf->writestring(" : "); - specValue->toCBuffer(buf, hgs); - } - if (defaultValue) - { - buf->writestring(" = "); - defaultValue->toCBuffer(buf, hgs); - } -} - - void *TemplateValueParameter::dummyArg() { Expression *e = specValue; @@ -5804,8 +5474,7 @@ TemplateTupleParameter *TemplateTupleParameter::isTemplateTupleParameter() TemplateParameter *TemplateTupleParameter::syntaxCopy() { - TemplateTupleParameter *tp = new TemplateTupleParameter(loc, ident); - return tp; + return new TemplateTupleParameter(loc, ident); } void TemplateTupleParameter::declareParameter(Scope *sc) @@ -5920,13 +5589,6 @@ void TemplateTupleParameter::print(RootObject *oarg, RootObject *oded) printf("]\n"); } -void TemplateTupleParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(ident->toChars()); - buf->writestring("..."); -} - - void *TemplateTupleParameter::dummyArg() { return NULL; @@ -5961,9 +5623,10 @@ TemplateInstance::TemplateInstance(Loc loc, Identifier *ident) this->name = ident; this->tiargs = NULL; this->tempdecl = NULL; - this->instantiatingModule = NULL; this->inst = NULL; this->tinst = NULL; + this->tnext = NULL; + this->minst = NULL; this->deferred = NULL; this->argsym = NULL; this->aliasdecl = NULL; @@ -5972,7 +5635,6 @@ TemplateInstance::TemplateInstance(Loc loc, Identifier *ident) this->havetempdecl = false; this->enclosing = NULL; this->gagged = false; - this->speculative = false; this->hash = 0; this->fargs = NULL; } @@ -5992,9 +5654,10 @@ TemplateInstance::TemplateInstance(Loc loc, TemplateDeclaration *td, Objects *ti this->name = td->ident; this->tiargs = tiargs; this->tempdecl = td; - this->instantiatingModule = NULL; this->inst = NULL; this->tinst = NULL; + this->tnext = NULL; + this->minst = NULL; this->deferred = NULL; this->argsym = NULL; this->aliasdecl = NULL; @@ -6003,7 +5666,6 @@ TemplateInstance::TemplateInstance(Loc loc, TemplateDeclaration *td, Objects *ti this->havetempdecl = true; this->enclosing = NULL; this->gagged = false; - this->speculative = false; this->hash = 0; this->fargs = NULL; @@ -6019,24 +5681,17 @@ Objects *TemplateInstance::arraySyntaxCopy(Objects *objs) a = new Objects(); a->setDim(objs->dim); for (size_t i = 0; i < objs->dim; i++) - { (*a)[i] = objectSyntaxCopy((*objs)[i]); - } } return a; } Dsymbol *TemplateInstance::syntaxCopy(Dsymbol *s) { - TemplateInstance *ti; - - if (s) - ti = (TemplateInstance *)s; - else - ti = new TemplateInstance(loc, name); - + TemplateInstance *ti = + s ? (TemplateInstance *)s + : new TemplateInstance(loc, name); ti->tiargs = arraySyntaxCopy(tiargs); - TemplateDeclaration *td; if (inst && tempdecl && (td = tempdecl->isTemplateDeclaration()) != NULL) td->ScopeDsymbol::syntaxCopy(ti); @@ -6045,7 +5700,6 @@ Dsymbol *TemplateInstance::syntaxCopy(Dsymbol *s) return ti; } - void TemplateInstance::semantic(Scope *sc) { semantic(sc, NULL); @@ -6146,8 +5800,11 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs) #if LOG printf("Recursive template expansion\n"); #endif + Ungag ungag(global.gag); + if (!gagged) + global.gag = 0; error(loc, "recursive template expansion"); - if (global.gag) + if (gagged) semanticRun = PASSinit; else inst = this; @@ -6155,32 +5812,13 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs) return; } - /* If a TemplateInstance is ever instantiated by non-root modules, - * we do not have to generate code for it, - * because it will be generated when the non-root module is compiled. - */ - Module *mi = sc->instantiatingModule(); - if (!instantiatingModule || instantiatingModule->isRoot()) - instantiatingModule = mi; - //printf("mi = %s\n", mi->toChars()); - - /* Get the enclosing template instance from the scope tinst - */ + // Get the enclosing template instance from the scope tinst tinst = sc->tinst; - if (global.gag) - gagged = true; - if (sc->speculative || (tinst && tinst->speculative)) - { - //printf("\tspeculative ti %s '%s' gag = %d, spec = %d\n", tempdecl->parent->toChars(), toChars(), global.gag, sc->speculative); - speculative = true; - } - if (sc->flags & (SCOPEstaticif | SCOPEstaticassert | SCOPEcompile)) - { - // Disconnect the chain if this instantiation is in definitely speculative context. - // It should be done after sc->instantiatingModule(). - tinst = NULL; - } + // Get the instantiating module from the scope minst + minst = sc->minst; + + gagged = (global.gag > 0); semanticRun = PASSsemantic; @@ -6217,88 +5855,73 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs) /* See if there is an existing TemplateInstantiation that already * implements the typeargs. If so, just refer to that one instead. */ + inst = tempdecl->findExistingInstance(this, fargs); + if (!inst) { - TemplateInstance *ti = tempdecl->findExistingInstance(this, fargs); - if (ti) + // So, we need to implement 'this' instance. + } + else if (inst->gagged && !gagged && inst->errors) + { + // If the first instantiation had failed, re-run semantic, + // so that error messages are shown. + } + else + { + // It's a match + parent = inst->parent; + errors = inst->errors; + + // If both this and the previous instantiation were gagged, + // use the number of errors that happened last time. + global.errors += errors; + global.gaggedErrors += errors; + + // If the first instantiation was gagged, but this is not: + if (inst->gagged) { - // It's a match - inst = ti; - parent = ti->parent; + // It had succeeded, mark it is a non-gagged instantiation, + // and reuse it. + inst->gagged = gagged; + } - // If both this and the previous instantiation were gagged, - // use the number of errors that happened last time. - if (inst->gagged && gagged) - { - global.errors += inst->errors; - global.gaggedErrors += inst->errors; - } + this->tnext = inst->tnext; + inst->tnext = this; - // If the first instantiation was gagged, but this is not: - if (inst->gagged && !gagged) - { - // If the first instantiation had failed, re-run semantic, - // so that error messages are shown. - if (inst->errors) - goto L1; - // It had succeeded, mark it is a non-gagged instantiation, - // and reuse it. - inst->gagged = false; - } + // If the first instantiation was in speculative context, but this is not: + if (tinst && !inst->tinst && !inst->minst) + { + // Reconnect the chain if this instantiation is not in speculative context. + TemplateInstance *ti = tinst; + while (ti && ti != inst) + ti = ti->tinst; + if (ti != inst) // Bugzilla 13379: Prevent circular chain + inst->tinst = tinst; + } - // If the first instantiation was speculative, but this is not: - if (inst->speculative && !sc->speculative) - { - // Mark it is a non-speculative instantiation. - inst->speculative = false; - - // Bugzilla 13400: When an instance is changed to non-speculative, - // its instantiatingModule should also be updated. - // See test/runnable/link13400.d - inst->instantiatingModule = mi; - } - - // If the first instantiation was in speculative context, but this is not: - if (!inst->tinst && inst->speculative && - tinst && !(sc->flags & (SCOPEstaticif | SCOPEstaticassert | SCOPEcompile))) - { - // Reconnect the chain if this instantiation is not in speculative context. - TemplateInstance *tix = tinst; - while (tix && tix != inst) - tix = tix->tinst; - if (tix != inst) // Bugzilla 13379: Prevent circular chain - inst->tinst = tinst; - } + // If the first instantiation was speculative, but this is not: + if (!inst->minst) + { + // Mark it is a non-speculative instantiation. + inst->minst = minst; + } #if LOG - printf("\tit's a match with instance %p, %d\n", inst, inst->semanticRun); + printf("\tit's a match with instance %p, %d\n", inst, inst->semanticRun); #endif - // If this is not a speculative instantiation, it might allow us to - // elide codegen for the template instance. - if (!speculative && - (!inst->instantiatingModule || inst->instantiatingModule->isRoot())) - { - inst->instantiatingModule = mi; - } - errors = inst->errors; - return; - } - L1: ; + return; } - - /* So, we need to implement 'this' instance. - */ #if LOG printf("\timplement template instance %s '%s'\n", tempdecl->parent->toChars(), toChars()); printf("\ttempdecl %s\n", tempdecl->toChars()); #endif unsigned errorsave = global.errors; + inst = this; - - TemplateInstance *tempdecl_instance_idx = tempdecl->addInstance(this); - parent = enclosing ? enclosing : tempdecl->parent; //printf("parent = '%s'\n", parent->kind()); + TemplateInstance *tempdecl_instance_idx = tempdecl->addInstance(this); + //getIdent(); // Add 'this' to the enclosing scope's members[] so the semantic routines @@ -6306,110 +5929,69 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs) // in target_symbol_list(_idx) so we can remove it later if we encounter // an error. #if 1 - Dsymbols *target_symbol_list = NULL; + Dsymbols *target_symbol_list; size_t target_symbol_list_idx = 0; - + //if (sc->scopesym) printf("3: sc is %s %s\n", sc->scopesym->kind(), sc->scopesym->toChars()); + if (!tinst && sc->scopesym && sc->scopesym->members) { - Dsymbols *a; - Scope *scx = sc; -#if 0 - for (scx = sc; scx; scx = scx->enclosing) - if (scx->scopesym) - break; -#endif - - //if (scx && scx->scopesym) printf("3: scx is %s %s\n", scx->scopesym->kind(), scx->scopesym->toChars()); - /* The problem is if A imports B, and B imports A, and both A - * and B instantiate the same template, does the compilation of A - * or the compilation of B do the actual instantiation? - * - * see bugzilla 2500. - * - * && !scx->module->selfImports() + /* A module can have explicit template instance and its alias + * in module scope (e,g, `alias Base64Impl!('+', '/') Base64;`). + * When the module is just imported, compiler can assume that + * its instantiated code would be contained in the separately compiled + * obj/lib file (e.g. phobos.lib). So we can omit their semantic3 running. */ - if (scx && scx->scopesym && scx->scopesym->members && - !scx->scopesym->isTemplateMixin()) - { - /* A module can have explicit template instance and its alias - * in module scope (e,g, `alias Base64Impl!('+', '/') Base64;`). - * When the module is just imported, compiler can assume that - * its instantiated code would be contained in the separately compiled - * obj/lib file (e.g. phobos.lib). So we can omit their semantic3 running. - */ - //if (scx->scopesym->isModule()) - // printf("module level instance %s\n", toChars()); + //if (sc->scopesym->isModule()) + // printf("module level instance %s\n", toChars()); - //printf("\t1: adding to %s %s\n", scx->scopesym->kind(), scx->scopesym->toChars()); - a = scx->scopesym->members; - } - else - { - Dsymbol *s = enclosing ? enclosing : tempdecl->parent; - for (; s; s = s->toParent2()) - { - if (s->isModule()) - break; - } - assert(s); - Module *m = (Module *)s; - if (!m->isRoot()) - { - m = m->importedFrom; - } - //printf("\t2: adding to module %s instead of module %s\n", m->toChars(), sc->module->toChars()); - a = m->members; + //printf("\t1: adding to %s %s\n", sc->scopesym->kind(), sc->scopesym->toChars()); + target_symbol_list = sc->scopesym->members; + } + else + { + Dsymbol *s = enclosing ? enclosing : tempdecl->parent; + while (s && !s->isModule()) + s = s->toParent2(); + assert(s); + Module *m = (Module *)s; + if (!m->isRoot()) + m = m->importedFrom; - /* Defer semantic3 running in order to avoid mutual forward reference. - * See test/runnable/test10736.d - */ - if (m->semanticRun >= PASSsemantic3done) - Module::addDeferredSemantic3(this); - } - for (size_t i = 0; 1; i++) + //printf("\t2: adding to module %s instead of module %s\n", m->toChars(), sc->module->toChars()); + target_symbol_list = m->members; + + /* Defer semantic3 running in order to avoid mutual forward reference. + * See test/runnable/test10736.d + */ + if (m->semanticRun >= PASSsemantic3done) + Module::addDeferredSemantic3(this); + } + for (size_t i = 0; 1; i++) + { + if (i == target_symbol_list->dim) { - if (i == a->dim) - { - target_symbol_list = a; - target_symbol_list_idx = i; - a->push(this); - break; - } - if (this == (*a)[i]) // if already in Array - break; + target_symbol_list_idx = i; + target_symbol_list->push(this); + break; + } + if (this == (*target_symbol_list)[i]) // if already in Array + { + target_symbol_list = NULL; + break; } } #endif // Copy the syntax trees from the TemplateDeclaration - if (members && speculative && !errors) // todo - { - // Don't copy again so they were previously created. - } - else - members = Dsymbol::arraySyntaxCopy(tempdecl->members); + members = Dsymbol::arraySyntaxCopy(tempdecl->members); - // todo for TemplateThisParameter + // resolve TemplateThisParameter for (size_t i = 0; i < tempdecl->parameters->dim; i++) { if ((*tempdecl->parameters)[i]->isTemplateThisParameter() == NULL) continue; Type *t = isType((*tiargs)[i]); assert(t); - - StorageClass stc = 0; - if (t->mod & MODimmutable) - stc |= STCimmutable; - else - { - if (t->mod & MODconst) - stc |= STCconst; - else if (t->mod & MODwild) - stc |= STCwild; - - if (t->mod & MODshared) - stc |= STCshared; - } - if (stc != 0) + if (StorageClass stc = ModToStc(t->mod)) { //printf("t = %s, stc = x%llx\n", t->toChars(), stc); Dsymbols *s = new Dsymbols(); @@ -6434,6 +6016,7 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs) argsym->parent = scope->parent; scope = scope->push(argsym); scope->tinst = this; + scope->minst = minst; //scope->stc = 0; // Declare each template parameter as an alias for the argument type @@ -6516,11 +6099,7 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs) //printf("enclosing = %d, sc->parent = %s\n", enclosing, sc->parent->toChars()); sc2->parent = this; sc2->tinst = this; - sc2->speculative = speculative; -#if BUGZILLA_11946 - if (enclosing && tempdecl->isstatic) - sc2->stc &= ~STCstatic; -#endif + sc2->minst = minst; tryExpandMembers(sc2); @@ -7466,12 +7045,6 @@ bool TemplateInstance::needsTypeInference(Scope *sc, int flag) if (!flag) { - ti->tinst = td->getInstantiating(sc); - if (ti->tinst) - ti->instantiatingModule = ti->tinst->instantiatingModule; - else - ti->instantiatingModule = sc->instantiatingModule(); - /* Calculate the need for overload resolution. * When only one template can match with tiargs, inference is not necessary. */ @@ -7719,33 +7292,11 @@ Identifier *TemplateInstance::genIdent(Objects *args) ea = ea->ctfeInterpret(); if (ea->op == TOKerror || olderr != global.errors) continue; -#if !IN_LLVM + /* Use deco that matches what it would be for a function parameter */ buf.writestring(ea->type->deco); -#else - // This is a workaround for DMD bug 7469 (https://issues.dlang.org/show_bug.cgi?id=7469) - // FIXME: The bug is resolved in DMD 2.066. Remove in 0.15.0 - - // The declared parameter list might be shorter because of variadic arguments - if (((TemplateDeclaration*)tempdecl)->parameters->dim > i) - { - // Use type of parameter, not type of argument - TemplateParameter *tp = (*((TemplateDeclaration*)tempdecl)->parameters)[i]; - assert(tp); - TemplateValueParameter *tvp = tp->isTemplateValueParameter(); - if (tvp && tvp->valType->deco) - buf.writestring(tvp->valType->deco); - else - goto Lusetypeofvalue; - } - else - { - Lusetypeofvalue: - buf.writestring(ea->type->deco); - } -#endif - ea->toMangleBuffer(&buf); + mangleToBuffer(ea, &buf); } else if (sa) { @@ -7836,6 +7387,7 @@ void TemplateInstance::semantic2(Scope *sc) sc = sc->push(argsym); sc = sc->push(this); sc->tinst = this; + sc->minst = minst; int needGagging = (gagged && !global.gag); unsigned int olderrors = global.errors; @@ -7894,6 +7446,7 @@ void TemplateInstance::semantic3(Scope *sc) sc = sc->push(argsym); sc = sc->push(this); sc->tinst = this; + sc->minst = minst; int needGagging = (gagged && !global.gag); unsigned int olderrors = global.errors; @@ -8014,64 +7567,6 @@ void TemplateInstance::printInstantiationTrace() } } -void TemplateInstance::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - Identifier *id = name; - buf->writestring(id->toChars()); - toCBufferTiargs(buf, hgs); -} - -void TemplateInstance::toCBufferTiargs(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writeByte('!'); - if (nest) - buf->writestring("(...)"); - else if (!tiargs) - buf->writestring("()"); - else - { - if (tiargs->dim == 1) - { - RootObject *oarg = (*tiargs)[0]; - if (Type *t = isType(oarg)) - { - if (t->equals(Type::tstring) || - t->mod == 0 && - (t->isTypeBasic() || - t->ty == Tident && ((TypeIdentifier *)t)->idents.dim == 0)) - { - buf->writestring(t->toChars()); - return; - } - } - else if (Expression *e = isExpression(oarg)) - { - if (e->op == TOKint64 || - e->op == TOKfloat64 || - e->op == TOKnull || - e->op == TOKstring || - e->op == TOKthis) - { - buf->writestring(e->toChars()); - return; - } - } - } - buf->writeByte('('); - nest++; - for (size_t i = 0; i < tiargs->dim; i++) - { - if (i) - buf->writestring(", "); - RootObject *oarg = (*tiargs)[i]; - ObjectToCBuffer(buf, hgs, oarg); - } - nest--; - buf->writeByte(')'); - } -} - - Dsymbol *TemplateInstance::toAlias() { #if LOG @@ -8117,21 +7612,14 @@ bool TemplateInstance::oneMember(Dsymbol **ps, Identifier *ident) char *TemplateInstance::toChars() { OutBuffer buf; - HdrGenState hgs; - char *s; - - toCBuffer(&buf, &hgs); - s = buf.extractString(); - return s; + toCBufferInstance(this, &buf); + return buf.extractString(); } char *TemplateInstance::toPrettyCharsHelper() { OutBuffer buf; - HdrGenState hgs; - hgs.fullQualification = 1; - toCBuffer(&buf, &hgs); - + toCBufferInstance(this, &buf, true); return buf.extractString(); } @@ -8199,11 +7687,74 @@ hash_t TemplateInstance::hashCode() return hash; } +/************************************** + * IsExpression can evaluate the specified type speculatively, and even if + * it instantiates any symbols, they are normally unnecessary for the + * final executable. + * However, if those symbols leak to the actual code, compiler should remark + * them as non-speculative to generate their code and link to the final executable. + */ +void unSpeculative(Scope *sc, RootObject *o) +{ + if (!o) + return; + + if (Tuple *tup = isTuple(o)) + { + for (size_t i = 0; i < tup->objects.dim; i++) + { + unSpeculative(sc, tup->objects[i]); + } + return; + } + + Dsymbol *s = getDsymbol(o); + if (!s) + return; + + Declaration *d = s->isDeclaration(); + if (d) + { + if (VarDeclaration *vd = d->isVarDeclaration()) + o = vd->type; + else if (AliasDeclaration *ad = d->isAliasDeclaration()) + { + o = ad->getType(); + if (!o) + o = ad->toAlias(); + } + else + o = d->toAlias(); + + s = getDsymbol(o); + if (!s) + return; + } + + if (TemplateInstance *ti = s->isTemplateInstance()) + { + // If the instance is already non-speculative, + // or it is leaked to the speculative scope. + if (ti->minst != NULL || sc->minst == NULL) + return; + + // Remark as non-speculative instance. + ti->minst = sc->minst; + if (!ti->tinst) + ti->tinst = sc->tinst; + + unSpeculative(sc, ti->tempdecl); + } + + if (TemplateInstance *ti = s->isInstantiated()) + unSpeculative(sc, ti); +} + /*********************************************** * Returns true if this is not instantiated in non-root module, and * is a part of non-speculative instantiatiation. * - * Note: instantiatingModule does not stabilize until semantic analysis is completed, + * Note: minst does not stabilize until semantic analysis is completed, * so don't call this function during semantic analysis to return precise result. */ bool TemplateInstance::needsCodegen() @@ -8218,8 +7769,8 @@ bool TemplateInstance::needsCodegen() global.params.allInst || global.params.debuglevel) { - //printf("%s instantiatingModule = %s, speculative = %d, enclosing in nonRoot = %d\n", - // toPrettyChars(), instantiatingModule ? instantiatingModule->toChars() : NULL, speculative, + //printf("%s minst = %s, enclosing in nonRoot = %d\n", + // toPrettyChars(), minst ? minst->toChars() : NULL, // enclosing && !enclosing->isInstantiated() && enclosing->inNonRoot()); if (enclosing) { @@ -8233,46 +7784,53 @@ bool TemplateInstance::needsCodegen() return true; } - if (instantiatingModule && !instantiatingModule->isRoot()) + // If this may be a speculative instantiation: + if (!minst) { - Module *mi = instantiatingModule; - - // If mi imports any root modules, we still need to generate the code. - for (size_t i = 0; i < Module::amodules.dim; ++i) + for (TemplateInstance *ti = this; ti; ti = ti->tnext) { - Module *m = Module::amodules[i]; - m->insearch = 0; - } - bool importsRoot = false; - for (size_t i = 0; i < Module::amodules.dim; ++i) - { - Module *m = Module::amodules[i]; - if (m->isRoot() && mi->imports(m)) + TemplateInstance *tix = ti; + while (tix && !tix->minst) + tix = tix->tinst; + if (tix) { - importsRoot = true; - break; + assert(tix->minst); + + // cache the result, ti is in non-speculative instantiation chain + minst = tix->minst; + return tix->needsCodegen(); } + // ti was speculative. } - for (size_t i = 0; i < Module::amodules.dim; ++i) + + // cache the result, mark as definitely speculative + tinst = NULL; + minst = NULL; + return false; + } + + if (!minst->isRoot()) + { + /* If a TemplateInstance is ever instantiated by non-root modules, + * we do not have to generate code for it, + * because it will be generated when the non-root module is compiled. + * + * But, if minst imports any root modules, we still need to generate the code. + * + * The problem is if A imports B, and B imports A, and both A + * and B instantiate the same template, does the compilation of A + * or the compilation of B do the actual instantiation? + * + * See bugzilla 2500. + */ + + if (!minst->rootImports()) { - Module *m = Module::amodules[i]; - m->insearch = 0; - } - if (!importsRoot) - { - //printf("instantiated by %s %s\n", instantiatingModule->toChars(), toChars()); + //printf("instantiated by %s %s\n", minst->toChars(), toChars()); return false; } } - - for (TemplateInstance *ti = this; ti; ti = ti->tinst) - { - //printf("\tti = %s spec = %d\n", ti->toChars(), ti->speculative); - if (!ti->speculative) - return true; - } - - return false; + return true; } /* ======================== TemplateMixin ================================ */ @@ -8291,8 +7849,7 @@ Dsymbol *TemplateMixin::syntaxCopy(Dsymbol *s) { TemplateMixin *tm = new TemplateMixin(loc, ident, (TypeQualified *)tqual->syntaxCopy(), tiargs); - TemplateInstance::syntaxCopy(tm); - return tm; + return TemplateInstance::syntaxCopy(tm); } bool TemplateMixin::findTempDecl(Scope *sc) @@ -8520,12 +8077,7 @@ void TemplateMixin::semantic(Scope *sc) } // Copy the syntax trees from the TemplateDeclaration - if (scx && members && !errors) - { - // Don't copy again so they were previously created. - } - else - members = Dsymbol::arraySyntaxCopy(tempdecl->members); + members = Dsymbol::arraySyntaxCopy(tempdecl->members); if (!members) return; @@ -8536,7 +8088,7 @@ void TemplateMixin::semantic(Scope *sc) ScopeDsymbol *sds = (ScopeDsymbol *)sce->scopesym; if (sds) { - sds->importScope(this, PROTpublic); + sds->importScope(this, Prot(PROTpublic)); break; } } @@ -8605,35 +8157,11 @@ void TemplateMixin::semantic(Scope *sc) nest--; - 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 : sc->copy(); - scope->setNoFree(); - scope->module->addDeferredSemantic(this); - } - return; - } + /* In DeclDefs scope, TemplateMixin does not have to handle deferred symbols. + * Because the members would already call Module::addDeferredSemantic() for themselves. + * See Struct, Class, Interface, and EnumDeclaration::semantic(). + */ + //if (!sc->func && Module::deferred.dim > deferred_dim) {} AggregateDeclaration *ad = toParent()->isAggregateDeclaration(); if (sc->func && !ad) @@ -8774,26 +8302,6 @@ void TemplateMixin::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, char *TemplateMixin::toChars() { OutBuffer buf; - HdrGenState hgs; - char *s; - - TemplateInstance::toCBuffer(&buf, &hgs); - s = buf.extractString(); - return s; -} - -void TemplateMixin::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("mixin "); - - tqual->toCBuffer(buf, NULL, hgs); - toCBufferTiargs(buf, hgs); - - if (ident && memcmp(ident->string, "__mixin", 7) != 0) - { - buf->writeByte(' '); - buf->writestring(ident->toChars()); - } - buf->writeByte(';'); - buf->writenl(); + toCBufferInstance(this, &buf); + return buf.extractString(); } diff --git a/dmd2/template.h b/dmd2/template.h index 69cfee6bea..f24ad2902a 100644 --- a/dmd2/template.h +++ b/dmd2/template.h @@ -40,7 +40,6 @@ struct Scope; class Expression; class AliasDeclaration; class FuncDeclaration; -struct HdrGenState; class Parameter; enum MATCH; enum PASS; @@ -82,7 +81,7 @@ public: bool literal; // this template declaration is a literal bool ismixin; // template declaration is only to be used as a mixin bool isstatic; // this is static template declaration - PROT protection; + Prot protection; TemplatePrevious *previous; // threaded list of previous instantiation attempts on stack @@ -91,12 +90,11 @@ public: Dsymbol *syntaxCopy(Dsymbol *); void semantic(Scope *sc); bool overloadInsert(Dsymbol *s); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); bool hasStaticCtorOrDtor(); const char *kind(); char *toChars(); - PROT prot(); + Prot prot(); bool evaluateConstraint(TemplateInstance *ti, Scope *sc, Scope *paramscope, Objects *dedtypes, FuncDeclaration *fd); @@ -110,8 +108,6 @@ public: TemplateInstance *addInstance(TemplateInstance *ti); void removeInstance(TemplateInstance *handle); - TemplateInstance *getInstantiating(Scope *sc); - TemplateDeclaration *isTemplateDeclaration() { return this; } TemplateTupleParameter *isVariadic(); @@ -166,7 +162,6 @@ public: virtual void declareParameter(Scope *sc) = 0; virtual void semantic(Scope *sc, TemplateParameters *parameters) = 0; virtual void print(RootObject *oarg, RootObject *oded) = 0; - virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs) = 0; virtual RootObject *specialization() = 0; virtual RootObject *defaultArg(Loc loc, Scope *sc) = 0; virtual bool hasDefaultArg() = 0; @@ -183,6 +178,7 @@ public: /* Create dummy argument based on parameter. */ virtual void *dummyArg() = 0; + virtual void accept(Visitor *v) { v->visit(this); } }; /* Syntax: @@ -203,13 +199,13 @@ public: void declareParameter(Scope *sc); void semantic(Scope *sc, TemplateParameters *parameters); void print(RootObject *oarg, RootObject *oded); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); RootObject *specialization(); RootObject *defaultArg(Loc loc, Scope *sc); bool hasDefaultArg(); int overloadMatch(TemplateParameter *); MATCH matchArg(Scope *sc, RootObject *oarg, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); void *dummyArg(); + void accept(Visitor *v) { v->visit(this); } }; /* Syntax: @@ -222,7 +218,7 @@ public: TemplateThisParameter *isTemplateThisParameter(); TemplateParameter *syntaxCopy(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void accept(Visitor *v) { v->visit(this); } }; /* Syntax: @@ -244,13 +240,13 @@ public: void declareParameter(Scope *sc); void semantic(Scope *sc, TemplateParameters *parameters); void print(RootObject *oarg, RootObject *oded); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); RootObject *specialization(); RootObject *defaultArg(Loc loc, Scope *sc); bool hasDefaultArg(); int overloadMatch(TemplateParameter *); MATCH matchArg(Scope *sc, RootObject *oarg, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); void *dummyArg(); + void accept(Visitor *v) { v->visit(this); } }; /* Syntax: @@ -272,13 +268,13 @@ public: void declareParameter(Scope *sc); void semantic(Scope *sc, TemplateParameters *parameters); void print(RootObject *oarg, RootObject *oded); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); RootObject *specialization(); RootObject *defaultArg(Loc loc, Scope *sc); bool hasDefaultArg(); int overloadMatch(TemplateParameter *); MATCH matchArg(Scope *sc, RootObject *oarg, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); void *dummyArg(); + void accept(Visitor *v) { v->visit(this); } }; /* Syntax: @@ -294,7 +290,6 @@ public: void declareParameter(Scope *sc); void semantic(Scope *sc, TemplateParameters *parameters); void print(RootObject *oarg, RootObject *oded); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); RootObject *specialization(); RootObject *defaultArg(Loc loc, Scope *sc); bool hasDefaultArg(); @@ -302,6 +297,7 @@ public: MATCH matchArg(Loc loc, Scope *sc, Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); MATCH matchArg(Scope *sc, RootObject *oarg, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); void *dummyArg(); + void accept(Visitor *v) { v->visit(this); } }; /* Given: @@ -327,7 +323,6 @@ public: Dsymbol *enclosing; // if referencing local symbols, this is the context Dsymbol *aliasdecl; // !=NULL if instance is an alias for its sole member TemplateInstance *inst; // refer to existing instance - TemplateInstance *tinst; // enclosing template instance ScopeDsymbol *argsym; // argument symbol table int nest; // for recursion detection bool semantictiargsdone; // has semanticTiargs() been done? @@ -340,8 +335,9 @@ public: // Used to determine the instance needs code generation. // Note that these are inaccurate until semantic analysis phase completed. - Module *instantiatingModule; // the top module that instantiated this instance - bool speculative; // if the instantiation is speculative + TemplateInstance *tinst; // enclosing template instance + TemplateInstance *tnext; // non-first instantiated instances + Module *minst; // the top module that instantiated this instance TemplateInstance(Loc loc, Identifier *temp_id); TemplateInstance(Loc loc, TemplateDeclaration *tempdecl, Objects *tiargs); @@ -351,8 +347,6 @@ public: void semantic(Scope *sc); void semantic2(Scope *sc); void semantic3(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toCBufferTiargs(OutBuffer *buf, HdrGenState *hgs); Dsymbol *toAlias(); // resolve real symbol const char *kind(); bool oneMember(Dsymbol **ps, Identifier *ident); @@ -402,7 +396,6 @@ public: bool hasPointers(); void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion); char *toChars(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); #if IN_DMD void toObjFile(bool multiobj); // compile to .obj file @@ -424,7 +417,6 @@ int isError(RootObject *o); Type *getType(RootObject *o); Dsymbol *getDsymbol(RootObject *o); -void ObjectToCBuffer(OutBuffer *buf, HdrGenState *hgs, RootObject *oarg); RootObject *objectSyntaxCopy(RootObject *o); #endif /* DMD_TEMPLATE_H */ diff --git a/dmd2/traits.c b/dmd2/traits.c index 04118d4ca9..ac151c37b7 100644 --- a/dmd2/traits.c +++ b/dmd2/traits.c @@ -34,7 +34,6 @@ #include "dsymbol.h" #include "module.h" #include "attrib.h" -#include "hdrgen.h" #include "parse.h" #include "speller.h" @@ -262,9 +261,9 @@ StringTable traitsStringTable; void initTraitsStringTable() { - traitsStringTable._init(); + traitsStringTable._init(40); - for (size_t idx = 0; ; idx++) + for (size_t idx = 0;; idx++) { const char *s = traits[idx]; if (!s) break; @@ -284,6 +283,38 @@ void *trait_search_fp(void *arg, const char *seed) return sv ? (void*)sv->ptrvalue : NULL; } +static int fpisTemplate(void *param, Dsymbol *s) +{ + if (s->isTemplateDeclaration()) + return 1; + + return 0; +} + +bool isTemplate(Dsymbol *s) +{ + if (!s->toAlias()->isOverloadable()) + return false; + + return overloadApply(s, NULL, &fpisTemplate) != 0; +} + +Expression *isSymbolX(TraitsExp *e, bool (*fp)(Dsymbol *s)) +{ + int result = 0; + if (!e->args || !e->args->dim) + goto Lfalse; + for (size_t i = 0; i < e->args->dim; i++) + { + Dsymbol *s = getDsymbol((*e->args)[i]); + if (!s || !fp(s)) + goto Lfalse; + } + result = 1; +Lfalse: + return new IntegerExp(e->loc, result, Type::tbool); +} + Expression *semanticTraits(TraitsExp *e, Scope *sc) { #if LOGSEMANTIC @@ -333,6 +364,10 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) { return isTypeX(e, &isTypeFinalClass); } + else if (e->ident == Id::isTemplate) + { + return isSymbolX(e, &isTemplate); + } else if (e->ident == Id::isPOD) { if (dim != 1) @@ -477,7 +512,7 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) if (s->scope) s->semantic(s->scope); - const char *protName = protectionToChars(s->prot()); + const char *protName = protectionToChars(s->prot().kind); // TODO: How about package(names) assert(protName); StringExp *se = new StringExp(e->loc, (char *) protName); return se->semantic(sc); @@ -700,6 +735,10 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) e->error("first argument is not a symbol"); goto Lfalse; } + if (s->isImport()) + { + s = s->isImport()->mod; + } //printf("getAttributes %s, attrs = %p, scope = %p\n", s->toChars(), s->userAttribDecl, s->scope); UserAttributeDeclaration *udad = s->userAttribDecl; TupleExp *tup = new TupleExp(e->loc, udad ? udad->getAttributes() : new Expressions()); @@ -797,7 +836,8 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) /* Skip if already present in idents[] */ for (size_t j = 0; j < idents->dim; j++) - { Identifier *id = (*idents)[j]; + { + Identifier *id = (*idents)[j]; if (id == sm->ident) return 0; #ifdef DEBUG @@ -827,6 +867,9 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) ClassDeclaration *cd = sds->isClassDeclaration(); if (cd && e->ident == Id::allMembers) { + if (cd->scope) + cd->semantic(NULL); // Bugzilla 13668: Try to resolve forward reference + struct PushBaseMembers { static void dg(ClassDeclaration *cd, Identifiers *idents) @@ -834,6 +877,7 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) for (size_t i = 0; i < cd->baseclasses->dim; i++) { ClassDeclaration *cb = (*cd->baseclasses)[i]->base; + assert(cb); ScopeDsymbol::foreach(NULL, cb->members, &PushIdentsDg::dg, idents); if (cb->baseclasses->dim) dg(cb, idents); @@ -873,8 +917,9 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) { unsigned errors = global.startGagging(); Scope *sc2 = sc->push(); - sc2->speculative = true; - sc2->flags = (sc->flags & ~SCOPEctfe) | SCOPEcompile; + sc2->tinst = NULL; + sc2->minst = NULL; + sc2->flags = (sc->flags & ~(SCOPEctfe | SCOPEcondition)) | SCOPEcompile; bool err = false; RootObject *o = (*e->args)[i]; diff --git a/dmd2/version.c b/dmd2/version.c index 201fa4b840..68722e4af6 100644 --- a/dmd2/version.c +++ b/dmd2/version.c @@ -92,17 +92,6 @@ void DebugSymbol::semantic(Scope *sc) //printf("DebugSymbol::semantic() %s\n", toChars()); } -void DebugSymbol::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("debug = "); - if (ident) - buf->writestring(ident->toChars()); - else - buf->printf("%u", level); - buf->writestring(";"); - buf->writenl(); -} - const char *DebugSymbol::kind() { return "debug"; @@ -180,20 +169,7 @@ void VersionSymbol::semantic(Scope *sc) { } -void VersionSymbol::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("version = "); - if (ident) - buf->writestring(ident->toChars()); - else - buf->printf("%u", level); - buf->writestring(";"); - buf->writenl(); -} - const char *VersionSymbol::kind() { return "version"; } - - diff --git a/dmd2/version.h b/dmd2/version.h index 2dec2765d1..4baea36835 100644 --- a/dmd2/version.h +++ b/dmd2/version.h @@ -18,9 +18,6 @@ #include "dsymbol.h" -struct OutBuffer; -struct HdrGenState; - class DebugSymbol : public Dsymbol { public: @@ -32,7 +29,6 @@ public: int addMember(Scope *sc, ScopeDsymbol *sds, int memnum); void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); const char *kind(); void accept(Visitor *v) { v->visit(this); } }; @@ -48,7 +44,6 @@ public: int addMember(Scope *sc, ScopeDsymbol *sds, int memnum); void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); const char *kind(); void accept(Visitor *v) { v->visit(this); } }; diff --git a/dmd2/visitor.h b/dmd2/visitor.h index 00f58b30e5..6ed9844d2a 100644 --- a/dmd2/visitor.h +++ b/dmd2/visitor.h @@ -55,6 +55,7 @@ class AsmStatement; #if IN_LLVM class AsmBlockStatement; #endif +class CompoundAsmStatement; class ImportStatement; class Type; @@ -77,7 +78,6 @@ class TypeTypeof; class TypeReturn; class TypeStruct; class TypeEnum; -class TypeTypedef; class TypeClass; class TypeTuple; class TypeSlice; @@ -116,6 +116,7 @@ class Package; class Module; class WithScopeSymbol; class ArrayScopeSymbol; +class Nspace; class AggregateDeclaration; class StructDeclaration; @@ -125,7 +126,6 @@ class InterfaceDeclaration; class Declaration; class TupleDeclaration; -class TypedefDeclaration; class AliasDeclaration; class OverDeclaration; class VarDeclaration; @@ -137,7 +137,6 @@ class TypeInfoDeclaration; class TypeInfoStructDeclaration; class TypeInfoClassDeclaration; class TypeInfoInterfaceDeclaration; -class TypeInfoTypedefDeclaration; class TypeInfoPointerDeclaration; class TypeInfoArrayDeclaration; class TypeInfoStaticArrayDeclaration; @@ -286,6 +285,21 @@ class ClassReferenceExp; class VoidInitExp; class ThrownExceptionExp; +class TemplateParameter; +class TemplateTypeParameter; +class TemplateThisParameter; +class TemplateValueParameter; +class TemplateAliasParameter; +class TemplateTupleParameter; + +class Condition; +class DVCondition; +class DebugCondition; +class VersionCondition; +class StaticIfCondition; + +class Parameter; + class Visitor { public: @@ -331,6 +345,7 @@ public: #if IN_LLVM virtual void visit(AsmBlockStatement *s) { visit((Statement *)s); } #endif + virtual void visit(CompoundAsmStatement *s) { visit((CompoundStatement *)s); } virtual void visit(ImportStatement *s) { visit((Statement *)s); } virtual void visit(Type *) { assert(0); } @@ -353,7 +368,6 @@ public: virtual void visit(TypeReturn *t) { visit((TypeQualified *)t); } virtual void visit(TypeStruct *t) { visit((Type *)t); } virtual void visit(TypeEnum *t) { visit((Type *)t); } - virtual void visit(TypeTypedef *t) { visit((Type *)t); } virtual void visit(TypeClass *t) { visit((Type *)t); } virtual void visit(TypeTuple *t) { visit((Type *)t); } virtual void visit(TypeSlice *t) { visit((TypeNext *)t); } @@ -392,6 +406,7 @@ public: virtual void visit(Module *s) { visit((Package *)s); } virtual void visit(WithScopeSymbol *s) { visit((ScopeDsymbol *)s); } virtual void visit(ArrayScopeSymbol *s) { visit((ScopeDsymbol *)s); } + virtual void visit(Nspace *s) { visit((ScopeDsymbol *)s); } virtual void visit(AggregateDeclaration *s) { visit((ScopeDsymbol *)s); } virtual void visit(StructDeclaration *s) { visit((AggregateDeclaration *)s); } @@ -401,7 +416,6 @@ public: virtual void visit(Declaration *s) { visit((Dsymbol *)s); } virtual void visit(TupleDeclaration *s) { visit((Declaration *)s); } - virtual void visit(TypedefDeclaration *s) { visit((Declaration *)s); } virtual void visit(AliasDeclaration *s) { visit((Declaration *)s); } virtual void visit(OverDeclaration *s) { visit((Declaration *)s); } virtual void visit(VarDeclaration *s) { visit((Declaration *)s); } @@ -413,7 +427,6 @@ public: virtual void visit(TypeInfoStructDeclaration *s) { visit((TypeInfoDeclaration *)s); } virtual void visit(TypeInfoClassDeclaration *s) { visit((TypeInfoDeclaration *)s); } virtual void visit(TypeInfoInterfaceDeclaration *s) { visit((TypeInfoDeclaration *)s); } - virtual void visit(TypeInfoTypedefDeclaration *s) { visit((TypeInfoDeclaration *)s); } virtual void visit(TypeInfoPointerDeclaration *s) { visit((TypeInfoDeclaration *)s); } virtual void visit(TypeInfoArrayDeclaration *s) { visit((TypeInfoDeclaration *)s); } virtual void visit(TypeInfoStaticArrayDeclaration *s) { visit((TypeInfoDeclaration *)s); } @@ -561,6 +574,21 @@ public: virtual void visit(ClassReferenceExp *e) { visit((Expression *)e); } virtual void visit(VoidInitExp *e) { visit((Expression *)e); } virtual void visit(ThrownExceptionExp *e) { visit((Expression *)e); } + + virtual void visit(TemplateParameter *) { assert(0); } + virtual void visit(TemplateTypeParameter *tp) { visit((TemplateParameter *)tp); } + virtual void visit(TemplateThisParameter *tp) { visit((TemplateTypeParameter *)tp); } + virtual void visit(TemplateValueParameter *tp) { visit((TemplateParameter *)tp); } + virtual void visit(TemplateAliasParameter *tp) { visit((TemplateParameter *)tp); } + virtual void visit(TemplateTupleParameter *tp) { visit((TemplateParameter *)tp); } + + virtual void visit(Condition *) { assert(0); } + virtual void visit(DVCondition *c) { visit((Condition *)c); } + virtual void visit(DebugCondition *c) { visit((DVCondition *)c); } + virtual void visit(VersionCondition *c) { visit((DVCondition *)c); } + virtual void visit(StaticIfCondition *c) { visit((Condition *)c); } + + virtual void visit(Parameter *) { assert(0); } }; class StoppableVisitor : public Visitor diff --git a/driver/main.cpp b/driver/main.cpp index e1b2a42d51..0644724eb8 100644 --- a/driver/main.cpp +++ b/driver/main.cpp @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// #include "module.h" -#include "color.h" +#include "errors.h" #include "doc.h" #include "id.h" #include "hdrgen.h" diff --git a/gen/arrays.cpp b/gen/arrays.cpp index d76506d321..4bd068d24c 100644 --- a/gen/arrays.cpp +++ b/gen/arrays.cpp @@ -569,13 +569,6 @@ static bool isInitialized(Type* et) { et = bt->nextOf(); bt = et->toBasetype(); } - // If it's a typedef with "= void" initializer then don't initialize. - if (et->ty == Ttypedef) { - IF_LOG Logger::println("Typedef: %s", et->toChars()); - TypedefDeclaration* tdd = static_cast(et)->sym; - if (tdd && tdd->init && tdd->init->isVoidInitializer()) - return false; - } // Otherwise, it's always initialized. return true; } diff --git a/gen/asm-x86.h b/gen/asm-x86.h index 5f936a3c6d..4f017b0701 100644 --- a/gen/asm-x86.h +++ b/gen/asm-x86.h @@ -2970,7 +2970,7 @@ namespace AsmParserx8664 } bool isDollar ( Expression * exp ) { - return exp->op == TOKidentifier && ( ( IdentifierExp * ) exp )->ident == Id::__dollar; + return exp->op == TOKidentifier && ( ( IdentifierExp * ) exp )->ident == Id::dollar; } Expression * newRegExp ( int regno ) @@ -3491,7 +3491,7 @@ namespace AsmParserx8664 { return new IdentifierExp ( stmt->loc, ident ); } - else if ( ident == Id::__dollar ) + else if ( ident == Id::dollar ) { do_dollar: return new IdentifierExp ( stmt->loc, ident ); @@ -3608,7 +3608,7 @@ namespace AsmParserx8664 break; case TOKdollar: nextToken(); - ident = Id::__dollar; + ident = Id::dollar; goto do_dollar; break; default: diff --git a/gen/declarations.cpp b/gen/declarations.cpp index 7d3a754973..5e9ba2244c 100644 --- a/gen/declarations.cpp +++ b/gen/declarations.cpp @@ -295,24 +295,6 @@ public: ////////////////////////////////////////////////////////////////////////// - void visit(TypedefDeclaration *decl) LLVM_OVERRIDE { - IF_LOG Logger::println("TypedefDeclaration::codegen: '%s'", decl->toPrettyChars()); - LOG_SCOPE; - - if (decl->ir.isDefined()) return; - decl->ir.setDefined(); - - if (decl->type->ty == Terror) - { error(decl->loc, "had semantic errors when compiling"); - return; - } - - // generate typeinfo - DtoTypeInfoOf(decl->type, false); - } - - ////////////////////////////////////////////////////////////////////////// - void visit(EnumDeclaration *decl) LLVM_OVERRIDE { IF_LOG Logger::println("Ignoring EnumDeclaration::codegen: '%s'", decl->toPrettyChars()); diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index 3a7399e42b..82e30ab3fe 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -1142,12 +1142,6 @@ DValue* DtoDeclarationExp(Dsymbol* declaration) Logger::println("ClassDeclaration"); Declaration_codegen(e); } - // typedef - else if (TypedefDeclaration* tdef = declaration->isTypedefDeclaration()) - { - Logger::println("TypedefDeclaration"); - DtoTypeInfoOf(tdef->type, false); - } // attribute declaration else if (AttribDeclaration* a = declaration->isAttribDeclaration()) { @@ -1268,8 +1262,6 @@ LLConstant* DtoConstInitializer(Loc& loc, Type* type, Initializer* init) { IF_LOG Logger::println("const default initializer for %s", type->toChars()); Expression *initExp = type->defaultInit(); - if (type->ty == Ttypedef) - initExp->type = type; // This carries the typedef type into toConstElem. _init = DtoConstExpInit(loc, type, initExp); } else if (ExpInitializer* ex = init->isExpInitializer()) diff --git a/gen/target.cpp b/gen/target.cpp index 086880306a..8d4ae25f2f 100644 --- a/gen/target.cpp +++ b/gen/target.cpp @@ -23,7 +23,8 @@ int Target::ptrsize; int Target::realsize; int Target::realpad; int Target::realalignsize; -int Target::longsize; +int Target::c_longsize; +int Target::c_long_doublesize; bool Target::reverseCppOverloads; void Target::init() @@ -34,7 +35,8 @@ void Target::init() realsize = gDataLayout->getTypeAllocSize(real); realpad = realsize - gDataLayout->getTypeStoreSize(real); realalignsize = gDataLayout->getABITypeAlignment(real); - longsize = global.params.is64bit ? 8 : 4; + c_longsize = global.params.is64bit ? 8 : 4; + c_long_doublesize = realsize; reverseCppOverloads = false; // DMC is not supported. } @@ -145,3 +147,18 @@ Expression *Target::paintAsType(Expression *e, Type *type) return NULL; // avoid warning } + +/****************************** +* Check if the given type is supported for this target +* 0: supported +* 1: not supported +* 2: wrong size +* 3: wrong base type +*/ + +int Target::checkVectorType(int sz, Type *type) +{ + // FIXME: It is possible to query the LLVM target about supported vectors? + return 0; +} + diff --git a/gen/toir.cpp b/gen/toir.cpp index 54107e4ee6..c56d3e93ec 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -1335,7 +1335,7 @@ public: // Also, private methods are always not virtual. const bool nonFinal = !fdecl->isFinalFunc() && (fdecl->isAbstract() || fdecl->isVirtual()) && - fdecl->prot() != PROTprivate; + fdecl->prot().kind != PROTprivate; // If we are calling a non-final interface function, we need to get // the pointer to the underlying object instead of passing the diff --git a/gen/tollvm.cpp b/gen/tollvm.cpp index 1b3963be01..39530ae9f6 100644 --- a/gen/tollvm.cpp +++ b/gen/tollvm.cpp @@ -208,7 +208,6 @@ LLType* DtoType(Type* t) // enum // FIXME: maybe just call toBasetype first ? - case Ttypedef: case Tenum: { Type* bt = t->toBasetype(); diff --git a/gen/typinf.cpp b/gen/typinf.cpp index 87b45d1214..9de24c2a52 100644 --- a/gen/typinf.cpp +++ b/gen/typinf.cpp @@ -182,11 +182,6 @@ TypeInfoDeclaration *Type::getTypeInfoDeclaration() return new TypeInfoDeclaration(this, 0); } -TypeInfoDeclaration *TypeTypedef::getTypeInfoDeclaration() -{ - return new TypeInfoTypedefDeclaration(this); -} - TypeInfoDeclaration *TypePointer::getTypeInfoDeclaration() { return new TypeInfoPointerDeclaration(this); @@ -349,44 +344,6 @@ public: /* ========================================================================= */ - void visit(TypeInfoTypedefDeclaration *decl) - { - IF_LOG Logger::println("TypeInfoTypedefDeclaration::llvmDefine() %s", decl->toChars()); - LOG_SCOPE; - - RTTIBuilder b(Type::typeinfotypedef); - - assert(decl->tinfo->ty == Ttypedef); - TypeTypedef *tc = static_cast(decl->tinfo); - TypedefDeclaration *sd = tc->sym; - - // TypeInfo base - sd->basetype = sd->basetype->merge(); // dmd does it ... why? - b.push_typeinfo(sd->basetype); - - // char[] name - b.push_string(sd->toPrettyChars()); - - // void[] init - // emit null array if we should use the basetype, or if the basetype - // uses default initialization. - if (decl->tinfo->isZeroInit(Loc()) || !sd->init) - { - b.push_null_void_array(); - } - // otherwise emit a void[] with the default initializer - else - { - LLConstant* C = DtoConstInitializer(sd->loc, sd->basetype, sd->init); - b.push_void_array(C, sd->basetype, sd); - } - - // finish - b.finalize(getIrGlobal(decl)); - } - - /* ========================================================================= */ - void visit(TypeInfoEnumDeclaration *decl) { IF_LOG Logger::println("TypeInfoEnumDeclaration::llvmDefine() %s", decl->toChars()); diff --git a/ir/irclass.cpp b/ir/irclass.cpp index bcc2e36dce..b190d86b86 100644 --- a/ir/irclass.cpp +++ b/ir/irclass.cpp @@ -204,7 +204,7 @@ LLConstant * IrAggr::getVtblInit() if (tf->ty == Tfunction) cd->deprecation("use of %s%s hidden by %s is deprecated; use 'alias %s = %s.%s;' to introduce base class overload set", fd->toPrettyChars(), - Parameter::argsTypesToChars(tf->parameters, tf->varargs), + "?FIXME?", //Parameter::argsTypesToChars(tf->parameters, tf->varargs), cd->toChars(), fd->toChars(), diff --git a/runtime/druntime b/runtime/druntime index 1f20d43531..f6ce1b9315 160000 --- a/runtime/druntime +++ b/runtime/druntime @@ -1 +1 @@ -Subproject commit 1f20d43531d0a34688376757ed3f48787b2a857f +Subproject commit f6ce1b931532d111fbb0cf23a3bdac9b9818693c diff --git a/runtime/phobos b/runtime/phobos index 79af61f846..7f8b6d5c9c 160000 --- a/runtime/phobos +++ b/runtime/phobos @@ -1 +1 @@ -Subproject commit 79af61f846fe1b298cca7340c2b38b43e46b7807 +Subproject commit 7f8b6d5c9c128a9ff49a8b9beaf5e9e88d6217ff