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