C# allows a goto to leave blocks but not to enter one: the label has to be in
the same block as the goto, or in one enclosing it. 4GL puts no such limit on
it and neither does C, so a program can be perfectly good 4GL and have no valid
C# translation. That used to surface as
error CS0159: No such label 'x' within the scope of the goto statement
against generated code, which takes some tracing before it is clear that the
4GL is what needs changing. It is now reported where it happens:
| Error at line 529, character 19
| GOTO carryon jumps into a block - the label is not in this branch, nor in
| one containing it. C# does not allow that, so this needs restructuring
| (move the label out, or use a flag and test it after the branch)
Every command list is a block: entering one pushes a fresh id and leaving pops
it, so the stack is the path from the function body to the current point. A
label's path is recorded where it is declared and a goto's likewise, and the
jump is legal exactly when the label's path is a prefix of the goto's.
The prefix test is the point. Comparing nesting depth is not enough: in the
case that prompted this the goto sits deeper than its label and still cannot
reach it, because the two are in the IF and the ELSE of the same statement -
siblings, not ancestor and descendant.
A goto to a label that is declared nowhere is left alone. That is a different
fault and not one this check should be guessing about.
Checked against 160 programs: no program that compiled before fails now, and
besides the case that prompted it the check found one more genuine instance.