diff --git a/arm64-gen.c b/arm64-gen.c index 1ebbd2b..86b3af7 100644 --- a/arm64-gen.c +++ b/arm64-gen.c @@ -249,7 +249,6 @@ static int arm64_type_size(int t) case VT_BYTE: return 0; case VT_SHORT: return 1; case VT_PTR: return 3; - case VT_ENUM: return 2; case VT_FUNC: return 3; case VT_FLOAT: return 2; case VT_DOUBLE: return 3; diff --git a/tcc.h b/tcc.h index 77fd938..3e81e03 100644 --- a/tcc.h +++ b/tcc.h @@ -416,8 +416,7 @@ struct SymAttr { visibility : 2, dllexport : 1, dllimport : 1, - unsigned_enum : 1, - unused : 4; + unused : 5; }; /* function attributes or temporary attributes for parsing */ @@ -852,14 +851,13 @@ struct filespec { #define VT_PTR 5 /* pointer */ #define VT_FUNC 6 /* function type */ #define VT_STRUCT 7 /* struct/union definition */ -#define VT_ENUM 8 /* enum definition */ -#define VT_FLOAT 9 /* IEEE float */ -#define VT_DOUBLE 10 /* IEEE double */ -#define VT_LDOUBLE 11 /* IEEE long double */ -#define VT_BOOL 12 /* ISOC99 boolean type */ -#define VT_LONG 13 /* long integer (NEVER USED as type, only during parsing) */ -#define VT_QLONG 14 /* 128-bit integer. Only used for x86-64 ABI */ -#define VT_QFLOAT 15 /* 128-bit float. Only used for x86-64 ABI */ +#define VT_FLOAT 8 /* IEEE float */ +#define VT_DOUBLE 9 /* IEEE double */ +#define VT_LDOUBLE 10 /* IEEE long double */ +#define VT_BOOL 11 /* ISOC99 boolean type */ +#define VT_LONG 12 /* long integer (NEVER USED as type, only during parsing) */ +#define VT_QLONG 13 /* 128-bit integer. Only used for x86-64 ABI */ +#define VT_QFLOAT 14 /* 128-bit float. Only used for x86-64 ABI */ #define VT_UNSIGNED 0x0010 /* unsigned type */ #define VT_DEFSIGN 0x0020 /* explicitly signed or unsigned */ @@ -868,7 +866,6 @@ struct filespec { #define VT_CONSTANT 0x0100 /* const modifier */ #define VT_VOLATILE 0x0200 /* volatile modifier */ #define VT_VLA 0x0400 /* VLA type (also has VT_PTR and VT_ARRAY) */ -#define VT_UNION (VT_STRUCT|VT_UNSIGNED) /* VT_STRUCT type with some modifier */ /* storage */ #define VT_EXTERN 0x00001000 /* extern definition */ @@ -882,9 +879,17 @@ struct filespec { #define BIT_POS(t) (((t) >> VT_STRUCT_SHIFT) & 0x3f) #define BIT_SIZE(t) (((t) >> (VT_STRUCT_SHIFT + 6)) & 0x3f) +#define VT_UNION (1 << VT_STRUCT_SHIFT | VT_STRUCT) +#define VT_ENUM (2 << VT_STRUCT_SHIFT) /* integral type is an enum really */ +#define VT_ENUM_VAL (3 << VT_STRUCT_SHIFT) /* integral type is an enum constant really */ + +#define IS_ENUM(t) ((t & VT_STRUCT_MASK) == VT_ENUM) +#define IS_ENUM_VAL(t) ((t & VT_STRUCT_MASK) == VT_ENUM_VAL) +#define IS_UNION(t) ((t & (VT_STRUCT_MASK|VT_BTYPE)) == VT_UNION) + /* type mask (except storage) */ -#define VT_STORAGE (VT_EXTERN | VT_STATIC | VT_TYPEDEF | VT_INLINE | VT_STRUCT_MASK) -#define VT_TYPE (~VT_STORAGE) +#define VT_STORAGE (VT_EXTERN | VT_STATIC | VT_TYPEDEF | VT_INLINE) +#define VT_TYPE (~(VT_STORAGE|VT_STRUCT_MASK)) /* token values */ diff --git a/tccgen.c b/tccgen.c index 4f2b501..49938b9 100644 --- a/tccgen.c +++ b/tccgen.c @@ -86,7 +86,7 @@ static void expr_eq(void); static void vla_runtime_type_size(CType *type, int *a); static void vla_sp_restore(void); static void vla_sp_restore_root(void); -static int is_compatible_parameter_types(CType *type1, CType *type2); +static int is_compatible_unqualified_types(CType *type1, CType *type2); static inline int64_t expr_const64(void); ST_FUNC void vpush64(int ty, unsigned long long v); ST_FUNC void vpush(CType *type); @@ -1087,10 +1087,8 @@ ST_FUNC int gv(int rc) bits = 64; } else type.t = VT_INT; - if((vtop->type.t & VT_UNSIGNED) || - (vtop->type.t & VT_BTYPE) == VT_BOOL || - (((vtop->type.t & VT_BTYPE) == VT_ENUM) && - vtop->type.ref->a.unsigned_enum)) + if((vtop->type.t & VT_UNSIGNED) + || (vtop->type.t & VT_BTYPE) == VT_BOOL) type.t |= VT_UNSIGNED; gen_cast(&type); /* generate shifts */ @@ -2479,6 +2477,8 @@ ST_FUNC int type_size(CType *type, int *a) *a = PTR_SIZE; return PTR_SIZE; } + } else if (IS_ENUM(type->t) && type->ref->c == -1) { + return -1; /* incomplete enum */ } else if (bt == VT_LDOUBLE) { *a = LDOUBLE_ALIGN; return LDOUBLE_SIZE; @@ -2508,10 +2508,6 @@ ST_FUNC int type_size(CType *type, int *a) } else if (bt == VT_QLONG || bt == VT_QFLOAT) { *a = 8; return 16; - } else if (bt == VT_ENUM) { - *a = 4; - /* Enums might be incomplete, so don't just return '4' here. */ - return type->ref->c; } else { /* char, void, function, _Bool */ *a = 1; @@ -2554,7 +2550,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_TYPE); + type->t = VT_PTR | (type->t & VT_STORAGE); type->ref = s; } @@ -2578,7 +2574,7 @@ static int is_compatible_func(CType *type1, CType *type2) while (s1 != NULL) { if (s2 == NULL) return 0; - if (!is_compatible_parameter_types(&s1->type, &s2->type)) + if (!is_compatible_unqualified_types(&s1->type, &s2->type)) return 0; s1 = s1->next; s2 = s2->next; @@ -2609,21 +2605,7 @@ static int compare_types(CType *type1, CType *type2, int unqualified) t1 &= ~VT_DEFSIGN; t2 &= ~VT_DEFSIGN; } - /* An enum is compatible with (unsigned) int. Ideally we would - store the enums signedness in type->ref.a. and - only accept unsigned enums with unsigned int and vice versa. - But one of our callers (gen_assign_cast) always strips VT_UNSIGNED - from pointer target types, so we can't add it here either. */ - if ((t1 & VT_BTYPE) == VT_ENUM) { - t1 = VT_INT; - if (type1->ref->a.unsigned_enum) - t1 |= VT_UNSIGNED; - } - if ((t2 & VT_BTYPE) == VT_ENUM) { - t2 = VT_INT; - if (type2->ref->a.unsigned_enum) - t2 |= VT_UNSIGNED; - } + /* XXX: bitfields ? */ if (t1 != t2) return 0; @@ -2652,7 +2634,7 @@ static int is_compatible_types(CType *type1, CType *type2) /* return true if type1 and type2 are the same (ignoring qualifiers). */ -static int is_compatible_parameter_types(CType *type1, CType *type2) +static int is_compatible_unqualified_types(CType *type1, CType *type2) { return compare_types(type1,type2,1); } @@ -2690,6 +2672,10 @@ static void type_to_str(char *buf, int buf_size, pstrcat(buf, buf_size, "inline "); buf_size -= strlen(buf); buf += strlen(buf); + if (IS_ENUM(type->t)) { + tstr = "enum "; + goto tstruct; + } switch(bt) { case VT_VOID: tstr = "void"; @@ -2723,12 +2709,11 @@ static void type_to_str(char *buf, int buf_size, add_tstr: pstrcat(buf, buf_size, tstr); break; - case VT_ENUM: case VT_STRUCT: - if (bt == VT_STRUCT) - tstr = "struct "; - else - tstr = "enum "; + tstr = "struct "; + if (IS_UNION(t)) + tstr = "union "; + tstruct: pstrcat(buf, buf_size, tstr); v = type->ref->v & ~SYM_STRUCT; if (v >= SYM_FIRST_ANOM) @@ -2827,21 +2812,16 @@ static void gen_assign_cast(CType *dt) (type2->t & VT_BTYPE) == VT_VOID) { /* void * can match anything */ } else { + //printf("types %08x %08x\n", type1->t, type2->t); /* exact type match, except for qualifiers */ - tmp_type1 = *type1; - tmp_type2 = *type2; - tmp_type1.t &= ~(VT_CONSTANT | VT_VOLATILE); - tmp_type2.t &= ~(VT_CONSTANT | VT_VOLATILE); - if (!is_compatible_types(&tmp_type1, &tmp_type2)) { + if (!is_compatible_unqualified_types(type1, type2)) { /* Like GCC don't warn by default for merely changes in pointer target signedness. Do warn for different base types, though, in particular for unsigned enums and signed int targets. */ - if ((tmp_type1.t & (VT_DEFSIGN | VT_UNSIGNED)) != - (tmp_type2.t & (VT_DEFSIGN | VT_UNSIGNED)) && - (tmp_type1.t & VT_BTYPE) == (tmp_type2.t & VT_BTYPE)) - ; - else + if ((type1->t & VT_BTYPE) != (type2->t & VT_BTYPE) + || IS_ENUM(type1->t) || IS_ENUM(type2->t) + ) tcc_warning("assignment from incompatible pointer type"); } } @@ -3486,7 +3466,7 @@ static void struct_layout(CType *type, AttributeDef *ad) tcc_warning("will touch memory past end of the struct (internal limitation)"); } -/* enum/struct/union declaration. u is either VT_ENUM or VT_STRUCT */ +/* enum/struct/union declaration. u is VT_ENUM/VT_STRUCT/VT_UNION */ static void struct_decl(CType *type, int u) { int v, c, size, align, flexible, alignoverride; @@ -3506,9 +3486,11 @@ static void struct_decl(CType *type, int u) expect("struct/union/enum name"); s = struct_find(v); if (s && (s->sym_scope == local_scope || tok != '{')) { - if ((s->type.t & (VT_BTYPE|VT_UNION)) != u) - tcc_error("redefinition of '%s'", get_tok_str(v, NULL)); - goto do_decl; + if (u == s->type.t) + goto do_decl; + if (u == VT_ENUM && IS_ENUM(s->type.t)) + goto do_decl; + tcc_error("redefinition of '%s'", get_tok_str(v, NULL)); } } else { v = anon_sym++; @@ -3520,7 +3502,7 @@ static void struct_decl(CType *type, int u) s = sym_push(v | SYM_STRUCT, &type1, 0, -1); s->r = 0; /* default alignment is zero as gcc */ do_decl: - type->t = u & VT_BTYPE; /* VT_UNION becomes VT_STRUCT */ + type->t = s->type.t; type->ref = s; if (tok == '{') { @@ -3528,13 +3510,15 @@ do_decl: if (s->c != -1) tcc_error("struct/union/enum already defined"); /* cannot be empty */ - c = 0; /* non empty enums are not allowed */ + ps = &s->next; if (u == VT_ENUM) { - int seen_neg = 0; - int seen_wide = 0; + long long ll = 0, pl = 0, nl = 0; + CType t; + t.ref = s; + /* enum symbols have static storage */ + t.t = VT_INT|VT_STATIC|VT_ENUM_VAL; for(;;) { - CType *t = &int_type; v = tok; if (v < TOK_UIDENT) expect("identifier"); @@ -3545,38 +3529,48 @@ do_decl: next(); if (tok == '=') { next(); -#if PTR_SIZE == 8 - c = expr_const64(); -#else - /* We really want to support long long enums - on i386 as well, but the Sym structure only - holds a 'long' for associated constants, - and enlarging it would bump its size (no - available padding). So punt for now. */ - c = expr_const(); -#endif + ll = expr_const64(); } - if (c < 0) - seen_neg = 1; - if (c != (int)c && (unsigned long)c != (unsigned int)c) - seen_wide = 1, t = &size_type; - /* enum symbols have static storage */ - ss = sym_push(v, t, VT_CONST, c); - ss->type.t |= VT_STATIC; + ss = sym_push(v, &t, VT_CONST, 0); + ss->enum_val = ll; + *ps = ss, ps = &ss->next; + if (ll < nl) + nl = ll; + if (ll > pl) + pl = ll; if (tok != ',') break; next(); - c++; + ll++; /* NOTE: we accept a trailing comma */ if (tok == '}') break; } - if (!seen_neg) - s->a.unsigned_enum = 1; - s->c = type_size(seen_wide ? &size_type : &int_type, &align); skip('}'); + /* set integral type of the enum */ + t.t = VT_INT; + if (nl == 0) { + if (pl != (unsigned)pl) + t.t = VT_LLONG; + t.t |= VT_UNSIGNED; + } else if (pl != (int)pl || nl != (int)nl) + t.t = VT_LLONG; + s->type.t = type->t = t.t | VT_ENUM; + s->c = 0; + /* set type for enum members */ + for (ss = s->next; ss; ss = ss->next) { + ll = ss->enum_val; + if (ll == (int)ll) /* default is int if it fits */ + continue; + if (t.t & VT_UNSIGNED) { + ss->type.t |= VT_UNSIGNED; + if (ll == (unsigned)ll) + continue; + } + ss->type.t = (ss->type.t & ~VT_BTYPE) | VT_LLONG; + } } else { - ps = &s->next; + c = 0; flexible = 0; while (tok != '}') { if (!parse_btype(&btype, &ad1)) { @@ -3646,7 +3640,6 @@ do_decl: bt != VT_BYTE && bt != VT_SHORT && bt != VT_BOOL && - bt != VT_ENUM && bt != VT_LLONG) tcc_error("bitfields must have scalar type"); bsize = size * 8; @@ -3657,9 +3650,9 @@ do_decl: /* no need for bit fields */ ; } else { - type1.t |= VT_BITFIELD | - (0 << VT_STRUCT_SHIFT) | - (bit_size << (VT_STRUCT_SHIFT + 6)); + type1.t = (type1.t & ~VT_STRUCT_MASK) + | VT_BITFIELD + | (bit_size << (VT_STRUCT_SHIFT + 6)); } } if (v != 0 || (type1.t & VT_BTYPE) == VT_STRUCT) { @@ -4124,6 +4117,7 @@ static CType *type_decl(CType *type, AttributeDef *ad, int *v, int td) storage = type->t & VT_STORAGE; type->t &= ~VT_STORAGE; post = ret = type; + while (tok == '*') { qualifiers = 0; redo: @@ -4813,8 +4807,11 @@ ST_FUNC void unary(void) Will be used by at least the x86 inline asm parser for regvars. */ vtop->sym = s; - if (vtop->r & VT_SYM) { + + if (r & VT_SYM) { vtop->c.i = 0; + } else if (r == VT_CONST && IS_ENUM_VAL(s->type.t)) { + vtop->c.i = s->enum_val; } break; } @@ -6352,7 +6349,7 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c, /* Use i_c_parameter_t, to strip toplevel qualifiers. The source type might have VT_CONSTANT set, which is of course assignable to non-const elements. */ - is_compatible_parameter_types(type, &vtop->type)) { + is_compatible_unqualified_types(type, &vtop->type)) { init_putv(type, sec, c); } else if (type->t & VT_ARRAY) { s = type->ref; @@ -6858,16 +6855,18 @@ static int decl0(int l, int is_for_loop_init, Sym *func_sym) break; btype.t = VT_INT; } - if (((btype.t & VT_BTYPE) == VT_ENUM || - (btype.t & VT_BTYPE) == VT_STRUCT) && - tok == ';') { + if (tok == ';') { if ((btype.t & VT_BTYPE) == VT_STRUCT) { int v = btype.ref->v; if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) >= SYM_FIRST_ANOM) tcc_warning("unnamed struct/union that defines no instances"); + next(); + continue; } - next(); - continue; + if (IS_ENUM(btype.t)) { + next(); + continue; + } } while (1) { /* iterate thru each declaration */ type = btype; diff --git a/x86_64-gen.c b/x86_64-gen.c index feedc12..a71e209 100644 --- a/x86_64-gen.c +++ b/x86_64-gen.c @@ -415,9 +415,11 @@ void load(int r, SValue *sv) } else if ((ft & VT_TYPE) == (VT_SHORT | VT_UNSIGNED)) { b = 0xb70f; /* movzwl */ } else { - assert(((ft & VT_BTYPE) == VT_INT) || ((ft & VT_BTYPE) == VT_LLONG) - || ((ft & VT_BTYPE) == VT_PTR) || ((ft & VT_BTYPE) == VT_ENUM) - || ((ft & VT_BTYPE) == VT_FUNC)); + assert(((ft & VT_BTYPE) == VT_INT) + || ((ft & VT_BTYPE) == VT_LLONG) + || ((ft & VT_BTYPE) == VT_PTR) + || ((ft & VT_BTYPE) == VT_FUNC) + ); ll = is64_type(ft); b = 0x8b; } @@ -1092,7 +1094,7 @@ static X86_64_Mode classify_x86_64_inner(CType *ty) case VT_BOOL: case VT_PTR: case VT_FUNC: - case VT_ENUM: return x86_64_mode_integer; + return x86_64_mode_integer; case VT_FLOAT: case VT_DOUBLE: return x86_64_mode_sse;