diff --git a/libtcc.c b/libtcc.c index ec33591..956ee0f 100644 --- a/libtcc.c +++ b/libtcc.c @@ -788,6 +788,7 @@ LIBTCCAPI TCCState *tcc_new(void) s->cversion = 199901; /* default unless -std=c11 is supplied */ s->warn_implicit_function_declaration = 1; s->ms_extensions = 1; + s->plan9_extensions = 1; #ifdef CHAR_IS_UNSIGNED s->char_is_unsigned = 1; @@ -1594,6 +1595,7 @@ static const FlagDef options_f[] = { { offsetof(TCCState, nocommon), FD_INVERT, "common" }, { offsetof(TCCState, leading_underscore), 0, "leading-underscore" }, { offsetof(TCCState, ms_extensions), 0, "ms-extensions" }, + { offsetof(TCCState, plan9_extensions), 0, "plan9-extensions" }, { offsetof(TCCState, dollars_in_identifiers), 0, "dollars-in-identifiers" }, { offsetof(TCCState, test_coverage), 0, "test-coverage" }, { 0, 0, NULL } diff --git a/tcc.h b/tcc.h index 2e27850..090c939 100644 --- a/tcc.h +++ b/tcc.h @@ -480,7 +480,7 @@ typedef struct CString { /* type definition */ typedef struct CType { - int t; + int t, td; /* td: token used for typedef, if applicable */ struct Sym *ref; } CType; @@ -591,7 +591,7 @@ typedef struct Section { struct Section *reloc; /* corresponding section for relocation, if any */ struct Section *hash; /* hash table for symbols */ struct Section *prev; /* previous section on section stack */ - char name[1]; /* section name */ + char name[1]; /* section name */ } Section; typedef struct DLLReference { @@ -760,6 +760,10 @@ struct TCCState { unsigned char char_is_unsigned; unsigned char leading_underscore; unsigned char ms_extensions; /* allow nested named struct w/o identifier behave like unnamed */ + unsigned char plan9_extensions; /* allow referring to unnamed nexted struct by its typedef name (if + present); and, convert a pointer to a structure to a pointer to + its unnamed field (if present) */ + unsigned char dollars_in_identifiers; /* allows '$' char in identifiers */ unsigned char ms_bitfields; /* if true, emulate MS algorithm for aligning bitfields */ @@ -1485,12 +1489,12 @@ ST_FUNC void greloca(Section *s, Sym *sym, unsigned long offset, int type, addr_ ST_INLN void sym_free(Sym *sym); ST_FUNC Sym *sym_push(int v, CType *type, int r, int c); ST_FUNC void sym_pop(Sym **ptop, Sym *b, int keep); -ST_FUNC Sym *sym_push2(Sym **ps, int v, int t, int c); +ST_FUNC Sym *sym_push2(Sym **ps, int v, int t, int td, int c); ST_FUNC Sym *sym_find2(Sym *s, int v); ST_INLN Sym *sym_find(int v); ST_INLN Sym *struct_find(int v); -ST_FUNC Sym *global_identifier_push(int v, int t, int c); +ST_FUNC Sym *global_identifier_push(int v, int t, int td, int c); ST_FUNC Sym *external_global_sym(int v, CType *type); ST_FUNC Sym *external_helper_sym(int v); ST_FUNC void vpush_helper_func(int v); diff --git a/tccasm.c b/tccasm.c index 097f41c..20c42f0 100644 --- a/tccasm.c +++ b/tccasm.c @@ -78,7 +78,7 @@ static Sym *asm_label_push(int v) /* We always add VT_EXTERN, for sym definition that's tentative (for .set, removed for real defs), for mere references it's correct as is. */ - Sym *sym = global_identifier_push(v2, VT_ASM | VT_EXTERN | VT_STATIC, 0); + Sym *sym = global_identifier_push(v2, VT_ASM | VT_EXTERN | VT_STATIC, 0, 0); if (addeddot) sym->asm_label = v; return sym; diff --git a/tccgen.c b/tccgen.c index c36032a..1c16f02 100644 --- a/tccgen.c +++ b/tccgen.c @@ -958,6 +958,7 @@ ST_FUNC void tccgen_init(TCCState *s1) memset(vtop, 0, sizeof *vtop); /* define some often used types */ + int_type.td = char_type.td = 0; int_type.t = VT_INT; char_type.t = VT_BYTE; @@ -967,6 +968,7 @@ ST_FUNC void tccgen_init(TCCState *s1) mk_pointer(&char_pointer_type); func_old_type.t = VT_FUNC; + func_old_type.td = 0; func_old_type.ref = sym_push(SYM_FIELD, &int_type, 0, 0); func_old_type.ref->f.func_call = FUNC_CDECL; func_old_type.ref->f.func_type = FUNC_OLD; @@ -1222,7 +1224,7 @@ ST_INLN void sym_free(Sym *sym) } /* push, without hashing */ -ST_FUNC Sym *sym_push2(Sym **ps, int v, int t, int c) +ST_FUNC Sym *sym_push2(Sym **ps, int v, int t, int td, int c) { Sym *s; @@ -1230,6 +1232,7 @@ ST_FUNC Sym *sym_push2(Sym **ps, int v, int t, int c) memset(s, 0, sizeof *s); s->v = v; s->type.t = t; + s->type.td = td; s->c = c; /* add in stack */ s->prev = *ps; @@ -1287,7 +1290,7 @@ ST_FUNC Sym *sym_push(int v, CType *type, int r, int c) ps = &local_stack; else ps = &global_stack; - s = sym_push2(ps, v, type->t, c); + s = sym_push2(ps, v, type->t, type->td, c); s->type.ref = type->ref; s->r = r; /* don't record fields or anonymous symbols */ @@ -1310,10 +1313,10 @@ ST_FUNC Sym *sym_push(int v, CType *type, int r, int c) } /* push a global identifier */ -ST_FUNC Sym *global_identifier_push(int v, int t, int c) +ST_FUNC Sym *global_identifier_push(int v, int t, int td, int c) { Sym *s, **ps; - s = sym_push2(&global_stack, v, t, c); + s = sym_push2(&global_stack, v, t, td, c); s->r = VT_CONST | VT_SYM; /* don't record anonymous symbol */ if (v < SYM_FIRST_ANOM) { @@ -1431,6 +1434,7 @@ static void vpush64(int ty, unsigned long long v) CValue cval; CType ctype; ctype.t = ty; + ctype.td = 0; ctype.ref = NULL; cval.i = v; vsetc(&ctype, VT_CONST, &cval); @@ -1465,6 +1469,7 @@ static void vseti(int r, int v) { CType type; type.t = VT_INT; + type.td = 0; type.ref = NULL; vset(&type, r, v); } @@ -1644,7 +1649,7 @@ ST_FUNC Sym *external_global_sym(int v, CType *type) s = sym_find(v); if (!s) { /* push forward reference */ - s = global_identifier_push(v, type->t | VT_EXTERN, 0); + s = global_identifier_push(v, type->t | VT_EXTERN, type->td, 0); s->type.ref = type->ref; } else if (IS_ASM_SYM(s)) { s->type.t = type->t | (s->type.t & VT_EXTERN); @@ -1658,7 +1663,7 @@ ST_FUNC Sym *external_global_sym(int v, CType *type) This avoids type conflicts if the symbol is used from C too */ ST_FUNC Sym *external_helper_sym(int v) { - CType ct = { VT_ASM_FUNC, NULL }; + CType ct = { VT_ASM_FUNC, 0, NULL }; return external_global_sym(v, &ct); } @@ -1732,6 +1737,7 @@ static void patch_type(Sym *sym, CType *type) if (IS_ASM_SYM(sym)) { /* stay static if both are static */ sym->type.t = type->t & (sym->type.t | ~VT_STATIC); + sym->type.td = type->td; sym->type.ref = type->ref; } @@ -1761,6 +1767,7 @@ 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; + sym->type.td = type->td; sym->type.ref = type->ref; merge_funcattr(&sym->type.ref->f, &f); } else { @@ -1839,7 +1846,7 @@ static Sym *external_sym(int v, CType *type, int r, AttributeDef *ad) if (!s) { /* push forward reference */ - s = global_identifier_push(v, type->t, 0); + s = global_identifier_push(v, type->t, type->td, 0); s->r |= r; s->a = ad->a; s->asm_label = ad->asm_label; @@ -2049,6 +2056,7 @@ static void move_reg(int r, int s, int t) if (r != s) { save_reg(r); sv.type.t = t; + sv.type.td = 0; sv.type.ref = NULL; sv.r = s; sv.c.i = 0; @@ -2326,6 +2334,7 @@ ST_FUNC int gv(int rc) vtop->type.t &= ~VT_STRUCT_MASK; type.ref = NULL; + type.td = 0; type.t = vtop->type.t & VT_UNSIGNED; if ((vtop->type.t & VT_BTYPE) == VT_BOOL) type.t |= VT_UNSIGNED; @@ -3083,6 +3092,11 @@ static void type_to_str(char *buf, int buf_size, char buf1[256]; const char *tstr; + if (type->td) { + pstrcpy(buf, buf_size, get_tok_str(type->td, NULL)); + return; + } + t = type->t; bt = t & VT_BTYPE; buf[0] = '\0'; @@ -3095,6 +3109,7 @@ static void type_to_str(char *buf, int buf_size, pstrcat(buf, buf_size, "typedef "); if (t & VT_INLINE) pstrcat(buf, buf_size, "inline "); + if (bt != VT_PTR) { if (t & VT_VOLATILE) pstrcat(buf, buf_size, "volatile "); @@ -3336,6 +3351,7 @@ static int combine_types(CType *dest, SValue *op1, SValue *op2, int op) int ret = 1; type.t = VT_VOID; + type.td = 0; type.ref = NULL; if (bt1 == VT_VOID || bt2 == VT_VOID) { @@ -3666,6 +3682,7 @@ static void gen_cast_s(int t) { CType type; type.t = t; + type.td = 0; type.ref = NULL; gen_cast(&type); } @@ -3991,6 +4008,7 @@ ST_FUNC void mk_pointer(CType *type) Sym *s; s = sym_push(SYM_FIELD, type, 0, -1); type->t = VT_PTR | (type->t & VT_STORAGE); + type->td = 0; type->ref = s; } @@ -4533,18 +4551,23 @@ redo: static Sym * find_field (CType *type, int v, int *cumofs) { Sym *s = type->ref; - v |= SYM_FIELD; + int fv = v | SYM_FIELD; while ((s = s->next) != NULL) { if ((s->v & SYM_FIELD) && (s->type.t & VT_BTYPE) == VT_STRUCT && (s->v & ~SYM_FIELD) >= SYM_FIRST_ANOM) { - Sym *ret = find_field (&s->type, v, cumofs); + Sym *ret; + + if (tcc_state->plan9_extensions && s->type.td == v) + break; + + ret = find_field (&s->type, fv, cumofs); if (ret) { *cumofs += s->c; return ret; } } - if (s->v == v) + if (s->v == fv) break; } return s; @@ -4556,13 +4579,22 @@ static void check_fields (CType *type, int check) while ((s = s->next) != NULL) { int v = s->v & ~SYM_FIELD; - if (v < SYM_FIRST_ANOM) { - TokenSym *ts = table_ident[v - TOK_IDENT]; - if (check && (ts->tok & SYM_FIELD)) - tcc_error("duplicate member '%s'", get_tok_str(v, NULL)); - ts->tok ^= SYM_FIELD; - } else if ((s->type.t & VT_BTYPE) == VT_STRUCT) + TokenSym *ts; + if ((s->type.t & VT_BTYPE) == VT_STRUCT && + v >= SYM_FIRST_ANOM) { check_fields (&s->type, check); + v = s->type.td & ~SYM_FIELD; + if (!(tcc_state->plan9_extensions && s->type.td + && TOK_IDENT < v)) + continue; + } + if (v > SYM_FIRST_ANOM) + continue; + + ts = table_ident[v - TOK_IDENT]; + if (check && (ts->tok & SYM_FIELD)) + tcc_error("duplicate member '%s'", get_tok_str(v, NULL)); + ts->tok ^= SYM_FIELD; } } @@ -4744,7 +4776,7 @@ static void struct_layout(CType *type, AttributeDef *ad) /* check whether we can access bitfields by their type */ for (f = type->ref->next; f; f = f->next) { int s, px, cx, c0; - CType t; + CType t = {0}; if (0 == (f->type.t & VT_BITFIELD)) continue; @@ -4846,12 +4878,14 @@ static void struct_decl(CType *type, int u) } /* Record the original enum/struct/union token. */ type1.t = u == VT_ENUM ? u | VT_INT | VT_UNSIGNED : u; + type1.td = 0; type1.ref = NULL; /* we put an undefined size for struct/union */ s = sym_push(v | SYM_STRUCT, &type1, 0, -1); s->r = 0; /* default alignment is zero as gcc */ do_decl: type->t = s->type.t; + type->td = 0; type->ref = s; if (tok == '{') { @@ -4865,6 +4899,7 @@ do_decl: if (u == VT_ENUM) { long long ll = 0, pl = 0, nl = 0; CType t; + t.td = 0; t.ref = s; /* enum symbols have static storage */ t.t = VT_INT|VT_STATIC|VT_ENUM_VAL; @@ -4944,7 +4979,7 @@ do_decl: else { int v = btype.ref->v; if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) { - if (tcc_state->ms_extensions == 0) + if (!tcc_state->ms_extensions && !tcc_state->plan9_extensions) expect("identifier"); } } @@ -5066,6 +5101,7 @@ static int parse_btype(CType *type, AttributeDef *ad) typespec_found = 0; t = VT_INT; bt = st = -1; + type->td = 0; type->ref = NULL; while(1) { @@ -5288,6 +5324,7 @@ static int parse_btype(CType *type, AttributeDef *ad) t &= ~(VT_BTYPE|VT_LONG); u = t & ~(VT_CONSTANT | VT_VOLATILE), t ^= u; type->t = (s->type.t & ~VT_TYPEDEF) | u; + type->td = n; type->ref = s->type.ref; if (t) parse_btype_qualify(type, t); @@ -5392,6 +5429,7 @@ static int post_type(CType *type, AttributeDef *ad, int storage, int td) if (n < TOK_UIDENT) expect("identifier"); pt.t = VT_VOID; /* invalid type */ + pt.td = 0; pt.ref = NULL; next(); } @@ -5434,6 +5472,7 @@ static int post_type(CType *type, AttributeDef *ad, int storage, int td) s->f = ad->f; s->next = first; type->t = VT_FUNC; + type->td = 0; type->ref = s; } else if (tok == '[') { int saved_nocode_wanted = nocode_wanted; @@ -5513,6 +5552,7 @@ static int post_type(CType *type, AttributeDef *ad, int storage, int td) element type */ s = sym_push(SYM_FIELD, type, 0, n); type->t = (t1 ? VT_VLA : VT_ARRAY) | VT_PTR; + type->td = 0; type->ref = s; } return 1; @@ -5636,6 +5676,7 @@ static void gfunc_param_typed(Sym *func, Sym *arg) gen_cast_s(VT_DOUBLE); } else if (vtop->type.t & VT_BITFIELD) { type.t = vtop->type.t & (VT_BTYPE | VT_UNSIGNED); + type.td = vtop->type.td; type.ref = vtop->type.ref; gen_cast(&type); } else if (vtop->r & VT_MUSTCAST) { @@ -5705,8 +5746,8 @@ static void parse_builtin_params(int nc, const char *args) continue; } expr_eq(); + type.t = type.td = 0; type.ref = NULL; - type.t = 0; switch (c) { case 'e': continue; @@ -5857,6 +5898,7 @@ ST_FUNC void unary(void) sizeof_caller = in_sizeof; in_sizeof = 0; + type.td = 0; type.ref = NULL; /* XXX: GCC 2.95.3 does not generate a table although it should be better here */ @@ -7606,9 +7648,9 @@ again: if (s->r & LABEL_FORWARD) { /* start new goto chain for cleanups, linked via label->next */ if (cur_scope->cl.s && !nocode_wanted) { - sym_push2(&pending_gotos, SYM_FIELD, 0, cur_scope->cl.n); + sym_push2(&pending_gotos, SYM_FIELD, 0, 0, cur_scope->cl.n); pending_gotos->prev_tok = s; - s = sym_push2(&s->next, SYM_FIELD, 0, 0); + s = sym_push2(&s->next, SYM_FIELD, 0, 0, 0); pending_gotos->next = s; } s->jnext = gjmp(s->jnext); @@ -7922,7 +7964,7 @@ static int decl_designator(init_params *p, CType *type, unsigned long c, if (!(flags & DIF_SIZE_ONLY) && nb_elems > 1) { Sym aref = {0}; - CType t1; + CType t1 = {0}; int i; if (p->sec || (type->t & VT_ARRAY)) { /* make init_putv/vstore believe it were a struct */ @@ -8469,7 +8511,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, sym = sym_push(v, type, r, addr); if (ad->cleanup_func) { Sym *cls = sym_push2(&all_cleanups, - SYM_FIELD | ++cur_scope->cl.n, 0, 0); + SYM_FIELD | ++cur_scope->cl.n, 0, 0, 0); cls->prev_tok = sym; cls->next = ad->cleanup_func; cls->ncl = cur_scope->cl.s; @@ -8632,7 +8674,7 @@ static void gen_function(Sym *sym) /* put debug symbol */ tcc_debug_funcstart(tcc_state, sym); /* push a dummy symbol to enable local sym storage */ - sym_push2(&local_stack, SYM_FIELD, 0, 0); + sym_push2(&local_stack, SYM_FIELD, 0, 0, 0); local_scope = 1; /* for function parameters */ gfunc_prolog(sym); local_scope = 0; @@ -8656,6 +8698,7 @@ static void gen_function(Sym *sym) cur_text_section = NULL; funcname = ""; /* for safety */ func_vt.t = VT_VOID; /* for safety */ + func_vt.td = 0; /* for unsafety */ func_var = 0; /* for safety */ ind = 0; /* for safety */ nocode_wanted = 0x80000000; diff --git a/tccpp.c b/tccpp.c index 815ffe4..db747e4 100644 --- a/tccpp.c +++ b/tccpp.c @@ -1364,7 +1364,7 @@ ST_INLN void define_push(int v, int macro_type, int *str, Sym *first_arg) Sym *s, *o; o = define_find(v); - s = sym_push2(&define_stack, v, macro_type, 0); + s = sym_push2(&define_stack, v, macro_type, 0, 0); s->d = str; s->next = first_arg; table_ident[v - TOK_IDENT]->sym_define = s; @@ -1413,7 +1413,7 @@ ST_FUNC Sym *label_find(int v) ST_FUNC Sym *label_push(Sym **ptop, int v, int flags) { Sym *s, **ps; - s = sym_push2(ptop, v, 0, 0); + s = sym_push2(ptop, v, 0, 0, 0); s->r = flags; ps = &table_ident[v - TOK_IDENT]->sym_label; if (ptop == &global_label_stack) { @@ -1575,7 +1575,7 @@ ST_FUNC void parse_define(void) if (varg < TOK_IDENT) bad_list: tcc_error("bad macro parameter list"); - s = sym_push2(&define_stack, varg | SYM_FIELD, is_vaargs, 0); + s = sym_push2(&define_stack, varg | SYM_FIELD, is_vaargs, 0, 0); *ps = s; ps = &s->next; if (tok == ')') @@ -3140,7 +3140,7 @@ static int *macro_arg_subst(Sym **nested_list, const int *macro_str, Sym *args) used multiple times, but not if the argument contains the __COUNTER__ macro. */ TokenString str2; - sym_push2(&s->next, s->v, s->type.t, 0); + sym_push2(&s->next, s->v, s->type.t, s->type.td, 0); tok_str_new(&str2); macro_subst(&str2, nested_list, st); tok_str_add(&str2, 0); @@ -3456,7 +3456,7 @@ static int macro_subst_tok( str.len -= spc; tok_str_add(&str, -1); tok_str_add(&str, 0); - sa1 = sym_push2(&args, sa->v & ~SYM_FIELD, sa->type.t, 0); + sa1 = sym_push2(&args, sa->v & ~SYM_FIELD, sa->type.t, sa->type.td, 0); sa1->d = str.str; sa = sa->next; if (tok == ')') { @@ -3491,7 +3491,7 @@ static int macro_subst_tok( parse_flags = saved_parse_flags; } - sym_push2(nested_list, s->v, 0, 0); + sym_push2(nested_list, s->v, 0, 0, 0); parse_flags = saved_parse_flags; joined_str = macro_twosharps(mstr); macro_subst(tok_str, nested_list, joined_str ? joined_str : mstr);