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
|
#ifdef TCC_ARM_VFP
|
||||||
static uint32_t vfpr(int r)
|
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)
|
static int arm64_type_size(int t)
|
||||||
{
|
{
|
||||||
switch (t & VT_BTYPE) {
|
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,
|
// these are regs that tcc doesn't really know about,
|
||||||
// but assign them unique values so the mapping routines
|
// but assign them unique values so the mapping routines
|
||||||
// can distinguish them
|
// 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 */
|
/* instruction + 4 bytes data. Return the address of the data */
|
||||||
static int oad(int c, int s)
|
static int oad(int c, int s)
|
||||||
{
|
{
|
||||||
|
@ -60,6 +60,7 @@ void *__va_arg(__va_list_struct *ap,
|
|||||||
|
|
||||||
default: /* should never happen */
|
default: /* should never happen */
|
||||||
abort();
|
abort();
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
2
tcc.h
2
tcc.h
@ -453,6 +453,8 @@ struct FuncAttr {
|
|||||||
unsigned
|
unsigned
|
||||||
func_call : 3, /* calling convention (0..5), see below */
|
func_call : 3, /* calling convention (0..5), see below */
|
||||||
func_type : 2, /* FUNC_OLD/NEW/ELLIPSIS */
|
func_type : 2, /* FUNC_OLD/NEW/ELLIPSIS */
|
||||||
|
func_noreturn : 1, /* attribute((noreturn)) */
|
||||||
|
xxxx : 2,
|
||||||
func_args : 8; /* PE __stdcall args */
|
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();
|
next();
|
||||||
if (tok == TOK_EOF)
|
if (tok == TOK_EOF)
|
||||||
break;
|
break;
|
||||||
/* generate line number info */
|
|
||||||
if (global && s1->do_debug)
|
|
||||||
tcc_debug_line(s1);
|
|
||||||
parse_flags |= PARSE_FLAG_LINEFEED; /* XXX: suppress that hack */
|
parse_flags |= PARSE_FLAG_LINEFEED; /* XXX: suppress that hack */
|
||||||
redo:
|
redo:
|
||||||
if (tok == '#') {
|
if (tok == '#') {
|
||||||
@ -1148,7 +1145,6 @@ ST_FUNC void asm_instr(void)
|
|||||||
uint8_t clobber_regs[NB_ASM_REGS];
|
uint8_t clobber_regs[NB_ASM_REGS];
|
||||||
Section *sec;
|
Section *sec;
|
||||||
|
|
||||||
next();
|
|
||||||
/* since we always generate the asm() instruction, we can ignore
|
/* since we always generate the asm() instruction, we can ignore
|
||||||
volatile */
|
volatile */
|
||||||
if (tok == TOK_VOLATILE1 || tok == TOK_VOLATILE2 || tok == TOK_VOLATILE3) {
|
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 local_scope;
|
||||||
static int in_sizeof;
|
static int in_sizeof;
|
||||||
|
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 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 */
|
ST_DATA int nocode_wanted; /* no code generation wanted */
|
||||||
#define NODATA_WANTED (nocode_wanted > 0) /* no static data output wanted either */
|
#define NODATA_WANTED (nocode_wanted > 0) /* no static data output wanted either */
|
||||||
#define STATIC_DATA_WANTED (nocode_wanted & 0xC0000000) /* only static data output */
|
#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 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 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) */
|
ST_DATA int func_var; /* true if current function is variadic (used by return instruction) */
|
||||||
@ -3544,8 +3563,7 @@ redo:
|
|||||||
break;
|
break;
|
||||||
case TOK_NORETURN1:
|
case TOK_NORETURN1:
|
||||||
case TOK_NORETURN2:
|
case TOK_NORETURN2:
|
||||||
/* currently, no need to handle it because tcc does not
|
ad->f.func_noreturn = 1;
|
||||||
track unused objects */
|
|
||||||
break;
|
break;
|
||||||
case TOK_CDECL1:
|
case TOK_CDECL1:
|
||||||
case TOK_CDECL2:
|
case TOK_CDECL2:
|
||||||
@ -4129,7 +4147,7 @@ static void parse_btype_qualify(CType *type, int qualifiers)
|
|||||||
*/
|
*/
|
||||||
static int parse_btype(CType *type, AttributeDef *ad)
|
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;
|
Sym *s;
|
||||||
CType type1;
|
CType type1;
|
||||||
|
|
||||||
@ -4336,6 +4354,14 @@ static int parse_btype(CType *type, AttributeDef *ad)
|
|||||||
s = sym_find(tok);
|
s = sym_find(tok);
|
||||||
if (!s || !(s->type.t & VT_TYPEDEF))
|
if (!s || !(s->type.t & VT_TYPEDEF))
|
||||||
goto the_end;
|
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);
|
t &= ~(VT_BTYPE|VT_LONG);
|
||||||
u = t & ~(VT_CONSTANT | VT_VOLATILE), t ^= u;
|
u = t & ~(VT_CONSTANT | VT_VOLATILE), t ^= u;
|
||||||
type->t = (s->type.t & ~VT_TYPEDEF) | u;
|
type->t = (s->type.t & ~VT_TYPEDEF) | u;
|
||||||
@ -4345,7 +4371,6 @@ static int parse_btype(CType *type, AttributeDef *ad)
|
|||||||
t = type->t;
|
t = type->t;
|
||||||
/* get attributes from typedef */
|
/* get attributes from typedef */
|
||||||
sym_to_attr(ad, s);
|
sym_to_attr(ad, s);
|
||||||
next();
|
|
||||||
typespec_found = 1;
|
typespec_found = 1;
|
||||||
st = bt = -2;
|
st = bt = -2;
|
||||||
break;
|
break;
|
||||||
@ -5237,7 +5262,11 @@ ST_FUNC void unary(void)
|
|||||||
AttributeDef ad_tmp;
|
AttributeDef ad_tmp;
|
||||||
int itmp;
|
int itmp;
|
||||||
CType cur_type;
|
CType cur_type;
|
||||||
|
|
||||||
|
in_generic++;
|
||||||
parse_btype(&cur_type, &ad_tmp);
|
parse_btype(&cur_type, &ad_tmp);
|
||||||
|
in_generic--;
|
||||||
|
|
||||||
type_decl(&cur_type, &ad_tmp, &itmp, TYPE_ABSTRACT);
|
type_decl(&cur_type, &ad_tmp, &itmp, TYPE_ABSTRACT);
|
||||||
if (compare_types(&controlling_type, &cur_type, 0)) {
|
if (compare_types(&controlling_type, &cur_type, 0)) {
|
||||||
if (has_match) {
|
if (has_match) {
|
||||||
@ -5501,6 +5530,8 @@ special_math_val:
|
|||||||
}
|
}
|
||||||
vset(&s->type, VT_LOCAL | VT_LVAL, addr);
|
vset(&s->type, VT_LOCAL | VT_LVAL, addr);
|
||||||
}
|
}
|
||||||
|
if (s->f.func_noreturn)
|
||||||
|
CODE_OFF();
|
||||||
} else {
|
} else {
|
||||||
break;
|
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)
|
static void expr_land(void)
|
||||||
{
|
{
|
||||||
expr_or();
|
expr_or();
|
||||||
if (tok == TOK_LAND) {
|
if (tok == TOK_LAND)
|
||||||
int t = 0;
|
expr_landor(expr_or, TOK_LAND, 1);
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void expr_lor(void)
|
static void expr_lor(void)
|
||||||
{
|
{
|
||||||
expr_land();
|
expr_land();
|
||||||
if (tok == TOK_LOR) {
|
if (tok == TOK_LOR)
|
||||||
int t = 0;
|
expr_landor(expr_land, TOK_LOR, 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Assuming vtop is a value used in a conditional context
|
/* 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;
|
int tt, u, r1, r2, rc, t1, t2, bt1, bt2, islv, c, g;
|
||||||
SValue sv;
|
SValue sv;
|
||||||
CType type, type1, type2;
|
CType type, type1, type2;
|
||||||
|
int ncw_prev;
|
||||||
|
|
||||||
expr_lor();
|
expr_lor();
|
||||||
if (tok == '?') {
|
if (tok == '?') {
|
||||||
next();
|
next();
|
||||||
c = condition_3way();
|
c = condition_3way();
|
||||||
g = (tok == ':' && gnu_ext);
|
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
|
/* needed to avoid having different registers saved in
|
||||||
each branch */
|
each branch */
|
||||||
|
rc = RC_INT;
|
||||||
if (is_float(vtop->type.t)) {
|
if (is_float(vtop->type.t)) {
|
||||||
rc = RC_FLOAT;
|
rc = RC_FLOAT;
|
||||||
#ifdef TCC_TARGET_X86_64
|
#ifdef TCC_TARGET_X86_64
|
||||||
@ -5722,20 +5727,14 @@ static void expr_cond(void)
|
|||||||
rc = RC_ST0;
|
rc = RC_ST0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
} else
|
}
|
||||||
rc = RC_INT;
|
|
||||||
gv(rc);
|
gv(rc);
|
||||||
save_regs(1);
|
save_regs(1);
|
||||||
if (g)
|
gv_dup();
|
||||||
gv_dup();
|
tt = gvtst(0, 0);
|
||||||
tt = gvtst(1, 0);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
if (!g)
|
|
||||||
vpop();
|
|
||||||
tt = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ncw_prev = nocode_wanted;
|
||||||
if (1) {
|
if (1) {
|
||||||
if (c == 0)
|
if (c == 0)
|
||||||
nocode_wanted++;
|
nocode_wanted++;
|
||||||
@ -5747,20 +5746,21 @@ static void expr_cond(void)
|
|||||||
type1 = vtop->type;
|
type1 = vtop->type;
|
||||||
sv = *vtop; /* save value to handle it later */
|
sv = *vtop; /* save value to handle it later */
|
||||||
vtop--; /* no vpop so that FP stack is not flushed */
|
vtop--; /* no vpop so that FP stack is not flushed */
|
||||||
skip(':');
|
|
||||||
|
|
||||||
u = 0;
|
if (g) {
|
||||||
if (c < 0)
|
u = tt;
|
||||||
|
} else if (c < 0) {
|
||||||
u = gjmp(0);
|
u = gjmp(0);
|
||||||
gsym(tt);
|
gsym(tt);
|
||||||
|
} else
|
||||||
|
u = 0;
|
||||||
|
|
||||||
if (c == 0)
|
nocode_wanted = ncw_prev;
|
||||||
nocode_wanted--;
|
|
||||||
if (c == 1)
|
if (c == 1)
|
||||||
nocode_wanted++;
|
nocode_wanted++;
|
||||||
|
skip(':');
|
||||||
expr_cond();
|
expr_cond();
|
||||||
if (c == 1)
|
|
||||||
nocode_wanted--;
|
|
||||||
|
|
||||||
if ((vtop->type.t & VT_BTYPE) == VT_FUNC)
|
if ((vtop->type.t & VT_BTYPE) == VT_FUNC)
|
||||||
mk_pointer(&vtop->type);
|
mk_pointer(&vtop->type);
|
||||||
@ -5771,7 +5771,6 @@ static void expr_cond(void)
|
|||||||
bt2 = t2 & VT_BTYPE;
|
bt2 = t2 & VT_BTYPE;
|
||||||
type.ref = NULL;
|
type.ref = NULL;
|
||||||
|
|
||||||
|
|
||||||
/* cast operands to correct type according to ISOC rules */
|
/* cast operands to correct type according to ISOC rules */
|
||||||
if (bt1 == VT_VOID || bt2 == VT_VOID) {
|
if (bt1 == VT_VOID || bt2 == VT_VOID) {
|
||||||
type.t = VT_VOID; /* NOTE: as an extension, we accept void on only one side */
|
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();
|
gaddrof();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c < 0 || islv) {
|
if (c < 0) {
|
||||||
r1 = gv(rc);
|
r1 = gv(rc);
|
||||||
move_reg(r2, r1, type.t);
|
move_reg(r2, r1, type.t);
|
||||||
vtop->r = r2;
|
vtop->r = r2;
|
||||||
gsym(tt);
|
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 c;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* return the label token if current token is a label, otherwise
|
/* ------------------------------------------------------------------------- */
|
||||||
return zero */
|
/* return from function */
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef TCC_TARGET_ARM64
|
#ifndef TCC_TARGET_ARM64
|
||||||
static void gfunc_return(CType *func_type)
|
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)
|
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;
|
Sym *s;
|
||||||
|
|
||||||
/* generate line number info */
|
|
||||||
if (tcc_state->do_debug)
|
|
||||||
tcc_debug_line(tcc_state);
|
|
||||||
|
|
||||||
if (is_expr) {
|
if (is_expr) {
|
||||||
/* default return value is (void) */
|
/* default return value is (void) */
|
||||||
vpushi(0);
|
vpushi(0);
|
||||||
vtop->type.t = VT_VOID;
|
vtop->type.t = VT_VOID;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tok == TOK_IF) {
|
t = tok, next();
|
||||||
/* if test */
|
|
||||||
int saved_nocode_wanted = nocode_wanted;
|
if (t == TOK_IF) {
|
||||||
next();
|
|
||||||
skip('(');
|
skip('(');
|
||||||
gexpr();
|
gexpr();
|
||||||
skip(')');
|
skip(')');
|
||||||
cond = condition_3way();
|
a = gvtst(1, 0);
|
||||||
if (cond == 1)
|
|
||||||
a = 0, vpop();
|
|
||||||
else
|
|
||||||
a = gvtst(1, 0);
|
|
||||||
if (cond == 0)
|
|
||||||
nocode_wanted |= 0x20000000;
|
|
||||||
block(bsym, bcl, csym, ccl, 0);
|
block(bsym, bcl, csym, ccl, 0);
|
||||||
if (cond != 1)
|
|
||||||
nocode_wanted = saved_nocode_wanted;
|
|
||||||
if (tok == TOK_ELSE) {
|
if (tok == TOK_ELSE) {
|
||||||
next();
|
|
||||||
d = gjmp(0);
|
d = gjmp(0);
|
||||||
gsym(a);
|
gsym(a);
|
||||||
if (cond == 1)
|
next();
|
||||||
nocode_wanted |= 0x20000000;
|
|
||||||
block(bsym, bcl, csym, ccl, 0);
|
block(bsym, bcl, csym, ccl, 0);
|
||||||
gsym(d); /* patch else jmp */
|
gsym(d); /* patch else jmp */
|
||||||
if (cond != 0)
|
} else {
|
||||||
nocode_wanted = saved_nocode_wanted;
|
|
||||||
} else
|
|
||||||
gsym(a);
|
gsym(a);
|
||||||
} else if (tok == TOK_WHILE) {
|
}
|
||||||
int saved_nocode_wanted;
|
|
||||||
nocode_wanted &= ~0x20000000;
|
} else if (t == TOK_WHILE) {
|
||||||
next();
|
d = gind();
|
||||||
d = ind;
|
|
||||||
vla_sp_restore();
|
vla_sp_restore();
|
||||||
skip('(');
|
skip('(');
|
||||||
gexpr();
|
gexpr();
|
||||||
skip(')');
|
skip(')');
|
||||||
a = gvtst(1, 0);
|
a = gvtst(1, 0);
|
||||||
b = 0;
|
b = 0;
|
||||||
++local_scope;
|
|
||||||
saved_nocode_wanted = nocode_wanted;
|
|
||||||
block(&a, current_cleanups, &b, current_cleanups, 0);
|
block(&a, current_cleanups, &b, current_cleanups, 0);
|
||||||
nocode_wanted = saved_nocode_wanted;
|
|
||||||
--local_scope;
|
|
||||||
gjmp_addr(d);
|
gjmp_addr(d);
|
||||||
gsym(a);
|
|
||||||
gsym_addr(b, d);
|
gsym_addr(b, d);
|
||||||
} else if (tok == '{') {
|
gsym(a);
|
||||||
|
|
||||||
|
} else if (t == '{') {
|
||||||
Sym *llabel, *lcleanup;
|
Sym *llabel, *lcleanup;
|
||||||
int block_vla_sp_loc = vla_sp_loc, saved_vlas_in_scope = vlas_in_scope;
|
int block_vla_sp_loc = vla_sp_loc, saved_vlas_in_scope = vlas_in_scope;
|
||||||
int lncleanups = ncleanups;
|
int lncleanups = ncleanups;
|
||||||
|
|
||||||
next();
|
|
||||||
/* record local declaration stack position */
|
/* record local declaration stack position */
|
||||||
s = local_stack;
|
s = local_stack;
|
||||||
llabel = local_label_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 */
|
/* handle local labels declarations */
|
||||||
while (tok == TOK_LABEL) {
|
while (tok == TOK_LABEL) {
|
||||||
next();
|
do {
|
||||||
for(;;) {
|
next();
|
||||||
if (tok < TOK_UIDENT)
|
if (tok < TOK_UIDENT)
|
||||||
expect("label identifier");
|
expect("label identifier");
|
||||||
label_push(&local_label_stack, tok, LABEL_DECLARED);
|
label_push(&local_label_stack, tok, LABEL_DECLARED);
|
||||||
next();
|
next();
|
||||||
if (tok == ',') {
|
} while (tok == ',');
|
||||||
next();
|
skip(';');
|
||||||
} else {
|
|
||||||
skip(';');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while (tok != '}') {
|
while (tok != '}') {
|
||||||
if ((a = is_label()))
|
decl(VT_LOCAL);
|
||||||
unget_tok(a);
|
|
||||||
else
|
|
||||||
decl(VT_LOCAL);
|
|
||||||
if (tok != '}') {
|
if (tok != '}') {
|
||||||
if (is_expr)
|
if (is_expr)
|
||||||
vpop();
|
vpop();
|
||||||
@ -6238,39 +6237,12 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (current_cleanups != lcleanup) {
|
if (current_cleanups != lcleanup)
|
||||||
int jmp = 0;
|
block_cleanup(lcleanup, lncleanups);
|
||||||
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);
|
|
||||||
if (!nocode_wanted) {
|
|
||||||
try_call_scope_cleanup(lcleanup);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
current_cleanups = lcleanup;
|
|
||||||
ncleanups = lncleanups;
|
|
||||||
/* pop locally defined labels */
|
/* pop locally defined labels */
|
||||||
label_pop(&local_label_stack, llabel, is_expr);
|
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),
|
/* In the is_expr case (a statement expression is finished here),
|
||||||
vtop might refer to symbols on the local_stack. Either via the
|
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
|
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
|
any symbols in that case; some upper level call to block() will
|
||||||
do that. We do have to remove such symbols from the lookup
|
do that. We do have to remove such symbols from the lookup
|
||||||
tables, though. sym_pop will do that. */
|
tables, though. sym_pop will do that. */
|
||||||
|
|
||||||
|
/* pop locally defined symbols */
|
||||||
sym_pop(&local_stack, s, is_expr);
|
sym_pop(&local_stack, s, is_expr);
|
||||||
|
|
||||||
/* Pop VLA frames and restore stack pointer if required */
|
/* 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;
|
vlas_in_scope = saved_vlas_in_scope;
|
||||||
|
|
||||||
|
if (0 == --local_scope && !nocode_wanted)
|
||||||
|
check_func_return();
|
||||||
next();
|
next();
|
||||||
} else if (tok == TOK_RETURN) {
|
|
||||||
next();
|
} else if (t == TOK_RETURN) {
|
||||||
if (tok != ';') {
|
a = tok != ';';
|
||||||
gexpr();
|
b = (func_vt.t & VT_BTYPE) != VT_VOID;
|
||||||
gen_assign_cast(&func_vt);
|
if (a)
|
||||||
try_call_scope_cleanup(NULL);
|
gexpr(), gen_assign_cast(&func_vt);
|
||||||
if ((func_vt.t & VT_BTYPE) == VT_VOID)
|
try_call_scope_cleanup(NULL);
|
||||||
vtop--;
|
if (a && b)
|
||||||
else
|
gfunc_return(&func_vt);
|
||||||
gfunc_return(&func_vt);
|
else if (a)
|
||||||
} else {
|
vtop--;
|
||||||
try_call_scope_cleanup(NULL);
|
else if (b)
|
||||||
}
|
tcc_warning("'return' with no value.");
|
||||||
skip(';');
|
skip(';');
|
||||||
/* jump unless last stmt in top-level block */
|
/* jump unless last stmt in top-level block */
|
||||||
if (tok != '}' || local_scope != 1)
|
if (tok != '}' || local_scope != 1)
|
||||||
rsym = gjmp(rsym);
|
rsym = gjmp(rsym);
|
||||||
nocode_wanted |= 0x20000000;
|
CODE_OFF();
|
||||||
} else if (tok == TOK_BREAK) {
|
|
||||||
|
} else if (t == TOK_BREAK) {
|
||||||
/* compute jump */
|
/* compute jump */
|
||||||
if (!bsym)
|
if (!bsym)
|
||||||
tcc_error("cannot break");
|
tcc_error("cannot break");
|
||||||
try_call_scope_cleanup(bcl);
|
try_call_scope_cleanup(bcl);
|
||||||
*bsym = gjmp(*bsym);
|
*bsym = gjmp(*bsym);
|
||||||
next();
|
|
||||||
skip(';');
|
skip(';');
|
||||||
nocode_wanted |= 0x20000000;
|
|
||||||
} else if (tok == TOK_CONTINUE) {
|
} else if (t == TOK_CONTINUE) {
|
||||||
/* compute jump */
|
/* compute jump */
|
||||||
if (!csym)
|
if (!csym)
|
||||||
tcc_error("cannot continue");
|
tcc_error("cannot continue");
|
||||||
try_call_scope_cleanup(ccl);
|
try_call_scope_cleanup(ccl);
|
||||||
vla_sp_restore_root();
|
vla_sp_restore_root();
|
||||||
*csym = gjmp(*csym);
|
*csym = gjmp(*csym);
|
||||||
next();
|
|
||||||
skip(';');
|
skip(';');
|
||||||
nocode_wanted |= 0x20000000;
|
|
||||||
} else if (tok == TOK_FOR) {
|
} else if (t == TOK_FOR) {
|
||||||
int e;
|
|
||||||
int saved_nocode_wanted;
|
|
||||||
Sym *lcleanup = current_cleanups;
|
Sym *lcleanup = current_cleanups;
|
||||||
int lncleanups = ncleanups;
|
int lncleanups = ncleanups;
|
||||||
|
|
||||||
nocode_wanted &= ~0x20000000;
|
|
||||||
next();
|
|
||||||
skip('(');
|
skip('(');
|
||||||
s = local_stack;
|
s = local_stack;
|
||||||
++local_scope;
|
++local_scope;
|
||||||
@ -6345,11 +6316,9 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
skip(';');
|
skip(';');
|
||||||
d = ind;
|
a = b = 0;
|
||||||
c = ind;
|
c = d = gind();
|
||||||
vla_sp_restore();
|
vla_sp_restore();
|
||||||
a = 0;
|
|
||||||
b = 0;
|
|
||||||
if (tok != ';') {
|
if (tok != ';') {
|
||||||
gexpr();
|
gexpr();
|
||||||
a = gvtst(1, 0);
|
a = gvtst(1, 0);
|
||||||
@ -6357,55 +6326,43 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
|
|||||||
skip(';');
|
skip(';');
|
||||||
if (tok != ')') {
|
if (tok != ')') {
|
||||||
e = gjmp(0);
|
e = gjmp(0);
|
||||||
c = ind;
|
d = gind();
|
||||||
vla_sp_restore();
|
vla_sp_restore();
|
||||||
gexpr();
|
gexpr();
|
||||||
vpop();
|
vpop();
|
||||||
gjmp_addr(d);
|
gjmp_addr(c);
|
||||||
gsym(e);
|
gsym(e);
|
||||||
}
|
}
|
||||||
skip(')');
|
skip(')');
|
||||||
saved_nocode_wanted = nocode_wanted;
|
|
||||||
block(&a, current_cleanups, &b, current_cleanups, 0);
|
block(&a, current_cleanups, &b, current_cleanups, 0);
|
||||||
nocode_wanted = saved_nocode_wanted;
|
gjmp_addr(d);
|
||||||
gjmp_addr(c);
|
gsym_addr(b, d);
|
||||||
gsym(a);
|
gsym(a);
|
||||||
gsym_addr(b, c);
|
|
||||||
--local_scope;
|
--local_scope;
|
||||||
try_call_scope_cleanup(lcleanup);
|
try_call_scope_cleanup(lcleanup);
|
||||||
ncleanups = lncleanups;
|
ncleanups = lncleanups;
|
||||||
current_cleanups = lcleanup;
|
current_cleanups = lcleanup;
|
||||||
sym_pop(&local_stack, s, 0);
|
sym_pop(&local_stack, s, 0);
|
||||||
|
|
||||||
} else
|
} else if (t == TOK_DO) {
|
||||||
if (tok == TOK_DO) {
|
a = b = 0;
|
||||||
int saved_nocode_wanted;
|
d = gind();
|
||||||
nocode_wanted &= ~0x20000000;
|
|
||||||
next();
|
|
||||||
a = 0;
|
|
||||||
b = 0;
|
|
||||||
d = ind;
|
|
||||||
vla_sp_restore();
|
vla_sp_restore();
|
||||||
saved_nocode_wanted = nocode_wanted;
|
|
||||||
block(&a, current_cleanups, &b, current_cleanups, 0);
|
block(&a, current_cleanups, &b, current_cleanups, 0);
|
||||||
|
gsym(b);
|
||||||
skip(TOK_WHILE);
|
skip(TOK_WHILE);
|
||||||
skip('(');
|
skip('(');
|
||||||
gsym(b);
|
|
||||||
if (b)
|
|
||||||
nocode_wanted = saved_nocode_wanted;
|
|
||||||
gexpr();
|
gexpr();
|
||||||
|
skip(')');
|
||||||
|
skip(';');
|
||||||
c = gvtst(0, 0);
|
c = gvtst(0, 0);
|
||||||
gsym_addr(c, d);
|
gsym_addr(c, d);
|
||||||
nocode_wanted = saved_nocode_wanted;
|
|
||||||
skip(')');
|
|
||||||
gsym(a);
|
gsym(a);
|
||||||
skip(';');
|
|
||||||
} else
|
} else if (t == TOK_SWITCH) {
|
||||||
if (tok == TOK_SWITCH) {
|
|
||||||
struct switch_t *saved, sw;
|
struct switch_t *saved, sw;
|
||||||
int saved_nocode_wanted = nocode_wanted;
|
|
||||||
SValue switchval;
|
SValue switchval;
|
||||||
next();
|
|
||||||
skip('(');
|
skip('(');
|
||||||
gexpr();
|
gexpr();
|
||||||
skip(')');
|
skip(')');
|
||||||
@ -6416,7 +6373,6 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
|
|||||||
saved = cur_switch;
|
saved = cur_switch;
|
||||||
cur_switch = &sw;
|
cur_switch = &sw;
|
||||||
block(&a, current_cleanups, csym, ccl, 0);
|
block(&a, current_cleanups, csym, ccl, 0);
|
||||||
nocode_wanted = saved_nocode_wanted;
|
|
||||||
a = gjmp(a); /* add implicit break */
|
a = gjmp(a); /* add implicit break */
|
||||||
/* case lookup */
|
/* case lookup */
|
||||||
gsym(b);
|
gsym(b);
|
||||||
@ -6437,13 +6393,11 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
|
|||||||
cur_switch = saved;
|
cur_switch = saved;
|
||||||
/* break label */
|
/* break label */
|
||||||
gsym(a);
|
gsym(a);
|
||||||
} else
|
|
||||||
if (tok == TOK_CASE) {
|
} else if (t == TOK_CASE) {
|
||||||
struct case_t *cr = tcc_malloc(sizeof(struct case_t));
|
struct case_t *cr = tcc_malloc(sizeof(struct case_t));
|
||||||
if (!cur_switch)
|
if (!cur_switch)
|
||||||
expect("switch");
|
expect("switch");
|
||||||
nocode_wanted &= ~0x20000000;
|
|
||||||
next();
|
|
||||||
cr->v1 = cr->v2 = expr_const64();
|
cr->v1 = cr->v2 = expr_const64();
|
||||||
if (gnu_ext && tok == TOK_DOTS) {
|
if (gnu_ext && tok == TOK_DOTS) {
|
||||||
next();
|
next();
|
||||||
@ -6451,25 +6405,23 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
|
|||||||
if (cr->v2 < cr->v1)
|
if (cr->v2 < cr->v1)
|
||||||
tcc_warning("empty case range");
|
tcc_warning("empty case range");
|
||||||
}
|
}
|
||||||
cr->sym = ind;
|
cr->sym = gind();
|
||||||
dynarray_add(&cur_switch->p, &cur_switch->n, cr);
|
dynarray_add(&cur_switch->p, &cur_switch->n, cr);
|
||||||
skip(':');
|
skip(':');
|
||||||
is_expr = 0;
|
is_expr = 0;
|
||||||
goto block_after_label;
|
goto block_after_label;
|
||||||
} else
|
|
||||||
if (tok == TOK_DEFAULT) {
|
} else if (t == TOK_DEFAULT) {
|
||||||
next();
|
|
||||||
skip(':');
|
|
||||||
if (!cur_switch)
|
if (!cur_switch)
|
||||||
expect("switch");
|
expect("switch");
|
||||||
if (cur_switch->def_sym)
|
if (cur_switch->def_sym)
|
||||||
tcc_error("too many 'default'");
|
tcc_error("too many 'default'");
|
||||||
cur_switch->def_sym = ind;
|
cur_switch->def_sym = gind();
|
||||||
|
skip(':');
|
||||||
is_expr = 0;
|
is_expr = 0;
|
||||||
goto block_after_label;
|
goto block_after_label;
|
||||||
} else
|
|
||||||
if (tok == TOK_GOTO) {
|
} else if (t == TOK_GOTO) {
|
||||||
next();
|
|
||||||
if (tok == '*' && gnu_ext) {
|
if (tok == '*' && gnu_ext) {
|
||||||
/* computed goto */
|
/* computed goto */
|
||||||
next();
|
next();
|
||||||
@ -6500,18 +6452,20 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
|
|||||||
gjmp_addr(s->jnext);
|
gjmp_addr(s->jnext);
|
||||||
}
|
}
|
||||||
next();
|
next();
|
||||||
} else {
|
|
||||||
|
} else {
|
||||||
expect("label identifier");
|
expect("label identifier");
|
||||||
}
|
}
|
||||||
skip(';');
|
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();
|
asm_instr();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
b = is_label();
|
if (tok == ':' && t >= TOK_UIDENT) {
|
||||||
if (b) {
|
|
||||||
/* label case */
|
/* label case */
|
||||||
next();
|
next();
|
||||||
s = label_find(b);
|
s = label_find(t);
|
||||||
if (s) {
|
if (s) {
|
||||||
if (s->r == LABEL_DEFINED)
|
if (s->r == LABEL_DEFINED)
|
||||||
tcc_error("duplicate label '%s'", get_tok_str(s->v, NULL));
|
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
|
} else
|
||||||
gsym(s->jnext);
|
gsym(s->jnext);
|
||||||
} else {
|
} else {
|
||||||
s = label_push(&global_label_stack, b, LABEL_DEFINED);
|
s = label_push(&global_label_stack, t, LABEL_DEFINED);
|
||||||
}
|
}
|
||||||
s->jnext = ind;
|
s->jnext = gind();
|
||||||
s->cleanupstate = current_cleanups;
|
s->cleanupstate = current_cleanups;
|
||||||
|
|
||||||
|
block_after_label:
|
||||||
vla_sp_restore();
|
vla_sp_restore();
|
||||||
/* we accept this, but it is a mistake */
|
/* we accept this, but it is a mistake */
|
||||||
block_after_label:
|
|
||||||
nocode_wanted &= ~0x20000000;
|
|
||||||
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 {
|
||||||
@ -6539,9 +6493,11 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
|
|||||||
vpop();
|
vpop();
|
||||||
block(bsym, bcl, csym, ccl, is_expr);
|
block(bsym, bcl, csym, ccl, is_expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
/* expression case */
|
/* expression case */
|
||||||
if (tok != ';') {
|
if (t != ';') {
|
||||||
|
unget_tok(t);
|
||||||
if (is_expr) {
|
if (is_expr) {
|
||||||
vpop();
|
vpop();
|
||||||
gexpr();
|
gexpr();
|
||||||
@ -6549,8 +6505,8 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
|
|||||||
gexpr();
|
gexpr();
|
||||||
vpop();
|
vpop();
|
||||||
}
|
}
|
||||||
|
skip(';');
|
||||||
}
|
}
|
||||||
skip(';');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -6661,10 +6617,17 @@ static int decl_designator(CType *type, Section *sec, unsigned long c,
|
|||||||
|
|
||||||
elem_size = 0;
|
elem_size = 0;
|
||||||
nb_elems = 1;
|
nb_elems = 1;
|
||||||
|
|
||||||
if (flags & DIF_HAVE_ELEM)
|
if (flags & DIF_HAVE_ELEM)
|
||||||
goto no_designator;
|
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 */
|
/* NOTE: we only support ranges for last designator */
|
||||||
while (nb_elems == 1 && (tok == '[' || tok == '.')) {
|
while (nb_elems == 1 && (tok == '[' || tok == '.')) {
|
||||||
if (tok == '[') {
|
if (tok == '[') {
|
||||||
@ -7413,19 +7376,10 @@ static void gen_function(Sym *sym)
|
|||||||
gfunc_prolog(&sym->type);
|
gfunc_prolog(&sym->type);
|
||||||
reset_local_scope();
|
reset_local_scope();
|
||||||
rsym = 0;
|
rsym = 0;
|
||||||
clear_temp_local_var_list();
|
clear_temp_local_var_list();
|
||||||
block(NULL, NULL, NULL, NULL, 0);
|
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;
|
|
||||||
gsym(rsym);
|
gsym(rsym);
|
||||||
|
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);
|
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 */
|
/* return next token with macro substitution */
|
||||||
ST_FUNC void next(void)
|
ST_FUNC void next(void)
|
||||||
{
|
{
|
||||||
|
/* generate line number info */
|
||||||
|
if (tcc_state->do_debug)
|
||||||
|
tcc_debug_line(tcc_state);
|
||||||
redo:
|
redo:
|
||||||
if (parse_flags & PARSE_FLAG_SPACES)
|
if (parse_flags & PARSE_FLAG_SPACES)
|
||||||
next_nomacro_spc();
|
next_nomacro_spc();
|
||||||
|
@ -209,6 +209,7 @@ int test16()
|
|||||||
printf("alloca: %s\n", strcpy(alloca(strlen(demo)+1),demo) );
|
printf("alloca: %s\n", strcpy(alloca(strlen(demo)+1),demo) );
|
||||||
|
|
||||||
fprintf(stderr, "%s end\n", __FUNCTION__);
|
fprintf(stderr, "%s end\n", __FUNCTION__);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* error */
|
/* error */
|
||||||
@ -227,6 +228,7 @@ int test17()
|
|||||||
printf("alloca: %s\n", strcpy(alloca(strlen(demo)),demo) );
|
printf("alloca: %s\n", strcpy(alloca(strlen(demo)),demo) );
|
||||||
|
|
||||||
fprintf(stderr, "%s end\n", __FUNCTION__);
|
fprintf(stderr, "%s end\n", __FUNCTION__);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int (*table_test[])(void) = {
|
int (*table_test[])(void) = {
|
||||||
|
@ -179,7 +179,7 @@ static int onetwothree = 123;
|
|||||||
|
|
||||||
#ifdef __TINYC__
|
#ifdef __TINYC__
|
||||||
/* We try to handle this syntax. Make at least sure it doesn't segfault. */
|
/* 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
|
#endif
|
||||||
|
|
||||||
#define __INT64_C(c) c ## LL
|
#define __INT64_C(c) c ## LL
|
||||||
@ -572,6 +572,7 @@ void goto_test()
|
|||||||
printf("goto:\n");
|
printf("goto:\n");
|
||||||
i = 0;
|
i = 0;
|
||||||
/* This needs to parse as label, not as start of decl. */
|
/* This needs to parse as label, not as start of decl. */
|
||||||
|
typedef_and_label x;
|
||||||
typedef_and_label:
|
typedef_and_label:
|
||||||
s_loop:
|
s_loop:
|
||||||
if (i >= 10)
|
if (i >= 10)
|
||||||
@ -3767,6 +3768,7 @@ int fcompare (double a, double b, int code)
|
|||||||
case 4: return a > b;
|
case 4: return a > b;
|
||||||
case 5: return a <= b;
|
case 5: return a <= b;
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void math_cmp_test(void)
|
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). */
|
only with certain internal checking added that's not committed). */
|
||||||
if (0)
|
if (0)
|
||||||
ret = 0 != (!!(addr > limit - size));
|
ret = 0 != (!!(addr > limit - size));
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
|
@ -45,6 +45,7 @@ int convert_like_real (tree convs)
|
|||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
printf("unsigned enum bit-fields broken\n");
|
printf("unsigned enum bit-fields broken\n");
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
|
@ -41,7 +41,7 @@
|
|||||||
#define __MSVCRT__ 1
|
#define __MSVCRT__ 1
|
||||||
#undef _MSVCRT_
|
#undef _MSVCRT_
|
||||||
#define __MINGW_IMPORT extern __declspec(dllimport)
|
#define __MINGW_IMPORT extern __declspec(dllimport)
|
||||||
#define __MINGW_ATTRIB_NORETURN
|
#define __MINGW_ATTRIB_NORETURN __declspec(noreturn)
|
||||||
#define __MINGW_ATTRIB_CONST
|
#define __MINGW_ATTRIB_CONST
|
||||||
#define __MINGW_ATTRIB_DEPRECATED
|
#define __MINGW_ATTRIB_DEPRECATED
|
||||||
#define __MINGW_ATTRIB_MALLOC
|
#define __MINGW_ATTRIB_MALLOC
|
||||||
@ -138,7 +138,7 @@ typedef struct localeinfo_struct _locale_tstruct,*_locale_t;
|
|||||||
/* for winapi */
|
/* for winapi */
|
||||||
#define _ANONYMOUS_UNION
|
#define _ANONYMOUS_UNION
|
||||||
#define _ANONYMOUS_STRUCT
|
#define _ANONYMOUS_STRUCT
|
||||||
#define DECLSPEC_NORETURN
|
#define DECLSPEC_NORETURN __declspec(noreturn)
|
||||||
#define DECLARE_STDCALL_P(type) __stdcall type
|
#define DECLARE_STDCALL_P(type) __stdcall type
|
||||||
#define NOSERVICE 1
|
#define NOSERVICE 1
|
||||||
#define NOMCX 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)
|
static int is64_type(int t)
|
||||||
{
|
{
|
||||||
return ((t & VT_BTYPE) == VT_PTR ||
|
return ((t & VT_BTYPE) == VT_PTR ||
|
||||||
|
Loading…
Reference in New Issue
Block a user