The following code snippet does not parse correctly: typedef int T; void h() { for(int T; ;) if(1) ; T *x; x = 0; } However, this one does: typedef int T; void h() { for(int T; ;) if(1) ; ; T *x; x = 0; }
My explanation of the problem is that the parser has to do a lookahead to make sure that there is no "else" associated to the selection statement. However, this lookahead is done in the wrong context, which make T look like a variable (while it is actually a type name).
Confirmed. It seems that in the first case we parse "T *x;" using c_parser_statement_after_labels (that fails) while in the second case with c_parser_declaration_or_fndef (that succeeds). That is because in the first case the parser sees "T" as an ID while in the second case as a TYPENAME. I don't know yet why is that so.
The reason is as stated in comment#1: it's necessary to examine the token after "if ( 1 ) ;" to see if it's the "else" keyword; if it were "else", that token would be within the C99/C11 block scope of the "for" loop, but if it's something else then it's outside that block scope. But examining it to determine whether it's "else" also classifies it as not a typedef, using information from the wrong scope. So on leaving such a scope for a "for" loop, any previously-lexed identifier token after the loop may need reclassifying based on the correct scope.
Thanks. I think I've a fix now.
Note that I've found an ICE-on-invalid: void h () { int T; for (typedef int T;;) if (1) ; T *x; }
And another that seems to be caused by something else and isn't fixed by my patch: void h () { for (typedef int T;;) if (1) ; T *x; x = 0; } I'm opening a separate PR for this one.
Author: mpolacek Date: Thu Nov 12 21:07:04 2015 New Revision: 230273 URL: https://gcc.gnu.org/viewcvs?rev=230273&root=gcc&view=rev Log: PR c/67784 * c-parser.c (c_parser_for_statement): Reclassify the token in a correct scope. * gcc.dg/pr67784-1.c: New test. * gcc.dg/pr67784-2.c: New test. Added: trunk/gcc/testsuite/gcc.dg/pr67784-1.c trunk/gcc/testsuite/gcc.dg/pr67784-2.c Modified: trunk/gcc/c/ChangeLog trunk/gcc/c/c-parser.c trunk/gcc/testsuite/ChangeLog
Fixed.
I am sorry, but it appears a similar bug is still in the 6.1 RC, with the following variant of my first example: typedef int T; void f(void) { if(sizeof(enum { T }) == 0); T x; // T should be resolved outside of the scope of "if" x = 0; }
Sorry about that. I'll have another look.
Author: mpolacek Date: Tue Apr 26 14:59:40 2016 New Revision: 235446 URL: https://gcc.gnu.org/viewcvs?rev=235446&root=gcc&view=rev Log: PR c/67784 * c-parser.c (c_parser_maybe_reclassify_token): New function factored out of ... (c_parser_for_statement): ... here. (c_parser_if_statement): Use it. (c_parser_switch_statement): Use it. (c_parser_while_statement): Use it. * gcc.dg/pr67784-3.c: New test. * gcc.dg/pr67784-4.c: New test. * gcc.dg/pr67784-5.c: New test. Added: trunk/gcc/testsuite/gcc.dg/pr67784-3.c trunk/gcc/testsuite/gcc.dg/pr67784-4.c trunk/gcc/testsuite/gcc.dg/pr67784-5.c Modified: trunk/gcc/c/ChangeLog trunk/gcc/c/c-parser.c trunk/gcc/testsuite/ChangeLog
Fixed again.