From e9280781bd3831de9504f56a8cba5965b9335a0a Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Thu, 23 Jan 2014 23:22:02 -0800 Subject: [PATCH] Merge pull request #3103 from 9rnsr/fix10133 Issue 10133 - ICE for templated static conditional lambda --- src/attrib.c | 2 +- src/clone.c | 2 - src/cond.c | 2 +- src/ctfeexpr.c | 6 +- src/expression.c | 31 +- src/func.c | 22 +- src/glue.c | 3 + src/import.c | 2 +- src/mars.c | 2 + src/mtype.c | 7 +- src/opover.c | 2 +- src/scope.c | 13 +- src/scope.h | 3 +- src/struct.c | 2 +- src/template.c | 749 +++++++++++++----------------- src/template.h | 9 +- src/toobj.c | 18 + test/compilable/ice6538.d | 43 ++ test/fail_compilation/diag11769.d | 4 +- test/fail_compilation/diag9880.d | 2 +- test/fail_compilation/fail319.d | 2 +- test/fail_compilation/ice6538.d | 66 +-- test/fail_compilation/test8556.d | 2 +- test/runnable/funclit.d | 43 ++ 24 files changed, 502 insertions(+), 535 deletions(-) create mode 100644 test/compilable/ice6538.d diff --git a/src/attrib.c b/src/attrib.c index b91c1261333e..1d1295e6469e 100644 --- a/src/attrib.c +++ b/src/attrib.c @@ -1061,7 +1061,7 @@ void PragmaDeclaration::semantic(Scope *sc) if (global.params.moduleDeps && !global.params.moduleDepsFile) { OutBuffer *ob = global.params.moduleDeps; - Module* imod = sc->instantiatingModule ? sc->instantiatingModule : sc->module; + Module *imod = sc->instantiatingModule(); ob->writestring("depsLib "); ob->writestring(imod->toPrettyChars()); ob->writestring(" ("); diff --git a/src/clone.c b/src/clone.c index cfddfcc25d45..82b99458b70d 100644 --- a/src/clone.c +++ b/src/clone.c @@ -76,7 +76,6 @@ FuncDeclaration *AggregateDeclaration::hasIdentityOpAssign(Scope *sc) unsigned oldspec = global.speculativeGag; // template opAssign fbody makes it. global.speculativeGag = global.gag; sc = sc->push(); - sc->tinst = NULL; sc->speculative = true; for (size_t i = 0; i < 2; i++) @@ -416,7 +415,6 @@ FuncDeclaration *AggregateDeclaration::hasIdentityOpEquals(Scope *sc) unsigned oldspec = global.speculativeGag; // template opAssign fbody makes it. global.speculativeGag = global.gag; sc = sc->push(); - sc->tinst = NULL; sc->speculative = true; for (size_t j = 0; j < 2; j++) diff --git a/src/cond.c b/src/cond.c index 3129ec4744ab..1265f6ae58b0 100644 --- a/src/cond.c +++ b/src/cond.c @@ -90,7 +90,7 @@ void printDepsConditional(Scope *sc, DVCondition* condition, const char* depType if (!global.params.moduleDeps || global.params.moduleDepsFile) return; OutBuffer *ob = global.params.moduleDeps; - Module* imod = sc ? (sc->instantiatingModule ? sc->instantiatingModule : sc->module) : condition->mod; + Module* imod = sc ? sc->instantiatingModule() : condition->mod; if (!imod) return; ob->writestring(depType); diff --git a/src/ctfeexpr.c b/src/ctfeexpr.c index da4025967098..c19a9c03afd6 100644 --- a/src/ctfeexpr.c +++ b/src/ctfeexpr.c @@ -546,9 +546,9 @@ TypeAArray *toBuiltinAAType(Type *t) assert(t->ty == Tstruct); StructDeclaration *sym = ((TypeStruct *)t)->sym; assert(sym->ident == Id::AssociativeArray); - TemplateInstance *tinst = sym->parent->isTemplateInstance(); - assert(tinst); - return new TypeAArray((Type *)(*tinst->tiargs)[1], (Type *)(*tinst->tiargs)[0]); + TemplateInstance *ti = sym->parent->isTemplateInstance(); + assert(ti); + return new TypeAArray((Type *)(*ti->tiargs)[1], (Type *)(*ti->tiargs)[0]); #else assert(0); return NULL; diff --git a/src/expression.c b/src/expression.c index 58ebdf7a945f..12b11d184f64 100644 --- a/src/expression.c +++ b/src/expression.c @@ -159,15 +159,6 @@ FuncDeclaration *hasThis(Scope *sc) FuncDeclaration *fdthis = p ? p->isFuncDeclaration() : NULL; //printf("fdthis = %p, '%s'\n", fdthis, fdthis ? fdthis->toChars() : ""); - /* Special case for inside template constraint - */ - if (fdthis && (sc->flags & SCOPEstaticif) && fdthis->parent->isTemplateDeclaration()) - { - //TemplateDeclaration *td = fdthis->parent->isTemplateDeclaration(); - //printf("[%s] td = %s, fdthis->vthis = %p\n", td->loc.toChars(), td->toChars(), fdthis->vthis); - return fdthis->vthis ? fdthis : NULL; - } - // Go upwards until we find the enclosing member function FuncDeclaration *fd = fdthis; while (1) @@ -234,11 +225,6 @@ bool isNeedThisScope(Scope *sc, Declaration *d) continue; if (f->isMember2()) break; - if (TemplateDeclaration *td = f->parent->isTemplateDeclaration()) - { - if ((td->scope->stc & STCstatic) && td->isMember()) - break; // no valid 'this' - } } } return true; @@ -3674,6 +3660,11 @@ Expression *ThisExp::semantic(Scope *sc) var = fd->vthis; assert(var->parent); type = var->type; + if (TemplateInstance *ti = fd->parent->isTemplateInstance()) + { + if (ti->members == NULL) + type = type->mutableOf(); + } var->isVarDeclaration()->checkNestedReference(sc, loc); if (!sc->intypeof) sc->callSuper |= CSXthis; @@ -3765,9 +3756,8 @@ Expression *SuperExp::semantic(Scope *sc) if (!fd) goto Lerr; - assert(fd->vthis); var = fd->vthis; - assert(var->parent); + assert(var && var->parent); s = fd->toParent(); while (s && s->isTemplateInstance()) @@ -3782,13 +3772,18 @@ Expression *SuperExp::semantic(Scope *sc) if (!cd->baseClass) { error("no base class for %s", cd->toChars()); - type = fd->vthis->type; + type = var->type; } else { type = cd->baseClass->type; type = type->castMod(var->type->mod); } + if (TemplateInstance *ti = fd->parent->isTemplateInstance()) + { + if (ti->members == NULL) + type = type->mutableOf(); + } var->isVarDeclaration()->checkNestedReference(sc, loc); @@ -7276,7 +7271,7 @@ Expression *FileExp::semantic(Scope *sc) if (global.params.moduleDeps != NULL) { OutBuffer *ob = global.params.moduleDeps; - Module* imod = sc->instantiatingModule ? sc->instantiatingModule : sc->module; + Module* imod = sc->instantiatingModule(); if (!global.params.moduleDepsFile) ob->writestring("depsFile "); diff --git a/src/func.c b/src/func.c index 7abfc41a4850..978ce49faf3c 100644 --- a/src/func.c +++ b/src/func.c @@ -2876,26 +2876,16 @@ FuncDeclaration *resolveFuncCall(Loc loc, Scope *sc, Dsymbol *s, } else if (m.nextf) { - /* CAUTION: m.lastf and m.nextf might be incompletely instantiated functions - * (created by doHeaderInstantiation), so call toPrettyChars will segfault. - */ - assert(m.lastf); - TypeFunction *t1 = (TypeFunction *)m.lastf->type; - TypeFunction *t2 = (TypeFunction *)m.nextf->type; - TemplateInstance *lastti = m.lastf->parent->isTemplateInstance(); - TemplateInstance *nextti = m.nextf->parent->isTemplateInstance(); - if (lastti && lastti->name != m.lastf->ident) lastti = NULL; - if (nextti && nextti->name != m.nextf->ident) nextti = NULL; - Dsymbol *lasts = lastti ? (Dsymbol *)lastti->tempdecl : (Dsymbol *)m.lastf; - Dsymbol *nexts = nextti ? (Dsymbol *)nextti->tempdecl : (Dsymbol *)m.nextf; - const char *lastprms = lastti ? "" : Parameter::argsTypesToChars(t1->parameters, t1->varargs); - const char *nextprms = nextti ? "" : Parameter::argsTypesToChars(t2->parameters, t2->varargs); + 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); ::error(loc, "%s.%s called with argument types %s matches both:\n" "\t%s(%d): %s%s\nand:\n\t%s(%d): %s%s", s->parent->toPrettyChars(), s->ident->toChars(), fargsBuf.toChars(), - lasts->loc.filename, lasts->loc.linnum, lasts->toChars(), lastprms, - nexts->loc.filename, nexts->loc.linnum, nexts->toChars(), nextprms); + m.lastf->loc.filename, m.lastf->loc.linnum, m.lastf->toPrettyChars(), lastprms, + m.nextf->loc.filename, m.nextf->loc.linnum, m.nextf->toPrettyChars(), nextprms); } return NULL; } diff --git a/src/glue.c b/src/glue.c index d67d1a6582cf..c8ed988dd491 100644 --- a/src/glue.c +++ b/src/glue.c @@ -567,6 +567,9 @@ void FuncDeclaration::toObjFile(int multiobj) if (semanticRun >= PASSobj) // if toObjFile() already run return; + if (type && type->ty == Tfunction && ((TypeFunction *)type)->next == NULL) + return; + // If errors occurred compiling it, such as bugzilla 6118 if (type && type->ty == Tfunction && ((TypeFunction *)type)->next->ty == Terror) return; diff --git a/src/import.c b/src/import.c index f5ad6301a66f..e6ff22038011 100644 --- a/src/import.c +++ b/src/import.c @@ -291,7 +291,7 @@ void Import::semantic(Scope *sc) */ OutBuffer *ob = global.params.moduleDeps; - Module* imod = sc->instantiatingModule ? sc->instantiatingModule : sc->module; + Module* imod = sc->instantiatingModule(); if (!global.params.moduleDepsFile) ob->writestring("depsImport "); ob->writestring(imod->toPrettyChars()); diff --git a/src/mars.c b/src/mars.c index bb807a249ee5..dedcde443fee 100644 --- a/src/mars.c +++ b/src/mars.c @@ -280,6 +280,8 @@ void verror(Loc loc, const char *format, va_list ap, } else { + //fprintf(stderr, "(gag:%d) ", global.gag); + //verrorPrint(loc, header, format, ap, p1, p2); global.gaggedErrors++; } global.errors++; diff --git a/src/mtype.c b/src/mtype.c index 8cce8a8b1120..7d1f3f43e4ac 100644 --- a/src/mtype.c +++ b/src/mtype.c @@ -4909,8 +4909,11 @@ StructDeclaration *TypeAArray::getImpl() TemplateInstance *ti = dti->ti; #endif // Instantiate on the root module of import dependency graph. - Scope *scx = sc->push(sc->module->importedFrom); - scx->instantiatingModule = sc->module->importedFrom; + Module *mi = sc->module->importedFrom; + Scope *scx = sc->push(mi); + scx->module = mi; + scx->tinst = NULL; + assert(scx->instantiatingModule() == mi); ti->semantic(scx); ti->semantic2(scx); ti->semantic3(scx); diff --git a/src/opover.c b/src/opover.c index ca9e611dcf70..89f7a6270c04 100644 --- a/src/opover.c +++ b/src/opover.c @@ -1569,7 +1569,7 @@ void inferApplyArgTypesZ(TemplateDeclaration *tstart, Parameters *arguments) error("forward reference to template %s", td->toChars()); return; } - if (!td->onemember || !td->onemember->toAlias()->isFuncDeclaration()) + if (!td->onemember || !td->onemember->isFuncDeclaration()) { error("is not a function template"); return; diff --git a/src/scope.c b/src/scope.c index f51a30c62443..62b4c58f0a7c 100644 --- a/src/scope.c +++ b/src/scope.c @@ -26,6 +26,7 @@ #include "module.h" #include "id.h" #include "lexer.h" +#include "template.h" Scope *Scope::freelist = NULL; @@ -47,11 +48,11 @@ void *Scope::operator new(size_t size) } Scope::Scope() -{ // Create root scope +{ + // Create root scope //printf("Scope::Scope() %p\n", this); this->module = NULL; - this->instantiatingModule = NULL; this->scopesym = NULL; this->sd = NULL; this->enclosing = NULL; @@ -93,7 +94,6 @@ Scope::Scope(Scope *enclosing) //printf("Scope::Scope(enclosing = %p) %p\n", enclosing, this); assert(!(enclosing->flags & SCOPEfree)); this->module = enclosing->module; - this->instantiatingModule = enclosing->instantiatingModule; this->func = enclosing->func; this->parent = enclosing->parent; this->scopesym = NULL; @@ -398,6 +398,13 @@ void Scope::mergeFieldInit(Loc loc, unsigned *fies) } } +Module *Scope::instantiatingModule() +{ + if (tinst && tinst->instantiatingModule) + return tinst->instantiatingModule; + return module; +} + Dsymbol *Scope::search(Loc loc, Identifier *ident, Dsymbol **pscopesym) { Dsymbol *s; Scope *sc; diff --git a/src/scope.h b/src/scope.h index c461327c1145..294a9472f198 100644 --- a/src/scope.h +++ b/src/scope.h @@ -66,7 +66,6 @@ struct Scope Scope *enclosing; // enclosing Scope Module *module; // Root module - Module *instantiatingModule; // top level module that started a chain of template instantiations ScopeDsymbol *scopesym; // current symbol ScopeDsymbol *sd; // if in static if, and declaring new symbols, // sd gets the addMember() @@ -132,6 +131,8 @@ struct Scope unsigned *saveFieldInit(); void mergeFieldInit(Loc loc, unsigned *cses); + Module *instantiatingModule(); + Dsymbol *search(Loc loc, Identifier *ident, Dsymbol **pscopesym); Dsymbol *search_correct(Identifier *ident); Dsymbol *insert(Dsymbol *s); diff --git a/src/struct.c b/src/struct.c index 80c1713933ff..f807a18b546d 100644 --- a/src/struct.c +++ b/src/struct.c @@ -169,7 +169,7 @@ void AggregateDeclaration::semantic3(Scope *sc) Expression *e = new DsymbolExp(Loc(), s, 0); Scope *sc2 = ti->tempdecl->scope->startCTFE(); - sc2->instantiatingModule = sc->instantiatingModule ? sc->instantiatingModule : sc->module; + sc2->tinst = sc->tinst; e = e->semantic(sc2); sc2->endCTFE(); diff --git a/src/template.c b/src/template.c index 139b28b0926a..868455972396 100644 --- a/src/template.c +++ b/src/template.c @@ -544,8 +544,7 @@ void TemplateDeclaration::semantic(Scope *sc) if (!parent) parent = sc->parent; - isstatic = toParent()->isModule() || - toParent()->isFuncDeclaration() && (scope->stc & STCstatic); + isstatic = toParent()->isModule() || (scope->stc & STCstatic); protection = sc->protection; @@ -668,44 +667,73 @@ bool TemplateDeclaration::overloadInsert(Dsymbol *s) } /**************************** - * Declare all the function parameters as variables - * and add them to the scope + * Check to see if constraint is satisfied. */ -void TemplateDeclaration::makeParamNamesVisibleInConstraint(Scope *paramscope, Expressions *fargs) -{ - /* We do this ONLY if there is only one function in the template. +bool TemplateDeclaration::evaluateConstraint( + TemplateInstance *ti, Scope *sc, Scope *paramscope, + Objects *dedtypes, FuncDeclaration *fd) +{ + /* Detect recursive attempts to instantiate this template declaration, + * Bugzilla 4072 + * void foo(T)(T x) if (is(typeof(foo(x)))) { } + * static assert(!is(typeof(foo(7)))); + * Recursive attempts are regarded as a constraint failure. + */ + /* There's a chicken-and-egg problem here. We don't know yet if this template + * instantiation will be a local one (enclosing is set), and we won't know until + * after selecting the correct template. Thus, function we're nesting inside + * is not on the sc scope chain, and this can cause errors in FuncDeclaration::getLevel(). + * Workaround the problem by setting a flag to relax the checking on frame errors. */ - FuncDeclaration *fd = onemember && onemember->toAlias() ? - onemember->toAlias()->isFuncDeclaration() : NULL; - if (fd && fd->type->ty == Tfunction) + + int nmatches = 0; + for (TemplatePrevious *p = previous; p; p = p->prev) { - /* - Making parameters is similar to FuncDeclaration::semantic3 + if (arrayObjectMatch(p->dedargs, dedtypes)) + { + //printf("recursive, no match p->sc=%p %p %s\n", p->sc, this, this->toChars()); + /* It must be a subscope of p->sc, other scope chains are not recursive + * instantiations. + */ + for (Scope *scx = sc; scx; scx = scx->enclosing) + { + if (scx == p->sc) + return false; + } + } + /* BUG: should also check for ref param differences */ - paramscope->parent = fd; + } - TypeFunction *tf = (TypeFunction *)fd->type->syntaxCopy(); - assert(tf->ty == Tfunction); + TemplatePrevious pr; + pr.prev = previous; + pr.sc = paramscope; + pr.dedargs = dedtypes; + previous = ≺ // add this to threaded list - // Shouldn't run semantic on default arguments and return type. - for (size_t i = 0; iparameters->dim; i++) - (*tf->parameters)[i]->defaultArg = NULL; - tf->next = NULL; + int nerrors = global.errors; - // Resolve parameter types and 'auto ref's. - tf->fargs = fargs; - tf = (TypeFunction *)tf->semantic(loc, paramscope); - if (tf->ty != Tfunction) - return; + Scope *scx = paramscope->push(ti); + scx->parent = ti; + scx->tinst = ti; + + if (fd) + { + /* Declare all the function parameters as variables and add them to the scope + * Making parameters is similar to FuncDeclaration::semantic3 + */ + TypeFunction *tf = (TypeFunction *)fd->type; + assert(tf->ty == Tfunction); + + scx->parent = fd; Parameters *fparameters = tf->parameters; int fvarargs = tf->varargs; - size_t nfparams = Parameter::dim(fparameters); // Num function parameters + size_t nfparams = Parameter::dim(fparameters); for (size_t i = 0; i < nfparams; i++) { Parameter *fparam = Parameter::getNth(fparameters, i); - // Remove addMod same as func.d L1065 of FuncDeclaration::semantic3 fparam->storageClass &= (STCin | STCout | STCref | STClazy | STCfinal | STC_TYPECTOR | STCnodtor); fparam->storageClass |= STCparameter; if (fvarargs == 2 && i + 1 == nfparams) @@ -718,13 +746,47 @@ void TemplateDeclaration::makeParamNamesVisibleInConstraint(Scope *paramscope, E continue; // don't add it, if it has no name VarDeclaration *v = new VarDeclaration(loc, fparam->type, fparam->ident, NULL); v->storage_class = fparam->storageClass; - v->semantic(paramscope); - if (!paramscope->insert(v)) + v->semantic(scx); + if (!scx->insert(v)) error("parameter %s.%s is already defined", toChars(), v->toChars()); else v->parent = fd; } + if (isstatic) + fd->storage_class |= STCstatic; + + fd->vthis = fd->declareThis(scx, fd->isThis()); + } + + Expression *e = constraint->syntaxCopy(); + + scx = scx->startCTFE(); + scx->flags |= SCOPEstaticif; + + //printf("\tscx->parent = %s %s\n", scx->parent->kind(), scx->parent->toPrettyChars()); + e = e->semantic(scx); + e = resolveProperties(scx, e); + + scx = scx->endCTFE(); + + scx = scx->pop(); + previous = pr.prev; // unlink from threaded list + + if (nerrors != global.errors) // if any errors from evaluating the constraint, no match + return false; + if (e->op == TOKerror) + return false; + + e = e->ctfeInterpret(); + if (e->isBool(true)) + ; + else if (e->isBool(false)) + return false; + else + { + e->error("constraint %s is not constant or does not evaluate to a bool", e->toChars()); } + return true; } /*************************************** @@ -741,21 +803,21 @@ void TemplateDeclaration::makeParamNamesVisibleInConstraint(Scope *paramscope, E MATCH TemplateDeclaration::matchWithInstance(Scope *sc, TemplateInstance *ti, Objects *dedtypes, Expressions *fargs, int flag) -{ MATCH m; - size_t dedtypes_dim = dedtypes->dim; - +{ #define LOGM 0 #if LOGM printf("\n+TemplateDeclaration::matchWithInstance(this = %s, ti = %s, flag = %d)\n", toChars(), ti->toChars(), flag); #endif - #if 0 - printf("dedtypes->dim = %d, parameters->dim = %d\n", dedtypes_dim, parameters->dim); + printf("dedtypes->dim = %d, parameters->dim = %d\n", dedtypes->dim, parameters->dim); if (ti->tiargs->dim) printf("ti->tiargs->dim = %d, [0] = %p\n", ti->tiargs->dim, (*ti->tiargs)[0]); #endif + MATCH m; + size_t dedtypes_dim = dedtypes->dim; + dedtypes->zero(); if (errors) @@ -776,13 +838,13 @@ MATCH TemplateDeclaration::matchWithInstance(Scope *sc, TemplateInstance *ti, assert(dedtypes_dim == parameters_dim); assert(dedtypes_dim >= ti->tiargs->dim || variadic); - // Set up scope for parameters assert(scope); + + // Set up scope for template parameters ScopeDsymbol *paramsym = new ScopeDsymbol(); paramsym->parent = scope->parent; Scope *paramscope = scope->push(paramsym); - Module *mi = ti->instantiatingModule ? ti->instantiatingModule : sc->instantiatingModule; - paramscope->instantiatingModule = mi; + paramscope->tinst = ti; paramscope->callsc = sc; paramscope->stc = 0; @@ -831,7 +893,8 @@ MATCH TemplateDeclaration::matchWithInstance(Scope *sc, TemplateInstance *ti, for (size_t i = 0; i < dedtypes_dim; i++) { if (!(*dedtypes)[i]) - { assert(i < ti->tiargs->dim); + { + assert(i < ti->tiargs->dim); (*dedtypes)[i] = (Type *)(*ti->tiargs)[i]; } } @@ -839,83 +902,39 @@ MATCH TemplateDeclaration::matchWithInstance(Scope *sc, TemplateInstance *ti, if (m > MATCHnomatch && constraint && !flag) { - /* Check to see if constraint is satisfied. - */ - makeParamNamesVisibleInConstraint(paramscope, fargs); - Expression *e = constraint->syntaxCopy(); - - /* There's a chicken-and-egg problem here. We don't know yet if this template - * instantiation will be a local one (enclosing is set), and we won't know until - * after selecting the correct template. Thus, function we're nesting inside - * is not on the sc scope chain, and this can cause errors in FuncDeclaration::getLevel(). - * Workaround the problem by setting a flag to relax the checking on frame errors. - */ + // minimum requred settings + ti->symtab = new DsymbolTable(); + //ti->parent = this->parent; + if (ti->hasNestedArgs(ti->tiargs, this->isstatic)) // TODO: should gag error + ti->parent = ti->enclosing; + else + ti->parent = this->parent; - int nmatches = 0; - for (TemplatePrevious *p = previous; p; p = p->prev) + // Similar to doHeaderInstantiation + FuncDeclaration *fd = onemember ? onemember->isFuncDeclaration() : NULL; + if (fd) { - if (arrayObjectMatch(p->dedargs, dedtypes)) - { - //printf("recursive, no match p->sc=%p %p %s\n", p->sc, this, this->toChars()); - /* It must be a subscope of p->sc, other scope chains are not recursive - * instantiations. - */ - for (Scope *scx = sc; scx; scx = scx->enclosing) - { - if (scx == p->sc) - goto Lnomatch; - } - } - /* BUG: should also check for ref param differences - */ - } + assert(fd->type->ty == Tfunction); + TypeFunction *tf = (TypeFunction *)fd->type->syntaxCopy(); - TemplatePrevious pr; - pr.prev = previous; - pr.sc = paramscope; - pr.dedargs = dedtypes; - previous = ≺ // add this to threaded list + fd = new FuncDeclaration(fd->loc, fd->endloc, fd->ident, fd->storage_class, tf); + fd->parent = ti; + fd->inferRetType = true; - int nerrors = global.errors; + // Shouldn't run semantic on default arguments and return type. + for (size_t i = 0; i < tf->parameters->dim; i++) + (*tf->parameters)[i]->defaultArg = NULL; + tf->next = NULL; - FuncDeclaration *fd = onemember && onemember->toAlias() ? - onemember->toAlias()->isFuncDeclaration() : NULL; - Dsymbol *s = parent; - while (s->isTemplateInstance() || s->isTemplateMixin()) - s = s->parent; - AggregateDeclaration *ad = s->isAggregateDeclaration(); - VarDeclaration *vthissave; - if (fd && ad) - { - vthissave = fd->vthis; - fd->vthis = fd->declareThis(paramscope, ad); + // Resolve parameter types and 'auto ref's. + tf->fargs = fargs; + fd->type = tf->semantic(loc, paramscope); + if (fd->type->ty != Tfunction) + goto Lnomatch; } - Scope *scx = paramscope->startCTFE(); - scx->flags |= SCOPEstaticif; - e = e->semantic(scx); - e = resolveProperties(scx, e); - scx = scx->endCTFE(); - - if (fd && fd->vthis) - fd->vthis = vthissave; - - previous = pr.prev; // unlink from threaded list - - if (nerrors != global.errors) // if any errors from evaluating the constraint, no match + if (!evaluateConstraint(ti, sc, paramscope, dedtypes, fd)) goto Lnomatch; - if (e->op == TOKerror) - goto Lnomatch; - - e = e->ctfeInterpret(); - if (e->isBool(true)) - ; - else if (e->isBool(false)) - goto Lnomatch; - else - { - e->error("constraint %s is not constant or does not evaluate to a bool", e->toChars()); - } } #if LOGM @@ -1032,22 +1051,23 @@ MATCH TemplateDeclaration::leastAsSpecialized(Scope *sc, TemplateDeclaration *td /************************************************* * Match function arguments against a specific template function. * Input: - * loc instantiation location + * ti * sc instantiation scope - * tiargs Expression/Type initial list of template arguments + * fd * tthis 'this' argument if !NULL * fargs arguments to function * Output: - * dedargs Expression/Type deduced template arguments + * fd Partially instantiated function declaration + * ti->tdtypes Expression/Type deduced template arguments * Returns: * match level * bit 0-3 Match template parameters by inferred template arguments * bit 4-7 Match template parameters by initial template arguments */ -MATCH TemplateDeclaration::deduceFunctionTemplateMatch(FuncDeclaration *f, Loc loc, Scope *sc, Objects *tiargs, - Type *tthis, Expressions *fargs, - Objects *dedargs) +MATCH TemplateDeclaration::deduceFunctionTemplateMatch( + TemplateInstance *ti, Scope *sc, + FuncDeclaration *&fd, Type *tthis, Expressions *fargs) { size_t nfparams; size_t nfargs; @@ -1056,17 +1076,21 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(FuncDeclaration *f, Loc l size_t tuple_dim = 0; MATCH match = MATCHexact; MATCH matchTiargs = MATCHexact; - FuncDeclaration *fd = f; Parameters *fparameters; // function parameter list int fvarargs; // function varargs Objects dedtypes; // for T:T*, the dedargs is the T*, dedtypes is the T unsigned wildmatch = 0; TemplateParameters *inferparams = parameters; + Loc loc = ti->loc; + Objects *tiargs = ti->tiargs; + Objects *dedargs = &ti->tdtypes; + #if 0 printf("\nTemplateDeclaration::deduceFunctionTemplateMatch() %s\n", toChars()); for (size_t i = 0; i < (fargs ? fargs->dim : 0); i++) - { Expression *e = (*fargs)[i]; + { + Expression *e = (*fargs)[i]; printf("\tfarg[%d] is %s, type is %s\n", i, e->toChars(), e->type->toChars()); } printf("fd = %s\n", fd->toChars()); @@ -1083,19 +1107,14 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(FuncDeclaration *f, Loc l dedtypes.setDim(parameters->dim); dedtypes.zero(); - if (errors || f->errors) + if (errors || fd->errors) return MATCHnomatch; // Set up scope for parameters ScopeDsymbol *paramsym = new ScopeDsymbol(); - paramsym->parent = scope->parent; + paramsym->parent = scope->parent; // should use hasnestedArgs and enclosing? Scope *paramscope = scope->push(paramsym); - - paramscope->instantiatingModule = sc->instantiatingModule; - Module *mi = sc->instantiatingModule ? sc->instantiatingModule : sc->module; - if (!sc->instantiatingModule || sc->instantiatingModule->isRoot()) - paramscope->instantiatingModule = mi; - + paramscope->tinst = ti; paramscope->callsc = sc; paramscope->stc = 0; @@ -1115,14 +1134,15 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(FuncDeclaration *f, Loc l ntargs = 0; if (tiargs) - { // Set initial template arguments - + { + // Set initial template arguments ntargs = tiargs->dim; size_t n = parameters->dim; if (tp) n--; if (ntargs > n) - { if (!tp) + { + if (!tp) goto Lnomatch; /* The extra initial template arguments @@ -1147,11 +1167,10 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(FuncDeclaration *f, Loc l memcpy(dedargs->tdata(), tiargs->tdata(), n * sizeof(*dedargs->tdata())); for (size_t i = 0; i < n; i++) - { assert(i < parameters->dim); - MATCH m; + { + assert(i < parameters->dim); Declaration *sparam = NULL; - - m = (*parameters)[i]->matchArg(loc, paramscope, dedargs, i, parameters, &dedtypes, &sparam); + MATCH m = (*parameters)[i]->matchArg(loc, paramscope, dedargs, i, parameters, &dedtypes, &sparam); //printf("\tdeduceType m = %d\n", m); if (m <= MATCHnomatch) goto Lnomatch; @@ -1246,7 +1265,8 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(FuncDeclaration *f, Loc l { TemplateThisParameter *ttp = (*parameters)[i]->isTemplateThisParameter(); if (ttp) - { hasttp = true; + { + hasttp = true; Type *t = new TypeIdentifier(Loc(), ttp->ident); MATCH m = tthis->deduceType(paramscope, t, parameters, &dedtypes); @@ -1432,7 +1452,8 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(FuncDeclaration *f, Loc l if (argi >= nfargs) // if not enough arguments { if (fparam->defaultArg) - { /* Default arguments do not participate in template argument + { + /* Default arguments do not participate in template argument * deduction. */ goto Lmatch; @@ -1483,7 +1504,8 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(FuncDeclaration *f, Loc l /* Allow implicit function literals to delegate conversion */ if (farg->op == TOKfunction) - { FuncExp *fe = (FuncExp *)farg; + { + FuncExp *fe = (FuncExp *)farg; Expression *e = fe->inferType(prmtype, 1, paramscope, inferparams); if (!e) goto Lvarargs; @@ -1522,7 +1544,8 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(FuncDeclaration *f, Loc l /* If no match, see if there's a conversion to a delegate */ if (m == MATCHnomatch) - { Type *tbp = prmtype->toBasetype(); + { + Type *tbp = prmtype->toBasetype(); Type *tba = farg->type->toBasetype(); if (tbp->ty == Tdelegate) { @@ -1563,14 +1586,16 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(FuncDeclaration *f, Loc l { } else if (farg->op == TOKslice && argtype->ty == Tsarray) - { // Allow conversion from T[lwr .. upr] to ref T[upr-lwr] + { + // Allow conversion from T[lwr .. upr] to ref T[upr-lwr] } else goto Lnomatch; } } if (m > MATCHnomatch && (fparam->storageClass & STCout)) - { if (!farg->isLvalue()) + { + if (!farg->isLvalue()) goto Lnomatch; } if (m == MATCHnomatch && (fparam->storageClass & STClazy) && prmtype->ty == Tvoid && @@ -1578,7 +1603,8 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(FuncDeclaration *f, Loc l m = MATCHconvert; if (m != MATCHnomatch) - { if (m < match) + { + if (m < match) match = m; // pick worst match argi++; continue; @@ -1600,20 +1626,24 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(FuncDeclaration *f, Loc l // 6764 fix - TypeAArray may be TypeSArray have not yet run semantic(). case Tsarray: case Taarray: - { // Perhaps we can do better with this, see TypeFunction::callMatch() + { + // Perhaps we can do better with this, see TypeFunction::callMatch() if (tb->ty == Tsarray) - { TypeSArray *tsa = (TypeSArray *)tb; + { + TypeSArray *tsa = (TypeSArray *)tb; dinteger_t sz = tsa->dim->toInteger(); if (sz != nfargs - argi) goto Lnomatch; } else if (tb->ty == Taarray) - { TypeAArray *taa = (TypeAArray *)tb; + { + TypeAArray *taa = (TypeAArray *)tb; Expression *dim = new IntegerExp(loc, nfargs - argi, Type::tsize_t); size_t i = templateParameterLookup(taa->index, parameters); if (i == IDX_NOTFOUND) - { Expression *e; + { + Expression *e; Type *t; Dsymbol *s; taa->index->resolve(loc, sc, &e, &t, &s); @@ -1626,7 +1656,8 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(FuncDeclaration *f, Loc l goto Lnomatch; } else - { // This code matches code in TypeInstance::deduceType() + { + // This code matches code in TypeInstance::deduceType() TemplateParameter *tprm = (*parameters)[i]; TemplateValueParameter *tvp = tprm->isTemplateValueParameter(); if (!tvp) @@ -1650,15 +1681,16 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(FuncDeclaration *f, Loc l /* fall through */ } case Tarray: - { TypeArray *ta = (TypeArray *)tb; + { + TypeArray *ta = (TypeArray *)tb; for (; argi < nfargs; argi++) { Expression *arg = (*fargs)[argi]; assert(arg); if (arg->op == TOKfunction) - { FuncExp *fe = (FuncExp *)arg; - + { + FuncExp *fe = (FuncExp *)arg; Expression *e = fe->inferType(tb->nextOf(), 1, paramscope, inferparams); if (!e) goto Lnomatch; @@ -1673,7 +1705,8 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(FuncDeclaration *f, Loc l if (tret) { if (ta->next->equals(arg->type)) - { m = MATCHexact; + { + m = MATCHexact; } else { @@ -1730,7 +1763,8 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(FuncDeclaration *f, Loc l if (oded) { if (tparam->specialization() || !tparam->isTemplateTypeParameter()) - { /* The specialization can work as long as afterwards + { + /* The specialization can work as long as afterwards * the oded == oarg */ (*dedargs)[i] = oded; @@ -1750,13 +1784,15 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(FuncDeclaration *f, Loc l } } else - { oded = tparam->defaultArg(loc, paramscope); + { + oded = tparam->defaultArg(loc, paramscope); if (!oded) { if (tp && // if tuple parameter and fptupindex == IDX_NOTFOUND && // tuple parameter was not in function parameter list and ntargs == dedargs->dim - 1) // we're one argument short (i.e. no tuple argument) - { // make tuple argument an empty tuple + { + // make tuple argument an empty tuple oded = (RootObject *)new Tuple(); } else @@ -1768,91 +1804,38 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(FuncDeclaration *f, Loc l } } - if (constraint) + // Partially instantiate function for constraint and fd->leastAsSpecialized() { - /* Check to see if constraint is satisfied. - * Most of this code appears twice; this is a good candidate for refactoring. - */ - makeParamNamesVisibleInConstraint(paramscope, fargs); - Expression *e = constraint->syntaxCopy(); - - /* Detect recursive attempts to instantiate this template declaration, - * Bugzilla 4072 - * void foo(T)(T x) if (is(typeof(foo(x)))) { } - * static assert(!is(typeof(foo(7)))); - * Recursive attempts are regarded as a constraint failure. - */ - int nmatches = 0; - for (TemplatePrevious *p = previous; p; p = p->prev) - { - if (arrayObjectMatch(p->dedargs, dedargs)) - { - //printf("recursive, no match p->sc=%p %p %s\n", p->sc, this, this->toChars()); - /* It must be a subscope of p->sc, other scope chains are not recursive - * instantiations. - */ - for (Scope *scx = sc; scx; scx = scx->enclosing) - { - if (scx == p->sc) - goto Lnomatch; - } - } - /* BUG: should also check for ref param differences - */ - } - - TemplatePrevious pr; - pr.prev = previous; - pr.sc = paramscope; - pr.dedargs = dedargs; - previous = ≺ // add this to threaded list + assert(paramsym); + Scope *sc1 = scope->push(paramsym); + sc1->tinst = ti; - int nerrors = global.errors; + Scope *sc2 = sc1->push(ti); + sc2->parent = ti; + sc2->tinst = ti; - Dsymbol *s = parent; - while (s->isTemplateInstance() || s->isTemplateMixin()) - s = s->parent; - AggregateDeclaration *ad = s->isAggregateDeclaration(); - VarDeclaration *vthissave; - if (fd && ad) - { - vthissave = fd->vthis; - fd->vthis = fd->declareThis(paramscope, ad); - } + fd = doHeaderInstantiation(ti, sc2, fd, tthis, fargs); - Scope *scx = paramscope->startCTFE(); - scx->flags |= SCOPEstaticif; - e = e->semantic(scx); - e = resolveProperties(scx, e); - scx->endCTFE(); - - if (fd && fd->vthis) - fd->vthis = vthissave; - - previous = pr.prev; // unlink from threaded list + sc2->pop(); + sc1->pop(); - if (nerrors != global.errors) // if any errors from evaluating the constraint, no match - goto Lnomatch; - if (e->op == TOKerror) + if (!fd) goto Lnomatch; - - e = e->ctfeInterpret(); - if (e->isBool(true)) - ; - else if (e->isBool(false)) + } + if (constraint) + { + if (!evaluateConstraint(ti, sc, paramscope, dedargs, fd)) goto Lnomatch; - else - { - e->error("constraint %s is not constant or does not evaluate to a bool", e->toChars()); - } } #if 0 for (i = 0; i < dedargs->dim; i++) - { Type *t = (*dedargs)[i]; + { + Type *t = (*dedargs)[i]; printf("\tdedargs[%d] = %d, %s\n", i, t->dyncast(), t->toChars()); } #endif + ti->tiargs = &ti->tdtypes; // for better error message paramscope->pop(); //printf("\tmatch %d\n", match); @@ -1985,14 +1968,17 @@ void functionResolve(Match *m, Dsymbol *dstart, Loc loc, Scope *sc, printf("functionResolve() dstart = %s\n", dstart->toChars()); printf(" tiargs:\n"); if (tiargs) - { for (size_t i = 0; i < tiargs->dim; i++) - { RootObject *arg = (*tiargs)[i]; + { + for (size_t i = 0; i < tiargs->dim; i++) + { + RootObject *arg = (*tiargs)[i]; printf("\t%s\n", arg->toChars()); } } printf(" fargs:\n"); for (size_t i = 0; i < (fargs ? fargs->dim : 0); i++) - { Expression *arg = (*fargs)[i]; + { + Expression *arg = (*fargs)[i]; printf("\t%s %s\n", arg->type->toChars(), arg->toChars()); //printf("\tty = %d\n", arg->type->ty); } @@ -2015,8 +2001,8 @@ void functionResolve(Match *m, Dsymbol *dstart, Loc loc, Scope *sc, // 2: not @property size_t ov_index; TemplateDeclaration *td_best; + TemplateInstance *ti_best; MATCH ta_last; - Objects *tdargs; Type *tthis_best; static int fp(void *param, Dsymbol *s) @@ -2061,7 +2047,8 @@ void functionResolve(Match *m, Dsymbol *dstart, Loc loc, Scope *sc, if (MODimplicitConv(tf->mod, tthis_fd->mod) || tf->isWild() && tf->isShared() == tthis_fd->isShared() || fd->isolateReturn()/* && tf->isShared() == tthis_fd->isShared()*/) - { // Uniquely constructed object can ignore shared qualifier. + { + // Uniquely constructed object can ignore shared qualifier. // TODO: Is this appropriate? tthis_fd = NULL; } @@ -2119,13 +2106,13 @@ void functionResolve(Match *m, Dsymbol *dstart, Loc loc, Scope *sc, LfIsBetter: td_best = NULL; + ti_best = NULL; ta_last = MATCHexact; m->last = mfa; m->lastf = fd; tthis_best = tthis_fd; ov_index = 0; m->count = 1; - tdargs->setDim(0); return 0; } return 0; @@ -2238,6 +2225,7 @@ void functionResolve(Match *m, Dsymbol *dstart, Loc loc, Scope *sc, // td is the new best match assert(td->scope); td_best = td; + ti_best = NULL; property = 0; // (backward compatibility) ta_last = mta; m->last = mfa; @@ -2246,8 +2234,6 @@ void functionResolve(Match *m, Dsymbol *dstart, Loc loc, Scope *sc, ov_index = 0; m->nextf = NULL; m->count = 1; - tdargs->setDim(dedtypes.dim); - memcpy(tdargs->tdata(), dedtypes.tdata(), tdargs->dim * sizeof(void *)); return 0; } @@ -2257,26 +2243,30 @@ void functionResolve(Match *m, Dsymbol *dstart, Loc loc, Scope *sc, if (f->type->ty != Tfunction || f->errors) goto Lerror; - Objects dedtypes; - FuncDeclaration *fd = NULL; - int x = td->deduceFunctionTemplateMatch(f, loc, sc, tiargs, tthis, fargs, &dedtypes); + TemplateInstance *ti = new TemplateInstance(loc, td, tiargs); + ti->tinst = td->getInstantiating(sc); + ti->instantiatingModule = sc->instantiatingModule(); + ti->parent = td->parent; // Maybe calculating valid 'enclosing' is unnecessary. + ti->semantictiargsdone = true; + ti->symtab = new DsymbolTable(); + + FuncDeclaration *fd = f; + int x = td->deduceFunctionTemplateMatch(ti, sc, fd, tthis, fargs); MATCH mta = (MATCH)(x >> 4); MATCH mfa = (MATCH)(x & 0xF); //printf("match:t/f = %d/%d\n", mta, mfa); - if (mfa <= MATCHnomatch) // if no match + if (!fd) + goto Lerror; + if (mfa == MATCHnomatch) continue; - Type *tthis_fd = NULL; - if (f->isCtorDeclaration()) + Type *tthis_fd = fd->needThis() ? tthis : NULL; + + if (fd->isCtorDeclaration()) { // Constructor call requires additional check. - // For that, do instantiate in early stage. - fd = td->doHeaderInstantiation(sc, &dedtypes, tthis, fargs); - if (!fd) - goto Lerror; TypeFunction *tf = (TypeFunction *)fd->type; - tthis_fd = fd->needThis() ? tthis : NULL; if (tthis_fd) { assert(tf->next); @@ -2306,22 +2296,7 @@ void functionResolve(Match *m, Dsymbol *dstart, Loc loc, Scope *sc, if (c1 > c2) goto Ltd; if (c1 < c2) goto Ltd_best; } - - if (!m->lastf) - { - assert(td_best); - m->lastf = td_best->doHeaderInstantiation(sc, tdargs, tthis, fargs); - if (!m->lastf) goto Lerror; - tthis_best = m->lastf->needThis() ? tthis : NULL; - } - if (!fd) - { - fd = td->doHeaderInstantiation(sc, &dedtypes, tthis, fargs); - if (!fd) goto Lerror; - tthis_fd = fd->needThis() ? tthis : NULL; - } assert(fd && m->lastf); - { // Disambiguate by tf->callMatch TypeFunction *tf1 = (TypeFunction *)fd->type; @@ -2345,7 +2320,7 @@ void functionResolve(Match *m, Dsymbol *dstart, Loc loc, Scope *sc, Lambig: // td_best and td are ambiguous //printf("Lambig\n"); - m->nextf = fd; // Caution! m->nextf isn't complete instantiated fd, so must not call toPrettyChars() + m->nextf = fd; m->count++; continue; @@ -2357,6 +2332,7 @@ void functionResolve(Match *m, Dsymbol *dstart, Loc loc, Scope *sc, //printf("Ltd\n"); assert(td->scope); td_best = td; + ti_best = ti; property = 0; // (backward compatibility) ta_last = mta; m->last = mfa; @@ -2365,8 +2341,6 @@ void functionResolve(Match *m, Dsymbol *dstart, Loc loc, Scope *sc, ov_index = ovi; m->nextf = NULL; m->count = 1; - tdargs->setDim(dedtypes.dim); - memcpy(tdargs->tdata(), dedtypes.tdata(), tdargs->dim * sizeof(void *)); continue; } return 0; @@ -2385,8 +2359,8 @@ void functionResolve(Match *m, Dsymbol *dstart, Loc loc, Scope *sc, p.property = 0; p.ov_index = 0; p.td_best = NULL; + p.ti_best = NULL; p.ta_last = m->last != MATCHnomatch ? MATCHexact : MATCHnomatch; - p.tdargs = new Objects(); p.tthis_best = NULL; FuncDeclaration *fd = dstart->isFuncDeclaration(); @@ -2396,10 +2370,10 @@ void functionResolve(Match *m, Dsymbol *dstart, Loc loc, Scope *sc, overloadApply(dstart, &p, &ParamDeduce::fp); //printf("td_best = %p, m->lastf = %p\n", p.td_best, m->lastf); - if (p.td_best) + if (p.td_best && p.ti_best) { // Matches to template function - if (!p.td_best->onemember || !p.td_best->onemember->toAlias()->isFuncDeclaration()) + if (!p.td_best->onemember || !p.td_best->onemember->isFuncDeclaration()) return; // goto Lerror? /* The best match is td_best with arguments tdargs. @@ -2408,7 +2382,7 @@ void functionResolve(Match *m, Dsymbol *dstart, Loc loc, Scope *sc, assert(p.td_best->scope); if (!sc) sc = p.td_best->scope; // workaround for Type::aliasthisOf - TemplateInstance *ti = new TemplateInstance(loc, p.td_best, p.tdargs); + TemplateInstance *ti = new TemplateInstance(loc, p.td_best, &p.ti_best->tdtypes); // TODO? ti->semantic(sc, fargs); m->lastf = ti->toAlias()->isFuncDeclaration(); @@ -2478,112 +2452,80 @@ void functionResolve(Match *m, Dsymbol *dstart, Loc loc, Scope *sc, /************************************************* * Limited function template instantiation for using fd->leastAsSpecialized() */ -FuncDeclaration *TemplateDeclaration::doHeaderInstantiation(Scope *sc, - Objects *tdargs, Type *tthis, Expressions *fargs) +FuncDeclaration *TemplateDeclaration::doHeaderInstantiation( + TemplateInstance *ti, Scope *sc2, + FuncDeclaration *fd, Type *tthis, Expressions *fargs) { - FuncDeclaration *fd = onemember->toAlias()->isFuncDeclaration(); - if (!fd) - return NULL; - + assert(fd); #if 0 printf("doHeaderInstantiation this = %s\n", toChars()); - for (size_t i = 0; i < tdargs->dim; ++i) - printf("\ttdargs[%d] = %s\n", i, ((RootObject *)tdargs->data[i])->toChars()); #endif - assert(scope); - TemplateInstance *ti = new TemplateInstance(loc, this, tdargs); - ti->tinst = sc->tinst; - { - ti->tdtypes.setDim(parameters->dim); - if (matchWithInstance(sc, ti, &ti->tdtypes, fargs, 2) <= MATCHnomatch) - return NULL; - } - - ti->parent = parent; - // function body and contracts are not need - //fd = fd->syntaxCopy(NULL)->isFuncDeclaration(); if (fd->isCtorDeclaration()) fd = new CtorDeclaration(fd->loc, fd->endloc, fd->storage_class, fd->type->syntaxCopy()); else fd = new FuncDeclaration(fd->loc, fd->endloc, fd->ident, fd->storage_class, fd->type->syntaxCopy()); fd->parent = ti; - Module *mi = sc->instantiatingModule ? sc->instantiatingModule : sc->module; - - Scope *scope = this->scope; - ti->argsym = new ScopeDsymbol(); - ti->argsym->parent = scope->parent; - scope = scope->push(ti->argsym); - scope->instantiatingModule = mi; - - bool hasttp = false; - - Scope *paramscope = scope->push(); - paramscope->stc = 0; - ti->declareParameters(paramscope); - paramscope->pop(); + assert(fd->type->ty == Tfunction); + TypeFunction *tf = (TypeFunction *)fd->type; + tf->fargs = fargs; if (tthis) { // Match 'tthis' to any TemplateThisParameter's + bool hasttp = false; for (size_t i = 0; i < parameters->dim; i++) - { TemplateParameter *tp = (*parameters)[i]; + { + TemplateParameter *tp = (*parameters)[i]; TemplateThisParameter *ttp = tp->isTemplateThisParameter(); if (ttp) hasttp = true; } - } - { - TypeFunction *tf = (TypeFunction *)fd->type; - if (tf && tf->ty == Tfunction) - tf->fargs = fargs; + if (hasttp) + tf = (TypeFunction *)tf->addMod(tthis->mod); } - Scope *sc2; - sc2 = scope->push(ti); - sc2->parent = ti; - sc2->tinst = ti; + Scope *scx = sc2->push(); + // Shouldn't run semantic on default arguments and return type. + for (size_t i = 0; i < tf->parameters->dim; i++) + (*tf->parameters)[i]->defaultArg = NULL; + if (fd->isCtorDeclaration()) { - Scope *scx = sc2; - scx = scx->push(); + // For constructors, emitting return type is necessary for + // isolateReturn() in functionResolve. + scx->flags |= SCOPEctor; - if (hasttp) - fd->type = fd->type->addMod(tthis->mod); - //printf("tthis = %s, fdtype = %s\n", tthis->toChars(), fd->type->toChars()); - if (fd->isCtorDeclaration()) + Dsymbol *parent = toParent2(); + Type *tret; + AggregateDeclaration *ad = parent->isAggregateDeclaration(); + if (!ad || parent->isUnionDeclaration()) { - scx->flags |= SCOPEctor; - - Dsymbol *parent = toParent2(); - Type *tret; - AggregateDeclaration *ad = parent->isAggregateDeclaration(); - if (!ad || parent->isUnionDeclaration()) - { - tret = Type::tvoid; - } - else - { tret = ad->handle; - assert(tret); - tret = tret->addStorageClass(fd->storage_class | scx->stc); - tret = tret->addMod(fd->type->mod); - } - ((TypeFunction *)fd->type)->next = tret; - if (ad && ad->isStructDeclaration()) - ((TypeFunction *)fd->type)->isref = 1; - //printf("fd->type = %s\n", fd->type->toChars()); + tret = Type::tvoid; + } + else + { + tret = ad->handle; + assert(tret); + tret = tret->addStorageClass(fd->storage_class | scx->stc); + tret = tret->addMod(tf->mod); } - fd->type = fd->type->addSTC(scx->stc); - fd->type = fd->type->semantic(fd->loc, scx); - scx = scx->pop(); + tf->next = tret; + if (ad && ad->isStructDeclaration()) + tf->isref = 1; + //printf("tf = %s\n", tf->toChars()); } + else + tf->next = NULL; + fd->type = tf; + fd->type = fd->type->addSTC(scx->stc); + fd->type = fd->type->semantic(fd->loc, scx); //printf("\t[%s] fd->type = %s, mod = %x, ", loc.toChars(), fd->type->toChars(), fd->type->mod); //printf("fd->needThis() = %d\n", fd->needThis()); - sc2->pop(); - scope->pop(); + scx = scx->pop(); return fd->type->ty == Tfunction ? fd : NULL; } @@ -2747,9 +2689,6 @@ char *TemplateDeclaration::toChars() if (onemember) { - /* Bugzilla 9406: - * onemember->toAlias() might run semantic, so should not call it in stringizing - */ FuncDeclaration *fd = onemember->isFuncDeclaration(); if (fd && fd->type) { @@ -2880,6 +2819,21 @@ 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 ============================================ */ /**** @@ -4542,45 +4496,6 @@ int TemplateAliasParameter::overloadMatch(TemplateParameter *tp) return 0; } -/* Bugzilla 6538: In template constraint, each function parameters, 'this', - * and 'super' is *pseudo* symbol. If it is passed to other template through - * alias/tuple parameter, it will cause an error. Because such symbol - * does not have the actual entity yet. - * - * Example: - * template Sym(alias A) { enum Sym = true; } - * struct S { - * void foo() if (Sym!(this)) {} // Sym!(this) always make an error, - * } // because Sym template cannot - * void main() { S s; s.foo(); } // access to the valid 'this' symbol. - */ -bool isPseudoDsymbol(RootObject *o) -{ - Dsymbol *s = isDsymbol(o); - Expression *e = isExpression(o); - if (e && e->op == TOKvar) s = ((VarExp *)e)->var->isVarDeclaration(); - if (e && e->op == TOKthis) s = ((ThisExp *)e)->var->isThisDeclaration(); - if (e && e->op == TOKsuper) s = ((SuperExp *)e)->var->isThisDeclaration(); - - if (s && s->parent) - { - s = s->toAlias(); - VarDeclaration *v = s->isVarDeclaration(); - TupleDeclaration *t = s->isTupleDeclaration(); - if (v || t) - { - FuncDeclaration *fd = s->parent->isFuncDeclaration(); - if (fd && fd->parent && fd->parent->isTemplateDeclaration()) - { - const char *str = (e && e->op == TOKsuper) ? "super" : s->toChars(); - ::error(s->loc, "cannot take a not yet instantiated symbol '%s' inside template constraint", str); - return true; - } - } - } - return false; -} - MATCH TemplateAliasParameter::matchArg(Scope *sc, RootObject *oarg, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam) @@ -5340,20 +5255,10 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs) printf("Scope\n"); for (Scope *scx = sc; scx; scx = scx->enclosing) { - printf("\t%s parent %s instantiatingModule %p\n", scx->module ? scx->module->toChars() : "null", scx->parent ? scx->parent->toChars() : "null", scx->instantiatingModule); + printf("\t%s parent %s\n", scx->module ? scx->module->toChars() : "null", scx->parent ? scx->parent->toChars() : "null"); } #endif - Module *mi = sc->instantiatingModule ? sc->instantiatingModule : sc->module; - - /* 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. - */ - if (!instantiatingModule || instantiatingModule->isRoot()) - instantiatingModule = mi; - //printf("mi = %s\n", mi->toChars()); - #if LOG printf("\n+TemplateInstance::semantic('%s', this=%p)\n", toChars(), this); #endif @@ -5368,6 +5273,16 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs) // get the enclosing template instance from the scope tinst tinst = sc->tinst; + Module *mi = sc->instantiatingModule(); + + /* 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. + */ + if (!instantiatingModule || instantiatingModule->isRoot()) + instantiatingModule = mi; + //printf("mi = %s\n", mi->toChars()); + if (semanticRun != PASSinit) { #if LOG @@ -5593,8 +5508,8 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs) argsym = new ScopeDsymbol(); argsym->parent = scope->parent; scope = scope->push(argsym); - scope->instantiatingModule = mi; -// scope->stc = 0; + scope->tinst = this; + //scope->stc = 0; // Declare each template parameter as an alias for the argument type Scope *paramscope = scope->push(); @@ -6119,14 +6034,17 @@ void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f Ltype: if (ta->ty == Ttuple) - { // Expand tuple + { + // Expand tuple TypeTuple *tt = (TypeTuple *)ta; size_t dim = tt->arguments->dim; tiargs->remove(j); if (dim) - { tiargs->reserve(dim); + { + tiargs->reserve(dim); for (size_t i = 0; i < dim; i++) - { Parameter *arg = (*tt->arguments)[i]; + { + Parameter *arg = (*tt->arguments)[i]; if (flags & 2 && arg->ident) tiargs->insert(j + i, arg); else @@ -6161,7 +6079,8 @@ void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f } } else if (ea->op == TOKvar) - { /* This test is to skip substituting a const var with + { + /* This test is to skip substituting a const var with * its initializer. The problem is the initializer won't * match with an 'alias' parameter. Instead, do the * const substitution in TemplateValueParameter::matchArg(). @@ -6176,17 +6095,15 @@ void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f ea = new ErrorExp(); } //printf("-[%d] ea = %s %s\n", j, Token::toChars(ea->op), ea->toChars()); - if (!flags && isPseudoDsymbol(ea)) - { (*tiargs)[j] = new ErrorExp(); - continue; - } if (ea->op == TOKtuple) - { // Expand tuple + { + // Expand tuple TupleExp *te = (TupleExp *)ea; size_t dim = te->exps->dim; tiargs->remove(j); if (dim) - { tiargs->reserve(dim); + { + tiargs->reserve(dim); for (size_t i = 0; i < dim; i++) tiargs->insert(j + i, (*te->exps)[i]); } @@ -6196,42 +6113,50 @@ void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f (*tiargs)[j] = ea; if (ea->op == TOKtype) - { ta = ea->type; + { + ta = ea->type; goto Ltype; } if (ea->op == TOKimport) - { sa = ((ScopeExp *)ea)->sds; + { + sa = ((ScopeExp *)ea)->sds; goto Ldsym; } if (ea->op == TOKfunction) - { FuncExp *fe = (FuncExp *)ea; + { + FuncExp *fe = (FuncExp *)ea; /* A function literal, that is passed to template and * already semanticed as function pointer, never requires * outer frame. So convert it to global function is valid. */ if (fe->fd->tok == TOKreserved && fe->type->ty == Tpointer) - { // change to non-nested + { + // change to non-nested fe->fd->tok = TOKfunction; fe->fd->vthis = NULL; } else if (fe->td) - { /* If template argument is a template lambda, + { + /* If template argument is a template lambda, * get template declaration itself. */ //sa = fe->td; //goto Ldsym; } } if (ea->op == TOKdotvar) - { // translate expression to dsymbol. + { + // translate expression to dsymbol. sa = ((DotVarExp *)ea)->var; goto Ldsym; } if (ea->op == TOKtemplate) - { sa = ((TemplateExp *)ea)->td; + { + sa = ((TemplateExp *)ea)->td; goto Ldsym; } if (ea->op == TOKdottd) - { // translate expression to dsymbol. + { + // translate expression to dsymbol. sa = ((DotTemplateExp *)ea)->td; goto Ldsym; } @@ -6240,13 +6165,10 @@ void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f { Ldsym: //printf("dsym %s %s\n", sa->kind(), sa->toChars()); - if (!flags && isPseudoDsymbol(sa)) - { (*tiargs)[j] = new ErrorExp(); - continue; - } TupleDeclaration *d = sa->toAlias()->isTupleDeclaration(); if (d) - { // Expand tuple + { + // Expand tuple size_t dim = d->objects->dim; tiargs->remove(j); tiargs->insert(j, d->objects); @@ -6904,7 +6826,6 @@ void TemplateInstance::semantic2(Scope *sc) sc = tempdecl->scope; assert(sc); sc = sc->push(argsym); - sc->instantiatingModule = instantiatingModule; sc = sc->push(this); sc->tinst = this; for (size_t i = 0; i < members->dim; i++) @@ -6936,7 +6857,6 @@ void TemplateInstance::semantic3(Scope *sc) { sc = tempdecl->scope; sc = sc->push(argsym); - sc->instantiatingModule = instantiatingModule; sc = sc->push(this); sc->tinst = this; int needGagging = (speculative && !global.gag); @@ -7674,7 +7594,6 @@ void TemplateMixin::semantic3(Scope *sc) if (members) { sc = sc->push(argsym); - sc->instantiatingModule = instantiatingModule; sc = sc->push(this); for (size_t i = 0; i < members->dim; i++) { diff --git a/src/template.h b/src/template.h index 676582c43405..b1cea6241054 100644 --- a/src/template.h +++ b/src/template.h @@ -95,22 +95,25 @@ class TemplateDeclaration : public ScopeDsymbol PROT prot(); // void toDocBuffer(OutBuffer *buf); + bool evaluateConstraint(TemplateInstance *ti, Scope *sc, Scope *paramscope, Objects *dedtypes, FuncDeclaration *fd); + MATCH matchWithInstance(Scope *sc, TemplateInstance *ti, Objects *atypes, Expressions *fargs, int flag); MATCH leastAsSpecialized(Scope *sc, TemplateDeclaration *td2, Expressions *fargs); - MATCH deduceFunctionTemplateMatch(FuncDeclaration *f, Loc loc, Scope *sc, Objects *tiargs, Type *tthis, Expressions *fargs, Objects *dedargs); + MATCH deduceFunctionTemplateMatch(TemplateInstance *ti, Scope *sc, FuncDeclaration *&fd, Type *tthis, Expressions *fargs); RootObject *declareParameter(Scope *sc, TemplateParameter *tp, RootObject *o); - FuncDeclaration *doHeaderInstantiation(Scope *sc, Objects *tdargs, Type *tthis, Expressions *fargs); + FuncDeclaration *doHeaderInstantiation(TemplateInstance *ti, Scope *sc, FuncDeclaration *fd, Type *tthis, Expressions *fargs); TemplateInstance *findExistingInstance(TemplateInstance *tithis, Expressions *fargs); TemplateInstance *addInstance(TemplateInstance *ti); void removeInstance(TemplateInstance *handle); + TemplateInstance *getInstantiating(Scope *sc); + TemplateDeclaration *isTemplateDeclaration() { return this; } TemplateTupleParameter *isVariadic(); bool isOverloadable(); - void makeParamNamesVisibleInConstraint(Scope *paramscope, Expressions *fargs); void accept(Visitor *v) { v->visit(this); } }; diff --git a/src/toobj.c b/src/toobj.c index 793cab3f2696..c612b39cb620 100644 --- a/src/toobj.c +++ b/src/toobj.c @@ -1147,6 +1147,24 @@ void TemplateInstance::toObjFile(int multiobj) #endif if (!isError(this) && members) { + FuncDeclaration *fd = enclosing ? enclosing->isFuncDeclaration() : NULL; + if (fd && fd->fbody == NULL) + { + /* Prevent codegen if enclosing is an artificially instantiated function. + */ + return; + } + + TemplateDeclaration *tempdecl = this->tempdecl->isTemplateDeclaration(); + assert(tempdecl); + if (tempdecl->literal && tempdecl->ident == Id::empty) + { + /* Bugzilla 10313: Template lambdas that instantiated in template constraint + * cannot appear in runnable code block. So, this skip won't cause linker failure. + */ + return; + } + if (multiobj) // Append to list of object files to be written later obj_append(this); diff --git a/test/compilable/ice6538.d b/test/compilable/ice6538.d new file mode 100644 index 000000000000..12d1ed0fa918 --- /dev/null +++ b/test/compilable/ice6538.d @@ -0,0 +1,43 @@ + + +/**************************************/ +// 6538 + +template allSatisfy(alias F, T...) { enum bool allSatisfy = true; } +template isIntegral(T) { enum bool isIntegral = true; } + +void foo(I...)(I sizes) +if (allSatisfy!(isIntegral, sizes)) {} + +void test6538a() +{ + foo(42, 86); +} + +void bar(T1, T2)(T1 t1, T2 t2) +if (allSatisfy!(isIntegral, t1, t2)) {} + +void test6538b() +{ + bar(42, 86); +} + +/**************************************/ +// 9361 + +template Sym(alias A) +{ + enum Sym = true; +} + +struct S +{ + void foo()() if (Sym!(this)) {} + void bar()() { static assert(Sym!(this)); } // OK +} +void test9361a() +{ + S s; + s.foo(); // fail + s.bar(); // OK +} diff --git a/test/fail_compilation/diag11769.d b/test/fail_compilation/diag11769.d index 08fbc62ace66..2b2344ff72af 100644 --- a/test/fail_compilation/diag11769.d +++ b/test/fail_compilation/diag11769.d @@ -2,9 +2,9 @@ TEST_OUTPUT: --- fail_compilation/diag11769.d(18): Error: diag11769.foo!string.bar called with argument types (string) matches both: - fail_compilation/diag11769.d(13): bar(immutable(wchar)[] _param_0) + fail_compilation/diag11769.d(13): diag11769.foo!string.bar(immutable(wchar)[] _param_0) and: - fail_compilation/diag11769.d(14): bar(immutable(dchar)[] _param_0) + fail_compilation/diag11769.d(14): diag11769.foo!string.bar(immutable(dchar)[] _param_0) --- */ diff --git a/test/fail_compilation/diag9880.d b/test/fail_compilation/diag9880.d index b624d85298d8..9d893b8d5de2 100644 --- a/test/fail_compilation/diag9880.d +++ b/test/fail_compilation/diag9880.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/diag9880.d(9): Error: template instance foo!string does not match template declaration foo(T)(int) if (is(T == int)) +fail_compilation/diag9880.d(9): Error: template instance diag9880.foo!string does not match template declaration foo(T)(int) if (is(T == int)) --- */ diff --git a/test/fail_compilation/fail319.d b/test/fail_compilation/fail319.d index dc6a706fec9f..3c4459a89bde 100644 --- a/test/fail_compilation/fail319.d +++ b/test/fail_compilation/fail319.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail319.d(13): Error: template instance f!(int, int) does not match template declaration f(T...)() if (T.length > 20) +fail_compilation/fail319.d(13): Error: template instance fail319.f!(int, int) does not match template declaration f(T...)() if (T.length > 20) --- */ diff --git a/test/fail_compilation/ice6538.d b/test/fail_compilation/ice6538.d index d8574f10a578..dad6491c5e92 100644 --- a/test/fail_compilation/ice6538.d +++ b/test/fail_compilation/ice6538.d @@ -1,80 +1,22 @@ /**************************************/ -// 6538 - -template allSatisfy(alias F, T...) { enum bool allSatisfy = true; } -template isIntegral(T) { enum bool isIntegral = true; } - -/* -TEST_OUTPUT: ---- -fail_compilation/ice6538.d(17): Error: cannot take a not yet instantiated symbol 'sizes' inside template constraint -fail_compilation/ice6538.d(22): Error: template ice6538.foo cannot deduce function from argument types !()(int, int), candidates are: -fail_compilation/ice6538.d(17): ice6538.foo(I...)(I sizes) if (allSatisfy!(isIntegral, sizes)) ---- -*/ -void foo(I...)(I sizes) -if (allSatisfy!(isIntegral, sizes)) {} - -void test6538a() -{ - foo(42, 86); -} +// 9361 /* TEST_OUTPUT: --- -fail_compilation/ice6538.d(34): Error: cannot take a not yet instantiated symbol 't1' inside template constraint -fail_compilation/ice6538.d(34): Error: cannot take a not yet instantiated symbol 't2' inside template constraint -fail_compilation/ice6538.d(39): Error: template ice6538.bar cannot deduce function from argument types !()(int, int), candidates are: -fail_compilation/ice6538.d(34): ice6538.bar(T1, T2)(T1 t1, T2 t2) if (allSatisfy!(isIntegral, t1, t2)) +fail_compilation/ice6538.d(23): Error: expression super is not a valid template value argument +fail_compilation/ice6538.d(28): Error: template ice6538.D.foo cannot deduce function from argument types !()(), candidates are: +fail_compilation/ice6538.d(23): ice6538.D.foo()() if (Sym!(super)) --- */ -void bar(T1, T2)(T1 t1, T2 t2) -if (allSatisfy!(isIntegral, t1, t2)) {} - -void test6538b() -{ - bar(42, 86); -} - -/**************************************/ -// 9361 template Sym(alias A) { enum Sym = true; } -/* -TEST_OUTPUT: ---- -fail_compilation/ice6538.d(60): Error: cannot take a not yet instantiated symbol 'this' inside template constraint -fail_compilation/ice6538.d(66): Error: template ice6538.S.foo cannot deduce function from argument types !()(), candidates are: -fail_compilation/ice6538.d(60): ice6538.S.foo()() if (Sym!this) ---- -*/ -struct S -{ - void foo()() if (Sym!(this)) {} - void bar()() { static assert(Sym!(this)); } // OK -} -void test9361a() -{ - S s; - s.foo(); // fail - s.bar(); // OK -} - -/* -TEST_OUTPUT: ---- -fail_compilation/ice6538.d(81): Error: cannot take a not yet instantiated symbol 'super' inside template constraint -fail_compilation/ice6538.d(86): Error: template ice6538.D.foo cannot deduce function from argument types !()(), candidates are: -fail_compilation/ice6538.d(81): ice6538.D.foo()() if (Sym!(super)) ---- -*/ class C {} class D : C { diff --git a/test/fail_compilation/test8556.d b/test/fail_compilation/test8556.d index c5bff28a7a20..602212a5ee97 100644 --- a/test/fail_compilation/test8556.d +++ b/test/fail_compilation/test8556.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/test8556.d(22): Error: template instance Grab!(Circle!(uint[])) does not match template declaration Grab(Range) if (!isSliceable!Range) +fail_compilation/test8556.d(22): Error: template instance test8556.Grab!(Circle!(uint[])) does not match template declaration Grab(Range) if (!isSliceable!Range) fail_compilation/test8556.d(53): Error: template instance test8556.grab!(Circle!(uint[])) error instantiating --- */ diff --git a/test/runnable/funclit.d b/test/runnable/funclit.d index 74ae4e3fcd68..aa73de372df1 100644 --- a/test/runnable/funclit.d +++ b/test/runnable/funclit.d @@ -792,6 +792,48 @@ void test9928() void* smth = (int x) { return x; }; } +/***************************************************/ +// 10133 + +ptrdiff_t countUntil10133(alias pred, R)(R haystack) +{ + typeof(return) i; + + alias T = dchar; + + foreach (T elem; haystack) + { + if (pred(elem)) return i; + ++i; + } + + return -1; +} + +bool func10133(string s)() if (countUntil10133!(x => x == 'x')(s) == 1) +{ + return true; +} + +bool func10133a(string s)() if (countUntil10133!(x => s == "x")(s) != -1) +{ + return true; +} +bool func10133b(string s)() if (countUntil10133!(x => s == "x")(s) != -1) +{ + return true; +} + +void test10133() +{ + func10133!("ax")(); + + func10133a!("x")(); + static assert(!is(typeof(func10133a!("ax")()))); + static assert(!is(typeof(func10133b!("ax")()))); + func10133b!("x")(); +} + /***************************************************/ // 10288 @@ -965,6 +1007,7 @@ int main() test9415(); test9628(); test9928(); + test10133(); test10288(); test11661();