From 65c892ee62530db370eab4e6355d1de5cea81332 Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Sat, 1 Jan 2011 21:23:08 +0000 Subject: [PATCH] Merge SiegeLord's dmdfe 1.064 patch. --- dmd/aggregate.h | 3 ++ dmd/attrib.c | 23 +++++--- dmd/class.c | 35 +++++++++++- dmd/constfold.c | 38 +++++++------ dmd/declaration.c | 10 ++-- dmd/declaration.h | 2 +- dmd/doc.c | 80 ++++++++++++++++++++++++++- dmd/expression.c | 30 +++++++++-- dmd/expression.h | 1 + dmd/func.c | 4 +- dmd/impcnvgen.c | 4 +- dmd/interpret.c | 10 ++++ dmd/mars.c | 2 +- dmd/mtype.c | 24 ++++++--- dmd/mtype.h | 2 +- dmd/parse.c | 17 ++++++ dmd/statement.c | 6 +-- dmd/template.c | 134 ++++++++++++++++++++++++++++++++++++++++++---- 18 files changed, 356 insertions(+), 69 deletions(-) diff --git a/dmd/aggregate.h b/dmd/aggregate.h index 47be2648..e09d270c 100644 --- a/dmd/aggregate.h +++ b/dmd/aggregate.h @@ -220,6 +220,7 @@ struct BaseClass #define CLASSINFO_SIZE (0x3C+16+4) // value of ClassInfo.size #else #define CLASSINFO_SIZE (0x3C+12+4) // value of ClassInfo.size +#define CLASSINFO_SIZE_64 (0x98) // value of ClassInfo.size #endif struct ClassDeclaration : AggregateDeclaration @@ -267,6 +268,7 @@ struct ClassDeclaration : AggregateDeclaration #define OFFSET_RUNTIME 0x76543210 virtual int isBaseOf(ClassDeclaration *cd, int *poffset); + virtual int isBaseInfoComplete(); Dsymbol *search(Loc, Identifier *ident, int flags); #if DMDV2 int isFuncHidden(FuncDeclaration *fd); @@ -322,6 +324,7 @@ struct InterfaceDeclaration : ClassDeclaration int isBaseOf(ClassDeclaration *cd, int *poffset); int isBaseOf(BaseClass *bc, int *poffset); const char *kind(); + int isBaseInfoComplete(); int vtblOffset(); #if DMDV2 int isCPPinterface(); diff --git a/dmd/attrib.c b/dmd/attrib.c index a8883aab..3bc9bae8 100644 --- a/dmd/attrib.c +++ b/dmd/attrib.c @@ -341,17 +341,24 @@ void AttribDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { if (decl) { - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - for (unsigned i = 0; i < decl->dim; i++) + if (decl->dim == 0) + buf->writestring("{}"); + else if (decl->dim == 1) + ((Dsymbol *)decl->data[0])->toCBuffer(buf, hgs); + else { - Dsymbol *s = (Dsymbol *)decl->data[i]; + buf->writenl(); + buf->writeByte('{'); + buf->writenl(); + for (unsigned i = 0; i < decl->dim; i++) + { + Dsymbol *s = (Dsymbol *)decl->data[i]; - buf->writestring(" "); - s->toCBuffer(buf, hgs); + buf->writestring(" "); + s->toCBuffer(buf, hgs); + } + buf->writeByte('}'); } - buf->writeByte('}'); } else buf->writeByte(';'); diff --git a/dmd/class.c b/dmd/class.c index f5808287..c0ee4273 100644 --- a/dmd/class.c +++ b/dmd/class.c @@ -556,7 +556,7 @@ void ClassDeclaration::semantic(Scope *sc) } if (storage_class & STCauto) - error("storage class has no effect: auto"); + error("storage class 'auto' is invalid when declaring a class, did you mean to use 'scope'?"); if (storage_class & STCscope) isscope = 1; if (storage_class & STCabstract) @@ -823,6 +823,23 @@ int ClassDeclaration::isBaseOf(ClassDeclaration *cd, int *poffset) return 0; } +/********************************************* + * Determine if 'this' has complete base class information. + * This is used to detect forward references in covariant overloads. + */ + +int ClassDeclaration::isBaseInfoComplete() +{ + if (!baseClass) + return ident == Id::Object; + for (int i = 0; i < baseclasses->dim; i++) + { BaseClass *b = (BaseClass *)baseclasses->data[i]; + if (!b->base || !b->base->isBaseInfoComplete()) + return 0; + } + return 1; +} + Dsymbol *ClassDeclaration::search(Loc loc, Identifier *ident, int flags) { Dsymbol *s; @@ -1314,6 +1331,22 @@ int InterfaceDeclaration::isBaseOf(BaseClass *bc, int *poffset) return 0; } +/********************************************* + * Determine if 'this' has clomplete base class information. + * This is used to detect forward references in covariant overloads. + */ + +int InterfaceDeclaration::isBaseInfoComplete() +{ + assert(!baseClass); + for (int i = 0; i < baseclasses->dim; i++) + { BaseClass *b = (BaseClass *)baseclasses->data[i]; + if (!b->base || !b->base->isBaseInfoComplete ()) + return 0; + } + return 1; +} + /**************************************** * Determine if slot 0 of the vtbl[] is reserved for something else. * For class objects, yes, this is where the ClassInfo ptr goes. diff --git a/dmd/constfold.c b/dmd/constfold.c index e3671bd4..5e003435 100644 --- a/dmd/constfold.c +++ b/dmd/constfold.c @@ -562,13 +562,11 @@ Expression *Shl(Type *type, Expression *e1, Expression *e2) } Expression *Shr(Type *type, Expression *e1, Expression *e2) -{ Expression *e; +{ Loc loc = e1->loc; - unsigned count; - dinteger_t value; - value = e1->toInteger(); - count = e2->toInteger(); + dinteger_t value = e1->toInteger(); + unsigned count = e2->toInteger(); switch (e1->type->toBasetype()->ty) { case Tint8: @@ -603,21 +601,22 @@ Expression *Shr(Type *type, Expression *e1, Expression *e2) value = (d_uns64)(value) >> count; break; + case Terror: + return e1; + default: assert(0); } - e = new IntegerExp(loc, value, type); + Expression *e = new IntegerExp(loc, value, type); return e; } Expression *Ushr(Type *type, Expression *e1, Expression *e2) -{ Expression *e; +{ Loc loc = e1->loc; - unsigned count; - dinteger_t value; - value = e1->toInteger(); - count = e2->toInteger(); + dinteger_t value = e1->toInteger(); + unsigned count = e2->toInteger(); switch (e1->type->toBasetype()->ty) { case Tint8: @@ -642,10 +641,13 @@ Expression *Ushr(Type *type, Expression *e1, Expression *e2) value = (d_uns64)(value) >> count; break; + case Terror: + return e1; + default: assert(0); } - e = new IntegerExp(loc, value, type); + Expression *e = new IntegerExp(loc, value, type); return e; } @@ -1050,7 +1052,7 @@ Expression *Cast(Type *type, Type *to, Expression *e1) Loc loc = e1->loc; //printf("Cast(type = %s, to = %s, e1 = %s)\n", type->toChars(), to->toChars(), e1->toChars()); - //printf("e1->type = %s\n", e1->type->toChars()); + //printf("\te1->type = %s\n", e1->type->toChars()); if (type->equals(e1->type) && to->equals(type)) return e1; @@ -1069,14 +1071,10 @@ Expression *Cast(Type *type, Type *to, Expression *e1) } if (e1->op == TOKarrayliteral && typeb == tb) - { return e1; - } if (e1->isConst() != 1) - { return EXP_CANT_INTERPRET; - } if (tb->ty == Tbool) e = new IntegerExp(loc, e1->toInteger() != 0, type); @@ -1086,7 +1084,7 @@ Expression *Cast(Type *type, Type *to, Expression *e1) { dinteger_t result; real_t r = e1->toReal(); - switch (type->toBasetype()->ty) + switch (typeb->ty) { case Tint8: result = (d_int8)r; break; case Tchar: @@ -1327,7 +1325,7 @@ Expression *Cat(Type *type, Expression *e1, Expression *e2) Type *t2 = e2->type->toBasetype(); //printf("Cat(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars()); - //printf("\tt1 = %s, t2 = %s\n", t1->toChars(), t2->toChars()); + //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; @@ -1465,7 +1463,7 @@ Expression *Cat(Type *type, Expression *e1, Expression *e2) if (type->toBasetype()->ty == Tsarray) { - e->type = new TypeSArray(e1->type->toBasetype()->next, new IntegerExp(0, es1->elements->dim, Type::tindex)); + e->type = new TypeSArray(t1->next, new IntegerExp(loc, es1->elements->dim, Type::tindex)); e->type = e->type->semantic(loc, NULL); } else diff --git a/dmd/declaration.c b/dmd/declaration.c index 7c4bf949..cac1f3a8 100644 --- a/dmd/declaration.c +++ b/dmd/declaration.c @@ -678,7 +678,7 @@ VarDeclaration::VarDeclaration(Loc loc, Type *type, Identifier *id, Initializer #endif this->loc = loc; offset = 0; - noauto = 0; + noscope = 0; #if DMDV2 isargptr = FALSE; #endif @@ -821,7 +821,7 @@ void VarDeclaration::semantic(Scope *sc) } } if ((storage_class & STCauto) && !inferred) - error("both auto and explicit type given"); + error("storage class 'auto' has no effect if type is not inferred, did you mean 'scope'?"); if (tb->ty == Ttuple) { /* Instead, declare variables for each of the tuple elements @@ -959,7 +959,7 @@ void VarDeclaration::semantic(Scope *sc) } #endif - if (type->isscope() && !noauto) + if (type->isscope() && !noscope) { if (storage_class & (STCfield | STCout | STCref | STCstatic) || !fd) { @@ -1431,7 +1431,7 @@ Expression *VarDeclaration::callScopeDtor(Scope *sc) { Expression *e = NULL; //printf("VarDeclaration::callScopeDtor() %s\n", toChars()); - if (storage_class & STCscope && !noauto) + if (storage_class & STCscope && !noscope) { for (ClassDeclaration *cd = type->isClassHandle(); cd; @@ -1641,7 +1641,7 @@ TypeInfoTupleDeclaration::TypeInfoTupleDeclaration(Type *tinfo) ThisDeclaration::ThisDeclaration(Loc loc, Type *t) : VarDeclaration(loc, t, Id::This, NULL) { - noauto = 1; + noscope = 1; } Dsymbol *ThisDeclaration::syntaxCopy(Dsymbol *s) diff --git a/dmd/declaration.h b/dmd/declaration.h index 02c60be3..f000f00d 100644 --- a/dmd/declaration.h +++ b/dmd/declaration.h @@ -273,7 +273,7 @@ struct VarDeclaration : Declaration { Initializer *init; unsigned offset; - int noauto; // no scope semantics + int noscope; // no scope semantics #if DMDV2 FuncDeclarations nestedrefs; // referenced by these lexically nested functions bool isargptr; // if parameter that _argptr points to diff --git a/dmd/doc.c b/dmd/doc.c index 20cac454..00f6e9f1 100644 --- a/dmd/doc.c +++ b/dmd/doc.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2009 by Digital Mars +// Copyright (c) 1999-2010 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -358,6 +358,78 @@ void Module::gendocfile() #endif } +/**************************************************** + * Having unmatched parentheses can hose the output of Ddoc, + * as the macros depend on properly nested parentheses. + * Fix by replacing unmatched ( with $(LPAREN) and unmatched ) with $(RPAREN). + */ +void escapeStrayParenthesis(OutBuffer *buf, unsigned start, Loc loc) +{ + unsigned par_open = 0; + + for (unsigned u = start; u < buf->offset; u++) + { + unsigned char c = buf->data[u]; + switch(c) + { + case '(': + par_open++; + break; + + case ')': + if (par_open == 0) + { + //stray ')' + if (global.params.warnings) + warning(loc, "Ddoc: Stray ')'. This may cause incorrect Ddoc output." + " Use $(RPAREN) instead for unpaired right parentheses."); + buf->remove(u, 1); //remove the ) + buf->insert(u, "$(RPAREN)", 9); //insert this instead + u += 8; //skip over newly inserted macro + } + else + par_open--; + break; +#if 0 + // For this to work, loc must be set to the beginning of the passed + // text which is currently not possible + // (loc is set to the Loc of the Dsymbol) + case '\n': + loc.linnum++; + break; +#endif + } + } + + if (par_open) // if any unmatched lparens + { par_open = 0; + for (unsigned u = buf->offset; u > start;) + { u--; + unsigned char c = buf->data[u]; + switch(c) + { + case ')': + par_open++; + break; + + case '(': + if (par_open == 0) + { + //stray '(' + if (global.params.warnings) + warning(loc, "Ddoc: Stray '('. This may cause incorrect Ddoc output." + " Use $(LPAREN) instead for unpaired left parentheses."); + buf->remove(u, 1); //remove the ( + buf->insert(u, "$(LPAREN)", 9); //insert this instead + } + else + par_open--; + break; + } + } + } +} + /******************************* emitComment **********************************/ /* @@ -1082,6 +1154,7 @@ void DocComment::writeSections(Scope *sc, Dsymbol *s, OutBuffer *buf) buf->writestring("$(DDOC_SUMMARY "); unsigned o = buf->offset; buf->write(sec->body, sec->bodylen); + escapeStrayParenthesis(buf, o, s->loc); highlightText(sc, s, buf, o); buf->writestring(")\n"); } @@ -1119,10 +1192,12 @@ void Section::write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf) buf->writestring("$(DDOC_SECTION "); // Replace _ characters with spaces buf->writestring("$(DDOC_SECTION_H "); + unsigned o = buf->offset; for (unsigned u = 0; u < namelen; u++) { unsigned char c = name[u]; buf->writeByte((c == '_') ? ' ' : c); } + escapeStrayParenthesis(buf, o, s->loc); buf->writestring(":)\n"); } else @@ -1132,6 +1207,7 @@ void Section::write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf) L1: unsigned o = buf->offset; buf->write(body, bodylen); + escapeStrayParenthesis(buf, o, s->loc); highlightText(sc, s, buf, o); buf->writestring(")\n"); } @@ -1213,12 +1289,14 @@ void ParamSection::write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf) arg->type->toCBuffer(buf, arg->ident, &hgs); else buf->write(namestart, namelen); + escapeStrayParenthesis(buf, o, s->loc); highlightCode(sc, s, buf, o); buf->writestring(")\n"); buf->writestring("$(DDOC_PARAM_DESC "); o = buf->offset; buf->write(textstart, textlen); + escapeStrayParenthesis(buf, o, s->loc); highlightText(sc, s, buf, o); buf->writestring(")"); buf->writestring(")\n"); diff --git a/dmd/expression.c b/dmd/expression.c index 9bb45506..55399dfb 100644 --- a/dmd/expression.c +++ b/dmd/expression.c @@ -782,6 +782,13 @@ void functionParameters(Loc loc, Scope *sc, TypeFunction *tf, Expressions *argum void expToCBuffer(OutBuffer *buf, HdrGenState *hgs, Expression *e, enum 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->dump(0); if (precedence[e->op] < pr || /* Despite precedence, we don't allow aisSameAsInitializer() && type->toBasetype()->ty != Tsarray && v->init) { ExpInitializer *ei = v->init->isExpInitializer(); - if (ei) + if (ei && ei->exp->type) { //ei->exp->implicitCastTo(sc, type)->print(); return ei->exp->implicitCastTo(sc, type); @@ -4036,7 +4043,7 @@ void VarExp::checkEscape() // if reference type if (tb->ty == Tarray || tb->ty == Tsarray || tb->ty == Tclass) { - if (v->isScope() && !v->noauto) + if (v->isScope() && !v->noscope) error("escaping reference to auto local %s", v->toChars()); else if (v->storage_class & STCvariadic) error("escaping reference to variadic parameter %s", v->toChars()); @@ -6843,9 +6850,16 @@ Expression *CallExp::modifiableLvalue(Scope *sc, Expression *e) } void CallExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ int i; - - expToCBuffer(buf, hgs, e1, precedence[op]); +{ + if (e1->op == TOKtype) + /* Avoid parens around type to prevent forbidden cast syntax: + * (sometype)(arg1) + * This is ok since types in constructor calls + * can never depend on parens anyway + */ + e1->toCBuffer(buf, hgs); + else + expToCBuffer(buf, hgs, e1, precedence[op]); buf->writeByte('('); argsToCBuffer(buf, arguments, hgs); buf->writeByte(')'); @@ -7784,6 +7798,12 @@ Expression *DotExp::semantic(Scope *sc) return this; } +void DotExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + expToCBuffer(buf, hgs, e1, PREC_primary); + buf->writeByte('.'); + expToCBuffer(buf, hgs, e2, PREC_primary); +} /************************* CommaExp ***********************************/ diff --git a/dmd/expression.h b/dmd/expression.h index 6af35e5d..c5ea17cf 100644 --- a/dmd/expression.h +++ b/dmd/expression.h @@ -1314,6 +1314,7 @@ struct DotExp : BinExp { DotExp(Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); }; struct CommaExp : BinExp diff --git a/dmd/func.c b/dmd/func.c index bef4a80e..cf1189f6 100644 --- a/dmd/func.c +++ b/dmd/func.c @@ -1021,7 +1021,7 @@ void FuncDeclaration::semantic3(Scope *sc) loc = fensure->loc; v = new VarDeclaration(loc, type->nextOf(), outId, NULL); - v->noauto = 1; + v->noscope = 1; #if DMDV2 if (!isVirtual()) v->storage_class |= STCconst; @@ -1460,7 +1460,7 @@ void FuncDeclaration::semantic3(Scope *sc) if (v->type->toBasetype()->ty == Tsarray) continue; - Expression *e = v->callAutoDtor(sc); + Expression *e = v->callScopeDtor(sc); if (e) { Statement *s = new ExpStatement(0, e); s = s->semantic(sc); diff --git a/dmd/impcnvgen.c b/dmd/impcnvgen.c index b3f9f211..3701eeab 100644 --- a/dmd/impcnvgen.c +++ b/dmd/impcnvgen.c @@ -381,8 +381,8 @@ void init() Y(Tint64, Tdchar) Y(Tuns64, Tdchar) - Y(Tint64, Tuns64) - Y(Tuns64, Tint64) +// Y(Tint64, Tuns64) +// Y(Tuns64, Tint64) for (i = 0; i < TMAX; i++) for (j = 0; j < TMAX; j++) diff --git a/dmd/interpret.c b/dmd/interpret.c index da166bc6..870c0b3f 100644 --- a/dmd/interpret.c +++ b/dmd/interpret.c @@ -740,6 +740,10 @@ Expression *ForStatement::interpret(InterState *istate) Expression *ForeachStatement::interpret(InterState *istate) { +#if 1 + assert(0); // rewritten to ForStatement + return NULL; +#else #if LOG printf("ForeachStatement::interpret()\n"); #endif @@ -822,11 +826,16 @@ Expression *ForeachStatement::interpret(InterState *istate) if (key) key->value = keysave; return e; +#endif } #if DMDV2 Expression *ForeachRangeStatement::interpret(InterState *istate) { +#if 1 + assert(0); // rewritten to ForStatement + return NULL; +#else #if LOG printf("ForeachRangeStatement::interpret()\n"); #endif @@ -907,6 +916,7 @@ Expression *ForeachRangeStatement::interpret(InterState *istate) } key->value = keysave; return e; +#endif } #endif diff --git a/dmd/mars.c b/dmd/mars.c index e3eae8ad..5d28f5ba 100644 --- a/dmd/mars.c +++ b/dmd/mars.c @@ -59,7 +59,7 @@ Global::Global() copyright = "Copyright (c) 1999-2010 by Digital Mars and Tomas Lindquist Olsen"; written = "written by Walter Bright and Tomas Lindquist Olsen"; - version = "v1.063"; + version = "v1.064"; ldc_version = "LDC trunk"; llvm_version = "LLVM 2.8"; global.structalign = 8; diff --git a/dmd/mtype.c b/dmd/mtype.c index 95f93ad3..11101631 100644 --- a/dmd/mtype.c +++ b/dmd/mtype.c @@ -2846,18 +2846,26 @@ int Type::covariant(Type *t) if (t1n->equals(t2n)) goto Lcovariant; - if (t1n->ty != Tclass || t2n->ty != Tclass) - goto Lnotcovariant; - - // If t1n is forward referenced: - ClassDeclaration *cd = ((TypeClass *)t1n)->sym; - if (!cd->baseClass && cd->baseclasses->dim && !cd->isInterfaceDeclaration()) + if (t1n->ty == Tclass && t2n->ty == Tclass) { - return 3; - } + ClassDeclaration *cd = ((TypeClass *)t1n)->sym; + ClassDeclaration *cd2 = ((TypeClass *)t2n)->sym; + if (cd == cd2) + goto Lcovariant; + // If t1n is forward referenced: +#if 0 + if (!cd->baseClass && cd->baseclasses->dim && !cd->isInterfaceDeclaration()) +#else + if (!cd->isBaseInfoComplete()) +#endif + { + return 3; + } + } if (t1n->implicitConvTo(t2n)) goto Lcovariant; + goto Lnotcovariant; } diff --git a/dmd/mtype.h b/dmd/mtype.h index 9ce20a7f..ebac3854 100644 --- a/dmd/mtype.h +++ b/dmd/mtype.h @@ -532,7 +532,7 @@ struct TypeDelegate : Type Type *syntaxCopy(); Type *semantic(Loc loc, Scope *sc); d_uns64 size(Loc loc); - unsigned alignsize(); // added in LDC + unsigned alignsize(); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); Expression *defaultInit(Loc loc); int isZeroInit(Loc loc); diff --git a/dmd/parse.c b/dmd/parse.c index 2f5779f1..0db1d62e 100644 --- a/dmd/parse.c +++ b/dmd/parse.c @@ -5469,6 +5469,15 @@ enum PREC precedence[TOKMAX]; void initPrecedence() { + for (int i = 0; i < TOKMAX; i++) + precedence[i] = PREC_zero; + + precedence[TOKtype] = PREC_expr; + precedence[TOKerror] = PREC_expr; + + precedence[TOKtypeof] = PREC_primary; + precedence[TOKmixin] = PREC_primary; + precedence[TOKdotvar] = PREC_primary; precedence[TOKimport] = PREC_primary; precedence[TOKidentifier] = PREC_primary; @@ -5484,19 +5493,26 @@ void initPrecedence() precedence[TOKassert] = PREC_primary; precedence[TOKfunction] = PREC_primary; precedence[TOKvar] = PREC_primary; + precedence[TOKsymoff] = PREC_primary; + precedence[TOKstructliteral] = PREC_primary; + precedence[TOKarraylength] = PREC_primary; + precedence[TOKtuple] = PREC_primary; #if DMDV2 + precedence[TOKtraits] = PREC_primary; precedence[TOKdefault] = PREC_primary; #endif // post precedence[TOKdotti] = PREC_primary; precedence[TOKdot] = PREC_primary; + precedence[TOKdottd] = PREC_primary; // precedence[TOKarrow] = PREC_primary; precedence[TOKplusplus] = PREC_primary; precedence[TOKminusminus] = PREC_primary; precedence[TOKcall] = PREC_primary; precedence[TOKslice] = PREC_primary; precedence[TOKarray] = PREC_primary; + precedence[TOKindex] = PREC_primary; precedence[TOKaddress] = PREC_unary; precedence[TOKstar] = PREC_unary; @@ -5579,6 +5595,7 @@ void initPrecedence() precedence[TOKxorass] = PREC_assign; precedence[TOKcomma] = PREC_expr; + precedence[TOKdeclaration] = PREC_expr; } diff --git a/dmd/statement.c b/dmd/statement.c index 39199739..ee999dc7 100644 --- a/dmd/statement.c +++ b/dmd/statement.c @@ -1719,7 +1719,7 @@ Statement *ForeachStatement::semantic(Scope *sc) if (!sc->func->vresult && tret && tret != Type::tvoid) { VarDeclaration *v = new VarDeclaration(loc, tret, Id::result, NULL); - v->noauto = 1; + v->noscope = 1; v->semantic(sc); if (!sc->insert(v)) assert(0); @@ -2311,7 +2311,7 @@ Statement *IfStatement::semantic(Scope *sc) Type *t = arg->type ? arg->type : condition->type; match = new VarDeclaration(loc, t, arg->ident, NULL); - match->noauto = 1; + match->noscope = 1; match->semantic(scd); if (!scd->insert(match)) assert(0); @@ -3427,7 +3427,7 @@ Statement *ReturnStatement::semantic(Scope *sc) if (!fd->vresult) { // Declare vresult VarDeclaration *v = new VarDeclaration(loc, tret, Id::result, NULL); - v->noauto = 1; + v->noscope = 1; v->semantic(scx); if (!scx->insert(v)) assert(0); diff --git a/dmd/template.c b/dmd/template.c index 628a8022..338b3f5c 100644 --- a/dmd/template.c +++ b/dmd/template.c @@ -975,19 +975,26 @@ L2: #endif // Loop through the function parameters - for (i = 0; i < nfparams; i++) + for (size_t parami = 0; parami < nfparams; parami++) { /* Skip over function parameters which wound up * as part of a template tuple parameter. */ - if (i == fptupindex) - { if (fptupindex == nfparams - 1) - break; - i += tuple_dim - 1; + if (parami == fptupindex) continue; - } + /* Set i = index into function arguments + * Function parameters correspond to function arguments as follows. + * Note that tuple_dim may be zero, and there may be default or + * variadic arguments at the end. + * arg [0..fptupindex] == param[0..fptupindex] + * arg [fptupindex..fptupindex+tuple_dim] == param[fptupindex] + * arg[fputupindex+dim.. ] == param[fptupindex+1.. ] + */ + i = parami; + if (fptupindex >= 0 && parami > fptupindex) + i += tuple_dim - 1; - Parameter *fparam = Parameter::getNth(fparameters, i); + Parameter *fparam = Parameter::getNth(fparameters, parami); if (i >= nfargs) // if not enough arguments { @@ -2181,6 +2188,63 @@ MATCH TypeTypedef::deduceType(Scope *sc, Type *tparam, TemplateParameters *param return Type::deduceType(sc, tparam, parameters, dedtypes); } +/* Helper for TypeClass::deduceType(). + * Classes can match with implicit conversion to a base class or interface. + * This is complicated, because there may be more than one base class which + * matches. In such cases, one or more parameters remain ambiguous. + * For example, + * + * interface I(X, Y) {} + * class C : I(uint, double), I(char, double) {} + * C x; + * foo(T, U)( I!(T, U) x) + * + * deduces that U is double, but T remains ambiguous (could be char or uint). + * + * Given a baseclass b, and initial deduced types 'dedtypes', this function + * tries to match tparam with b, and also tries all base interfaces of b. + * If a match occurs, numBaseClassMatches is incremented, and the new deduced + * types are ANDed with the current 'best' estimate for dedtypes. + */ +void deduceBaseClassParameters(BaseClass *b, + Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, + Objects *best, int &numBaseClassMatches) +{ + TemplateInstance *parti = b->base->parent->isTemplateInstance(); + if (parti) + { + // Make a temporary copy of dedtypes so we don't destroy it + Objects *tmpdedtypes = new Objects(); + tmpdedtypes->setDim(dedtypes->dim); + memcpy(tmpdedtypes->data, dedtypes->data, dedtypes->dim * sizeof(void *)); + + TypeInstance *t = new TypeInstance(0, parti); + MATCH m = t->deduceType(sc, tparam, parameters, tmpdedtypes); + if (m != MATCHnomatch) + { + // If this is the first ever match, it becomes our best estimate + if (numBaseClassMatches==0) + memcpy(best->data, tmpdedtypes->data, tmpdedtypes->dim * sizeof(void *)); + else for (size_t k = 0; k < tmpdedtypes->dim; ++k) + { + // If we've found more than one possible type for a parameter, + // mark it as unknown. + if (tmpdedtypes->data[k] != best->data[k]) + best->data[k] = dedtypes->data[k]; + } + ++numBaseClassMatches; + } + } + // Now recursively test the inherited interfaces + for (size_t j = 0; j < b->baseInterfaces_dim; ++j) + { + deduceBaseClassParameters( &(b->baseInterfaces)[j], + sc, tparam, parameters, dedtypes, + best, numBaseClassMatches); + } + +} + MATCH TypeClass::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes) { //printf("TypeClass::deduceType(this = %s)\n", toChars()); @@ -2196,7 +2260,11 @@ MATCH TypeClass::deduceType(Scope *sc, Type *tparam, TemplateParameters *paramet if (ti && ti->toAlias() == sym) { TypeInstance *t = new TypeInstance(0, ti); - return t->deduceType(sc, tparam, parameters, dedtypes); + MATCH m = t->deduceType(sc, tparam, parameters, dedtypes); + // Even if the match fails, there is still a chance it could match + // a base class. + if (m != MATCHnomatch) + return m; } /* Match things like: @@ -2219,6 +2287,47 @@ MATCH TypeClass::deduceType(Scope *sc, Type *tparam, TemplateParameters *paramet } } } + + // If it matches exactly or via implicit conversion, we're done + MATCH m = Type::deduceType(sc, tparam, parameters, dedtypes); + if (m != MATCHnomatch) + return m; + + /* There is still a chance to match via implicit conversion to + * a base class or interface. Because there could be more than one such + * match, we need to check them all. + */ + + int numBaseClassMatches = 0; // Have we found an interface match? + + // Our best guess at dedtypes + Objects *best = new Objects(); + best->setDim(dedtypes->dim); + + ClassDeclaration *s = sym; + while(s && s->baseclasses->dim > 0) + { + // Test the base class + deduceBaseClassParameters((BaseClass *)(s->baseclasses->data[0]), + sc, tparam, parameters, dedtypes, + best, numBaseClassMatches); + + // Test the interfaces inherited by the base class + for (size_t i = 0; i < s->interfaces_dim; ++i) + { + BaseClass *b = s->interfaces[i]; + deduceBaseClassParameters(b, sc, tparam, parameters, dedtypes, + best, numBaseClassMatches); + } + s = ((BaseClass *)(s->baseclasses->data[0]))->base; + } + + if (numBaseClassMatches == 0) + return MATCHnomatch; + + // If we got at least one match, copy the known types into dedtypes + memcpy(dedtypes->data, best->data, best->dim * sizeof(void *)); + return MATCHconvert; } // Extra check @@ -2227,7 +2336,7 @@ MATCH TypeClass::deduceType(Scope *sc, Type *tparam, TemplateParameters *paramet TypeClass *tp = (TypeClass *)tparam; //printf("\t%d\n", (MATCH) implicitConvTo(tp)); - return (MATCH) implicitConvTo(tp); + return implicitConvTo(tp); } return Type::deduceType(sc, tparam, parameters, dedtypes); } @@ -3578,8 +3687,11 @@ void TemplateInstance::semantic(Scope *sc) if (global.gag) { // Try to reset things so we can try again later to instantiate it tempdecl->instances.remove(tempdecl_instance_idx); - semanticRun = 0; - inst = NULL; + if (!(sc->flags & SCOPEstaticif)) + { // Bugzilla 4302 for discussion + semanticRun = 0; + inst = NULL; + } } }