Bug 3190 – enum doesn't work as the increment in a for loop
Status
RESOLVED
Resolution
FIXED
Severity
major
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
x86_64
OS
Linux
Creation time
2009-07-19T02:16:00Z
Last change time
2015-06-09T01:28:06Z
Keywords
patch, wrong-code
Assigned to
nobody
Creator
bugzilla
Comments
Comment #0 by bugzilla — 2009-07-19T02:16:13Z
The following should print a list of numbers from 0 to 10:
enum real ONE = 1.0;
real x;
for (x=0.0; x<10.0; x+=ONE) writeln(x);
writeln(x);
Instead it prints:
0
nan
I.e. the loop is only executed once, and x is set to NaN after the first iteration. The same happens if float is used instead of real. If double is used, the program goes into a near-infinite loop, spitting out very small numbers (starting with 6.65345e-316).
The following makes the program behave as expected:
- making ONE a normal variable instead of an enum
- writing "enum { real ONE }" instead
- putting the increment inside the loop body
Comment #1 by clugdbug — 2009-07-20T00:15:11Z
I suspect this is related to bug#2414 or bug#2998. There's definitely something badly wrong with D2 enum (manifest constant) assignment.
Comment #2 by clugdbug — 2009-09-10T05:34:59Z
There are two problems here.
PROBLEM 1: This problem only shows up in for() loops because the increment condition isn't doing constant folding. This is a more general problem, which also affects D1.
statement.c line 1160 (DMD 2.032).
if (increment)
{ increment = increment->semantic(sc);
increment = resolveProperties(sc, increment);
+ increment = increment->optimize(0);
}
This change is enough to make the bug go away, but there's another oddity:
PROBLEM 2: It only happens for enum real ONE = 1.0; but not for enum : real { ONE = 1.0 }.
This is because expression.c DsymbolExp::semantic(Scope *sc) checks for enum members, but not for the new D2 manifest constants. I suspect that it probably should convert them, too, as in this second patch:
expression.c, line 2168.
if (v)
{
//printf("Identifier '%s' is a variable, type '%s'\n", toChars(), v->type->toChars());
if (!type)
{ type = v->type;
if (!v->type)
{ error("forward reference of %s %s", v->kind(), v->toChars());
type = Type::terror;
}
}
+ if ((v->storage_class & STCmanifest) && v->init) {
+ e = v->init->toExpression();
+ e->semantic(sc);
+ return e;
+ }
e = new VarExp(loc, v);
e->type = type;
e = e->semantic(sc);
return e->deref();
}
Comment #3 by clugdbug — 2009-10-13T09:12:18Z
*** Issue 3394 has been marked as a duplicate of this issue. ***