digitalmars.D - Quantum Superposition Observed in DMD at Compile Time
- Meta (42/42) Jun 30 2019 Jokes aside, this is very strange behaviour.
- Exil (7/49) Jun 30 2019 If anything the foreach should be a regular loop. The only time
- Meta (4/10) Jun 30 2019 I'm inclined to agree, except for the fact that changing it would
- John Colvin (15/57) Jun 30 2019 Pretty sure that's a compiler bug. Please report.
- Ataide (13/14) Jul 02 2019 Sorry to disturb here, but I tried to post over Learn but got a
- Jonathan M Davis (8/22) Jul 02 2019 Well, static foreach wasn't implemented until 2.076, so putting static i...
- Ataide (8/11) Jul 02 2019 In fact I had a hunch about this, but on the other hand it
- Iain Buclaw (5/47) Jul 02 2019 You could have just raised a bugzilla ticket.
- Meta (3/55) Jul 02 2019 I didn't know if this was a bug or not due to the mix of
Jokes aside, this is very strange behaviour. struct Test(T...) { this(T ts) { foreach (i, t; ts) { int[ts.length] nums; if (i % 2 == 0) { nums[i / 2] = i; } else { nums[(i - 1) / 2] = i; // Error:array index 9223372036854775807 is out of bounds nums[0 .. 4] } } } } void main() { auto t = Test!(int, string, double, bool)(0, "", 0, false); } Of course, the only possible way (i - 1) / 2 can be 9223372036854775807 is if i == 0 and thus i - 1 underflows. However, this should never be possible because the else branch should only be taken when i > 0. After some testing, I realized that this is a very weird side-effect of constant folding. Regardless of whether the "else" branch will be taken at runtime, nums[(i - 1) / 2] is computed *at compile time* for each loop... but, it's not actually a loop. This is a static foreach (old-style, but this problem occurs with `static foreach` as well). The loop body is unrolled N times (where N == ts.length), and as expected, when I change the foreach to a regular for-loop, this problem goes away. Also changing the runtime if to static if fixes it. This is very strange behaviour, but understandable after some investigation. What I don't quite know is whether there should be a bug report opened for this. It's not technically a bug, I don't think, but it is certainly unexpected and arguably should be fixed.
Jun 30 2019
On Monday, 1 July 2019 at 01:42:36 UTC, Meta wrote:Jokes aside, this is very strange behaviour. struct Test(T...) { this(T ts) { foreach (i, t; ts) { int[ts.length] nums; if (i % 2 == 0) { nums[i / 2] = i; } else { nums[(i - 1) / 2] = i; // Error:array index 9223372036854775807 is out of bounds nums[0 .. 4] } } } } void main() { auto t = Test!(int, string, double, bool)(0, "", 0, false); } Of course, the only possible way (i - 1) / 2 can be 9223372036854775807 is if i == 0 and thus i - 1 underflows. However, this should never be possible because the else branch should only be taken when i > 0. After some testing, I realized that this is a very weird side-effect of constant folding. Regardless of whether the "else" branch will be taken at runtime, nums[(i - 1) / 2] is computed *at compile time* for each loop... but, it's not actually a loop. This is a static foreach (old-style, but this problem occurs with `static foreach` as well). The loop body is unrolled N times (where N == ts.length), and as expected, when I change the foreach to a regular for-loop, this problem goes away. Also changing the runtime if to static if fixes it. This is very strange behaviour, but understandable after some investigation. What I don't quite know is whether there should be a bug report opened for this. It's not technically a bug, I don't think, but it is certainly unexpected and arguably should be fixed.If anything the foreach should be a regular loop. The only time CTFE should happen is with static foreach(). But that didn't exist until recently. Have no doubt this will break code, though they would just need to stick static infront of the loop to fix it? Possibly a deprecation? Doesn't make sense to have foreach() behave like static foreach() now that it exists.
Jun 30 2019
On Monday, 1 July 2019 at 02:29:57 UTC, Exil wrote:If anything the foreach should be a regular loop. The only time CTFE should happen is with static foreach(). But that didn't exist until recently. Have no doubt this will break code, though they would just need to stick static infront of the loop to fix it? Possibly a deprecation? Doesn't make sense to have foreach() behave like static foreach() now that it exists.I'm inclined to agree, except for the fact that changing it would be a metric ton of code. More likely the constant folding needs to be fixed, though I don't know if that's even possible.
Jun 30 2019
On Monday, 1 July 2019 at 01:42:36 UTC, Meta wrote:Jokes aside, this is very strange behaviour. struct Test(T...) { this(T ts) { foreach (i, t; ts) { int[ts.length] nums; if (i % 2 == 0) { nums[i / 2] = i; } else { nums[(i - 1) / 2] = i; // Error:array index 9223372036854775807 is out of bounds nums[0 .. 4] } } } } void main() { auto t = Test!(int, string, double, bool)(0, "", 0, false); } Of course, the only possible way (i - 1) / 2 can be 9223372036854775807 is if i == 0 and thus i - 1 underflows. However, this should never be possible because the else branch should only be taken when i > 0. After some testing, I realized that this is a very weird side-effect of constant folding. Regardless of whether the "else" branch will be taken at runtime, nums[(i - 1) / 2] is computed *at compile time* for each loop... but, it's not actually a loop. This is a static foreach (old-style, but this problem occurs with `static foreach` as well). The loop body is unrolled N times (where N == ts.length), and as expected, when I change the foreach to a regular for-loop, this problem goes away. Also changing the runtime if to static if fixes it. This is very strange behaviour, but understandable after some investigation. What I don't quite know is whether there should be a bug report opened for this. It's not technically a bug, I don't think, but it is certainly unexpected and arguably should be fixed.Pretty sure that's a compiler bug. Please report. Here's a simpler example, which for extra buggy joy prints the error message twice! void foo() { size_t[1] nums; static foreach (i; 0 .. 1) if (false) auto a = nums[i - 1]; } onlineapp.d(6): Error: array index 18446744073709551615 is out of bounds nums[0 .. 1] onlineapp.d(6): Error: array index 18446744073709551615 is out of bounds nums[0 .. 1]
Jun 30 2019
On Monday, 1 July 2019 at 05:57:25 UTC, John Colvin wrote:Here's a simpler example...Sorry to disturb here, but I tried to post over Learn but got a Forum error. Could you tell me why I am getting error on this code: //DMD64 D Compiler 2.072.2 import std.stdio; void main(){ static foreach(i;[1,2,3]){} } Error(s): source_file.d(4): Error: basic type expected, not foreach source_file.d(4): Error: no identifier for declarator _error_ Thanks.
Jul 02 2019
On Tuesday, July 2, 2019 8:44:38 AM MDT Ataide via Digitalmars-d wrote:On Monday, 1 July 2019 at 05:57:25 UTC, John Colvin wrote:Well, static foreach wasn't implemented until 2.076, so putting static in front of foreach like that would be illegal with 2.072.2. The fact that _error_ shows up in the message like that indicates a bug with how dmd dealt with the error (probably an issue with lowering), but the code isn't legal prior to 2.076. At that point, you would have had to iterate over an AliasSeq to force the foreach to be done at compile time. - Jonathan M DavisHere's a simpler example...Sorry to disturb here, but I tried to post over Learn but got a Forum error. Could you tell me why I am getting error on this code: //DMD64 D Compiler 2.072.2 import std.stdio; void main(){ static foreach(i;[1,2,3]){} } Error(s): source_file.d(4): Error: basic type expected, not foreach source_file.d(4): Error: no identifier for declarator _error_ Thanks.
Jul 02 2019
On Tuesday, 2 July 2019 at 17:10:34 UTC, Jonathan M Davis wrote:Well, static foreach wasn't implemented until 2.076, so putting static in front of foreach like that would be illegal with 2.072.2.In fact I had a hunch about this, but on the other hand it wouldn't be nice if docs show the minimum version required for I just remembered that in this case I even tried 2.074, and looking the docs there wasn't any mention about the minimum version. Ataide.
Jul 02 2019
On Mon, 1 Jul 2019 at 03:45, Meta via Digitalmars-d <digitalmars-d puremagic.com> wrote:Jokes aside, this is very strange behaviour. struct Test(T...) { this(T ts) { foreach (i, t; ts) { int[ts.length] nums; if (i % 2 == 0) { nums[i / 2] = i; } else { nums[(i - 1) / 2] = i; // Error:array index 9223372036854775807 is out of bounds nums[0 .. 4] } } } } void main() { auto t = Test!(int, string, double, bool)(0, "", 0, false); } Of course, the only possible way (i - 1) / 2 can be 9223372036854775807 is if i == 0 and thus i - 1 underflows. However, this should never be possible because the else branch should only be taken when i > 0. After some testing, I realized that this is a very weird side-effect of constant folding. Regardless of whether the "else" branch will be taken at runtime, nums[(i - 1) / 2] is computed *at compile time* for each loop... but, it's not actually a loop. This is a static foreach (old-style, but this problem occurs with `static foreach` as well). The loop body is unrolled N times (where N == ts.length), and as expected, when I change the foreach to a regular for-loop, this problem goes away. Also changing the runtime if to static if fixes it. This is very strange behaviour, but understandable after some investigation. What I don't quite know is whether there should be a bug report opened for this. It's not technically a bug, I don't think, but it is certainly unexpected and arguably should be fixed.You could have just raised a bugzilla ticket. -- Iain
Jul 02 2019
On Tuesday, 2 July 2019 at 13:37:11 UTC, Iain Buclaw wrote:On Mon, 1 Jul 2019 at 03:45, Meta via Digitalmars-d <digitalmars-d puremagic.com> wrote:I didn't know if this was a bug or not due to the mix of compile-time and runtime stuff going on in my example.Jokes aside, this is very strange behaviour. struct Test(T...) { this(T ts) { foreach (i, t; ts) { int[ts.length] nums; if (i % 2 == 0) { nums[i / 2] = i; } else { nums[(i - 1) / 2] = i; // Error:array index 9223372036854775807 is out of bounds nums[0 .. 4] } } } } void main() { auto t = Test!(int, string, double, bool)(0, "", 0, false); } Of course, the only possible way (i - 1) / 2 can be 9223372036854775807 is if i == 0 and thus i - 1 underflows. However, this should never be possible because the else branch should only be taken when i > 0. After some testing, I realized that this is a very weird side-effect of constant folding. Regardless of whether the "else" branch will be taken at runtime, nums[(i - 1) / 2] is computed *at compile time* for each loop... but, it's not actually a loop. This is a static foreach (old-style, but this problem occurs with `static foreach` as well). The loop body is unrolled N times (where N == ts.length), and as expected, when I change the foreach to a regular for-loop, this problem goes away. Also changing the runtime if to static if fixes it. This is very strange behaviour, but understandable after some investigation. What I don't quite know is whether there should be a bug report opened for this. It's not technically a bug, I don't think, but it is certainly unexpected and arguably should be fixed.You could have just raised a bugzilla ticket.
Jul 02 2019