mirror of
https://github.com/mirror/tinycc.git
synced 2024-12-28 04:00:06 +08:00
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:
parent
8569048031
commit
1b57560502
@ -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)
|
||||
{
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -60,6 +60,7 @@ void *__va_arg(__va_list_struct *ap,
|
||||
|
||||
default: /* should never happen */
|
||||
abort();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
2
tcc.h
2
tcc.h
@ -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 */
|
||||
};
|
||||
|
||||
|
4
tccasm.c
4
tccasm.c
@ -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
539
tccgen.c
@ -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
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
3
tccpp.c
3
tccpp.c
@ -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();
|
||||
|
@ -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) = {
|
||||
|
@ -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)
|
||||
|
@ -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()
|
||||
|
@ -45,6 +45,7 @@ int convert_like_real (tree convs)
|
||||
break;
|
||||
};
|
||||
printf("unsigned enum bit-fields broken\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main()
|
||||
|
@ -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
|
||||
|
@ -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 ||
|
||||
|
Loading…
Reference in New Issue
Block a user