Fix detection of labels with a typedef name

This needs to be accepted:
  typedef int foo;
  void f (void) { foo: return; }
namespaces for labels and types are different.  The problem is that
the block parser always tries to find a decl first and that routine
doesn't peek enough to detect this case.  Needs some adjustments
to unget_tok() so that we can call it even when we already called
it once, but next() didn't come around restoring the buffer yet.
(It lazily does so not when the buffer becomes empty, but rather
when the next call detects that the buffer is empty, i.e. it requires
two next() calls until the unget buffer gets switched back).
master
Michael Matz 2012-04-15 22:17:51 +02:00
parent 1d0a5c2515
commit 15f4ac2b1a
3 changed files with 33 additions and 3 deletions

View File

@ -4286,6 +4286,25 @@ static int is_label(void)
}
}
static void label_or_decl(int l)
{
int last_tok;
/* fast test first */
if (tok >= TOK_UIDENT)
{
/* no need to save tokc because tok is an identifier */
last_tok = tok;
next();
if (tok == ':') {
unget_tok(last_tok);
return;
}
unget_tok(last_tok);
}
decl(l);
}
static void block(int *bsym, int *csym, int *case_sym, int *def_sym,
int case_reg, int is_expr)
{
@ -4359,7 +4378,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym,
}
}
while (tok != '}') {
decl(VT_LOCAL);
label_or_decl(VT_LOCAL);
if (tok != '}') {
if (is_expr)
vpop();

12
tccpp.c
View File

@ -2995,8 +2995,16 @@ ST_INLN void unget_tok(int last_tok)
{
int i, n;
int *q;
unget_saved_macro_ptr = macro_ptr;
unget_buffer_enabled = 1;
if (unget_buffer_enabled)
{
/* assert(macro_ptr == unget_saved_buffer + 1);
assert(*macro_ptr == 0); */
}
else
{
unget_saved_macro_ptr = macro_ptr;
unget_buffer_enabled = 1;
}
q = unget_saved_buffer;
macro_ptr = q;
*q++ = tok;

View File

@ -432,6 +432,7 @@ void loop_test()
printf("\n");
}
typedef int typedef_and_label;
void goto_test()
{
@ -440,6 +441,8 @@ void goto_test()
printf("goto:\n");
i = 0;
/* This needs to parse as label, not as start of decl. */
typedef_and_label:
s_loop:
if (i >= 10)
goto s_end;