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:
grischka
2025-08-13 22:41:51 +02:00
parent deb7a3fc73
commit 2662b7b43c
12 changed files with 233 additions and 170 deletions

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;

View File

@@ -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
View File

@@ -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);

View File

@@ -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
View File

@@ -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) {

View File

@@ -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);

View File

@@ -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

View File

@@ -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

View File

@@ -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