introduce scopes for VLA & attribute cleanup

This commit is contained in:
grischka 2019-06-22 13:18:54 +02:00
parent 8227db3a23
commit 3d78918e63

401
tccgen.c
View File

@ -39,18 +39,12 @@ ST_DATA Sym *define_stack;
ST_DATA Sym *global_label_stack; ST_DATA Sym *global_label_stack;
ST_DATA Sym *local_label_stack; ST_DATA Sym *local_label_stack;
static Sym *all_cleanups, *current_cleanups, *pending_gotos; static Sym *all_cleanups, *pending_gotos;
static int ncleanups;
static int local_scope; static int local_scope;
static int in_sizeof; static int in_sizeof;
static int in_generic; static int in_generic;
static int section_sym; static int section_sym;
ST_DATA int vlas_in_scope; /* number of VLAs that are currently in scope */
ST_DATA int vla_sp_root_loc; /* vla_sp_loc for SP before any VLAs were pushed */
ST_DATA int vla_sp_loc; /* Pointer to variable holding location to store stack pointer on the stack when modifying stack pointer */
ST_DATA SValue __vstack[1+VSTACK_SIZE], *vtop, *pvtop; ST_DATA SValue __vstack[1+VSTACK_SIZE], *vtop, *pvtop;
ST_DATA int const_wanted; /* true if constant wanted */ ST_DATA int const_wanted; /* true if constant wanted */
@ -91,6 +85,8 @@ ST_DATA struct switch_t {
int sym; int sym;
} **p; int n; /* list of case ranges */ } **p; int n; /* list of case ranges */
int def_sym; /* default symbol */ int def_sym; /* default symbol */
int *bsym;
struct scope *scope;
} *cur_switch; /* current switch */ } *cur_switch; /* current switch */
#define MAX_TEMP_LOCAL_VARIABLE_NUMBER 0x4 #define MAX_TEMP_LOCAL_VARIABLE_NUMBER 0x4
@ -102,6 +98,14 @@ ST_DATA struct temp_local_variable {
} arr_temp_local_vars[MAX_TEMP_LOCAL_VARIABLE_NUMBER]; } arr_temp_local_vars[MAX_TEMP_LOCAL_VARIABLE_NUMBER];
short nb_temp_local_vars; short nb_temp_local_vars;
static struct scope {
struct scope *prev;
struct { int loc, num; } vla;
struct { Sym *s; int n; } cl;
int *bsym, *csym;
Sym *lstk, *llstk;
} *cur_scope, *loop_scope, *root_scope;
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
static void gen_cast(CType *type); static void gen_cast(CType *type);
@ -113,14 +117,12 @@ static CType *type_decl(CType *type, AttributeDef *ad, int *v, int td);
static void parse_expr_type(CType *type); static void parse_expr_type(CType *type);
static void init_putv(CType *type, Section *sec, unsigned long c); static void init_putv(CType *type, Section *sec, unsigned long c);
static void decl_initializer(CType *type, Section *sec, unsigned long c, int flags); static void decl_initializer(CType *type, Section *sec, unsigned long c, int flags);
static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr); static void block(int is_expr);
static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, int has_init, int v, int scope); static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, int has_init, int v, int scope);
static void decl(int l); static void decl(int l);
static int decl0(int l, int is_for_loop_init, Sym *); static int decl0(int l, int is_for_loop_init, Sym *);
static void expr_eq(void); static void expr_eq(void);
static void vla_runtime_type_size(CType *type, int *a); static void vla_runtime_type_size(CType *type, int *a);
static void vla_sp_restore(void);
static void vla_sp_restore_root(void);
static int is_compatible_unqualified_types(CType *type1, CType *type2); static int is_compatible_unqualified_types(CType *type1, CType *type2);
static inline int64_t expr_const64(void); static inline int64_t expr_const64(void);
static void vpush64(int ty, unsigned long long v); static void vpush64(int ty, unsigned long long v);
@ -132,15 +134,6 @@ static void gv_dup(void);
static int get_temp_local_var(int size,int align); static int get_temp_local_var(int size,int align);
static void clear_temp_local_var_list(); static void clear_temp_local_var_list();
static void reset_local_scope(void)
{
if (current_cleanups)
tcc_error("ICE current_cleanups");
sym_pop(&all_cleanups, NULL, 0);
local_scope = 0;
}
ST_INLN int is_float(int t) ST_INLN int is_float(int t)
{ {
int bt; int bt;
@ -2937,18 +2930,6 @@ ST_FUNC void vla_runtime_type_size(CType *type, int *a)
} }
} }
static void vla_sp_restore(void) {
if (vlas_in_scope) {
gen_vla_sp_restore(vla_sp_loc);
}
}
static void vla_sp_restore_root(void) {
if (vlas_in_scope) {
gen_vla_sp_restore(vla_sp_root_loc);
}
}
/* return the pointed type of t */ /* return the pointed type of t */
static inline CType *pointed_type(CType *type) static inline CType *pointed_type(CType *type)
{ {
@ -4843,43 +4824,6 @@ static void parse_builtin_params(int nc, const char *args)
nocode_wanted--; nocode_wanted--;
} }
static void try_call_scope_cleanup(Sym *stop)
{
Sym *cls = current_cleanups;
for (; cls != stop; cls = cls->ncl) {
Sym *fs = cls->next;
Sym *vs = cls->prev_tok;
vpushsym(&fs->type, fs);
vset(&vs->type, vs->r, vs->c);
vtop->sym = vs;
mk_pointer(&vtop->type);
gaddrof();
gfunc_call(1);
}
}
static void try_call_cleanup_goto(Sym *cleanupstate)
{
Sym *oc, *cc;
int ocd, ccd;
if (!current_cleanups)
return;
/* search NCA of both cleanup chains given parents and initial depth */
ocd = cleanupstate ? cleanupstate->v & ~SYM_FIELD : 0;
for (ccd = ncleanups, oc = cleanupstate; ocd > ccd; --ocd, oc = oc->ncl)
;
for (cc = current_cleanups; ccd > ocd; --ccd, cc = cc->ncl)
;
for (; cc != oc; cc = cc->ncl, oc = oc->ncl, --ccd)
;
try_call_scope_cleanup(cc);
}
ST_FUNC void unary(void) ST_FUNC void unary(void)
{ {
int n, t, align, size, r, sizeof_caller; int n, t, align, size, r, sizeof_caller;
@ -5015,7 +4959,7 @@ ST_FUNC void unary(void)
as statement expressions can't ever be entered from the as statement expressions can't ever be entered from the
outside, so any reactivation of code emission (from labels outside, so any reactivation of code emission (from labels
or loop heads) can be disabled again after the end of it. */ or loop heads) can be disabled again after the end of it. */
block(NULL, NULL, NULL, NULL, 1); block(1);
nocode_wanted = saved_nocode_wanted; nocode_wanted = saved_nocode_wanted;
skip(')'); skip(')');
} else { } else {
@ -6134,6 +6078,24 @@ static void gfunc_return(CType *func_type)
} }
#endif #endif
static void check_func_return(void)
{
if ((func_vt.t & VT_BTYPE) == VT_VOID)
return;
if (!strcmp (funcname, "main")
&& (func_vt.t & VT_BTYPE) == VT_INT) {
/* main returns 0 by default */
vpushi(0);
gen_assign_cast(&func_vt);
gfunc_return(&func_vt);
} else {
tcc_warning("function might return no value: '%s'", funcname);
}
}
/* ------------------------------------------------------------------------- */
/* switch/case */
static int case_cmp(const void *pa, const void *pb) static int case_cmp(const void *pa, const void *pb)
{ {
int64_t a = (*(struct case_t**) pa)->v1; int64_t a = (*(struct case_t**) pa)->v1;
@ -6202,22 +6164,62 @@ static void gcase(struct case_t **base, int len, int *bsym)
*bsym = gjmp(*bsym); *bsym = gjmp(*bsym);
} }
/* ------------------------------------------------------------------------- */
/* __attribute__((cleanup(fn))) */
static void try_call_scope_cleanup(Sym *stop)
{
Sym *cls = cur_scope->cl.s;
for (; cls != stop; cls = cls->ncl) {
Sym *fs = cls->next;
Sym *vs = cls->prev_tok;
vpushsym(&fs->type, fs);
vset(&vs->type, vs->r, vs->c);
vtop->sym = vs;
mk_pointer(&vtop->type);
gaddrof();
gfunc_call(1);
}
}
static void try_call_cleanup_goto(Sym *cleanupstate)
{
Sym *oc, *cc;
int ocd, ccd;
if (!cur_scope->cl.s)
return;
/* search NCA of both cleanup chains given parents and initial depth */
ocd = cleanupstate ? cleanupstate->v & ~SYM_FIELD : 0;
for (ccd = cur_scope->cl.n, oc = cleanupstate; ocd > ccd; --ocd, oc = oc->ncl)
;
for (cc = cur_scope->cl.s; ccd > ocd; --ccd, cc = cc->ncl)
;
for (; cc != oc; cc = cc->ncl, oc = oc->ncl, --ccd)
;
try_call_scope_cleanup(cc);
}
/* call 'func' for each __attribute__((cleanup(func))) */ /* call 'func' for each __attribute__((cleanup(func))) */
static void block_cleanup(Sym *lcleanup, int lncleanups) static void block_cleanup(struct scope *o)
{ {
int jmp = 0; int jmp = 0;
Sym *g, **pg; Sym *g, **pg;
for (pg = &pending_gotos; (g = *pg) && g->c > lncleanups;) { for (pg = &pending_gotos; (g = *pg) && g->c > o->cl.n;) {
if (g->prev_tok->r & LABEL_FORWARD) { if (g->prev_tok->r & LABEL_FORWARD) {
Sym *pcl = g->next; Sym *pcl = g->next;
if (!jmp) if (!jmp)
jmp = gjmp(0); jmp = gjmp(0);
gsym(pcl->jnext); gsym(pcl->jnext);
try_call_scope_cleanup(lcleanup); try_call_scope_cleanup(o->cl.s);
pcl->jnext = gjmp(0); pcl->jnext = gjmp(0);
if (!lncleanups) if (!o->cl.n)
goto remove_pending; goto remove_pending;
g->c = lncleanups; g->c = o->cl.n;
pg = &g->prev; pg = &g->prev;
} else { } else {
remove_pending: remove_pending:
@ -6226,27 +6228,96 @@ static void block_cleanup(Sym *lcleanup, int lncleanups)
} }
} }
gsym(jmp); gsym(jmp);
try_call_scope_cleanup(lcleanup); try_call_scope_cleanup(o->cl.s);
current_cleanups = lcleanup;
ncleanups = lncleanups;
} }
static void check_func_return(void) /* ------------------------------------------------------------------------- */
/* VLA */
static void vla_restore(int loc)
{ {
if ((func_vt.t & VT_BTYPE) == VT_VOID) if (loc)
gen_vla_sp_restore(loc);
}
static void vla_leave(struct scope *o)
{
if (o->vla.num < cur_scope->vla.num)
vla_restore(o->vla.loc);
}
/* ------------------------------------------------------------------------- */
/* local scopes */
void new_scope(struct scope *o)
{
/* copy and link previous scope */
*o = *cur_scope;
o->prev = cur_scope;
cur_scope = o;
/* record local declaration stack position */
o->lstk = local_stack;
o->llstk = local_label_stack;
++local_scope;
}
void prev_scope(struct scope *o, int is_expr)
{
vla_leave(o->prev);
if (o->cl.s != o->prev->cl.s)
block_cleanup(o->prev);
/* pop locally defined labels */
label_pop(&local_label_stack, o->llstk, is_expr);
/* In the is_expr case (a statement expression is finished here),
vtop might refer to symbols on the local_stack. Either via the
type or via vtop->sym. We can't pop those nor any that in turn
might be referred to. To make it easier we don't roll back
any symbols in that case; some upper level call to block() will
do that. We do have to remove such symbols from the lookup
tables, though. sym_pop will do that. */
/* pop locally defined symbols */
sym_pop(&local_stack, o->lstk, is_expr);
cur_scope = o->prev;
--local_scope;
}
/* leave a scope via break/continue(/goto) */
void leave_scope(struct scope *o)
{
if (!o)
return; return;
if (!strcmp (funcname, "main") try_call_scope_cleanup(o->cl.s);
&& (func_vt.t & VT_BTYPE) == VT_INT) { vla_leave(o);
/* main returns 0 by default */ }
vpushi(0);
gen_assign_cast(&func_vt); /* ------------------------------------------------------------------------- */
gfunc_return(&func_vt); /* call block from 'for do while' loops */
} else {
tcc_warning("function might return no value: '%s'", funcname); static void lblock(int *bsym, int *csym)
{
struct scope *lo = loop_scope, *co = cur_scope;
int *b = co->bsym, *c = co->csym;
if (csym) {
co->csym = csym;
loop_scope = co;
}
co->bsym = bsym;
block(0);
co->bsym = b;
if (csym) {
co->csym = c;
loop_scope = lo;
} }
} }
static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr) static void block(int is_expr)
{ {
int a, b, c, d, e, t; int a, b, c, d, e, t;
Sym *s; Sym *s;
@ -6257,6 +6328,7 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
vtop->type.t = VT_VOID; vtop->type.t = VT_VOID;
} }
again:
t = tok, next(); t = tok, next();
if (t == TOK_IF) { if (t == TOK_IF) {
@ -6264,12 +6336,12 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
gexpr(); gexpr();
skip(')'); skip(')');
a = gvtst(1, 0); a = gvtst(1, 0);
block(bsym, bcl, csym, ccl, 0); block(0);
if (tok == TOK_ELSE) { if (tok == TOK_ELSE) {
d = gjmp(0); d = gjmp(0);
gsym(a); gsym(a);
next(); next();
block(bsym, bcl, csym, ccl, 0); block(0);
gsym(d); /* patch else jmp */ gsym(d); /* patch else jmp */
} else { } else {
gsym(a); gsym(a);
@ -6277,27 +6349,19 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
} else if (t == TOK_WHILE) { } else if (t == TOK_WHILE) {
d = gind(); d = gind();
vla_sp_restore();
skip('('); skip('(');
gexpr(); gexpr();
skip(')'); skip(')');
a = gvtst(1, 0); a = gvtst(1, 0);
b = 0; b = 0;
block(&a, current_cleanups, &b, current_cleanups, 0); lblock(&a, &b);
gjmp_addr(d); gjmp_addr(d);
gsym_addr(b, d); gsym_addr(b, d);
gsym(a); gsym(a);
} else if (t == '{') { } else if (t == '{') {
Sym *llabel, *lcleanup; struct scope o;
int block_vla_sp_loc = vla_sp_loc, saved_vlas_in_scope = vlas_in_scope; new_scope(&o);
int lncleanups = ncleanups;
/* record local declaration stack position */
s = local_stack;
llabel = local_label_stack;
lcleanup = current_cleanups;
++local_scope;
/* handle local labels declarations */ /* handle local labels declarations */
while (tok == TOK_LABEL) { while (tok == TOK_LABEL) {
@ -6316,35 +6380,13 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
if (tok != '}') { if (tok != '}') {
if (is_expr) if (is_expr)
vpop(); vpop();
block(bsym, bcl, csym, ccl, is_expr); block(is_expr);
} }
} }
if (current_cleanups != lcleanup) prev_scope(&o, is_expr);
block_cleanup(lcleanup, lncleanups);
/* pop locally defined labels */ if (0 == local_scope && !nocode_wanted)
label_pop(&local_label_stack, llabel, is_expr);
/* In the is_expr case (a statement expression is finished here),
vtop might refer to symbols on the local_stack. Either via the
type or via vtop->sym. We can't pop those nor any that in turn
might be referred to. To make it easier we don't roll back
any symbols in that case; some upper level call to block() will
do that. We do have to remove such symbols from the lookup
tables, though. sym_pop will do that. */
/* pop locally defined symbols */
sym_pop(&local_stack, s, is_expr);
/* Pop VLA frames and restore stack pointer if required */
if (vlas_in_scope > saved_vlas_in_scope) {
vla_sp_loc = saved_vlas_in_scope ? block_vla_sp_loc : vla_sp_root_loc;
vla_sp_restore();
}
vlas_in_scope = saved_vlas_in_scope;
if (0 == --local_scope && !nocode_wanted)
check_func_return(); check_func_return();
next(); next();
@ -6353,7 +6395,7 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
b = (func_vt.t & VT_BTYPE) != VT_VOID; b = (func_vt.t & VT_BTYPE) != VT_VOID;
if (a) if (a)
gexpr(), gen_assign_cast(&func_vt); gexpr(), gen_assign_cast(&func_vt);
try_call_scope_cleanup(NULL); leave_scope(root_scope);
if (a && b) if (a && b)
gfunc_return(&func_vt); gfunc_return(&func_vt);
else if (a) else if (a)
@ -6368,28 +6410,28 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
} else if (t == TOK_BREAK) { } else if (t == TOK_BREAK) {
/* compute jump */ /* compute jump */
if (!bsym) if (!cur_scope->bsym)
tcc_error("cannot break"); tcc_error("cannot break");
try_call_scope_cleanup(bcl); if (!cur_switch || cur_scope->bsym != cur_switch->bsym)
*bsym = gjmp(*bsym); leave_scope(loop_scope);
else
leave_scope(cur_switch->scope);
*cur_scope->bsym = gjmp(*cur_scope->bsym);
skip(';'); skip(';');
} else if (t == TOK_CONTINUE) { } else if (t == TOK_CONTINUE) {
/* compute jump */ /* compute jump */
if (!csym) if (!cur_scope->csym)
tcc_error("cannot continue"); tcc_error("cannot continue");
try_call_scope_cleanup(ccl); leave_scope(loop_scope);
vla_sp_restore_root(); *cur_scope->csym = gjmp(*cur_scope->csym);
*csym = gjmp(*csym);
skip(';'); skip(';');
} else if (t == TOK_FOR) { } else if (t == TOK_FOR) {
Sym *lcleanup = current_cleanups; struct scope o;
int lncleanups = ncleanups; new_scope(&o);
skip('('); skip('(');
s = local_stack;
++local_scope;
if (tok != ';') { if (tok != ';') {
/* c99 for-loop init decl? */ /* c99 for-loop init decl? */
if (!decl0(VT_LOCAL, 1, NULL)) { if (!decl0(VT_LOCAL, 1, NULL)) {
@ -6401,7 +6443,6 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
skip(';'); skip(';');
a = b = 0; a = b = 0;
c = d = gind(); c = d = gind();
vla_sp_restore();
if (tok != ';') { if (tok != ';') {
gexpr(); gexpr();
a = gvtst(1, 0); a = gvtst(1, 0);
@ -6410,28 +6451,22 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
if (tok != ')') { if (tok != ')') {
e = gjmp(0); e = gjmp(0);
d = gind(); d = gind();
vla_sp_restore();
gexpr(); gexpr();
vpop(); vpop();
gjmp_addr(c); gjmp_addr(c);
gsym(e); gsym(e);
} }
skip(')'); skip(')');
block(&a, current_cleanups, &b, current_cleanups, 0); lblock(&a, &b);
gjmp_addr(d); gjmp_addr(d);
gsym_addr(b, d); gsym_addr(b, d);
gsym(a); gsym(a);
--local_scope; prev_scope(&o, 0);
try_call_scope_cleanup(lcleanup);
ncleanups = lncleanups;
current_cleanups = lcleanup;
sym_pop(&local_stack, s, 0);
} else if (t == TOK_DO) { } else if (t == TOK_DO) {
a = b = 0; a = b = 0;
d = gind(); d = gind();
vla_sp_restore(); lblock(&a, &b);
block(&a, current_cleanups, &b, current_cleanups, 0);
gsym(b); gsym(b);
skip(TOK_WHILE); skip(TOK_WHILE);
skip('('); skip('(');
@ -6446,17 +6481,23 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
struct switch_t *saved, sw; struct switch_t *saved, sw;
SValue switchval; SValue switchval;
sw.p = NULL;
sw.n = 0;
sw.def_sym = 0;
sw.bsym = &a;
sw.scope = cur_scope;
saved = cur_switch;
cur_switch = &sw;
skip('('); skip('(');
gexpr(); gexpr();
skip(')'); skip(')');
switchval = *vtop--; switchval = *vtop--;
sw.p = NULL; sw.n = 0; sw.def_sym = 0;
saved = cur_switch;
cur_switch = &sw;
a = 0; a = 0;
b = gjmp(0); /* jump to first case */ b = gjmp(0); /* jump to first case */
block(&a, current_cleanups, csym, ccl, 0); lblock(&a, NULL);
a = gjmp(a); /* add implicit break */ a = gjmp(a); /* add implicit break */
/* case lookup */ /* case lookup */
gsym(b); gsym(b);
@ -6465,6 +6506,7 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
for (b = 1; b < sw.n; b++) for (b = 1; b < sw.n; b++)
if (sw.p[b - 1]->v2 >= sw.p[b]->v1) if (sw.p[b - 1]->v2 >= sw.p[b]->v1)
tcc_error("duplicate case value"); tcc_error("duplicate case value");
/* Our switch table sorting is signed, so the compared /* Our switch table sorting is signed, so the compared
value needs to be as well when it's 64bit. */ value needs to be as well when it's 64bit. */
if ((switchval.type.t & VT_BTYPE) == VT_LLONG) if ((switchval.type.t & VT_BTYPE) == VT_LLONG)
@ -6479,6 +6521,7 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
gsym(d); gsym(d);
/* break label */ /* break label */
gsym(a); gsym(a);
dynarray_reset(&sw.p, &sw.n); dynarray_reset(&sw.p, &sw.n);
cur_switch = saved; cur_switch = saved;
@ -6510,6 +6553,7 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
goto block_after_label; goto block_after_label;
} else if (t == TOK_GOTO) { } else if (t == TOK_GOTO) {
vla_restore(root_scope->vla.loc);
if (tok == '*' && gnu_ext) { if (tok == '*' && gnu_ext) {
/* computed goto */ /* computed goto */
next(); next();
@ -6517,6 +6561,7 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
if ((vtop->type.t & VT_BTYPE) != VT_PTR) if ((vtop->type.t & VT_BTYPE) != VT_PTR)
expect("pointer"); expect("pointer");
ggoto(); ggoto();
} else if (tok >= TOK_UIDENT) { } else if (tok >= TOK_UIDENT) {
s = label_find(tok); s = label_find(tok);
/* put forward definition if needed */ /* put forward definition if needed */
@ -6525,11 +6570,10 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
else if (s->r == LABEL_DECLARED) else if (s->r == LABEL_DECLARED)
s->r = LABEL_FORWARD; s->r = LABEL_FORWARD;
vla_sp_restore_root();
if (s->r & LABEL_FORWARD) { if (s->r & LABEL_FORWARD) {
/* start new goto chain for cleanups, linked via label->next */ /* start new goto chain for cleanups, linked via label->next */
if (current_cleanups) { if (cur_scope->cl.s && !nocode_wanted) {
sym_push2(&pending_gotos, SYM_FIELD, 0, ncleanups); sym_push2(&pending_gotos, SYM_FIELD, 0, cur_scope->cl.n);
pending_gotos->prev_tok = s; pending_gotos->prev_tok = s;
s = sym_push2(&s->next, SYM_FIELD, 0, 0); s = sym_push2(&s->next, SYM_FIELD, 0, 0);
pending_gotos->next = s; pending_gotos->next = s;
@ -6569,17 +6613,15 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
s = label_push(&global_label_stack, t, LABEL_DEFINED); s = label_push(&global_label_stack, t, LABEL_DEFINED);
} }
s->jnext = gind(); s->jnext = gind();
s->cleanupstate = current_cleanups; s->cleanupstate = cur_scope->cl.s;
block_after_label: block_after_label:
vla_sp_restore(); vla_restore(cur_scope->vla.loc);
/* we accept this, but it is a mistake */ /* we accept this, but it is a mistake */
if (tok == '}') { if (tok == '}') {
tcc_warning("deprecated use of label at end of compound statement"); tcc_warning("deprecated use of label at end of compound statement");
} else { } else {
if (is_expr) goto again;
vpop();
block(bsym, bcl, csym, ccl, is_expr);
} }
} else { } else {
@ -7317,11 +7359,12 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
#endif #endif
sym = sym_push(v, type, r, addr); sym = sym_push(v, type, r, addr);
if (ad->cleanup_func) { if (ad->cleanup_func) {
Sym *cls = sym_push2(&all_cleanups, SYM_FIELD | ++ncleanups, 0, 0); Sym *cls = sym_push2(&all_cleanups,
SYM_FIELD | ++cur_scope->cl.n, 0, 0);
cls->prev_tok = sym; cls->prev_tok = sym;
cls->next = ad->cleanup_func; cls->next = ad->cleanup_func;
cls->ncl = current_cleanups; cls->ncl = cur_scope->cl.s;
current_cleanups = cls; cur_scope->cl.s = cls;
} }
sym->a = ad->a; sym->a = ad->a;
@ -7398,10 +7441,10 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
goto no_alloc; goto no_alloc;
/* save current stack pointer */ /* save current stack pointer */
if (vlas_in_scope == 0) { if (root_scope->vla.loc == 0) {
if (vla_sp_root_loc == -1) struct scope *v = cur_scope;
vla_sp_root_loc = (loc -= PTR_SIZE); gen_vla_sp_save(loc -= PTR_SIZE);
gen_vla_sp_save(vla_sp_root_loc); do v->vla.loc = loc; while ((v = v->prev));
} }
vla_runtime_type_size(type, &a); vla_runtime_type_size(type, &a);
@ -7412,8 +7455,8 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
gen_vla_result(addr), addr = (loc -= PTR_SIZE); gen_vla_result(addr), addr = (loc -= PTR_SIZE);
#endif #endif
gen_vla_sp_save(addr); gen_vla_sp_save(addr);
vla_sp_loc = addr; cur_scope->vla.loc = addr;
vlas_in_scope++; cur_scope->vla.num++;
} else if (has_init) { } else if (has_init) {
size_t oldreloc_offset = 0; size_t oldreloc_offset = 0;
@ -7442,6 +7485,10 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
'cur_text_section' */ 'cur_text_section' */
static void gen_function(Sym *sym) static void gen_function(Sym *sym)
{ {
/* Initialize VLA state */
struct scope f = { 0 };
cur_scope = root_scope = &f;
nocode_wanted = 0; nocode_wanted = 0;
ind = cur_text_section->data_offset; ind = cur_text_section->data_offset;
if (sym->a.aligned) { if (sym->a.aligned) {
@ -7451,32 +7498,32 @@ static void gen_function(Sym *sym)
} }
/* NOTE: we patch the symbol size later */ /* NOTE: we patch the symbol size later */
put_extern_sym(sym, cur_text_section, ind, 0); put_extern_sym(sym, cur_text_section, ind, 0);
funcname = get_tok_str(sym->v, NULL); funcname = get_tok_str(sym->v, NULL);
func_ind = ind; func_ind = ind;
/* Initialize VLA state */
vla_sp_loc = -1;
vla_sp_root_loc = -1;
/* put debug symbol */ /* put debug symbol */
tcc_debug_funcstart(tcc_state, sym); tcc_debug_funcstart(tcc_state, sym);
/* push a dummy symbol to enable local sym storage */ /* push a dummy symbol to enable local sym storage */
sym_push2(&local_stack, SYM_FIELD, 0, 0); sym_push2(&local_stack, SYM_FIELD, 0, 0);
local_scope = 1; /* for function parameters */ local_scope = 1; /* for function parameters */
gfunc_prolog(&sym->type); gfunc_prolog(&sym->type);
reset_local_scope(); local_scope = 0;
rsym = 0; rsym = 0;
clear_temp_local_var_list(); clear_temp_local_var_list();
block(NULL, NULL, NULL, NULL, 0); block(0);
gsym(rsym); gsym(rsym);
nocode_wanted = 0; nocode_wanted = 0;
gfunc_epilog(); gfunc_epilog();
cur_text_section->data_offset = ind; cur_text_section->data_offset = ind;
label_pop(&global_label_stack, NULL, 0);
/* reset local stack */ /* reset local stack */
reset_local_scope();
sym_pop(&local_stack, NULL, 0); sym_pop(&local_stack, NULL, 0);
/* end of function */ local_scope = 0;
label_pop(&global_label_stack, NULL, 0);
sym_pop(&all_cleanups, NULL, 0);
/* patch symbol size */ /* patch symbol size */
elfsym(sym)->st_size = ind - func_ind; elfsym(sym)->st_size = ind - func_ind;
/* end of function */
tcc_debug_funcend(tcc_state, ind - func_ind); tcc_debug_funcend(tcc_state, ind - func_ind);
/* It's better to crash than to generate wrong code */ /* It's better to crash than to generate wrong code */
cur_text_section = NULL; cur_text_section = NULL;