------- Additional Comments From joseph at codesourcery dot com 2005-03-24 20:34 ------- Subject: Re: [4.0/4.1 Regression] ICE jumping into statement expression
On Thu, 24 Mar 2005, mmitchel at gcc dot gnu dot org wrote: > Joseph, do you think it is tractable and reasonable to diagnose jumps into > statement expressions for 4.0? If you and RTH agree that this should be > invalid, then that would be ideal. If you agree that this should be invalid, > but don't think it's possible to fix, would you please adjust the Keywords > entry > here, so that this is not marked as a wrong-code/ice-on-valid-code regression, > but rather accepts-invalid? I think it is tractable and reasonable to diagnose jumps into statement expressions (at least for C, not having looked at the implementation for C++) for 4.0. I also don't see anything *wrong* with the C front end changes in the patch posted for this bug, given that the rest of the patch could still be of use if there are front ends which want to continue to allow jumps into conditional expressions which might otherwise get folded. (And in abstract there's nothing wrong with a front end trying to fold a COND_EXPR arising from if (0) { ... } else { ... }, which certainly can be jumped into; just that in practice trying to fold such a tree is unlikely to be useful.) Having spent an hour working out how to diagnose jumps into statement expressions I've arrived at the following approach which I'd try; I expect something similar would work for C++ as well: * Add three flags to labels: one for "this label was in a statement expression which has finished, so you can't jump to it any more", one for "this label has a goto jumping to it from the current level of statement expression nesting" and one for "this label has a goto jumping to it from outside the current level of statement expression nesting". * Keep a list at each level of statement expression nesting (including inside a function but outside all statement expressions) of all labels defined at that level, and a list of all labels with gotos to them at that level. * When a goto is encountered, it mustn't be to a label with the first flag. Otherwise, if it doesn't have the second or third flag, give it the second flag and put it on the current list of gotos. * When a label is defined, it mustn't have the third flag. Otherwise, put it on the list of labels defined at that level. * When starting a statement expression, start new lists as above. Given all labels on the immediately previous list of gotos the third flag (so they can't be defined until that statement expression ends). * When ending a statement expression, give all labels defined in that expression the first flag. Remove the third flag from all gotos in the level to which we are returning, leaving the second flag on them. Move the gotos in the list of the level we are leaving to the list of the level which we are returning (and leave the second flag on them). * Keep a flag for whether the current switch statement started outside the current statement expression. When starting a statement expression, save the flag's value and set it to true; restore it when ending a statement expression. When starting a switch statement, save the flag's value and set it to false; restore it when ending a switch statement. Do not allow case or default labels when the flag is true. * Generate a testcase involving all cases of a function with two statement expressions inside, each of those containing two statement expressions and the label and goto in all possible places, i.e. void f (void) { ^({ ^({^0;}); ^({^0;}); ^0;}); ^({ ^({^0;}); ^({^0;}); ^0;}); ^0;^ } with the goto at any place marked ^ and the label on the goto or at any of those places other than right at the end of the function, i.e. 196 such functions, making sure that the correct subset are rejected. (This is operating on the basis that we will continue to allow jumps *out* of statement expressions, as people have real uses for such, with it simply being unspecified which collateral expressions of the statement expression (subexpressions of the larger expression containing the statement expression not separated from it by a sequence point, e.g. foo() in foo() + ({ goto a; 0; })) have been evaluated.) (The second flag on labels is only used to avoid listing labels more than once at the same level of nesting; it isn't strictly required, and actually implementing it would mean multipurposing another one of the DECL_LANG_FLAG fields: C is using 0-5 with 4 already multipurposed.) -- http://gcc.gnu.org/bugzilla/show_bug.cgi?id=17913