diff --git a/tcc.h b/tcc.h index 07b9286..38bbda8 100644 --- a/tcc.h +++ b/tcc.h @@ -448,7 +448,6 @@ struct FuncAttr { unsigned func_call : 3, /* calling convention (0..5), see below */ func_type : 2, /* FUNC_OLD/NEW/ELLIPSIS */ - func_body : 1, /* body was defined */ func_args : 8; /* PE __stdcall args */ }; diff --git a/tccgen.c b/tccgen.c index 7ddde72..97ea94c 100644 --- a/tccgen.c +++ b/tccgen.c @@ -852,22 +852,63 @@ ST_FUNC Sym *external_global_sym(int v, CType *type, int r) return s; } +/* Merge some type attributes. */ +static void patch_type(Sym *sym, CType *type) +{ + if (!(type->t & VT_EXTERN)) { + if (!(sym->type.t & VT_EXTERN)) + tcc_error("redefinition of '%s'", get_tok_str(sym->v, NULL)); + sym->type.t &= ~VT_EXTERN; + } + + if (IS_ASM_SYM(sym)) { + sym->type = *type; + + } else if (!is_compatible_types(&sym->type, type)) { + tcc_error("incompatible types for redefinition of '%s'", + get_tok_str(sym->v, NULL)); + + } else if ((sym->type.t & VT_BTYPE) == VT_FUNC) { + int static_proto = sym->type.t & VT_STATIC; + /* warn if static follows non-static function declaration */ + if ((type->t & VT_STATIC) && !static_proto && !(type->t & VT_INLINE)) + tcc_warning("static storage ignored for redefinition of '%s'", + get_tok_str(sym->v, NULL)); + + if (0 == (type->t & VT_EXTERN)) { + /* put complete type */ + sym->type = *type; + /* use static from prototype */ + sym->type.t |= static_proto; + } + + } else { + if ((sym->type.t & VT_ARRAY) && type->ref->c >= 0) { + /* set array size if it was omitted in extern declaration */ + if (sym->type.ref->c < 0) + sym->type.ref->c = type->ref->c; + else if (sym->type.ref->c != type->ref->c) + tcc_error("conflicting type for '%s'", get_tok_str(sym->v, NULL)); + } + if ((type->t ^ sym->type.t) & VT_STATIC) + tcc_warning("storage mismatch for redefinition of '%s'", + get_tok_str(sym->v, NULL)); + } +} + + /* Merge some storage attributes. */ static void patch_storage(Sym *sym, AttributeDef *ad, CType *type) { - if (type) { - if (IS_ASM_SYM(sym)) - sym->type = *type; - else if (!is_compatible_types(&sym->type, type)) - tcc_error("incompatible types for redefinition of '%s'", - get_tok_str(sym->v, NULL)); - } + if (type) + patch_type(sym, type); + #ifdef TCC_TARGET_PE if (sym->a.dllimport != ad->a.dllimport) tcc_error("incompatible dll linkage for redefinition of '%s'", get_tok_str(sym->v, NULL)); -#endif sym->a.dllexport |= ad->a.dllexport; +#endif sym->a.weak |= ad->a.weak; if (ad->a.visibility) { int vis = sym->a.visibility; @@ -6904,26 +6945,9 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, sym = sym_find(v); if (sym) { patch_storage(sym, ad, type); - if (sym->type.t & VT_EXTERN) { - /* if the variable is extern, it was not allocated */ - sym->type.t &= ~VT_EXTERN; - /* set array size if it was omitted in extern - declaration */ - if ((sym->type.t & VT_ARRAY) && - sym->type.ref->c < 0 && - type->ref->c >= 0) - sym->type.ref->c = type->ref->c; - } else if (!has_init) { - /* we accept several definitions of the same - global variable. this is tricky, because we - must play with the SHN_COMMON type of the symbol */ - /* no init data, we won't add more to the symbol */ + /* we accept several definitions of the same global variable. */ + if (!has_init && sym->c && elfsym(sym)->st_shndx != SHN_UNDEF) goto no_alloc; - } else if (sym->c) { - ElfSym *esym = elfsym(sym); - if (esym->st_shndx == data_section->sh_num) - tcc_error("redefinition of '%s'", get_tok_str(v, NULL)); - } } } @@ -7228,51 +7252,11 @@ static int decl0(int l, int is_for_loop_init, Sym *func_sym) /* XXX: cannot do better now: convert extern line to static inline */ if ((type.t & (VT_EXTERN | VT_INLINE)) == (VT_EXTERN | VT_INLINE)) type.t = (type.t & ~VT_EXTERN) | VT_STATIC; - - sym = sym_find(v); - if (sym && !IS_ASM_SYM(sym)) { - Sym *ref; - if ((sym->type.t & VT_BTYPE) != VT_FUNC) - goto func_error1; - - ref = sym->type.ref; - - /* use func_call from prototype if not defined */ - if (ref->f.func_call != FUNC_CDECL - && type.ref->f.func_call == FUNC_CDECL) - type.ref->f.func_call = ref->f.func_call; - - /* use static from prototype */ - if (sym->type.t & VT_STATIC) - type.t = (type.t & ~VT_EXTERN) | VT_STATIC; - - /* If the definition has no visibility use the - one from prototype. */ - if (!type.ref->a.visibility) - type.ref->a.visibility = ref->a.visibility; - /* apply other storage attributes from prototype */ - type.ref->a.dllexport |= ref->a.dllexport; - type.ref->a.weak |= ref->a.weak; - - if (!is_compatible_types(&sym->type, &type)) { - func_error1: - tcc_error("incompatible types for redefinition of '%s'", - get_tok_str(v, NULL)); - } - if (ref->f.func_body) - tcc_error("redefinition of '%s'", get_tok_str(v, NULL)); - /* if symbol is already defined, then put complete type */ - sym->type = type; - sym->r = VT_SYM | VT_CONST; - - } else { - /* put function symbol */ - sym = external_global_sym(v, &type, 0); - } - - sym->type.ref->f.func_body = 1; - patch_storage(sym, &ad, NULL); + /* put function symbol */ + sym = external_global_sym(v, &type, 0); + type.t &= ~VT_EXTERN; + patch_storage(sym, &ad, &type); /* static inline functions are just recorded as a kind of macro. Their code will be emitted at the end of @@ -7350,6 +7334,7 @@ found: /* NOTE: as GCC, uninitialized global static arrays of null size are considered as extern */ + type.t |= VT_EXTERN; sym = external_sym(v, &type, r, &ad); if (ad.alias_target) { Section tsec; @@ -7372,6 +7357,9 @@ found: r |= l; 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); } }