Bug 15166 – [REG2.069-devel] spurious statement not reachable warning in static foreach loop
Status
RESOLVED
Resolution
DUPLICATE
Severity
regression
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2015-10-06T06:43:00Z
Last change time
2015-10-13T16:03:08Z
Assigned to
nobody
Creator
code
Comments
Comment #0 by code — 2015-10-06T06:43:18Z
cat > bug.d << CODE
template Group(T...)
{
alias expand = T;
}
private bool compare(alias Group1, alias Group2)()
{
foreach (index, element; Group1.expand)
{
static if (!is(Group1.expand[index] == Group2.expand[index]))
return false;
}
return true;
}
unittest
{
alias a = Group!(int, double), b = Group!(double, int);
static assert (!compare!(a, b));
}
CODE
dmd -c -w -unittest bug
----
DMD v2.069-devel-6279af3 DEBUG
bug.d(13): Warning: statement is not reachable
----
This is similar to issue 14835, but now the warning is also emitted with static foreach loops.
This is as annoying as go's stupid "unused variable" warning, at least during development.
> I'm not sure how we can "fix" this and issue 14835.
I guess the fix would be to mark those returns as dependent on the template types and not account for them when computing not reachable statements, but that sounds like quite a difficult change.
I guess we might fix this in vibe.d but it might break a lot more code.
Comment #3 by code — 2015-10-12T22:47:07Z
I think something along this line could work.
override void visit(ConditionalStatement s)
{
if (s.condition.include(null, null))
{
result = s.ifbody.blockExit(func, mustNotThrow);
// mark as conditional fallthru, see Bugzilla 14835
if (!s.elsebody) result |= BEconditional;
}
else if (s.elsebody)
result = s.elsebody.blockExit(func, mustNotThrow);
else
result = BEfallthru;
}
if (!(result & (BEfallthru | BEconditional)) && !s.comeFrom())
{
if (s.blockExit(func, mustNotThrow) != BEhalt && s.hasCode())
s.warning("statement is not reachable");
}
But for this to work ConditionalStatement must no longer be flattened before computing blockExit, thus making this change very big (and somewhat risky).
Comment #4 by code — 2015-10-12T22:59:53Z
A workaround is to use a variable.
bool res = true;
foreach (index, element; Group1.expand)
{
static if (!is(Group1.expand[index] == Group2.expand[index]))
{
res = false;
break;
}
}
return res;
Comment #5 by code — 2015-10-12T23:00:17Z
*** This issue has been marked as a duplicate of issue 14835 ***
Comment #6 by schveiguy — 2015-10-13T16:03:08Z
(In reply to Martin Nowak from comment #4)
> A workaround is to use a variable.
I think this may be the right answer.
It boils down to this:
static if(someCondition) return false;
return true;
Which you would normally write with else, but it's not so simple in this case, because the "else" would be part of the loop.
I'm curious why the return short-circuits the loop. In other words, why aren't all the "return false" statements besides the first one flagged for unreachability? Is it because the compiler stops generating the statements? I mean, if you rewrote as a bunch of static ifs, then wouldn't you have the same problem?
Another possible answer is to do this:
private bool compare(alias Group1, alias Group2)()
{
foreach (index, element; Group!(Group1.expand, void).expand)
{
static if(index == Group1.expand.length)
return true;
else static if (!is(Group1.expand[index] == Group2.expand[index]))
return false;
}
}