mirror of
https://github.com/TinyCC/tinycc.git
synced 2025-11-16 04:24:45 +00:00
tccgen: local scope for types of function parameters
int foo(struct xxx {int x[3];} *p) { ...
We want 'xxx' be visible only inside the function. To get that,
the patch removes the 'sym_push(param)' in xxx-gen.c, and instead
(in tccgen.c:gen_function()) pushes all symbols that were newly
defined during parsing of the parameter list in post_type().
Also,
- decl_initializer_alloc():
patch existing globals earlier, which updates flex arrays too
- let patch_type() do the 'redefinition' check and FUNC_OLD update
This commit is contained in:
@@ -1493,8 +1493,7 @@ from_stack:
|
||||
addr = (n + nf + sn) * 4;
|
||||
sn += size;
|
||||
}
|
||||
sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL,
|
||||
addr + 12);
|
||||
gfunc_set_param(sym, addr + 12, 0);
|
||||
}
|
||||
last_itod_magic=0;
|
||||
leaffunc = 1;
|
||||
|
||||
@@ -1242,9 +1242,8 @@ ST_FUNC void gfunc_prolog(Sym *func_sym)
|
||||
int off = (a[i] < 16 ? 160 + a[i] / 2 * 8 :
|
||||
a[i] < 32 ? 16 + (a[i] - 16) / 2 * 16 :
|
||||
224 + ((a[i] - 32) >> 1 << 1));
|
||||
sym_push(sym->v & ~SYM_FIELD, &sym->type,
|
||||
(a[i] & 1 ? VT_LLOCAL : VT_LOCAL) | VT_LVAL,
|
||||
off);
|
||||
|
||||
gfunc_set_param(sym, off, a[i] & 1);
|
||||
|
||||
if (a[i] < 16) {
|
||||
int align, size = type_size(&sym->type, &align);
|
||||
|
||||
@@ -1968,7 +1968,7 @@ void gfunc_prolog(Sym *func_sym)
|
||||
/* define parameters */
|
||||
while ((sym = sym->next) != NULL) {
|
||||
type = &sym->type;
|
||||
sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL, addr);
|
||||
gfunc_set_param(sym, addr, 0);
|
||||
size = type_size(type, &align);
|
||||
size = (size + 3) & ~3;
|
||||
|
||||
|
||||
@@ -578,8 +578,7 @@ ST_FUNC void gfunc_prolog(Sym *func_sym)
|
||||
param_addr = addr;
|
||||
addr += size;
|
||||
}
|
||||
sym_push(sym->v & ~SYM_FIELD, type,
|
||||
VT_LOCAL | VT_LVAL, param_addr);
|
||||
gfunc_set_param(sym, param_addr, 0);
|
||||
param_index++;
|
||||
}
|
||||
func_ret_sub = 0;
|
||||
|
||||
@@ -833,9 +833,7 @@ ST_FUNC void gfunc_prolog(Sym *func_sym)
|
||||
}
|
||||
}
|
||||
}
|
||||
sym_push(sym->v & ~SYM_FIELD, &sym->type,
|
||||
(byref ? VT_LLOCAL : VT_LOCAL) | VT_LVAL,
|
||||
param_addr);
|
||||
gfunc_set_param(sym, param_addr, byref);
|
||||
}
|
||||
func_va_list_ofs = addr;
|
||||
num_va_regs = 0;
|
||||
|
||||
3
tcc.h
3
tcc.h
@@ -1506,6 +1506,7 @@ ST_FUNC int classify_x86_64_va_arg(CType *ty);
|
||||
ST_FUNC void gbound_args(int nb_args);
|
||||
ST_DATA int func_bound_add_epilog;
|
||||
#endif
|
||||
ST_FUNC Sym *gfunc_set_param(Sym *s, int c, int byref);
|
||||
|
||||
/* ------------ tccelf.c ------------ */
|
||||
|
||||
@@ -1856,7 +1857,7 @@ ST_FUNC void tcc_debug_eincl(TCCState *s1);
|
||||
ST_FUNC void tcc_debug_newfile(TCCState *s1);
|
||||
|
||||
ST_FUNC void tcc_debug_line(TCCState *s1);
|
||||
ST_FUNC void tcc_add_debug_info(TCCState *s1, int param, Sym *s, Sym *e);
|
||||
ST_FUNC void tcc_add_debug_info(TCCState *s1, Sym *s, Sym *e);
|
||||
ST_FUNC void tcc_debug_funcstart(TCCState *s1, Sym *sym);
|
||||
ST_FUNC void tcc_debug_prolog_epilog(TCCState *s1, int value);
|
||||
ST_FUNC void tcc_debug_funcend(TCCState *s1, int size);
|
||||
|
||||
12
tccdbg.c
12
tccdbg.c
@@ -1625,7 +1625,7 @@ static void tcc_get_debug_info(TCCState *s1, Sym *s, CString *result)
|
||||
|
||||
t = t->type.ref;
|
||||
debug_type = tcc_debug_find(s1, t, 0);
|
||||
if (debug_type == -1) {
|
||||
if (debug_type == -1 && t->c >= 0) {
|
||||
debug_type = tcc_debug_add(s1, t, 0);
|
||||
cstr_new (&str);
|
||||
cstr_printf (&str, "%s:T%d=%c%d",
|
||||
@@ -1664,7 +1664,7 @@ static void tcc_get_debug_info(TCCState *s1, Sym *s, CString *result)
|
||||
Sym *e = t = t->type.ref;
|
||||
|
||||
debug_type = tcc_debug_find(s1, t, 0);
|
||||
if (debug_type == -1) {
|
||||
if (debug_type == -1 && t->c >= 0) {
|
||||
debug_type = tcc_debug_add(s1, t, 0);
|
||||
cstr_new (&str);
|
||||
cstr_printf (&str, "%s:T%d=e",
|
||||
@@ -1741,7 +1741,7 @@ static int tcc_get_dwarf_info(TCCState *s1, Sym *s)
|
||||
if ((type & VT_BTYPE) == VT_STRUCT) {
|
||||
t = t->type.ref;
|
||||
debug_type = tcc_debug_find(s1, t, 1);
|
||||
if (debug_type == -1) {
|
||||
if (debug_type == -1 && t->c >= 0) {
|
||||
int pos_sib = 0, i, *pos_type;
|
||||
|
||||
debug_type = tcc_debug_add(s1, t, 1);
|
||||
@@ -1819,7 +1819,7 @@ static int tcc_get_dwarf_info(TCCState *s1, Sym *s)
|
||||
else if (IS_ENUM(type)) {
|
||||
t = t->type.ref;
|
||||
debug_type = tcc_debug_find(s1, t, 1);
|
||||
if (debug_type == -1) {
|
||||
if (debug_type == -1 && t->c >= 0) {
|
||||
int pos_sib, pos_type;
|
||||
Sym sym = {0}; sym.type.t = VT_INT | (type & VT_UNSIGNED);
|
||||
|
||||
@@ -2090,14 +2090,16 @@ static void tcc_debug_finish (TCCState *s1, struct _debug_info *cur)
|
||||
}
|
||||
}
|
||||
|
||||
ST_FUNC void tcc_add_debug_info(TCCState *s1, int param, Sym *s, Sym *e)
|
||||
ST_FUNC void tcc_add_debug_info(TCCState *s1, Sym *s, Sym *e)
|
||||
{
|
||||
CString debug_str;
|
||||
int param;
|
||||
|
||||
if (!(s1->do_debug & 2))
|
||||
return;
|
||||
|
||||
cstr_new (&debug_str);
|
||||
param = !e;
|
||||
for (; s != e; s = s->prev) {
|
||||
if (!s->v || (s->r & VT_VALMASK) != VT_LOCAL)
|
||||
continue;
|
||||
|
||||
285
tccgen.c
285
tccgen.c
@@ -683,20 +683,25 @@ ST_INLN Sym *sym_find(int v)
|
||||
return table_ident[v]->sym_identifier;
|
||||
}
|
||||
|
||||
static int sym_scope(Sym *s)
|
||||
/* make sym in-/visible to the parser */
|
||||
static inline void sym_link(Sym *s, int yes)
|
||||
{
|
||||
if (IS_ENUM_VAL (s->type.t))
|
||||
return s->type.ref->sym_scope;
|
||||
else
|
||||
return s->sym_scope;
|
||||
TokenSym *ts = table_ident[(s->v & ~SYM_STRUCT) - TOK_IDENT];
|
||||
Sym **ps;
|
||||
if (s->v & SYM_STRUCT)
|
||||
ps = &ts->sym_struct;
|
||||
else
|
||||
ps = &ts->sym_identifier;
|
||||
if (yes)
|
||||
s->prev_tok = *ps, *ps = s;
|
||||
else
|
||||
*ps = s->prev_tok;
|
||||
}
|
||||
|
||||
/* push a given symbol on the symbol stack */
|
||||
ST_FUNC Sym *sym_push(int v, CType *type, int r, int c)
|
||||
{
|
||||
Sym *s, **ps;
|
||||
TokenSym *ts;
|
||||
|
||||
if (local_stack)
|
||||
ps = &local_stack;
|
||||
else
|
||||
@@ -706,17 +711,15 @@ ST_FUNC Sym *sym_push(int v, CType *type, int r, int c)
|
||||
s->r = r;
|
||||
/* don't record fields or anonymous symbols */
|
||||
/* XXX: simplify */
|
||||
if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) {
|
||||
if ((v & ~SYM_STRUCT) < SYM_FIRST_ANOM) {
|
||||
/* record symbol in token array */
|
||||
ts = table_ident[(v & ~SYM_STRUCT) - TOK_IDENT];
|
||||
if (v & SYM_STRUCT)
|
||||
ps = &ts->sym_struct;
|
||||
else
|
||||
ps = &ts->sym_identifier;
|
||||
s->prev_tok = *ps;
|
||||
*ps = s;
|
||||
sym_link(s, 1);
|
||||
s->sym_scope = local_scope;
|
||||
if (s->prev_tok && sym_scope(s->prev_tok) == s->sym_scope)
|
||||
if (s->prev_tok
|
||||
&& (IS_ENUM_VAL (s->prev_tok->type.t)
|
||||
? s->prev_tok->type.ref->sym_scope
|
||||
: s->prev_tok->sym_scope)
|
||||
== s->sym_scope)
|
||||
tcc_error("redeclaration of '%s'",
|
||||
get_tok_str(v & ~SYM_STRUCT, NULL));
|
||||
}
|
||||
@@ -746,8 +749,7 @@ ST_FUNC Sym *global_identifier_push(int v, int t, int c)
|
||||
pop them yet from the list, but do remove them from the token array. */
|
||||
ST_FUNC void sym_pop(Sym **ptop, Sym *b, int keep)
|
||||
{
|
||||
Sym *s, *ss, **ps;
|
||||
TokenSym *ts;
|
||||
Sym *s, *ss;
|
||||
int v;
|
||||
|
||||
s = *ptop;
|
||||
@@ -755,15 +757,8 @@ ST_FUNC void sym_pop(Sym **ptop, Sym *b, int keep)
|
||||
ss = s->prev;
|
||||
v = s->v;
|
||||
/* remove symbol in token array */
|
||||
/* XXX: simplify */
|
||||
if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) {
|
||||
ts = table_ident[(v & ~SYM_STRUCT) - TOK_IDENT];
|
||||
if (v & SYM_STRUCT)
|
||||
ps = &ts->sym_struct;
|
||||
else
|
||||
ps = &ts->sym_identifier;
|
||||
*ps = s->prev_tok;
|
||||
}
|
||||
if ((v & ~SYM_STRUCT) < SYM_FIRST_ANOM)
|
||||
sym_link(s, 0);
|
||||
if (!keep)
|
||||
sym_free(s);
|
||||
s = ss;
|
||||
@@ -829,6 +824,19 @@ ST_FUNC void label_pop(Sym **ptop, Sym *slast, int keep)
|
||||
*ptop = slast;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* debug: print symbols on stack from s ... last */
|
||||
static inline void psyms(const char *msg, Sym *s, Sym *last)
|
||||
{
|
||||
printf("%-8s scope v c r type.t\n", msg);
|
||||
while (s && s != last) {
|
||||
printf(" %8x %08x %08x %08x %08x %s\n",
|
||||
s->sym_scope, s->v, s->c, s->r, s->type.t, get_tok_str(s->v, 0));
|
||||
s = s->prev;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
static void vcheck_cmp(void)
|
||||
{
|
||||
@@ -1219,6 +1227,9 @@ static void patch_type(Sym *sym, CType *type)
|
||||
|
||||
} else if ((sym->type.t & VT_BTYPE) == VT_FUNC) {
|
||||
int static_proto = sym->type.t & VT_STATIC;
|
||||
int ft1 = sym->type.ref->f.func_type;
|
||||
int ft2 = type->ref->f.func_type;
|
||||
|
||||
/* warn if static follows non-static function declaration */
|
||||
if ((type->t & VT_STATIC) && !static_proto
|
||||
/* XXX this test for inline shouldn't be here. Until we
|
||||
@@ -1239,15 +1250,14 @@ static void patch_type(Sym *sym, CType *type)
|
||||
struct FuncAttr f = sym->type.ref->f;
|
||||
/* put complete type, use static from prototype */
|
||||
sym->type.t = (type->t & ~(VT_STATIC|VT_INLINE)) | static_proto;
|
||||
if (ft1 != FUNC_OLD)
|
||||
type->ref->f.func_type = ft1;
|
||||
sym->type.ref = type->ref;
|
||||
merge_funcattr(&sym->type.ref->f, &f);
|
||||
} else {
|
||||
sym->type.t &= ~VT_INLINE | static_proto;
|
||||
}
|
||||
|
||||
if (sym->type.ref->f.func_type == FUNC_OLD
|
||||
&& type->ref->f.func_type != FUNC_OLD) {
|
||||
sym->type.ref = type->ref;
|
||||
if (ft1 == FUNC_OLD && ft2 != FUNC_OLD)
|
||||
sym->type.ref = type->ref;
|
||||
}
|
||||
|
||||
} else {
|
||||
@@ -1284,10 +1294,8 @@ static Sym *sym_copy(Sym *s0, Sym **ps)
|
||||
Sym *s;
|
||||
s = sym_malloc(), *s = *s0;
|
||||
s->prev = *ps, *ps = s;
|
||||
if (s->v < SYM_FIRST_ANOM) {
|
||||
ps = &table_ident[s->v - TOK_IDENT]->sym_identifier;
|
||||
s->prev_tok = *ps, *ps = s;
|
||||
}
|
||||
if ((s->v & ~SYM_STRUCT) < SYM_FIRST_ANOM)
|
||||
sym_link(s, 1);
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -1677,16 +1685,15 @@ static void add_local_bounds(Sym *s, Sym *e)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Wrapper around sym_pop, that potentially also registers local bounds. */
|
||||
static void pop_local_syms(Sym *b, int keep)
|
||||
/* add debug info for locals or function parameters, optionally
|
||||
register bounds */
|
||||
static void tcc_debug_end_scope(Sym *b, int bounds)
|
||||
{
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (tcc_state->do_bounds_check && !keep && (local_scope || !func_var))
|
||||
if (tcc_state->do_bounds_check && bounds)
|
||||
add_local_bounds(local_stack, b);
|
||||
#endif
|
||||
if (debug_modes)
|
||||
tcc_add_debug_info (tcc_state, !local_scope, local_stack, b);
|
||||
sym_pop(&local_stack, b, keep);
|
||||
tcc_add_debug_info (tcc_state, local_stack, b);
|
||||
}
|
||||
|
||||
/* increment an lvalue pointer */
|
||||
@@ -3853,10 +3860,14 @@ static void parse_attribute(AttributeDef *ad)
|
||||
{
|
||||
int t, n;
|
||||
char *astr;
|
||||
AttributeDef ad_tmp;
|
||||
|
||||
redo:
|
||||
if (tok != TOK_ATTRIBUTE1 && tok != TOK_ATTRIBUTE2)
|
||||
return;
|
||||
if (NULL == ad) /* skip over / ignore attributes */
|
||||
ad = &ad_tmp;
|
||||
|
||||
next();
|
||||
skip('(');
|
||||
skip('(');
|
||||
@@ -4511,7 +4522,7 @@ do_decl:
|
||||
expect("identifier");
|
||||
else {
|
||||
int v = btype.ref->v;
|
||||
if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) {
|
||||
if ((v & ~SYM_STRUCT) < SYM_FIRST_ANOM) {
|
||||
if (tcc_state->ms_extensions == 0)
|
||||
expect("identifier");
|
||||
}
|
||||
@@ -4924,7 +4935,7 @@ static int asm_label_instr(void)
|
||||
static int post_type(CType *type, AttributeDef *ad, int storage, int td)
|
||||
{
|
||||
int n, l, t1, arg_size, align;
|
||||
Sym **plast, *s, *first;
|
||||
Sym **plast, *s, *first, **ps, *sr;
|
||||
AttributeDef ad1;
|
||||
CType pt;
|
||||
TokenString *vla_array_tok = NULL;
|
||||
@@ -4935,11 +4946,20 @@ static int post_type(CType *type, AttributeDef *ad, int storage, int td)
|
||||
next();
|
||||
if (TYPE_DIRECT == (td & (TYPE_DIRECT|TYPE_ABSTRACT)))
|
||||
return 0;
|
||||
|
||||
/* we push a anonymous symbol which will contain the function prototype */
|
||||
/* it also serves as a boundary for the function parameter scope */
|
||||
ps = local_stack ? &local_stack : &global_stack;
|
||||
++local_scope;
|
||||
sr = sym_push2(ps, SYM_FIELD, 0, 0);
|
||||
|
||||
if (tok == ')')
|
||||
l = 0;
|
||||
else if (parse_btype(&pt, &ad1, 0))
|
||||
l = FUNC_NEW;
|
||||
else if (td & (TYPE_DIRECT|TYPE_ABSTRACT)) {
|
||||
sym_pop(ps, sr->prev, 0);
|
||||
--local_scope;
|
||||
merge_attr (ad, &ad1);
|
||||
return 0;
|
||||
} else
|
||||
@@ -4948,7 +4968,6 @@ static int post_type(CType *type, AttributeDef *ad, int storage, int td)
|
||||
first = NULL;
|
||||
plast = &first;
|
||||
arg_size = 0;
|
||||
++local_scope;
|
||||
if (l) {
|
||||
for(;;) {
|
||||
/* read param name and compute offset */
|
||||
@@ -4962,7 +4981,7 @@ static int post_type(CType *type, AttributeDef *ad, int storage, int td)
|
||||
n = SYM_FIELD;
|
||||
} else {
|
||||
n = tok;
|
||||
pt.t = VT_VOID; /* invalid type */
|
||||
pt.t = VT_INT | VT_EXTERN; /* default type */
|
||||
pt.ref = NULL;
|
||||
next();
|
||||
}
|
||||
@@ -4971,8 +4990,7 @@ static int post_type(CType *type, AttributeDef *ad, int storage, int td)
|
||||
convert_parameter_type(&pt);
|
||||
arg_size += (type_size(&pt, &align) + PTR_SIZE - 1) / PTR_SIZE;
|
||||
/* these symbols may be evaluated for VLArrays (see below, under
|
||||
nocode_wanted) which is why we push them here as normal symbols
|
||||
temporarily. Example: int func(int a, int b[++a]); */
|
||||
nocode_wanted) Example: int func(int a, int b[++a]); */
|
||||
s = sym_push(n, &pt, VT_LOCAL|VT_LVAL, 0);
|
||||
*plast = s;
|
||||
plast = &s->next;
|
||||
@@ -4991,12 +5009,6 @@ static int post_type(CType *type, AttributeDef *ad, int storage, int td)
|
||||
/* if no parameters, then old type prototype */
|
||||
l = FUNC_OLD;
|
||||
skip(')');
|
||||
/* remove parameter symbols from token table, keep on stack */
|
||||
if (first) {
|
||||
sym_pop(local_stack ? &local_stack : &global_stack, first->prev, 1);
|
||||
for (s = first; s; s = s->next)
|
||||
s->v |= SYM_FIELD;
|
||||
}
|
||||
--local_scope;
|
||||
/* NOTE: const is ignored in returned type as it has a special
|
||||
meaning in gcc / C++ */
|
||||
@@ -5009,15 +5021,19 @@ static int post_type(CType *type, AttributeDef *ad, int storage, int td)
|
||||
skip(']'); /* only handle simple "[]" */
|
||||
mk_pointer(type);
|
||||
}
|
||||
/* we push a anonymous symbol which will contain the function prototype */
|
||||
ad->f.func_args = arg_size;
|
||||
ad->f.func_type = l;
|
||||
s = sym_push(SYM_FIELD, type, 0, 0);
|
||||
sr->type = *type, s = sr;
|
||||
s->a = ad->a;
|
||||
s->f = ad->f;
|
||||
s->next = first;
|
||||
type->t = VT_FUNC;
|
||||
type->ref = s;
|
||||
|
||||
/* unlink symbols from the token table, keep on stack */
|
||||
sym_pop(ps, sr, 1);
|
||||
//psyms("---", *ps, sr);
|
||||
|
||||
} else if (tok == '[') {
|
||||
int saved_nocode_wanted = nocode_wanted;
|
||||
/* array definition */
|
||||
@@ -6972,6 +6988,9 @@ static void prev_scope(struct scope *o, int is_expr)
|
||||
if (o->cl.s != o->prev->cl.s)
|
||||
block_cleanup(o->prev);
|
||||
|
||||
if (debug_modes)
|
||||
tcc_debug_end_scope(o->lstk, !is_expr);
|
||||
|
||||
/* pop locally defined labels */
|
||||
label_pop(&local_label_stack, o->llstk, is_expr);
|
||||
|
||||
@@ -6984,7 +7003,7 @@ static void prev_scope(struct scope *o, int is_expr)
|
||||
tables, though. sym_pop will do that. */
|
||||
|
||||
/* pop locally defined symbols */
|
||||
pop_local_syms(o->lstk, is_expr);
|
||||
sym_pop(&local_stack, o->lstk, is_expr);
|
||||
cur_scope = o->prev;
|
||||
--local_scope;
|
||||
}
|
||||
@@ -7344,11 +7363,9 @@ again:
|
||||
s->cleanupstate = cur_scope->cl.s;
|
||||
|
||||
block_after_label:
|
||||
{
|
||||
/* Accept attributes after labels (e.g. 'unused') */
|
||||
AttributeDef ad_tmp;
|
||||
parse_attribute(&ad_tmp);
|
||||
}
|
||||
/* Accept attributes after labels (e.g. 'unused') */
|
||||
parse_attribute(NULL);
|
||||
|
||||
if (debug_modes)
|
||||
tcc_tcov_reset_ind(tcc_state);
|
||||
vla_restore(cur_scope->vla.loc);
|
||||
@@ -8068,20 +8085,32 @@ static void decl_initializer(init_params *p, CType *type, unsigned long c, int f
|
||||
is put in the value stack. If 'has_init' is 2, a special parsing
|
||||
is done to handle string constants. */
|
||||
static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
|
||||
int has_init, int v, int global)
|
||||
int has_init, int v, int scope)
|
||||
{
|
||||
int size, align, addr;
|
||||
TokenString *init_str = NULL;
|
||||
|
||||
Section *sec;
|
||||
Sym *flexible_array;
|
||||
Sym *sym;
|
||||
Sym *sym = NULL;
|
||||
int saved_nocode_wanted = nocode_wanted;
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
int bcheck = tcc_state->do_bounds_check && !NODATA_WANTED;
|
||||
#endif
|
||||
init_params p = {0};
|
||||
|
||||
if (scope == VT_CONST) {
|
||||
/* see if a global symbol was already defined */
|
||||
sym = sym_find(v);
|
||||
if (sym) {
|
||||
patch_storage(sym, ad, type);
|
||||
/* we accept several definitions of the same global variable. */
|
||||
if (!has_init && sym->c && elfsym(sym)->st_shndx != SHN_UNDEF)
|
||||
return;
|
||||
type = &sym->type;
|
||||
}
|
||||
}
|
||||
|
||||
/* Always allocate static or global variables */
|
||||
if (v && (r & VT_VALMASK) == VT_CONST)
|
||||
nocode_wanted |= DATA_ONLY_WANTED;
|
||||
@@ -8097,12 +8126,6 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
|
||||
// (arrays of incomplete types are handled in array parsing)
|
||||
if (!(type->t & VT_ARRAY))
|
||||
tcc_error("initialization of incomplete type");
|
||||
|
||||
/* If the base type itself was an array type of unspecified size
|
||||
(like in 'typedef int arr[]; arr x = {1};') then we will
|
||||
overwrite the unknown size by the real one for this decl.
|
||||
We need to unshare the ref symbol holding that size. */
|
||||
type->ref = sym_push(SYM_FIELD, &type->ref->type, 0, type->ref->c);
|
||||
p.flex_array_ref = type->ref;
|
||||
|
||||
} else if (has_init && (type->t & VT_BTYPE) == VT_STRUCT) {
|
||||
@@ -8208,26 +8231,6 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
|
||||
vset(type, r, addr);
|
||||
}
|
||||
} else {
|
||||
sym = NULL;
|
||||
if (v && global) {
|
||||
/* see if the symbol was already defined */
|
||||
sym = sym_find(v);
|
||||
if (sym) {
|
||||
if (p.flex_array_ref && (sym->type.t & type->t & VT_ARRAY)
|
||||
&& sym->type.ref->c > type->ref->c) {
|
||||
/* flex array was already declared with explicit size
|
||||
extern int arr[10];
|
||||
int arr[] = { 1,2,3 }; */
|
||||
type->ref->c = sym->type.ref->c;
|
||||
size = type_size(type, &align);
|
||||
}
|
||||
patch_storage(sym, ad, type);
|
||||
/* we accept several definitions of the same global variable. */
|
||||
if (!has_init && sym->c && elfsym(sym)->st_shndx != SHN_UNDEF)
|
||||
goto no_alloc;
|
||||
}
|
||||
}
|
||||
|
||||
/* allocate symbol in corresponding section */
|
||||
sec = ad->section;
|
||||
if (!sec) {
|
||||
@@ -8373,11 +8376,35 @@ static void func_vla_arg(Sym *sym)
|
||||
func_vla_arg_code(arg->type.ref);
|
||||
}
|
||||
|
||||
/* set the local stack address for function parameter from gfunc_prolog() */
|
||||
ST_FUNC Sym *gfunc_set_param(Sym *s, int c, int byref)
|
||||
{
|
||||
s = sym_find(s->v);
|
||||
if (!s) /* unnamed parameters, not enabled */
|
||||
return NULL;
|
||||
s->c = c;
|
||||
if (byref)
|
||||
s->r = VT_LLOCAL | VT_LVAL;
|
||||
return s;
|
||||
}
|
||||
|
||||
/* push parameters (and their types), last first */
|
||||
static void sym_push_params(Sym *ref)
|
||||
{
|
||||
Sym *s;
|
||||
for (s = ref; s->next; s = s->next)
|
||||
;
|
||||
for (; s && s != ref; s = s->prev)
|
||||
if ((s->v & ~SYM_STRUCT) < SYM_FIRST_ANOM)
|
||||
sym_copy(s, &local_stack);
|
||||
}
|
||||
|
||||
/* parse a function defined by symbol 'sym' and generate its code in
|
||||
'cur_text_section' */
|
||||
static void gen_function(Sym *sym)
|
||||
{
|
||||
struct scope f = { 0 };
|
||||
|
||||
cur_scope = root_scope = &f;
|
||||
nocode_wanted = 0;
|
||||
|
||||
@@ -8406,20 +8433,21 @@ static void gen_function(Sym *sym)
|
||||
|
||||
/* push a dummy symbol to enable local sym storage */
|
||||
sym_push2(&local_stack, SYM_FIELD, 0, 0);
|
||||
local_scope = 1; /* for function parameters */
|
||||
nb_temp_local_vars = 0;
|
||||
gfunc_prolog(sym);
|
||||
tcc_debug_prolog_epilog(tcc_state, 0);
|
||||
/* push parameters */
|
||||
sym_push_params(sym->type.ref);
|
||||
//psyms(funcname, local_stack, 0);
|
||||
|
||||
local_scope = 0;
|
||||
rsym = 0;
|
||||
nb_temp_local_vars = 0;
|
||||
|
||||
gfunc_prolog(sym);
|
||||
tcc_debug_prolog_epilog(tcc_state, 0);
|
||||
func_vla_arg(sym);
|
||||
block(0);
|
||||
gsym(rsym);
|
||||
|
||||
nocode_wanted = 0;
|
||||
/* reset local stack */
|
||||
pop_local_syms(NULL, 0);
|
||||
tcc_debug_end_scope(NULL, !func_var);
|
||||
tcc_debug_prolog_epilog(tcc_state, 1);
|
||||
gfunc_epilog();
|
||||
|
||||
@@ -8428,11 +8456,12 @@ static void gen_function(Sym *sym)
|
||||
|
||||
/* patch symbol size */
|
||||
elfsym(sym)->st_size = ind - func_ind;
|
||||
|
||||
cur_text_section->data_offset = ind;
|
||||
local_scope = 0;
|
||||
|
||||
sym_pop(&local_stack, NULL, 0);
|
||||
label_pop(&global_label_stack, NULL, 0);
|
||||
sym_pop(&all_cleanups, NULL, 0);
|
||||
local_scope = 0;
|
||||
|
||||
/* It's better to crash than to generate wrong code */
|
||||
cur_text_section = NULL;
|
||||
@@ -8538,7 +8567,7 @@ static int decl(int l)
|
||||
{
|
||||
int v, has_init, r, oldint;
|
||||
CType type, btype;
|
||||
Sym *sym, *s;
|
||||
Sym *sym;
|
||||
AttributeDef ad, adbase;
|
||||
ElfSym *esym;
|
||||
|
||||
@@ -8593,6 +8622,14 @@ static int decl(int l)
|
||||
while (1) { /* iterate thru each declaration */
|
||||
type = btype;
|
||||
ad = adbase;
|
||||
if ((btype.t & VT_ARRAY) && btype.ref->c < 0) {
|
||||
/* If the base type itself was an array type of unspecified
|
||||
size (like in 'typedef int arr[]; arr x = {1};') then
|
||||
we will overwrite the unknown size by the real one for
|
||||
this decl. We need to unshare the ref symbol holding
|
||||
that size. */
|
||||
type.ref = sym_push(SYM_FIELD, &type.ref->type, 0, type.ref->c);
|
||||
}
|
||||
type_decl(&type, &ad, &v, TYPE_DIRECT);
|
||||
#if 0
|
||||
{
|
||||
@@ -8610,23 +8647,7 @@ static int decl(int l)
|
||||
if (sym->f.func_type == FUNC_OLD && l == VT_CONST) {
|
||||
func_vt = type;
|
||||
decl(VT_CMP);
|
||||
|
||||
/* Allow mixing old/new prototypes
|
||||
* void func(float a);
|
||||
* int main(void) { func(1.0); }
|
||||
* void func(a) float a; { printf("%g\n", a); }
|
||||
*/
|
||||
s = sym_find(v);
|
||||
if (type.ref->next && // skip old func(); definitions
|
||||
s && s->type.ref &&
|
||||
s->type.ref->f.func_type == FUNC_NEW) {
|
||||
sym->f.func_type = FUNC_NEW;
|
||||
if (!is_compatible_types(&s->type, &type))
|
||||
tcc_error("incompatible redefinition of '%s'",
|
||||
get_tok_str(v, NULL));
|
||||
}
|
||||
}
|
||||
|
||||
if ((type.t & (VT_EXTERN|VT_INLINE)) == (VT_EXTERN|VT_INLINE)) {
|
||||
/* always_inline functions must be handled as if they
|
||||
don't generate multiple global defs, even if extern
|
||||
@@ -8658,31 +8679,30 @@ static int decl(int l)
|
||||
pe_check_linkage(&type, &ad);
|
||||
#endif
|
||||
if (tok == '{') {
|
||||
Sym *sa;
|
||||
|
||||
if (l != VT_CONST)
|
||||
tcc_error("cannot use local functions");
|
||||
if ((type.t & VT_BTYPE) != VT_FUNC)
|
||||
expect("function definition");
|
||||
|
||||
/* reject abstract declarators in function definition
|
||||
make old style params without decl have int type */
|
||||
sym = type.ref;
|
||||
while ((sym = sym->next) != NULL) {
|
||||
if (!(sym->v & ~SYM_FIELD))
|
||||
expect("identifier");
|
||||
if (type.ref->f.func_type == FUNC_OLD &&
|
||||
sym->type.t == VT_FLOAT)
|
||||
sym->type.t = VT_DOUBLE;
|
||||
if (sym->type.t == VT_VOID)
|
||||
sym->type = int_type;
|
||||
}
|
||||
|
||||
/* apply post-declaraton attributes */
|
||||
merge_funcattr(&type.ref->f, &ad.f);
|
||||
|
||||
/* put function symbol */
|
||||
type.t &= ~VT_EXTERN;
|
||||
sym = external_sym(v, &type, 0, &ad);
|
||||
|
||||
/* reject abstract declarators in function definition
|
||||
make old-style float params double */
|
||||
for (sa = sym->type.ref; (sa = sa->next) != NULL;) {
|
||||
if (!(sa->v & ~SYM_FIELD))
|
||||
expect("identifier");
|
||||
if (sa->type.t == VT_FLOAT
|
||||
&& sym->type.ref->f.func_type == FUNC_OLD) {
|
||||
sa->type.t = VT_DOUBLE;
|
||||
}
|
||||
}
|
||||
|
||||
/* static inline functions are just recorded as a kind
|
||||
of macro. Their code will be emitted at the end of
|
||||
the compilation unit only if they are used */
|
||||
@@ -8717,7 +8737,7 @@ static int decl(int l)
|
||||
if (type.t & VT_STORAGE) /* 'register' is okay */
|
||||
tcc_error("storage class specified for '%s'",
|
||||
get_tok_str(v, NULL));
|
||||
if (sym->type.t != VT_VOID)
|
||||
if (!(sym->type.t & VT_EXTERN))
|
||||
tcc_error("redefinition of parameter '%s'",
|
||||
get_tok_str(v, NULL));
|
||||
convert_parameter_type(&type);
|
||||
@@ -8772,12 +8792,13 @@ static int decl(int l)
|
||||
r |= VT_CONST;
|
||||
else
|
||||
r |= VT_LOCAL;
|
||||
type.t &= ~VT_EXTERN;
|
||||
if (has_init)
|
||||
next();
|
||||
else if (l == VT_CONST)
|
||||
/* uninitialized global variables may be overridden */
|
||||
type.t |= VT_EXTERN;
|
||||
decl_initializer_alloc(&type, &ad, r, has_init, v, l == VT_CONST);
|
||||
decl_initializer_alloc(&type, &ad, r, has_init, v, l);
|
||||
}
|
||||
|
||||
if (ad.alias_target && l == VT_CONST) {
|
||||
|
||||
4
tccpp.c
4
tccpp.c
@@ -102,7 +102,7 @@ ST_FUNC void skip(int c)
|
||||
if (tok != c) {
|
||||
char tmp[40];
|
||||
pstrcpy(tmp, sizeof tmp, get_tok_str(c, &tokc));
|
||||
tcc_error("'%s' expected (got \"%s\")", tmp, get_tok_str(tok, &tokc));
|
||||
tcc_error("'%s' expected (got '%s')", tmp, get_tok_str(tok, &tokc));
|
||||
}
|
||||
next();
|
||||
}
|
||||
@@ -3633,7 +3633,7 @@ static void putdefs(CString *cs, const char *p)
|
||||
|
||||
static void tcc_predefs(TCCState *s1, CString *cs, int is_asm)
|
||||
{
|
||||
cstr_printf(cs, "#define __TINYC__ 9%.2s\n", *& TCC_VERSION + 4);
|
||||
cstr_printf(cs, "#define __TINYC__ 9%.2s\n", &TCC_VERSION[4]);
|
||||
putdefs(cs, target_machine_defs);
|
||||
putdefs(cs, target_os_defs);
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
int printf(const char*, ...);
|
||||
|
||||
#if defined test_56_btype_excess_1
|
||||
struct A {} int i;
|
||||
|
||||
#elif defined test_57_btype_excess_2
|
||||
char int i;
|
||||
|
||||
#elif defined test_58_function_redefinition
|
||||
int f(void) { return 0; }
|
||||
int f(void) { return 1; }
|
||||
@@ -253,7 +253,7 @@ int main () {
|
||||
hello(123);
|
||||
return 0;
|
||||
}
|
||||
int printf(const char*, ...);
|
||||
|
||||
#if defined test_func_3
|
||||
static int hello(int a)
|
||||
#elif defined test_func_5
|
||||
@@ -272,7 +272,7 @@ int hello(int a)
|
||||
int xxx[];
|
||||
#endif
|
||||
int bar();
|
||||
int printf(const char*, ...);
|
||||
|
||||
int main ()
|
||||
{
|
||||
#if !defined test_var_3
|
||||
@@ -333,7 +333,7 @@ int main()
|
||||
x
|
||||
|
||||
#elif defined test_stray_backslash2
|
||||
int printf(const char*, ...);
|
||||
|
||||
int main()
|
||||
{
|
||||
#define _S(x) #x
|
||||
@@ -438,7 +438,7 @@ void func(int a, int if);
|
||||
int amain(int argc, char *argv[static argc + 1])
|
||||
{
|
||||
int i;
|
||||
int printf(const char*, ...);
|
||||
|
||||
for (i = 0; i < argc; ++i)
|
||||
printf("arg[%d] = \"%s\"\n", i, argv[i]);
|
||||
return 0;
|
||||
@@ -510,10 +510,45 @@ int main()
|
||||
#ifdef test_reverse_funcargs
|
||||
# pragma comment(option, "-freverse-funcargs")
|
||||
#endif
|
||||
int printf(const char*, ...);
|
||||
|
||||
int main()
|
||||
{
|
||||
printf(" %d %d %d\n", printf("1"), printf("22"), printf("333"));
|
||||
}
|
||||
|
||||
#elif defined test_scope_1 \
|
||||
|| defined test_scope_2 \
|
||||
|| defined test_scope_3
|
||||
|
||||
struct xxx {int x[4];};
|
||||
|
||||
/* 'ee' not defined outside of function, 'i' not redefined */
|
||||
int bar(enum ee { a = 12, b = 34 } i, int(*f)(int i))
|
||||
{
|
||||
printf("bar %d %d %d\n", i, a, b);
|
||||
return 0;
|
||||
}
|
||||
/* 'xxx' not defined outside of function */
|
||||
int foo(struct xxx {int x[3];}*p)
|
||||
{
|
||||
printf("foo %d", sizeof *p);
|
||||
return p->x[3];
|
||||
}
|
||||
#ifdef test_scope_2
|
||||
/* incompatible redefinition */
|
||||
int foo(struct xxx {int x[2];}*p);
|
||||
#endif
|
||||
#ifndef test_scope_3
|
||||
enum ee { a = 1, b };
|
||||
#endif
|
||||
|
||||
struct xxx x = { 11,22,33,44 };
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
printf(" %d %d\n", foo(&x), sizeof (struct xxx));
|
||||
enum ee e = b;
|
||||
bar(13 + e, 0);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
[test_56_btype_excess_1]
|
||||
60_errors_and_warnings.c:2: error: too many basic types
|
||||
60_errors_and_warnings.c:4: error: too many basic types
|
||||
|
||||
[test_57_btype_excess_2]
|
||||
60_errors_and_warnings.c:5: error: too many basic types
|
||||
60_errors_and_warnings.c:6: error: too many basic types
|
||||
|
||||
[test_58_function_redefinition]
|
||||
60_errors_and_warnings.c:9: error: redefinition of 'f'
|
||||
@@ -71,10 +71,10 @@
|
||||
60_errors_and_warnings.c:153: error: expression expected before ','
|
||||
|
||||
[test_invalid_2]
|
||||
60_errors_and_warnings.c:156: error: ';' expected (got "{")
|
||||
60_errors_and_warnings.c:156: error: ';' expected (got '{')
|
||||
|
||||
[test_invalid_3]
|
||||
60_errors_and_warnings.c:160: error: ',' expected (got "a")
|
||||
60_errors_and_warnings.c:160: error: ',' expected (got 'a')
|
||||
|
||||
[test_invalid_4]
|
||||
60_errors_and_warnings.c:164: error: division by zero in constant
|
||||
@@ -179,7 +179,7 @@ bar : 3 ; 3
|
||||
60_errors_and_warnings.c:372: error: statement expression outside of function
|
||||
|
||||
[test_invalid_tokckill]
|
||||
60_errors_and_warnings.c:375: error: ';' expected (got "3")
|
||||
60_errors_and_warnings.c:375: error: ';' expected (got '3')
|
||||
|
||||
[test_duplicate_member]
|
||||
60_errors_and_warnings.c:381: error: duplicate member 'a'
|
||||
@@ -188,7 +188,7 @@ bar : 3 ; 3
|
||||
60_errors_and_warnings.c:394: error: duplicate member 'd'
|
||||
|
||||
[test_conflicting_array_definition]
|
||||
60_errors_and_warnings.c:399: error: incompatible types for redefinition of 'array'
|
||||
60_errors_and_warnings.c:399: error: too many initializers
|
||||
|
||||
[test_incompatible_local_redef]
|
||||
60_errors_and_warnings.c:406: error: incompatible redefinition of 'localfunctype'
|
||||
@@ -250,3 +250,15 @@ arg[1] = "Y"
|
||||
|
||||
[test_reverse_funcargs]
|
||||
333221 1 2 3
|
||||
|
||||
[test_scope_1]
|
||||
60_errors_and_warnings.c:548: warning: assignment from incompatible pointer type
|
||||
foo 12 44 16
|
||||
bar 15 12 34
|
||||
|
||||
[test_scope_2]
|
||||
60_errors_and_warnings.c:539: error: incompatible types for redefinition of 'foo'
|
||||
|
||||
[test_scope_3]
|
||||
60_errors_and_warnings.c:548: warning: assignment from incompatible pointer type
|
||||
60_errors_and_warnings.c:549: error: initialization of incomplete type
|
||||
|
||||
@@ -975,8 +975,7 @@ void gfunc_prolog(Sym *func_sym)
|
||||
if (reg_param_index < REGN) {
|
||||
gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr);
|
||||
}
|
||||
sym_push(sym->v & ~SYM_FIELD, type,
|
||||
VT_LLOCAL | VT_LVAL, addr);
|
||||
gfunc_set_param(sym, addr, 1);
|
||||
} else {
|
||||
if (reg_param_index < REGN) {
|
||||
/* save arguments passed by register */
|
||||
@@ -989,8 +988,7 @@ void gfunc_prolog(Sym *func_sym)
|
||||
gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr);
|
||||
}
|
||||
}
|
||||
sym_push(sym->v & ~SYM_FIELD, type,
|
||||
VT_LOCAL | VT_LVAL, addr);
|
||||
gfunc_set_param(sym, addr, 0);
|
||||
}
|
||||
addr += 8;
|
||||
reg_param_index++;
|
||||
@@ -1587,8 +1585,7 @@ void gfunc_prolog(Sym *func_sym)
|
||||
}
|
||||
default: break; /* nothing to be done for x86_64_mode_none */
|
||||
}
|
||||
sym_push(sym->v & ~SYM_FIELD, type,
|
||||
VT_LOCAL | VT_LVAL, param_addr);
|
||||
gfunc_set_param(sym, param_addr, 0);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
|
||||
Reference in New Issue
Block a user