Bug 67784 - Incorrect parsing when using declarations in for loops and typedefs
Summary: Incorrect parsing when using declarations in for loops and typedefs
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c (show other bugs)
Version: 6.0
: P3 normal
Target Milestone: 6.0
Assignee: Marek Polacek
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2015-09-30 14:14 UTC by Jacques-Henri Jourdan
Modified: 2016-04-26 15:01 UTC (History)
0 users

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2015-11-12 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Jacques-Henri Jourdan 2015-09-30 14:14:04 UTC
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;
}
Comment 1 Jacques-Henri Jourdan 2015-09-30 15:18:49 UTC
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).
Comment 2 Marek Polacek 2015-11-12 13:26:56 UTC
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.
Comment 3 jsm-csl@polyomino.org.uk 2015-11-12 13:58:20 UTC
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.
Comment 4 Marek Polacek 2015-11-12 15:37:29 UTC
Thanks.  I think I've a fix now.
Comment 5 Marek Polacek 2015-11-12 18:13:28 UTC
Note that I've found an ICE-on-invalid:

void
h ()
{
  int T;
  for (typedef int T;;)
    if (1)
      ;
  T *x;
}
Comment 6 Marek Polacek 2015-11-12 18:22:34 UTC
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.
Comment 7 Marek Polacek 2015-11-12 21:07:36 UTC
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
Comment 8 Marek Polacek 2015-11-12 21:08:47 UTC
Fixed.
Comment 9 Jacques-Henri Jourdan 2016-04-24 18:33:58 UTC
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;
}
Comment 10 Marek Polacek 2016-04-25 13:22:36 UTC
Sorry about that.  I'll have another look.
Comment 11 Marek Polacek 2016-04-26 15:00:21 UTC
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
Comment 12 Marek Polacek 2016-04-26 15:01:55 UTC
Fixed again.