Fixing spurious "statement is not reachable" in template code
tsbockman via Digitalmars-d
digitalmars-d at puremagic.com
Mon Oct 26 10:08:42 PDT 2015
On Monday, 26 October 2015 at 12:31:37 UTC, Steven Schveighoffer
wrote:
>> 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.
I agree this is not ideal, however it would be much better than
what we have currently, and the compiler implementation should be
relatively simple.
>> 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.
My solution #2 is the same as the one you proposed - the dummy
parameter stuff is my vague proposal for a way to actual
implement this behavior in the compiler.
The halting problem is no more of an issue than it is for the
compiler today. (That is to say, the halting problem leads to
false negatives, but not false positives.)
I think the compiler currently does something like this:
void main(string[] args) {
reachIf!true(); // prints "reached"
reachIf!false(); // triggers warning
}
// A template will be instantiated and undergo semantic analysis
// once for each combination of CT parameters fed to it in the
program.
// reachIf!true pass:
void reachIf(bool x)() // VRP narrows x to true
{
if(!x) // VRP + constant folding says (!true) always == false
return; // never reached (this doesn't always generate a
warning)
writeln("reached"); // always reached
}
// reachIf!false pass:
void reachIf(bool x)() // VRP narrows x to false
{
if(!x) // VRP + constant folding says (!false) always == true
return; // always reached
writeln("reached"); // Warning: statement is not reachable
}
My solution #2 would add this before the reachIf!true pass:
// first instantiate the template with the widest possible
// VRP ranges for the CT paramters
void reachIf(bool x)() // VRP says x could be true or false
{
if(!x) // not constant; cannot be folded
return; // reachable
writeln("reached"); // reachable
}
"statement not reachable" warnings would only be generated during
this preliminary pass; they would be suppressed in the
reachIf!true and reachIf!false passes.
The reason solution #2 could end up being a ton of work, is that
a dummy type will have to be created to apply this solution to
cases like:
module main;
import std.stdio;
void reachIf(T...)()
{
if(T.length != 1 || T[0].sizeof != 4)
return;
writeln("reached"); // Warning: statement is not reachable
}
void main(string[] args) {
reachIf!int(); // prints "reached"
reachIf!long(); // triggers warning
stdin.readln();
}
(Note that this case can only be reproduced with my constant
folding upgrade patch applied.)
In order to apply solution #2 to this code, we need a dummy
AliasSeq of indeterminate length, whose elements have a sizeof
property of indeterminate value. I strongly suspect that a fake
type like that will require explicit support to be added all over
the DMD code base; it would be a huge change just to eliminate
some spurious warnings.
More information about the Digitalmars-d
mailing list