On 10/24/15 1:25 PM, tsbockman wrote:
While improving the DMD front-end's constant folding:
https://github.com/D-Programming-Language/dmd/pull/5229
I found out about DMD issue 14835:
https://issues.dlang.org/show_bug.cgi?id=14835
Briefly:
///////////////////////////////
module main;
import std.stdio;
void reachIf(bool x)()
{
if(!x)
return;
writeln("reached"); // Warning: statement is not reachable
}
void main(string[] args) {
reachIf!true(); // prints "reached"
reachIf!false(); // triggers warning
}
///////////////////////////////
This is, I think, a big problem.
I agree
Affected code is rare today, but that is only because DMD's constant
folding and value-range-propagation is weak. The more improvements are
made in this area, the more common erroneous "statement is not
reachable" warnings will become.
Unfortunately, from what I can tell, this bug is just a natural
consequence of DMD's current design; I think an ideal fix will not be
simple.
Some possible solutions:
1. Defer "not reachable" warnings until compilation has been completed,
and only issue the warning if *all* instantiations of the statement were
unreachable.
This isn't good either. One instantiation of reachIf being able to
compile shouldn't be dependent on whether another one was ever used.
2. For semantic analysis purposes, first instantiate each template using
dummy parameters with the widest possible VRP ranges. Only statements
found to be "not reachable" in this dummy run should actually generate
warnings.
How does the compiler figure this out? This seems like the halting
problem to me.
3. ??? I don't know the compiler internals very well, so I may be
missing a more elegant solution.
I think the easiest solution would be to just give up on worrying about
unreachable code if the branch is dependent on a compile time variable
that could legitimately change from instantiation to instantiation. In
other words, for that instantiation, you obviously don't need to include
the code, but you can't declare that the line of code is unreachable.
This means that this will compile:
void foo(int x)()
{
if(x == 5)
return;
writeln("boo!");
}
void main()
{
foo!5();
}
But this will not:
void main()
{
enum x = 5;
if(x == 5)
return;
writeln("boo!");
}
Even though they are effectively equivalent. But that's not a good
reason to create errors which are obviously untrue. In the second case,
the compiler can know definitively that the statement really will never
be executed or compiled. In the first case, it can only be sure for that
*instance*.
Even this could compile IMO (but a sufficiently smarter compiler may
complain):
void foo(int x)() if(x == 5)
{
if(x == 5)
return;
writeln("boo!");
}
Let's not forget that "unreachable statement" errors are really not
errors in the sense that it will cause a crash, or corrupt memory. It
just means some statements you wrote were wasted effort. It's OK to
-Steve