Bug 3276 – Recursion broken by alias template parameter

Status
RESOLVED
Resolution
FIXED
Severity
critical
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
x86
OS
Windows
Creation time
2009-08-31T15:52:00Z
Last change time
2015-06-09T01:26:48Z
Keywords
patch, rejects-valid
Assigned to
nobody
Creator
bartosz

Attachments

IDFilenameSummaryContent-TypeSize
442small.dbug exampleapplication/octet-stream362

Comments

Comment #0 by bartosz — 2009-08-31T15:52:50Z
Created attachment 442 bug example Recursion in templates works, but mutual recursion doesn’t. I’m attaching this example—it can’t be reduced much further. Each part of it works separately, but once they start recursing into each other, I get the error: small.d(3): Error: alias small.F!(void*).StripPtr recursive alias declaration
Comment #1 by clugdbug — 2010-05-12T12:35:28Z
Reduced test case shows it doesn't involve mutual recursion (original title was "Mutual recursion broken in type templates") template Bug3276(bool B) { static if (B) alias Bug3276!(false) Bug3276; else alias double Bug3276; } template Bug3276_b(alias W) { alias W!(true) Bug3276_b; } alias Bug3276_b!(Bug3276) Bug3276_c;
Comment #2 by rsinfu — 2010-11-02T22:09:58Z
The bug happens if a recursive template is instantiated via an alias: alias Bug3276 W; alias W!true w; In template.c, the following if at the line 4304 tries to get the relevant TemplateDeclaration for doing recursion: TemplateDeclaration *TemplateInstance::findTemplateDeclaration(Scope *sc) { ... TemplateInstance *ti; if (s->parent && (ti = s->parent->isTemplateInstance()) != NULL) { if ( (ti->name == id || ti->toAlias()->ident == id) // <-- the cause && ti->tempdecl) ... } Here 'this' refers to the recursive instantiation "Bug3276!(false)" and id="Bug3276" is its identifier. 'ti' is the enclosing TemplateInstance (i.e. "W!(true)"). The test sees if the identifier 'id' used in the instantiation "Bug3276!(false)" is the same as the one of enclosing 'ti'. But 'ti' was instantiated with the aliased identifier (ti->name="W"), so the first condition isn't met. Then it tests the next condition: ti->toAlias()->ident. It dives into the following code in TemplateInstance::toAlias(): if (aliasdecl) { return aliasdecl->toAlias(); } Here 'aliasdecl' is the "result" of the eponymous template "Bug3276!(true)", and it's exactly the "alias Bug3276!(false)" analyzing now. AliasDeclaration::toAlias() does the follownig check: if (inSemantic) { error("recursive alias declaration"); aliassym = new TypedefDeclaration(loc, ident, Type::terror, NULL); } Since it's in semantic, the compiler raises the error.
Comment #3 by rsinfu — 2010-11-02T22:11:39Z
Patch against dmd r737. --- src/template.c +++ src/template.c @@ -4304,11 +4304,7 @@ TemplateDeclaration *TemplateInstance::findTemplateDeclaration(Scope *sc) if (s->parent && (ti = s->parent->isTemplateInstance()) != NULL) { - if ( - (ti->name == id || - ti->toAlias()->ident == id) - && - ti->tempdecl) + if (ti->tempdecl && ti->tempdecl->ident == id) { /* This is so that one can refer to the enclosing * template, even if it has the same name as a member Getting 'ti' for recognizing recursion is good; but the identifier should be compared with the one of a TemplateDeclaration, not the TemplateInstance. As happened in the reported bug, ti->name is not always the appropriate identifier for recursion check. The patch removes ti->toAlias() for good. TemplateInstance::toAlias() does *not* resolve alias of itself; as seen in its implementation, it actually returns the "result" of the template and makes no sense. 'id' has to be compared with ti->tempdecl->ident. The patch passed dmd, druntime and phobos tests. It couldn't pass the broken test (runnable/interpret.d) though.
Comment #4 by bugzilla — 2010-12-05T23:00:13Z