aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbellard <bellard>2002-07-13 11:17:19 +0000
committerbellard <bellard>2002-07-13 11:17:19 +0000
commit3d3e2372c57e6e0acab74e3f95b9f78d13c6b9f3 (patch)
treef6f856f4bc8620247665c541477b526267583063
parent4e5a85292bd0e3f315ff0fa5b7b725837cb8a555 (diff)
downloadtinycc-3d3e2372c57e6e0acab74e3f95b9f78d13c6b9f3.tar.gz
tinycc-3d3e2372c57e6e0acab74e3f95b9f78d13c6b9f3.tar.bz2
added char/short types in lvalues to fix cast problems - added gcc style variadic macros - fixed zero arg macros - refuse extra comma at end of function call - fixed unused logical operation result case
-rw-r--r--tcc.c278
1 files changed, 177 insertions, 101 deletions
diff --git a/tcc.c b/tcc.c
index c3b3fde..8494e5a 100644
--- a/tcc.c
+++ b/tcc.c
@@ -135,7 +135,6 @@ typedef struct Reloc {
/* section definition */
typedef struct Section {
- char name[64]; /* section name */
unsigned char *data; /* section data */
unsigned char *data_ptr; /* current data pointer */
int sh_num; /* elf section number */
@@ -144,6 +143,7 @@ typedef struct Section {
int sh_entsize; /* elf entry size */
struct Section *link; /* link to another section */
struct Section *next;
+ char name[64]; /* section name */
} Section;
/* GNUC attribute definition */
@@ -283,12 +283,13 @@ struct TCCState {
#define VT_LVAL 0x0100 /* var is an lvalue */
#define VT_FORWARD 0x0200 /* value is forward reference */
#define VT_MUSTCAST 0x0400 /* value must be casted to be correct (used for
- char/short stored in integer registers) */
+ char/short stored in integer registers) */
#define VT_MUSTBOUND 0x0800 /* bound checking must be done before
dereferencing value */
#define VT_LVAL_BYTE 0x1000 /* lvalue is a byte */
#define VT_LVAL_SHORT 0x2000 /* lvalue is a short */
#define VT_LVAL_UNSIGNED 0x4000 /* lvalue is unsigned */
+#define VT_LVAL_TYPE (VT_LVAL_BYTE | VT_LVAL_SHORT | VT_LVAL_UNSIGNED)
/* types */
#define VT_STRUCT_SHIFT 16 /* structure/enum name shift (16 bits left) */
@@ -1466,7 +1467,7 @@ void tok_print(int *str)
void parse_define(void)
{
Sym *s, *first, **ps;
- int v, t;
+ int v, t, varg, is_vaargs;
TokenString str;
v = tok;
@@ -1479,12 +1480,21 @@ void parse_define(void)
next_nomacro();
ps = &first;
while (tok != ')') {
- if (tok == TOK_DOTS)
- tok = TOK___VA_ARGS__;
- s = sym_push1(&define_stack, tok | SYM_FIELD, 0, 0);
+ varg = tok;
+ next_nomacro();
+ is_vaargs = 0;
+ if (varg == TOK_DOTS) {
+ varg = TOK___VA_ARGS__;
+ is_vaargs = 1;
+ } else if (tok == TOK_DOTS && gnu_ext) {
+ is_vaargs = 1;
+ next_nomacro();
+ }
+ if (varg < TOK_IDENT)
+ error("badly punctuated parameter list");
+ s = sym_push1(&define_stack, varg | SYM_FIELD, is_vaargs, 0);
*ps = s;
ps = &s->next;
- next_nomacro();
if (tok != ',')
break;
next_nomacro();
@@ -2197,10 +2207,22 @@ int *macro_arg_subst(Sym **nested_list, int *macro_str, Sym *args)
s = sym_find2(args, t);
if (s) {
st = (int *)s->c;
- /* if '##' is present before or after , no arg substitution */
+ /* if '##' is present before or after, no arg substitution */
if (*macro_str == TOK_TWOSHARPS || last_tok == TOK_TWOSHARPS) {
- while (*st)
- tok_str_add(&str, *st++);
+ /* special case for var arg macros : ## eats the
+ ',' if empty VA_ARGS riable. */
+ /* XXX: test of the ',' is not 100%
+ reliable. should fix it to avoid security
+ problems */
+ if (gnu_ext && s->t && *st == 0 &&
+ last_tok == TOK_TWOSHARPS &&
+ str.len >= 2&& str.str[str.len - 2] == ',') {
+ /* suppress ',' '##' */
+ str.len -= 2;
+ } else {
+ while (*st)
+ tok_str_add(&str, *st++);
+ }
} else {
macro_subst(&str, nested_list, st);
}
@@ -2335,10 +2357,10 @@ void macro_subst(TokenString *tok_str,
get_tok_str(s->v, 0));
tok_str_new(&str);
parlevel = 0;
+ /* NOTE: non zero sa->t indicates VA_ARGS */
while ((parlevel > 0 ||
(tok != ')' &&
- (tok != ',' ||
- sa->v == (TOK___VA_ARGS__ | SYM_FIELD)))) &&
+ (tok != ',' || sa->t))) &&
tok != -1) {
if (tok == '(')
parlevel++;
@@ -2348,17 +2370,24 @@ void macro_subst(TokenString *tok_str,
next_nomacro();
}
tok_str_add(&str, 0);
- sym_push2(&args, sa->v & ~SYM_FIELD, 0, (int)str.str);
- if (tok == ')')
- break;
+ sym_push2(&args, sa->v & ~SYM_FIELD, sa->t, (int)str.str);
+ sa = sa->next;
+ if (tok == ')') {
+ /* special case for gcc var args: add an empty
+ var arg argument if it is omitted */
+ if (sa && sa->t && gnu_ext)
+ continue;
+ else
+ break;
+ }
if (tok != ',')
expect(",");
next_nomacro();
- sa = sa->next;
}
- if (sa->next)
+ if (sa) {
error("macro '%s' used with too few args",
get_tok_str(s->v, 0));
+ }
/* now subst each arg */
mstr = macro_arg_subst(nested_list, mstr, args);
@@ -2626,14 +2655,17 @@ void gaddrof(void)
/* generate lvalue bound code */
void gbound(void)
{
+ int lval_type;
+
vtop->r &= ~VT_MUSTBOUND;
/* if lvalue, then use checking code before dereferencing */
if (vtop->r & VT_LVAL) {
+ lval_type = vtop->r & (VT_LVAL_TYPE | VT_LVAL);
gaddrof();
vpushi(0);
gen_bounded_ptr_add1();
gen_bounded_ptr_add2(1);
- vtop->r |= VT_LVAL;
+ vtop->r |= lval_type;
}
}
#endif
@@ -2730,6 +2762,23 @@ int gv(int rc)
vpop();
/* write second register */
vtop->r2 = r2;
+ } else if ((vtop->r & VT_LVAL) && !is_float(vtop->t)) {
+ int t1, t;
+ /* lvalue of scalar type : need to use lvalue type
+ because of possible cast */
+ t = vtop->t;
+ t1 = t;
+ /* compute memory access type */
+ if (vtop->r & VT_LVAL_BYTE)
+ t = VT_BYTE;
+ else if (vtop->r & VT_LVAL_SHORT)
+ t = VT_SHORT;
+ if (vtop->r & VT_LVAL_UNSIGNED)
+ t |= VT_UNSIGNED;
+ vtop->t = t;
+ load(r, vtop);
+ /* restore wanted type */
+ vtop->t = t1;
} else {
/* one register type load */
load(r, vtop);
@@ -2806,12 +2855,18 @@ void vrotb(int n)
/* pop stack value */
void vpop(void)
{
+ int v;
+ v = vtop->r & VT_VALMASK;
#ifdef TCC_TARGET_I386
/* for x86, we need to pop the FP stack */
- if ((vtop->r & VT_VALMASK) == REG_ST0) {
+ if (v == REG_ST0) {
o(0xd9dd); /* fstp %st(1) */
- }
+ } else
#endif
+ if (v == VT_JMP || v == VT_JMPI) {
+ /* need to put correct jump if && or || without test */
+ gsym(vtop->c.ul);
+ }
vtop--;
}
@@ -3467,7 +3522,7 @@ void force_charshort_cast(int t)
/* cast 'vtop' to 't' type */
void gen_cast(int t)
{
- int sbt, dbt, sf, df, c, st1, dt1;
+ int sbt, dbt, sf, df, c;
/* special delayed cast for char/short */
/* XXX: in some cases (multiple cascaded casts), it may still
@@ -3477,8 +3532,8 @@ void gen_cast(int t)
force_charshort_cast(vtop->t);
}
- dbt = t & VT_BTYPE;
- sbt = vtop->t & VT_BTYPE;
+ dbt = t & (VT_BTYPE | VT_UNSIGNED);
+ sbt = vtop->t & (VT_BTYPE | VT_UNSIGNED);
if (sbt != dbt) {
sf = is_float(sbt);
@@ -3507,9 +3562,8 @@ void gen_cast(int t)
}
} else if (df) {
/* convert int to fp */
- st1 = vtop->t & (VT_BTYPE | VT_UNSIGNED);
if (c) {
- switch(st1) {
+ switch(sbt) {
case VT_LLONG | VT_UNSIGNED:
case VT_LLONG:
/* XXX: add const cases for long long */
@@ -3535,14 +3589,13 @@ void gen_cast(int t)
}
} else if (sf) {
/* convert fp to int */
- dt1 = t & (VT_BTYPE | VT_UNSIGNED);
/* we handle char/short/etc... with generic code */
- if (dt1 != (VT_INT | VT_UNSIGNED) &&
- dt1 != (VT_LLONG | VT_UNSIGNED) &&
- dt1 != VT_LLONG)
- dt1 = VT_INT;
+ if (dbt != (VT_INT | VT_UNSIGNED) &&
+ dbt != (VT_LLONG | VT_UNSIGNED) &&
+ dbt != VT_LLONG)
+ dbt = VT_INT;
if (c) {
- switch(dt1) {
+ switch(dbt) {
case VT_LLONG | VT_UNSIGNED:
case VT_LLONG:
/* XXX: add const cases for long long */
@@ -3565,59 +3618,58 @@ void gen_cast(int t)
}
} else {
do_ftoi:
- gen_cvt_ftoi1(dt1);
+ gen_cvt_ftoi1(dbt);
}
- if (dt1 == VT_INT && (t & (VT_BTYPE | VT_UNSIGNED)) != dt1) {
+ if (dbt == VT_INT && (t & (VT_BTYPE | VT_UNSIGNED)) != dbt) {
/* additionnal cast for char/short/bool... */
- vtop->t = dt1;
+ vtop->t = dbt;
gen_cast(t);
}
- } else if (dbt == VT_LLONG) {
- /* scalar to long long */
- if (c) {
- if ((vtop->t & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED))
- vtop->c.ll = vtop->c.ui;
- else
- vtop->c.ll = vtop->c.i;
- } else {
- /* machine independant conversion */
- gv(RC_INT);
- /* generate high word */
- if ((vtop->t & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED)) {
- vpushi(0);
- gv(RC_INT);
+ } else if ((dbt & VT_BTYPE) == VT_LLONG) {
+ if ((sbt & VT_BTYPE) != VT_LLONG) {
+ /* scalar to long long */
+ if (c) {
+ if (sbt == (VT_INT | VT_UNSIGNED))
+ vtop->c.ll = vtop->c.ui;
+ else
+ vtop->c.ll = vtop->c.i;
} else {
- gv_dup();
- vpushi(31);
- gen_op(TOK_SAR);
+ /* machine independant conversion */
+ gv(RC_INT);
+ /* generate high word */
+ if (sbt == (VT_INT | VT_UNSIGNED)) {
+ vpushi(0);
+ gv(RC_INT);
+ } else {
+ gv_dup();
+ vpushi(31);
+ gen_op(TOK_SAR);
+ }
+ /* patch second register */
+ vtop[-1].r2 = vtop->r;
+ vpop();
}
- /* patch second register */
- vtop[-1].r2 = vtop->r;
- vpop();
}
} else if (dbt == VT_BOOL) {
/* scalar to bool */
vpushi(0);
gen_op(TOK_NE);
- } else if (dbt == VT_BYTE || dbt == VT_SHORT) {
+ } else if ((dbt & VT_BTYPE) == VT_BYTE ||
+ (dbt & VT_BTYPE) == VT_SHORT) {
force_charshort_cast(t);
- } else if (dbt == VT_INT) {
+ } else if ((dbt & VT_BTYPE) == VT_INT) {
/* scalar to int */
if (sbt == VT_LLONG) {
/* from long long: just take low order word */
lexpand();
vpop();
- } else if (sbt == VT_PTR) {
- /* ok to cast */
- } else if (vtop->r & VT_LVAL) {
- /* if lvalue and single word type, nothing to do (XXX:
- maybe incorrect for sizeof op) */
- goto no_cast;
- }
+ }
+ /* if lvalue and single word type, nothing to do because
+ the lvalue already contains the real type size (see
+ VT_LVAL_xxx constants) */
}
}
vtop->t = t;
- no_cast: ;
}
/* return type size. Put alignment at 'a' */
@@ -3698,7 +3750,7 @@ int is_compatible_types(int t1, int t2)
if (t1 == VT_VOID || t2 == VT_VOID)
return 1;
return is_compatible_types(t1, t2);
- } else if (bt1 == VT_STRUCT) {
+ } else if (bt1 == VT_STRUCT || bt2 == VT_STRUCT) {
return (t2 == t1);
} else if (bt1 == VT_FUNC) {
if (bt2 != VT_FUNC)
@@ -3877,7 +3929,6 @@ void vstore(void)
/* if structure, only generate pointer */
/* structure assignment : generate memcpy */
/* XXX: optimize if small size */
-
vdup();
gfunc_start(&gf, FUNC_CDECL);
/* type size */
@@ -4488,7 +4539,25 @@ Sym *external_sym(int v, int u, int r)
return s;
}
-void indir(void)
+/* compute the lvalue VT_LVAL_xxx needed to match type t. */
+static int lvalue_type(int t)
+{
+ int bt, r;
+ r = VT_LVAL;
+ bt = t & VT_BTYPE;
+ if (bt == VT_BYTE)
+ r |= VT_LVAL_BYTE;
+ else if (bt == VT_SHORT)
+ r |= VT_LVAL_SHORT;
+ else
+ return r;
+ if (t & VT_UNSIGNED)
+ r |= VT_LVAL_UNSIGNED;
+ return r;
+}
+
+/* indirection with full error checking and bound check */
+static void indir(void)
{
if ((vtop->t & VT_BTYPE) != VT_PTR)
expect("pointer");
@@ -4497,7 +4566,7 @@ void indir(void)
vtop->t = pointed_type(vtop->t);
/* an array is never an lvalue */
if (!(vtop->t & VT_ARRAY)) {
- vtop->r |= VT_LVAL;
+ vtop->r |= lvalue_type(vtop->t);
/* if bound checking, the referenced pointer must be checked */
if (do_bounds_check)
vtop->r |= VT_MUSTBOUND;
@@ -4594,7 +4663,7 @@ void unary(void)
r = VT_LOCAL;
/* all except arrays are lvalues */
if (!(ft & VT_ARRAY))
- r |= VT_LVAL;
+ r |= lvalue_type(ft);
memset(&ad, 0, sizeof(AttributeDef));
fc = decl_initializer_alloc(ft, &ad, r, 1);
vset(ft, r, fc);
@@ -4615,7 +4684,9 @@ void unary(void)
except for unary '&' and sizeof. Since we consider that
functions are not lvalues, we only have to handle it
there and in function calls. */
- if ((vtop->t & VT_BTYPE) != VT_FUNC)
+ /* arrays can also be used although they are not lvalues */
+ if ((vtop->t & VT_BTYPE) != VT_FUNC &&
+ !(vtop->t & VT_ARRAY))
test_lvalue();
vtop->t = mk_pointer(vtop->t);
gaddrof();
@@ -4666,6 +4737,8 @@ void unary(void)
gen_op('-');
} else
{
+ if (t < TOK_UIDENT)
+ expect("identifier");
s = sym_find(t);
if (!s) {
if (tok != '(')
@@ -4716,7 +4789,7 @@ void unary(void)
vtop->t = s->t;
/* an array is never an lvalue */
if (!(vtop->t & VT_ARRAY))
- vtop->r |= VT_LVAL;
+ vtop->r |= lvalue_type(vtop->t);
next();
} else if (tok == '[') {
next();
@@ -4758,30 +4831,30 @@ void unary(void)
/* read each argument and store it on a stack */
/* XXX: merge it with macro args ? */
args = NULL;
- while (tok != ')') {
- tok_str_new(&str);
- parlevel = 0;
- while ((parlevel > 0 || (tok != ')' && tok != ',')) &&
- tok != -1) {
- if (tok == '(')
- parlevel++;
- else if (tok == ')')
- parlevel--;
- tok_str_add_tok(&str);
- next();
+ if (tok != ')') {
+ for(;;) {
+ tok_str_new(&str);
+ parlevel = 0;
+ while ((parlevel > 0 || (tok != ')' && tok != ',')) &&
+ tok != -1) {
+ if (tok == '(')
+ parlevel++;
+ else if (tok == ')')
+ parlevel--;
+ tok_str_add_tok(&str);
+ next();
+ }
+ tok_str_add(&str, -1); /* end of file added */
+ tok_str_add(&str, 0);
+ s1 = sym_push2(&args, 0, 0, (int)str.str);
+ s1->next = sa; /* add reference to argument */
+ if (sa)
+ sa = sa->next;
+ if (tok == ')')
+ break;
+ skip(',');
}
- tok_str_add(&str, -1); /* end of file added */
- tok_str_add(&str, 0);
- s1 = sym_push2(&args, 0, 0, (int)str.str);
- s1->next = sa; /* add reference to argument */
- if (sa)
- sa = sa->next;
- if (tok != ',')
- break;
- next();
}
- if (tok != ')')
- expect(")");
/* now generate code in reverse order by reading the stack */
save_parse_state(&saved_parse_state);
@@ -4826,13 +4899,16 @@ void unary(void)
ret.c.i = 0;
}
#ifndef INVERT_FUNC_PARAMS
- while (tok != ')') {
- expr_eq();
- gfunc_param_typed(&gf, s, sa);
- if (sa)
- sa = sa->next;
- if (tok == ',')
- next();
+ if (tok != ')') {
+ for(;;) {
+ expr_eq();
+ gfunc_param_typed(&gf, s, sa);
+ if (sa)
+ sa = sa->next;
+ if (tok == ')')
+ break;
+ skip(',');
+ }
}
#endif
if (sa)
@@ -5934,7 +6010,7 @@ void decl(int l)
/* not lvalue if array */
r = 0;
if (!(t & VT_ARRAY))
- r |= VT_LVAL;
+ r |= lvalue_type(t);
if (b & VT_EXTERN) {
/* external variable */
external_sym(v, t, r);