Bug 6518 – break inside a static foreach inside a switch
Status
RESOLVED
Resolution
FIXED
Severity
regression
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2011-08-17T06:05:00Z
Last change time
2012-03-18T10:15:00Z
Keywords
patch, rejects-valid
Assigned to
nobody
Creator
bearophile_hugs
Comments
Comment #0 by bearophile_hugs — 2011-08-17T06:05:15Z
import std.typetuple: TypeTuple;
enum Foo : uint { A, B, C }
alias TypeTuple!(Foo.A, Foo.B, Foo.C) FooNames;
void main() {
Foo fo;
switch (fo) {
/*static*/ foreach (i, op; __traits(allMembers, Foo))
case FooNames[i]: break;
default: assert(0);
}
}
test.d(8): Error: switch case fallthrough - use 'goto case;' if intended
test.d(8): Error: switch case fallthrough - use 'goto case;' if intended
test.d(8): Error: switch case fallthrough - use 'goto case;' if intended
test.d(10): Error: switch case fallthrough - use 'goto default;' if intended
I think DMD 2.042 doesn't have this problem, this code used to work. I think this problem comes from recent changes in switch switch semantics and analysis.
The following code gives the same errors, showing it's not a problem of break breaking the foreach loop (like it probably has to do; so maybe the first example not correct?):
import std.typetuple: TypeTuple;
enum Foo : uint { A, B, C }
alias TypeTuple!(Foo.A, Foo.B, Foo.C) FooNames;
void main() {
Foo fo;
LABEL: switch (fo) {
/*static*/ foreach (i, op; __traits(allMembers, Foo))
case FooNames[i]: break LABEL;
default: assert(0);
}
}
----------------
That code is a reduction of a problem found in a recent version of the modified regex module:
void parseFlags(S)(S flags)
{
foreach(ch; flags)//flags are ASCII anyway
{
switch(ch)
{
foreach(i, op; __traits(allMembers, RegexOption))
{
case RegexOptionNames[i]:
if(re_flags & mixin("RegexOption."~op))
throw new RegexException(text("redundant flag specified: ",ch));
re_flags |= mixin("RegexOption."~op);
break;
}
default:
if(__ctfe)
assert(text("unknown regex flag '",ch,"'"));
else
new RegexException(text("unknown regex flag '",ch,"'"));
}
Comment #1 by k.hara.pg — 2011-08-17T16:31:46Z
(In reply to comment #0)
> import std.typetuple: TypeTuple;
> enum Foo : uint { A, B, C }
> alias TypeTuple!(Foo.A, Foo.B, Foo.C) FooNames;
> void main() {
> Foo fo;
> switch (fo) {
> /*static*/ foreach (i, op; __traits(allMembers, Foo))
> case FooNames[i]: break;
>
> default: assert(0);
> }
> }
[snip]
> I think DMD 2.042 doesn't have this problem, this code used to work. I think
> this problem comes from recent changes in switch switch semantics and analysis.
This code could compile with trunk dmd (c98b611), and it asserts in run time.
Which version did you try it with?
> The following code gives the same errors, showing it's not a problem of break
> breaking the foreach loop (like it probably has to do; so maybe the first
> example not correct?):
>
> import std.typetuple: TypeTuple;
> enum Foo : uint { A, B, C }
> alias TypeTuple!(Foo.A, Foo.B, Foo.C) FooNames;
> void main() {
> Foo fo;
> LABEL: switch (fo) {
> /*static*/ foreach (i, op; __traits(allMembers, Foo))
> case FooNames[i]: break LABEL;
>
> default: assert(0);
> }
> }
This code could compile, and it succeeds to run.
I think these behaviors in my PC are correct.
In first sample code, break-statement eacapes from foreach, and always goes into default case, and asserts.
And in second sample, break-statement escapes from LABEL-ed switch statement.
Comment #2 by bearophile_hugs — 2011-08-17T19:59:11Z
(In reply to comment #1)
> This code could compile with trunk dmd (c98b611), and it asserts in run time.
> Which version did you try it with?
I have just compiled DMD, and both examples give me those errors still, on Windows. I have compiled the code using the -w DMD switch. The error messages don't appear if I don't use -w.
Comment #3 by k.hara.pg — 2011-08-21T07:00:55Z
More simple test case.
enum Foo : uint { A }
void main() {
Foo foo;
switch (foo) {
enum op = "A";
case Foo.A: break;
default: assert(0);
}
// Following gives same error
//final switch (foo) {
// enum op = "A";
// case Foo.A: break;
//}
}
The case statement treats the previous enum declaration as fall-through statement and warns.