nocode, noreturn

A more automatic approach to code suppression (aka. nocode_wanted)

The simple rules are:
- Clear 'nocode_wanted' at (im/explicit) label IF it was used
- Set 'nocode_wanted' after unconditional jumps

Also in order to test this then I did add the "function might
return no value" warning, and then to make that work again I
did add the __attribute__((noreturn)).

Also moved the look ahead label check into the type parser
to gain a little speed.
This commit is contained in:
grischka 2019-04-29 13:53:07 +02:00
parent 8569048031
commit 1b57560502
15 changed files with 263 additions and 325 deletions

View File

@ -382,11 +382,6 @@ void gsym_addr(int t, int a)
}
}
void gsym(int t)
{
gsym_addr(t, ind);
}
#ifdef TCC_ARM_VFP
static uint32_t vfpr(int r)
{

View File

@ -236,12 +236,6 @@ ST_FUNC void gsym_addr(int t_, int a_)
}
}
// Patch all branches in list pointed to by t to branch to current location:
ST_FUNC void gsym(int t)
{
gsym_addr(t, ind);
}
static int arm64_type_size(int t)
{
switch (t & VT_BTYPE) {

View File

@ -226,11 +226,6 @@ void gsym_addr(int t, int a)
}
}
void gsym(int t)
{
gsym_addr(t, ind);
}
// these are regs that tcc doesn't really know about,
// but assign them unique values so the mapping routines
// can distinguish them

View File

@ -140,11 +140,6 @@ ST_FUNC void gsym_addr(int t, int a)
}
}
ST_FUNC void gsym(int t)
{
gsym_addr(t, ind);
}
/* instruction + 4 bytes data. Return the address of the data */
static int oad(int c, int s)
{

View File

@ -60,6 +60,7 @@ void *__va_arg(__va_list_struct *ap,
default: /* should never happen */
abort();
return 0;
}
}
#endif

2
tcc.h
View File

@ -453,6 +453,8 @@ struct FuncAttr {
unsigned
func_call : 3, /* calling convention (0..5), see below */
func_type : 2, /* FUNC_OLD/NEW/ELLIPSIS */
func_noreturn : 1, /* attribute((noreturn)) */
xxxx : 2,
func_args : 8; /* PE __stdcall args */
};

View File

@ -912,9 +912,6 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global)
next();
if (tok == TOK_EOF)
break;
/* generate line number info */
if (global && s1->do_debug)
tcc_debug_line(s1);
parse_flags |= PARSE_FLAG_LINEFEED; /* XXX: suppress that hack */
redo:
if (tok == '#') {
@ -1148,7 +1145,6 @@ ST_FUNC void asm_instr(void)
uint8_t clobber_regs[NB_ASM_REGS];
Section *sec;
next();
/* since we always generate the asm() instruction, we can ignore
volatile */
if (tok == TOK_VOLATILE1 || tok == TOK_VOLATILE2 || tok == TOK_VOLATILE3) {

539
tccgen.c
View File

@ -44,6 +44,7 @@ static int ncleanups;
static int local_scope;
static int in_sizeof;
static int in_generic;
static int section_sym;
ST_DATA int vlas_in_scope; /* number of VLAs that are currently in scope */
@ -56,6 +57,24 @@ ST_DATA int const_wanted; /* true if constant wanted */
ST_DATA int nocode_wanted; /* no code generation wanted */
#define NODATA_WANTED (nocode_wanted > 0) /* no static data output wanted either */
#define STATIC_DATA_WANTED (nocode_wanted & 0xC0000000) /* only static data output */
/* Automagical code suppression ----> */
#define CODE_OFF() (nocode_wanted |= 0x20000000)
#define CODE_ON() (nocode_wanted &= ~0x20000000)
/* Clear 'nocode_wanted' at label if it was used */
ST_FUNC void gsym(int t) { if (t) { gsym_addr(t, ind); CODE_ON(); }}
static int gind(void) { CODE_ON(); return ind; }
/* Set 'nocode_wanted' after unconditional jumps */
static void gjmp_addr_acs(int t) { gjmp_addr(t); CODE_OFF(); }
static int gjmp_acs(int t) { t = gjmp(t); CODE_OFF(); return t; }
/* These are #undef'd at the end of this file */
#define gjmp_addr gjmp_addr_acs
#define gjmp gjmp_acs
/* <---- */
ST_DATA int global_expr; /* true if compound literals must be allocated globally (used during initializers parsing */
ST_DATA CType func_vt; /* current function return type (used by return instruction) */
ST_DATA int func_var; /* true if current function is variadic (used by return instruction) */
@ -3544,8 +3563,7 @@ redo:
break;
case TOK_NORETURN1:
case TOK_NORETURN2:
/* currently, no need to handle it because tcc does not
track unused objects */
ad->f.func_noreturn = 1;
break;
case TOK_CDECL1:
case TOK_CDECL2:
@ -4129,7 +4147,7 @@ static void parse_btype_qualify(CType *type, int qualifiers)
*/
static int parse_btype(CType *type, AttributeDef *ad)
{
int t, u, bt, st, type_found, typespec_found, g;
int t, u, bt, st, type_found, typespec_found, g, n;
Sym *s;
CType type1;
@ -4336,6 +4354,14 @@ static int parse_btype(CType *type, AttributeDef *ad)
s = sym_find(tok);
if (!s || !(s->type.t & VT_TYPEDEF))
goto the_end;
n = tok, next();
if (tok == ':' && !in_generic) {
/* ignore if it's a label */
unget_tok(n);
goto the_end;
}
t &= ~(VT_BTYPE|VT_LONG);
u = t & ~(VT_CONSTANT | VT_VOLATILE), t ^= u;
type->t = (s->type.t & ~VT_TYPEDEF) | u;
@ -4345,7 +4371,6 @@ static int parse_btype(CType *type, AttributeDef *ad)
t = type->t;
/* get attributes from typedef */
sym_to_attr(ad, s);
next();
typespec_found = 1;
st = bt = -2;
break;
@ -5237,7 +5262,11 @@ ST_FUNC void unary(void)
AttributeDef ad_tmp;
int itmp;
CType cur_type;
in_generic++;
parse_btype(&cur_type, &ad_tmp);
in_generic--;
type_decl(&cur_type, &ad_tmp, &itmp, TYPE_ABSTRACT);
if (compare_types(&controlling_type, &cur_type, 0)) {
if (has_match) {
@ -5501,6 +5530,8 @@ special_math_val:
}
vset(&s->type, VT_LOCAL | VT_LVAL, addr);
}
if (s->f.func_noreturn)
CODE_OFF();
} else {
break;
}
@ -5603,86 +5634,50 @@ static void expr_or(void)
}
}
static int condition_3way(void);
static void expr_landor(void(*e_fn)(void), int e_op, int i)
{
int t = 0, cc = 1, f = 0, c;
for(;;) {
c = f ? i : condition_3way();
if (c < 0) {
save_regs(1), cc = 0;
} else if (c != i) {
nocode_wanted++, f = 1;
}
if (tok != e_op) {
if (cc || f) {
vpop();
vpushi(i ^ f);
gsym(t);
nocode_wanted -= f;
} else {
vseti(VT_JMP + i, gvtst(i, t));
}
break;
}
if (c < 0)
t = gvtst(i, t);
else
vpop();
next();
e_fn();
}
}
static void expr_land(void)
{
expr_or();
if (tok == TOK_LAND) {
int t = 0;
for(;;) {
if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
gen_cast_s(VT_BOOL);
if (vtop->c.i) {
vpop();
} else {
nocode_wanted++;
while (tok == TOK_LAND) {
next();
expr_or();
vpop();
}
nocode_wanted--;
if (t)
gsym(t);
gen_cast_s(VT_INT);
break;
}
} else {
if (!t)
save_regs(1);
t = gvtst(1, t);
}
if (tok != TOK_LAND) {
if (t)
vseti(VT_JMPI, t);
else
vpushi(1);
break;
}
next();
expr_or();
}
}
if (tok == TOK_LAND)
expr_landor(expr_or, TOK_LAND, 1);
}
static void expr_lor(void)
{
expr_land();
if (tok == TOK_LOR) {
int t = 0;
for(;;) {
if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
gen_cast_s(VT_BOOL);
if (!vtop->c.i) {
vpop();
} else {
nocode_wanted++;
while (tok == TOK_LOR) {
next();
expr_land();
vpop();
}
nocode_wanted--;
if (t)
gsym(t);
gen_cast_s(VT_INT);
break;
}
} else {
if (!t)
save_regs(1);
t = gvtst(0, t);
}
if (tok != TOK_LOR) {
if (t)
vseti(VT_JMP, t);
else
vpushi(0);
break;
}
next();
expr_land();
}
}
if (tok == TOK_LOR)
expr_landor(expr_land, TOK_LOR, 0);
}
/* Assuming vtop is a value used in a conditional context
@ -5706,15 +5701,25 @@ static void expr_cond(void)
int tt, u, r1, r2, rc, t1, t2, bt1, bt2, islv, c, g;
SValue sv;
CType type, type1, type2;
int ncw_prev;
expr_lor();
if (tok == '?') {
next();
c = condition_3way();
g = (tok == ':' && gnu_ext);
if (c < 0) {
tt = 0;
if (!g) {
if (c < 0) {
save_regs(1);
tt = gvtst(1, 0);
} else {
vpop();
}
} else if (c < 0) {
/* needed to avoid having different registers saved in
each branch */
rc = RC_INT;
if (is_float(vtop->type.t)) {
rc = RC_FLOAT;
#ifdef TCC_TARGET_X86_64
@ -5722,20 +5727,14 @@ static void expr_cond(void)
rc = RC_ST0;
}
#endif
} else
rc = RC_INT;
}
gv(rc);
save_regs(1);
if (g)
gv_dup();
tt = gvtst(1, 0);
} else {
if (!g)
vpop();
tt = 0;
gv_dup();
tt = gvtst(0, 0);
}
ncw_prev = nocode_wanted;
if (1) {
if (c == 0)
nocode_wanted++;
@ -5747,20 +5746,21 @@ static void expr_cond(void)
type1 = vtop->type;
sv = *vtop; /* save value to handle it later */
vtop--; /* no vpop so that FP stack is not flushed */
skip(':');
u = 0;
if (c < 0)
if (g) {
u = tt;
} else if (c < 0) {
u = gjmp(0);
gsym(tt);
gsym(tt);
} else
u = 0;
if (c == 0)
nocode_wanted--;
nocode_wanted = ncw_prev;
if (c == 1)
nocode_wanted++;
skip(':');
expr_cond();
if (c == 1)
nocode_wanted--;
if ((vtop->type.t & VT_BTYPE) == VT_FUNC)
mk_pointer(&vtop->type);
@ -5771,7 +5771,6 @@ static void expr_cond(void)
bt2 = t2 & VT_BTYPE;
type.ref = NULL;
/* cast operands to correct type according to ISOC rules */
if (bt1 == VT_VOID || bt2 == VT_VOID) {
type.t = VT_VOID; /* NOTE: as an extension, we accept void on only one side */
@ -5902,15 +5901,17 @@ static void expr_cond(void)
gaddrof();
}
if (c < 0 || islv) {
if (c < 0) {
r1 = gv(rc);
move_reg(r2, r1, type.t);
vtop->r = r2;
gsym(tt);
if (islv)
indir();
}
if (islv)
indir();
}
nocode_wanted = ncw_prev;
}
}
@ -5982,25 +5983,8 @@ ST_FUNC int expr_const(void)
return c;
}
/* return the label token if current token is a label, otherwise
return zero */
static int is_label(void)
{
int last_tok;
/* fast test first */
if (tok < TOK_UIDENT)
return 0;
/* no need to save tokc because tok is an identifier */
last_tok = tok;
next();
if (tok == ':') {
return last_tok;
} else {
unget_tok(last_tok);
return 0;
}
}
/* ------------------------------------------------------------------------- */
/* return from function */
#ifndef TCC_TARGET_ARM64
static void gfunc_return(CType *func_type)
@ -6135,75 +6119,97 @@ static void gcase(struct case_t **base, int len, int *bsym)
}
}
/* call 'func' for each __attribute__((cleanup(func))) */
static void block_cleanup(Sym *lcleanup, int lncleanups)
{
int jmp = 0;
Sym *g, **pg;
for (pg = &pending_gotos; (g = *pg) && g->c > lncleanups;) {
if (g->prev_tok->r & LABEL_FORWARD) {
Sym *pcl = g->next;
if (!jmp)
jmp = gjmp(0);
gsym(pcl->jnext);
try_call_scope_cleanup(lcleanup);
pcl->jnext = gjmp(0);
if (!lncleanups)
goto remove_pending;
g->c = lncleanups;
pg = &g->prev;
} else {
remove_pending:
*pg = g->prev;
sym_free(g);
}
}
gsym(jmp);
try_call_scope_cleanup(lcleanup);
current_cleanups = lcleanup;
ncleanups = lncleanups;
}
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);
}
}
static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
{
int a, b, c, d, cond;
int a, b, c, d, e, t;
Sym *s;
/* generate line number info */
if (tcc_state->do_debug)
tcc_debug_line(tcc_state);
if (is_expr) {
/* default return value is (void) */
vpushi(0);
vtop->type.t = VT_VOID;
}
if (tok == TOK_IF) {
/* if test */
int saved_nocode_wanted = nocode_wanted;
next();
t = tok, next();
if (t == TOK_IF) {
skip('(');
gexpr();
skip(')');
cond = condition_3way();
if (cond == 1)
a = 0, vpop();
else
a = gvtst(1, 0);
if (cond == 0)
nocode_wanted |= 0x20000000;
a = gvtst(1, 0);
block(bsym, bcl, csym, ccl, 0);
if (cond != 1)
nocode_wanted = saved_nocode_wanted;
if (tok == TOK_ELSE) {
next();
d = gjmp(0);
gsym(a);
if (cond == 1)
nocode_wanted |= 0x20000000;
next();
block(bsym, bcl, csym, ccl, 0);
gsym(d); /* patch else jmp */
if (cond != 0)
nocode_wanted = saved_nocode_wanted;
} else
} else {
gsym(a);
} else if (tok == TOK_WHILE) {
int saved_nocode_wanted;
nocode_wanted &= ~0x20000000;
next();
d = ind;
}
} else if (t == TOK_WHILE) {
d = gind();
vla_sp_restore();
skip('(');
gexpr();
skip(')');
a = gvtst(1, 0);
b = 0;
++local_scope;
saved_nocode_wanted = nocode_wanted;
block(&a, current_cleanups, &b, current_cleanups, 0);
nocode_wanted = saved_nocode_wanted;
--local_scope;
gjmp_addr(d);
gsym(a);
gsym_addr(b, d);
} else if (tok == '{') {
gsym(a);
} else if (t == '{') {
Sym *llabel, *lcleanup;
int block_vla_sp_loc = vla_sp_loc, saved_vlas_in_scope = vlas_in_scope;
int lncleanups = ncleanups;
next();
/* record local declaration stack position */
s = local_stack;
llabel = local_label_stack;
@ -6212,25 +6218,18 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
/* handle local labels declarations */
while (tok == TOK_LABEL) {
next();
for(;;) {
do {
next();
if (tok < TOK_UIDENT)
expect("label identifier");
label_push(&local_label_stack, tok, LABEL_DECLARED);
next();
if (tok == ',') {
next();
} else {
skip(';');
break;
}
}
} while (tok == ',');
skip(';');
}
while (tok != '}') {
if ((a = is_label()))
unget_tok(a);
else
decl(VT_LOCAL);
decl(VT_LOCAL);
if (tok != '}') {
if (is_expr)
vpop();
@ -6238,39 +6237,12 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
}
}
if (current_cleanups != lcleanup) {
int jmp = 0;
Sym *g, **pg;
if (current_cleanups != lcleanup)
block_cleanup(lcleanup, lncleanups);
for (pg = &pending_gotos; (g = *pg) && g->c > lncleanups;)
if (g->prev_tok->r & LABEL_FORWARD) {
Sym *pcl = g->next;
if (!jmp)
jmp = gjmp(0);
gsym(pcl->jnext);
try_call_scope_cleanup(lcleanup);
pcl->jnext = gjmp(0);
if (!lncleanups)
goto remove_pending;
g->c = lncleanups;
pg = &g->prev;
} else {
remove_pending:
*pg = g->prev;
sym_free(g);
}
gsym(jmp);
if (!nocode_wanted) {
try_call_scope_cleanup(lcleanup);
}
}
current_cleanups = lcleanup;
ncleanups = lncleanups;
/* pop locally defined labels */
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),
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
@ -6278,6 +6250,8 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
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 */
@ -6287,52 +6261,49 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
}
vlas_in_scope = saved_vlas_in_scope;
if (0 == --local_scope && !nocode_wanted)
check_func_return();
next();
} else if (tok == TOK_RETURN) {
next();
if (tok != ';') {
gexpr();
gen_assign_cast(&func_vt);
try_call_scope_cleanup(NULL);
if ((func_vt.t & VT_BTYPE) == VT_VOID)
vtop--;
else
gfunc_return(&func_vt);
} else {
try_call_scope_cleanup(NULL);
}
} else if (t == TOK_RETURN) {
a = tok != ';';
b = (func_vt.t & VT_BTYPE) != VT_VOID;
if (a)
gexpr(), gen_assign_cast(&func_vt);
try_call_scope_cleanup(NULL);
if (a && b)
gfunc_return(&func_vt);
else if (a)
vtop--;
else if (b)
tcc_warning("'return' with no value.");
skip(';');
/* jump unless last stmt in top-level block */
if (tok != '}' || local_scope != 1)
rsym = gjmp(rsym);
nocode_wanted |= 0x20000000;
} else if (tok == TOK_BREAK) {
CODE_OFF();
} else if (t == TOK_BREAK) {
/* compute jump */
if (!bsym)
tcc_error("cannot break");
try_call_scope_cleanup(bcl);
*bsym = gjmp(*bsym);
next();
skip(';');
nocode_wanted |= 0x20000000;
} else if (tok == TOK_CONTINUE) {
} else if (t == TOK_CONTINUE) {
/* compute jump */
if (!csym)
tcc_error("cannot continue");
try_call_scope_cleanup(ccl);
vla_sp_restore_root();
*csym = gjmp(*csym);
next();
skip(';');
nocode_wanted |= 0x20000000;
} else if (tok == TOK_FOR) {
int e;
int saved_nocode_wanted;
} else if (t == TOK_FOR) {
Sym *lcleanup = current_cleanups;
int lncleanups = ncleanups;
nocode_wanted &= ~0x20000000;
next();
skip('(');
s = local_stack;
++local_scope;
@ -6345,11 +6316,9 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
}
}
skip(';');
d = ind;
c = ind;
a = b = 0;
c = d = gind();
vla_sp_restore();
a = 0;
b = 0;
if (tok != ';') {
gexpr();
a = gvtst(1, 0);
@ -6357,55 +6326,43 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
skip(';');
if (tok != ')') {
e = gjmp(0);
c = ind;
d = gind();
vla_sp_restore();
gexpr();
vpop();
gjmp_addr(d);
gjmp_addr(c);
gsym(e);
}
skip(')');
saved_nocode_wanted = nocode_wanted;
block(&a, current_cleanups, &b, current_cleanups, 0);
nocode_wanted = saved_nocode_wanted;
gjmp_addr(c);
gjmp_addr(d);
gsym_addr(b, d);
gsym(a);
gsym_addr(b, c);
--local_scope;
try_call_scope_cleanup(lcleanup);
ncleanups = lncleanups;
current_cleanups = lcleanup;
sym_pop(&local_stack, s, 0);
} else
if (tok == TOK_DO) {
int saved_nocode_wanted;
nocode_wanted &= ~0x20000000;
next();
a = 0;
b = 0;
d = ind;
} else if (t == TOK_DO) {
a = b = 0;
d = gind();
vla_sp_restore();
saved_nocode_wanted = nocode_wanted;
block(&a, current_cleanups, &b, current_cleanups, 0);
gsym(b);
skip(TOK_WHILE);
skip('(');
gsym(b);
if (b)
nocode_wanted = saved_nocode_wanted;
gexpr();
skip(')');
skip(';');
c = gvtst(0, 0);
gsym_addr(c, d);
nocode_wanted = saved_nocode_wanted;
skip(')');
gsym(a);
skip(';');
} else
if (tok == TOK_SWITCH) {
} else if (t == TOK_SWITCH) {
struct switch_t *saved, sw;
int saved_nocode_wanted = nocode_wanted;
SValue switchval;
next();
skip('(');
gexpr();
skip(')');
@ -6416,7 +6373,6 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
saved = cur_switch;
cur_switch = &sw;
block(&a, current_cleanups, csym, ccl, 0);
nocode_wanted = saved_nocode_wanted;
a = gjmp(a); /* add implicit break */
/* case lookup */
gsym(b);
@ -6437,13 +6393,11 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
cur_switch = saved;
/* break label */
gsym(a);
} else
if (tok == TOK_CASE) {
} else if (t == TOK_CASE) {
struct case_t *cr = tcc_malloc(sizeof(struct case_t));
if (!cur_switch)
expect("switch");
nocode_wanted &= ~0x20000000;
next();
cr->v1 = cr->v2 = expr_const64();
if (gnu_ext && tok == TOK_DOTS) {
next();
@ -6451,25 +6405,23 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
if (cr->v2 < cr->v1)
tcc_warning("empty case range");
}
cr->sym = ind;
cr->sym = gind();
dynarray_add(&cur_switch->p, &cur_switch->n, cr);
skip(':');
is_expr = 0;
goto block_after_label;
} else
if (tok == TOK_DEFAULT) {
next();
skip(':');
} else if (t == TOK_DEFAULT) {
if (!cur_switch)
expect("switch");
if (cur_switch->def_sym)
tcc_error("too many 'default'");
cur_switch->def_sym = ind;
cur_switch->def_sym = gind();
skip(':');
is_expr = 0;
goto block_after_label;
} else
if (tok == TOK_GOTO) {
next();
} else if (t == TOK_GOTO) {
if (tok == '*' && gnu_ext) {
/* computed goto */
next();
@ -6500,18 +6452,20 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
gjmp_addr(s->jnext);
}
next();
} else {
} else {
expect("label identifier");
}
skip(';');
} else if (tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3) {
} else if (t == TOK_ASM1 || t == TOK_ASM2 || t == TOK_ASM3) {
asm_instr();
} else {
b = is_label();
if (b) {
if (tok == ':' && t >= TOK_UIDENT) {
/* label case */
next();
s = label_find(b);
s = label_find(t);
if (s) {
if (s->r == LABEL_DEFINED)
tcc_error("duplicate label '%s'", get_tok_str(s->v, NULL));
@ -6524,14 +6478,14 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
} else
gsym(s->jnext);
} else {
s = label_push(&global_label_stack, b, LABEL_DEFINED);
s = label_push(&global_label_stack, t, LABEL_DEFINED);
}
s->jnext = ind;
s->cleanupstate = current_cleanups;
s->jnext = gind();
s->cleanupstate = current_cleanups;
block_after_label:
vla_sp_restore();
/* we accept this, but it is a mistake */
block_after_label:
nocode_wanted &= ~0x20000000;
if (tok == '}') {
tcc_warning("deprecated use of label at end of compound statement");
} else {
@ -6539,9 +6493,11 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
vpop();
block(bsym, bcl, csym, ccl, is_expr);
}
} else {
/* expression case */
if (tok != ';') {
if (t != ';') {
unget_tok(t);
if (is_expr) {
vpop();
gexpr();
@ -6549,8 +6505,8 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
gexpr();
vpop();
}
skip(';');
}
skip(';');
}
}
}
@ -6661,10 +6617,17 @@ static int decl_designator(CType *type, Section *sec, unsigned long c,
elem_size = 0;
nb_elems = 1;
if (flags & DIF_HAVE_ELEM)
goto no_designator;
if (gnu_ext && (l = is_label()) != 0)
goto struct_field;
if (gnu_ext && tok >= TOK_UIDENT) {
l = tok, next();
if (tok == ':')
goto struct_field;
unget_tok(l);
}
/* NOTE: we only support ranges for last designator */
while (nb_elems == 1 && (tok == '[' || tok == '.')) {
if (tok == '[') {
@ -7413,19 +7376,10 @@ static void gen_function(Sym *sym)
gfunc_prolog(&sym->type);
reset_local_scope();
rsym = 0;
clear_temp_local_var_list();
block(NULL, NULL, NULL, NULL, 0);
if (!(nocode_wanted & 0x20000000)
&& ((func_vt.t & VT_BTYPE) == VT_INT)
&& !strcmp (funcname, "main"))
{
nocode_wanted = 0;
vpushi(0);
gen_assign_cast(&func_vt);
gfunc_return(&func_vt);
}
nocode_wanted = 0;
clear_temp_local_var_list();
block(NULL, NULL, NULL, NULL, 0);
gsym(rsym);
nocode_wanted = 0;
gfunc_epilog();
cur_text_section->data_offset = ind;
label_pop(&global_label_stack, NULL, 0);
@ -7746,3 +7700,6 @@ static void decl(int l)
}
/* ------------------------------------------------------------------------- */
#undef gjmp_addr
#undef gjmp
/* ------------------------------------------------------------------------- */

View File

@ -3527,6 +3527,9 @@ no_subst:
/* return next token with macro substitution */
ST_FUNC void next(void)
{
/* generate line number info */
if (tcc_state->do_debug)
tcc_debug_line(tcc_state);
redo:
if (parse_flags & PARSE_FLAG_SPACES)
next_nomacro_spc();

View File

@ -209,6 +209,7 @@ int test16()
printf("alloca: %s\n", strcpy(alloca(strlen(demo)+1),demo) );
fprintf(stderr, "%s end\n", __FUNCTION__);
return 0;
}
/* error */
@ -227,6 +228,7 @@ int test17()
printf("alloca: %s\n", strcpy(alloca(strlen(demo)),demo) );
fprintf(stderr, "%s end\n", __FUNCTION__);
return 0;
}
int (*table_test[])(void) = {

View File

@ -179,7 +179,7 @@ static int onetwothree = 123;
#ifdef __TINYC__
/* We try to handle this syntax. Make at least sure it doesn't segfault. */
char invalid_function_def()[] {}
char invalid_function_def()[] {return 0;}
#endif
#define __INT64_C(c) c ## LL
@ -572,6 +572,7 @@ void goto_test()
printf("goto:\n");
i = 0;
/* This needs to parse as label, not as start of decl. */
typedef_and_label x;
typedef_and_label:
s_loop:
if (i >= 10)
@ -3767,6 +3768,7 @@ int fcompare (double a, double b, int code)
case 4: return a > b;
case 5: return a <= b;
}
return 0;
}
void math_cmp_test(void)

View File

@ -51,6 +51,7 @@ _Bool chk(unsigned long addr, unsigned long limit, unsigned long size)
only with certain internal checking added that's not committed). */
if (0)
ret = 0 != (!!(addr > limit - size));
return 0;
}
int main()

View File

@ -45,6 +45,7 @@ int convert_like_real (tree convs)
break;
};
printf("unsigned enum bit-fields broken\n");
return 0;
}
int main()

View File

@ -41,7 +41,7 @@
#define __MSVCRT__ 1
#undef _MSVCRT_
#define __MINGW_IMPORT extern __declspec(dllimport)
#define __MINGW_ATTRIB_NORETURN
#define __MINGW_ATTRIB_NORETURN __declspec(noreturn)
#define __MINGW_ATTRIB_CONST
#define __MINGW_ATTRIB_DEPRECATED
#define __MINGW_ATTRIB_MALLOC
@ -138,7 +138,7 @@ typedef struct localeinfo_struct _locale_tstruct,*_locale_t;
/* for winapi */
#define _ANONYMOUS_UNION
#define _ANONYMOUS_STRUCT
#define DECLSPEC_NORETURN
#define DECLSPEC_NORETURN __declspec(noreturn)
#define DECLARE_STDCALL_P(type) __stdcall type
#define NOSERVICE 1
#define NOMCX 1

View File

@ -211,12 +211,6 @@ ST_FUNC void gsym_addr(int t, int a)
}
}
void gsym(int t)
{
gsym_addr(t, ind);
}
static int is64_type(int t)
{
return ((t & VT_BTYPE) == VT_PTR ||