Fix interaction of (local) labels and stmt exprs

as per testcase.  We must not reset token.sym_label twice with
kept symbols.  This is no problem for non-label symbols because those
aren't generated on demand when mentioning them.
This commit is contained in:
Michael Matz 2020-04-14 22:35:58 +02:00
parent 6696da2f61
commit 096c93c0c6
3 changed files with 22 additions and 1 deletions

2
tcc.h
View File

@ -575,6 +575,8 @@ typedef struct DLLReference {
#define LABEL_DEFINED 0 /* label is defined */
#define LABEL_FORWARD 1 /* label is forward defined */
#define LABEL_DECLARED 2 /* label is declared but never used */
#define LABEL_GONE 3 /* label isn't in scope, but not yet popped
from local_label_stack (stmt exprs) */
/* type_decl() types */
#define TYPE_ABSTRACT 1 /* type without variable */

View File

@ -1402,9 +1402,12 @@ ST_FUNC void label_pop(Sym **ptop, Sym *slast, int keep)
}
}
/* remove label */
table_ident[s->v - TOK_IDENT]->sym_label = s->prev_tok;
if (s->r != LABEL_GONE)
table_ident[s->v - TOK_IDENT]->sym_label = s->prev_tok;
if (!keep)
sym_free(s);
else
s->r = LABEL_GONE;
}
if (!keep)
*ptop = slast;

View File

@ -3139,6 +3139,22 @@ void statement_expr_test(void)
/* Test that we can give out addresses of local labels. */
consume_ulong(({ __label__ __here; __here: (unsigned long)&&__here; }));
/* Test interaction between local and global label stacks and the
need to defer popping symbol from them when within statement
expressions. Note how the labels are both named LBL. */
i = 0;
({
{
__label__ LBL;
LBL: if (i++ == 0) goto LBL;
}
/* jump to a classical label out of an expr-stmt that had previously
overshadowed that classical label */
goto LBL;
});
LBL:
printf("stmtexpr: %d should be 2\n", i);
}
void local_label_test(void)