digitalmars.D.learn - Solution to "statement is not reachable" depending on template
- Johan Engelen (40/40) Mar 16 2016 Hi all,
- rikki cattermole (8/47) Mar 16 2016 Change those static if's to just plain old ifs.
- Johan Engelen (12/16) Mar 16 2016 But then this wouldn't compile, would it?
- rikki cattermole (6/16) Mar 16 2016 Hmm no.
- tsbockman (15/16) Mar 16 2016 This only works (sometimes) because D's value range propagation
- Steven Schveighoffer (6/21) Mar 17 2016 Yes. I agree. The way I look at it is that the code *is* reached in some...
- tsbockman (7/13) Mar 17 2016 That's what I think it should do, also. However, when we
- QAston (8/22) Mar 16 2016 On Wednesday, 16 March 2016 at 11:18:36 UTC, Johan Engelen wrote:
- Johan Engelen (3/14) Mar 16 2016 Thanks, but:
- QAston (4/20) Mar 19 2016 This method will work regarless of the predicate, just check if
- Steven Schveighoffer (12/25) Mar 16 2016 Instead of foreach, you could use recursive mechanism. Not ideal, but it...
- Johan Engelen (3/30) Mar 16 2016 I like your second solution, it's clever :)
- tsbockman (19/23) Mar 16 2016 "statement is not reachable" is fundamentally broken in D for
- Walter Bright (16/28) Mar 31 2016 bool nobool(T...)() {
- Johan Engelen (26/58) Apr 01 2016 As you can see from my first post, that is the solution I used
- ZombineDev (11/43) Apr 01 2016 Actually, I would expect every call of this fuction to be
- Johan Engelen (37/37) Jun 18 2017 Reviving this thread to see whether anything has changed on the
- Steven Schveighoffer (4/6) Jun 18 2017 If Timon gets static for each into the language, it can look a
- Johan Engelen (6/12) Jun 18 2017 Can you help me understand what you mean? How will it improve
- Moritz Maxeiner (25/37) Jun 18 2017 The new static foreach is AFAIK supposed to execute the loop
- Steven Schveighoffer (9/22) Jun 18 2017 On my phone so can't be too detailed, but you could do:
Hi all, I've found discussions, but not an actual "recommended" solution for the problem of "statement is not reachable" warnings in templates with early returns, e.g.: ``` bool nobool(T...)() { foreach (i, U; T) { static if (is(U == bool)) { return false; } } return true; // emits "Warning: statement is not reachable" } bool nobool_nowarning(T...)() { bool retval = true; foreach (i, U; T) { static if (is(U == bool)) { retval = false; } } return retval; } void main() { static assert ( nobool_nowarning!(int,bool)() == false ); static assert ( nobool_nowarning!(int,int)() == true ); static assert ( nobool!(int,bool)() == false ); static assert ( nobool!(int,int)() == true ); } ``` (I have heavily simplified the real-world code, please don't discuss alternative solutions to the "is(U==bool)" in particular. For sake of argument, assume that the predicate is a complicated beast.) The `nobool` template prevents compilation with `-w`. Is `nobool_nowarning`, with the early return eradicated, the only acceptable solution? (with the hope that there will not be a "dead store" warning in the future...) What if early returns cannot be avoided? Thanks, Johan
Mar 16 2016
On 16/03/16 11:18 PM, Johan Engelen wrote:Hi all, I've found discussions, but not an actual "recommended" solution for the problem of "statement is not reachable" warnings in templates with early returns, e.g.: ``` bool nobool(T...)() { foreach (i, U; T) { static if (is(U == bool)) { return false; } } return true; // emits "Warning: statement is not reachable" } bool nobool_nowarning(T...)() { bool retval = true; foreach (i, U; T) { static if (is(U == bool)) { retval = false; } } return retval; } void main() { static assert ( nobool_nowarning!(int,bool)() == false ); static assert ( nobool_nowarning!(int,int)() == true ); static assert ( nobool!(int,bool)() == false ); static assert ( nobool!(int,int)() == true ); } ``` (I have heavily simplified the real-world code, please don't discuss alternative solutions to the "is(U==bool)" in particular. For sake of argument, assume that the predicate is a complicated beast.) The `nobool` template prevents compilation with `-w`. Is `nobool_nowarning`, with the early return eradicated, the only acceptable solution? (with the hope that there will not be a "dead store" warning in the future...) What if early returns cannot be avoided? Thanks, JohanChange those static if's to just plain old ifs. Imagine those foreach loops being unrolled and what that happens there isn't just one return there, imagine many many many of them and all of them valid. --- This email has been checked for viruses by Avast antivirus software. https://www.avast.com/antivirus
Mar 16 2016
On Wednesday, 16 March 2016 at 11:22:02 UTC, rikki cattermole wrote:Change those static if's to just plain old ifs.But then this wouldn't compile, would it? ``` static if(__traits(compiles, __traits(getMember, a, "b"))) { return a.b; } ``` (real code, I am not making this up)Imagine those foreach loops being unrolled and what that happens there isn't just one return there, imagine many many many of them and all of them valid.Yep :-) Perhaps the only solution is to be able to annotate the code to "shut up" DMD about it.
Mar 16 2016
On 17/03/16 5:05 AM, Johan Engelen wrote:On Wednesday, 16 March 2016 at 11:22:02 UTC, rikki cattermole wrote:Hmm no. If that's in a foreach as well, you'll need to solve it some other way. --- This email has been checked for viruses by Avast antivirus software. https://www.avast.com/antivirusChange those static if's to just plain old ifs.But then this wouldn't compile, would it? ``` static if(__traits(compiles, __traits(getMember, a, "b"))) { return a.b; } ``` (real code, I am not making this up)
Mar 16 2016
On Wednesday, 16 March 2016 at 11:22:02 UTC, rikki cattermole wrote:Change those static if's to just plain old ifs.This only works (sometimes) because D's value range propagation doesn't understand comparisons or normal if statements very well. This will hopefully be fixed sooner or later: https://github.com/D-Programming-Language/dmd/pull/1913 https://github.com/D-Programming-Language/dmd/pull/5229 The only future-proof way to fix the "statement is not reachable" warning, is to guard the potentially unreachable code with a `static if` whose predicate precisely describes the circumstances in which it becomes unreachable... ...Which itself is a terrible solution that doesn't scale well at all to complex generic code and violates the "DRY" principle. We really ought to just remove the warning. It just doesn't mesh well with D's super-powered meta-programming features.
Mar 16 2016
On 3/16/16 9:48 PM, tsbockman wrote:On Wednesday, 16 March 2016 at 11:22:02 UTC, rikki cattermole wrote:Yes. I agree. The way I look at it is that the code *is* reached in some cases, so it should compile (and just remove that section in that instance). IMO any time a template value is used for branching, it should turn that warning off. -SteveChange those static if's to just plain old ifs.This only works (sometimes) because D's value range propagation doesn't understand comparisons or normal if statements very well. This will hopefully be fixed sooner or later: https://github.com/D-Programming-Language/dmd/pull/1913 https://github.com/D-Programming-Language/dmd/pull/5229 The only future-proof way to fix the "statement is not reachable" warning, is to guard the potentially unreachable code with a `static if` whose predicate precisely describes the circumstances in which it becomes unreachable... ....Which itself is a terrible solution that doesn't scale well at all to complex generic code and violates the "DRY" principle. We really ought to just remove the warning. It just doesn't mesh well with D's super-powered meta-programming features.
Mar 17 2016
On Thursday, 17 March 2016 at 17:12:07 UTC, Steven Schveighoffer wrote:Yes. I agree. The way I look at it is that the code *is* reached in some cases, so it should compile (and just remove that section in that instance). IMO any time a template value is used for branching, it should turn that warning off. -SteveThat's what I think it should do, also. However, when we discussed it before, Daniel Murphy pretty much told me there is no practical way to actually implement that behavior in the compiler. So, the next best thing is to just remove the warning entirely.
Mar 17 2016
On Wednesday, 16 March 2016 at 11:18:36 UTC, Johan Engelen wrote:Hi all, I've found discussions, but not an actual "recommended" solution for the problem of "statement is not reachable" warnings in templates with early returns, e.g.: ``` bool nobool(T...)() { foreach (i, U; T) { static if (is(U == bool)) { return false; } } return true; // emits "Warning: statement is not reachable" } [...]On Wednesday, 16 March 2016 at 11:18:36 UTC, Johan Engelen wrote: import std.meta; template isBool(U)() = is(U == bool); static if (!allSatisfy!(isBool, T)) { return true; // no longer emits a warning } Something like this should work.
Mar 16 2016
On Wednesday, 16 March 2016 at 11:47:35 UTC, QAston wrote:import std.meta; template isBool(U)() = is(U == bool); static if (!allSatisfy!(isBool, T)) { return true; // no longer emits a warning } Something like this should work.Thanks, but: On Wednesday, 16 March 2016 at 11:18:36 UTC, Johan Engelen wrote:(I have heavily simplified the real-world code, please don't discuss alternative solutions to the "is(U==bool)" in particular. For sake of argument, assume that the predicate is a complicated beast.)
Mar 16 2016
On Wednesday, 16 March 2016 at 17:08:20 UTC, Johan Engelen wrote:On Wednesday, 16 March 2016 at 11:47:35 UTC, QAston wrote:This method will work regarless of the predicate, just check if the predicate isn't matched for the whole array using allSatisfy/anySatisfy.import std.meta; template isBool(U)() = is(U == bool); static if (!allSatisfy!(isBool, T)) { return true; // no longer emits a warning } Something like this should work.Thanks, but: On Wednesday, 16 March 2016 at 11:18:36 UTC, Johan Engelen wrote:(I have heavily simplified the real-world code, please don't discuss alternative solutions to the "is(U==bool)" in particular. For sake of argument, assume that the predicate is a complicated beast.)
Mar 19 2016
On 3/16/16 7:18 AM, Johan Engelen wrote:Hi all, I've found discussions, but not an actual "recommended" solution for the problem of "statement is not reachable" warnings in templates with early returns, e.g.: ``` bool nobool(T...)() { foreach (i, U; T) { static if (is(U == bool)) { return false; } } return true; // emits "Warning: statement is not reachable" }Instead of foreach, you could use recursive mechanism. Not ideal, but it would work. Another possibility: foreach(i, U; T) { static if(is(U == bool)) { return false; } else static if(i + 1 == T.length) { return true; } } -Steve
Mar 16 2016
On Wednesday, 16 March 2016 at 17:34:13 UTC, Steven Schveighoffer wrote:On 3/16/16 7:18 AM, Johan Engelen wrote:I like your second solution, it's clever :)Hi all, I've found discussions, but not an actual "recommended" solution for the problem of "statement is not reachable" warnings in templates with early returns, e.g.: ``` bool nobool(T...)() { foreach (i, U; T) { static if (is(U == bool)) { return false; } } return true; // emits "Warning: statement is not reachable" }Instead of foreach, you could use recursive mechanism. Not ideal, but it would work. Another possibility: foreach(i, U; T) { static if(is(U == bool)) { return false; } else static if(i + 1 == T.length) { return true; } }
Mar 16 2016
On Wednesday, 16 March 2016 at 11:18:36 UTC, Johan Engelen wrote:Hi all, I've found discussions, but not an actual "recommended" solution for the problem of "statement is not reachable" warnings in templates with early returns..."statement is not reachable" is fundamentally broken in D for generic code: https://issues.dlang.org/show_bug.cgi?id=14835 It's mostly not too big of a deal right now, only because the D front end's value range propagation capabilities are very weak. Lionello Lunesu made a pull request a while back that majorly improves VRP in D as a part of his efforts to fix DMD issue 259. I decided to port it to DDMD a few months ago, and in the process discovered that with decent VRP, issue 14835 becomes 10-100x worse. There was a forum discussion a while back as to what should be done about this, but unfortunately the conclusion was that it probably cannot really be fixed with any reasonable effort: http://forum.dlang.org/thread/bnzfuekewfguvnwdznfk forum.dlang.org As far as I can tell, the only reasonable way forward is to simply remove the warning entirely (or ban meaningful upgrades to VRP).
Mar 16 2016
On 3/16/2016 4:18 AM, Johan Engelen wrote:I've found discussions, but not an actual "recommended" solution for the problem of "statement is not reachable" warnings in templates with early returns, e.g.: ``` bool nobool(T...)() { foreach (i, U; T) { static if (is(U == bool)) { return false; } } return true; // emits "Warning: statement is not reachable" }bool nobool(T...)() { bool result = true; foreach (i, U; T) { static if (is(U == bool)) { result = false; break; } else { ... } } return result; // emits "Warning: statement is not reachable" } Note that the optimizer will remove the dead loads.
Mar 31 2016
On Friday, 1 April 2016 at 01:21:32 UTC, Walter Bright wrote:On 3/16/2016 4:18 AM, Johan Engelen wrote:As you can see from my first post, that is the solution I used first (without the "break;" addition), but it works until...I've found discussions, but not an actual "recommended" solution for the problem of "statement is not reachable" warnings in templates with early returns, e.g.: ``` bool nobool(T...)() { foreach (i, U; T) { static if (is(U == bool)) { return false; } } return true; // emits "Warning: statement is not reachable" }bool nobool(T...)() { bool result = true; foreach (i, U; T) { static if (is(U == bool)) { result = false; break; } else { ... } } return result; // emits "Warning: statement is not reachable" }Note that the optimizer will remove the dead loads.... until someone adds a (imho useful) diagnostic of dead stores/loads. :-) In that case, I guess inverting all bools and then inverting the return value at the end will work (using default initialization of result); but this is not possible in a slightly more complicated case with non-bool return types. In another piece of code, the return type is a struct with an immutable member. That's when I gave up on working around the warning and just disabled it. Simplified, something like this: struct IMM { immutable bool result; } IMM immut(T...)() { IMM retval = IMM(true); foreach (i, U; T) { static if (is(U == bool)) { retval = IMM(false); // "Error: cannot modify struct retval IMM with immutable member". } } return retval; }
Apr 01 2016
On Friday, 1 April 2016 at 01:21:32 UTC, Walter Bright wrote:On 3/16/2016 4:18 AM, Johan Engelen wrote:Actually, I would expect every call of this fuction to be replaced by a boolean constant, since the result depends only on compile-time information. What happened to "obvious code should be correct"? Can we try to find a solution that doesn't look like a hack? I don't think that we should ask users of the language to uglify their code just to workaround a deficiency in the compiler. Instead, we should improve the lowering of the static foreach construct so the information that it is syntactically a loop is preserved after loop unrolling.I've found discussions, but not an actual "recommended" solution for the problem of "statement is not reachable" warnings in templates with early returns, e.g.: ``` bool nobool(T...)() { foreach (i, U; T) { static if (is(U == bool)) { return false; } } return true; // emits "Warning: statement is not reachable" }bool nobool(T...)() { bool result = true; foreach (i, U; T) { static if (is(U == bool)) { result = false; break; } else { ... } } return result; // emits "Warning: statement is not reachable" } Note that the optimizer will remove the dead loads.
Apr 01 2016
Reviving this thread to see whether anything has changed on the topic. I now have this monster: ``` struct FMT { // has immutable members. FMT cannot be assigned to. } FMT monsterThatCompilerAccepts(T)(){ alias TP = Tuple!(__traits(getAttributes, T)); foreach(i, att; TP){ static if( ... ) { return FMT( ... ); } // Make sure we return a default value in the last iteration. // Prevents "statement not reachable" warning when placed here instead of outside the foreach. else static if (i + 1 == TP.length) { return FMT( ... ); } } static if (TP.length == 0) { return FMT( ... ); } } FMT codeThatIsUnderstandableButNotAccepted(T)(){ alias TP = Tuple!(__traits(getAttributes, T)); foreach(i, att; TP){ static if( ... ) { return FMT( ... ); } } return FMT( ... ); } ``` Thanks, Johan
Jun 18 2017
On Sunday, 18 June 2017 at 09:28:57 UTC, Johan Engelen wrote:Reviving this thread to see whether anything has changed on the topic.If Timon gets static for each into the language, it can look a little better. -Steve
Jun 18 2017
On Sunday, 18 June 2017 at 09:56:50 UTC, Steven Schveighoffer wrote:On Sunday, 18 June 2017 at 09:28:57 UTC, Johan Engelen wrote:Can you help me understand what you mean? How will it improve things? (static foreach would disable the "statement not reachable" analysis?) -JohanReviving this thread to see whether anything has changed on the topic.If Timon gets static for each into the language, it can look a little better.
Jun 18 2017
On Sunday, 18 June 2017 at 11:11:59 UTC, Johan Engelen wrote:On Sunday, 18 June 2017 at 09:56:50 UTC, Steven Schveighoffer wrote:The new static foreach is AFAIK supposed to execute the loop instead of unrolling it, i.e. the expansion of --- foreach (i, U; T) { static if (is(U == bool)) { return false; } } return true; --- to --- static if (is(U1 == bool)) { return false; } static if (is(U2 == bool)) { return false; } ... return true; --- , which triggers that "statement is not reachable" if at least one of U1,U2,... = T is bool, will not occur if you instead use `static foreach (i, U; T)`.On Sunday, 18 June 2017 at 09:28:57 UTC, Johan Engelen wrote:Can you help me understand what you mean? How will it improve things? (static foreach would disable the "statement not reachable" analysis?)Reviving this thread to see whether anything has changed on the topic.If Timon gets static for each into the language, it can look a little better.
Jun 18 2017
On Sunday, 18 June 2017 at 11:11:59 UTC, Johan Engelen wrote:On Sunday, 18 June 2017 at 09:56:50 UTC, Steven Schveighoffer wrote:On my phone so can't be too detailed, but you could do: static foreach(i; 0..seq.length+1) static if(seq.length == i) return true; else static if(is(seq[i] == bool)) return false; Maybe looks a little better than the first workaround. -SteveOn Sunday, 18 June 2017 at 09:28:57 UTC, Johan Engelen wrote:Can you help me understand what you mean? How will it improve things? (static foreach would disable the "statement not reachable" analysis?) -JohanReviving this thread to see whether anything has changed on the topic.If Timon gets static for each into the language, it can look a little better.
Jun 18 2017