diff --git a/arm-gen.c b/arm-gen.c index 882b0986..81fa185a 100644 --- a/arm-gen.c +++ b/arm-gen.c @@ -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; diff --git a/arm64-gen.c b/arm64-gen.c index ead88824..03ae56c3 100644 --- a/arm64-gen.c +++ b/arm64-gen.c @@ -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); diff --git a/c67-gen.c b/c67-gen.c index 9490a27f..ea8ab822 100644 --- a/c67-gen.c +++ b/c67-gen.c @@ -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; diff --git a/i386-gen.c b/i386-gen.c index 653bbf29..c8d8af53 100644 --- a/i386-gen.c +++ b/i386-gen.c @@ -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; diff --git a/riscv64-gen.c b/riscv64-gen.c index 3a0f0a3f..c0db5613 100644 --- a/riscv64-gen.c +++ b/riscv64-gen.c @@ -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; diff --git a/tcc.h b/tcc.h index 154e6775..ab5d9981 100644 --- a/tcc.h +++ b/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); diff --git a/tccdbg.c b/tccdbg.c index fadd2765..4fd01502 100644 --- a/tccdbg.c +++ b/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; diff --git a/tccgen.c b/tccgen.c index a1d03298..e309f621 100644 --- a/tccgen.c +++ b/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) { diff --git a/tccpp.c b/tccpp.c index 80c4ea3f..9f9d2cf9 100644 --- a/tccpp.c +++ b/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); diff --git a/tests/tests2/60_errors_and_warnings.c b/tests/tests2/60_errors_and_warnings.c index 48fb421e..b89d7343 100644 --- a/tests/tests2/60_errors_and_warnings.c +++ b/tests/tests2/60_errors_and_warnings.c @@ -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 diff --git a/tests/tests2/60_errors_and_warnings.expect b/tests/tests2/60_errors_and_warnings.expect index 804522e3..403deb36 100644 --- a/tests/tests2/60_errors_and_warnings.expect +++ b/tests/tests2/60_errors_and_warnings.expect @@ -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 diff --git a/x86_64-gen.c b/x86_64-gen.c index 985204e4..c3d7c5c3 100644 --- a/x86_64-gen.c +++ b/x86_64-gen.c @@ -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