The following code, compiled with DMD 2.071.1-b2 crashes the compiler:
===============================================
import std.stdio, std.traits;
struct TreeItemChildren(T){}
struct TreeItemSiblings(T){}
class Foo
{
enum isStruct = is(typeof(this) == struct);
static if (isStruct)
alias TreeItemType = typeof(this)*;
else
alias TreeItemType = typeof(this);
TreeItemSiblings!TreeItemType _siblings; // remove this decl
TreeItemChildren!TreeItemType _children; // or this one : OK
}
template Bug(T)
{
bool check()
{
bool result;
import std.meta: aliasSeqOf;
import std.range: iota;
foreach(i; aliasSeqOf!(iota(0, T.tupleof.length)))
{
alias MT = typeof(T.tupleof[i]);
static if (is(MT == struct))
result |= Bug!MT; // result = result | ... : OK
if (result) break; // remove this line : OK
}
return result;
}
enum Bug = check();
}
void main()
{
assert(!Bug!Foo);
}
===============================================
produces
> Internal error: backend/cgcod.c 2297
The comments in the code indicates each time that the bug doesn't happen when the stuff is commented.
Comment #1 by b2.temp — 2016-06-01T04:37:51Z
definition of Foo can be reduced to
class Foo
{
alias TreeItemType = typeof(this);
TreeItemSiblings!TreeItemType _siblings; // remove this decl
TreeItemChildren!TreeItemType _children; // or this one : OK
}
The content was initially a mixin template, which explains why it was incoherant...anyway still the ICE.
Comment #2 by ag0aep6g — 2016-06-01T09:01:14Z
Reduced further:
----
bool check()
{
bool result = false;
result |= false; // result = result | ... : OK
if (result) goto ret; // remove this line : OK
result |= false; // result = result | ... : OK
if (result) {} // remove this line : OK
ret: return true;
}
enum e = check();
----
Comment #3 by b2.temp — 2016-06-01T18:41:59Z
(In reply to ag0aep6g from comment #2)
> Reduced further:
>
> ----
> bool check()
> {
> bool result = false;
>
> result |= false; // result = result | ... : OK
> if (result) goto ret; // remove this line : OK
>
> result |= false; // result = result | ... : OK
> if (result) {} // remove this line : OK
>
> ret: return true;
> }
>
> enum e = check();
> ----
OMG, Can someone fix this fast PLZ ? I don't know if you'll agree but this is not some "super sharp" code, just a bunch of OrEqual !
Comment #4 by b2.temp — 2016-07-18T10:38:29Z
ping. do you realize that by nature this bug is very disruptive ? It kills the boolean logic.
Comment #5 by hsteoh — 2016-09-02T17:04:41Z
I managed to trace the error to freenode() in backend/cgcod.c, for some reason it gets called with an elem with e->Ecomsub==0, so when it tries to decrement it, e->Ecomsub rolls over to 255, which eventually triggers this assert.
However, I couldn't figure out enough of the backend code to actually fix this. I tried changing the if-statement in freenode() to `if (e->Ecomsub==0 || e->Ecomsub--) return;`, and it works for this particular test case, but then it fails to compile the d_do_test tool, so obviously this is the wrong fix. So this will probably need Walter to look at it. :-P
Comment #6 by hsteoh — 2016-09-02T17:16:59Z
P.S. The faulty call to freenode() comes from codelem() in cgcod.c.
Comment #7 by slavo5150 — 2018-03-23T04:29:20Z
> bool check()
> {
> bool result = false;
>
> result |= false; // result = result | ... : OK
> if (result) goto ret; // remove this line : OK
>
> result |= false; // result = result | ... : OK
> if (result) {} // remove this line : OK
>
> ret: return true;
> }
>
> enum e = check();
According to https://run.dlang.io/is/98Uf5T, this has been working since 2.067.1.
Comment #8 by slavo5150 — 2018-03-23T04:35:33Z
> import std.stdio, std.traits;
>
> struct TreeItemChildren(T){}
>
> struct TreeItemSiblings(T){}
>
> class Foo
> {
> alias TreeItemType = typeof(this);
>
> TreeItemSiblings!TreeItemType _siblings; // remove this decl
> TreeItemChildren!TreeItemType _children; // or this one : OK
> }
>
> template Bug(T)
> {
> bool check()
> {
> bool result;
> import std.meta: aliasSeqOf;
> import std.range: iota;
>
> foreach(i; aliasSeqOf!(iota(0, T.tupleof.length)))
> {
> alias MT = typeof(T.tupleof[i]);
> static if (is(MT == struct))
> result |= Bug!MT; // result = result | ... : OK
> if (result) break; // remove this line : OK
>
> }
> return result;
> }
> enum Bug = check();
> }
>
> void main()
> {
> assert(!Bug!Foo);
> }
According to https://run.dlang.io/is/kosY23, this has been fixed since 2.070.2
Comment #9 by ag0aep6g — 2018-03-24T15:12:32Z
(In reply to Mike Franklin from comment #7)
> According to https://run.dlang.io/is/98Uf5T, this has been working since
> 2.067.1.
Fails on run.dlang.io when you compile with -c. https://run.dlang.io/is/gnOvlp
(In reply to Mike Franklin from comment #8)
> According to https://run.dlang.io/is/kosY23, this has been fixed since
> 2.070.2
Ditto. https://run.dlang.io/is/UCl87z
On my machine, both versions fail with and without -c. Maybe the bug is somewhat nondeterministic? It's consistently reproducible for me, though.
Reopening.
Comment #10 by b2.temp — 2018-03-25T06:04:07Z
Still reproducible here too.
I think that it works online because -g is added to the switches so that the object can be disasm and displayed. You can try on your machines with -g an you'll see that the ICE doesn't appear.
Seb, do you confirm that run.dlang.io adds -g ?
Comment #11 by greensunny12 — 2018-03-25T06:24:02Z