diff options
| author | Michael Matz <matz@suse.de> | 2017-07-10 22:25:11 +0200 |
|---|---|---|
| committer | Michael Matz <matz@suse.de> | 2017-07-10 22:25:11 +0200 |
| commit | 9bea88d61611dc12eeb211e342461f9157177464 (patch) | |
| tree | d8a3c666fce163dd132c7bf01e6c13c1396676c4 | |
| parent | 2240422da9b55b71cfb32220bb0246ec92bfc432 (diff) | |
| download | tinycc-9bea88d61611dc12eeb211e342461f9157177464.tar.gz tinycc-9bea88d61611dc12eeb211e342461f9157177464.tar.bz2 | |
Fix statement exprs returning a local label
Like returned local variables also labels local to a statement expression
can be returned, and so their symbols must not be immediately freed
(though they need to be removed from the symbol table).
| -rw-r--r-- | tcc.h | 2 | ||||
| -rw-r--r-- | tccgen.c | 4 | ||||
| -rw-r--r-- | tccpp.c | 8 | ||||
| -rw-r--r-- | tests/tcctest.c | 8 |
4 files changed, 16 insertions, 6 deletions
@@ -1234,7 +1234,7 @@ ST_INLN Sym *define_find(int v); ST_FUNC void free_defines(Sym *b); ST_FUNC Sym *label_find(int v); ST_FUNC Sym *label_push(Sym **ptop, int v, int flags); -ST_FUNC void label_pop(Sym **ptop, Sym *slast); +ST_FUNC void label_pop(Sym **ptop, Sym *slast, int keep); ST_FUNC void parse_define(void); ST_FUNC void preprocess(int is_bof); ST_FUNC void next_nomacro(void); @@ -5861,7 +5861,7 @@ static void block(int *bsym, int *csym, int is_expr) } } /* pop locally defined labels */ - label_pop(&local_label_stack, llabel); + label_pop(&local_label_stack, llabel, is_expr); /* pop locally defined symbols */ --local_scope; /* In the is_expr case (a statement expression is finished here), @@ -6948,7 +6948,7 @@ static void gen_function(Sym *sym) gsym(rsym); gfunc_epilog(); cur_text_section->data_offset = ind; - label_pop(&global_label_stack, NULL); + label_pop(&global_label_stack, NULL, 0); /* reset local stack */ local_scope = 0; sym_pop(&local_stack, NULL, 0); @@ -1376,7 +1376,7 @@ ST_FUNC Sym *label_push(Sym **ptop, int v, int flags) /* pop labels until element last is reached. Look if any labels are undefined. Define symbols if '&&label' was used. */ -ST_FUNC void label_pop(Sym **ptop, Sym *slast) +ST_FUNC void label_pop(Sym **ptop, Sym *slast, int keep) { Sym *s, *s1; for(s = *ptop; s != slast; s = s1) { @@ -1395,9 +1395,11 @@ ST_FUNC void label_pop(Sym **ptop, Sym *slast) } /* remove label */ table_ident[s->v - TOK_IDENT]->sym_label = s->prev_tok; - sym_free(s); + if (!keep) + sym_free(s); } - *ptop = slast; + if (!keep) + *ptop = slast; } /* eval an expression for #if/#elif */ diff --git a/tests/tcctest.c b/tests/tcctest.c index 10203ec..f657c14 100644 --- a/tests/tcctest.c +++ b/tests/tcctest.c @@ -2899,6 +2899,11 @@ struct hlist_head { struct hlist_node *first, *last; }; +void consume_ulong (unsigned long i) +{ + i = 0; +} + void statement_expr_test(void) { int a, i; @@ -2954,6 +2959,9 @@ void statement_expr_test(void) }); printf ("stmtexpr: %d %d %d\n", t, b, c); printf ("stmtexpr: %ld %ld\n", (long)h.first, (long)h.last); + + /* Test that we can give out addresses of local labels. */ + consume_ulong(({ __label__ __here; __here: (unsigned long)&&__here; })); } void local_label_test(void) |
