tccgen: C2x 'enum <tag> : <type> ...'
accept the new C2x typed enums (seems new android-NDK headers are using that now)
This commit is contained in:
parent
249a0b6b60
commit
4b0402825e
1 changed files with 52 additions and 21 deletions
73
tccgen.c
73
tccgen.c
|
@ -2791,6 +2791,13 @@ static int compare_types(CType *type1, CType *type2, int unqualified)
|
|||
{
|
||||
int bt1, t1, t2;
|
||||
|
||||
if (IS_ENUM(type1->t)) {
|
||||
if (IS_ENUM(type2->t))
|
||||
return type1->ref == type2->ref;
|
||||
type1 = &type1->ref->type;
|
||||
} else if (IS_ENUM(type2->t))
|
||||
type2 = &type2->ref->type;
|
||||
|
||||
t1 = type1->t & VT_TYPE;
|
||||
t2 = type2->t & VT_TYPE;
|
||||
if (unqualified) {
|
||||
|
@ -2824,10 +2831,6 @@ static int compare_types(CType *type1, CType *type2, int unqualified)
|
|||
return (type1->ref == type2->ref);
|
||||
} else if (bt1 == VT_FUNC) {
|
||||
return is_compatible_func(type1, type2);
|
||||
} else if (IS_ENUM(type1->t) && IS_ENUM(type2->t)) {
|
||||
/* If both are enums then they must be the same, if only one is then
|
||||
t1 and t2 must be equal, which was checked above already. */
|
||||
return type1->ref == type2->ref;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
|
@ -3191,6 +3194,9 @@ static void gen_cast(CType *type)
|
|||
if (vtop->type.t & VT_BITFIELD)
|
||||
gv(RC_INT);
|
||||
|
||||
if (IS_ENUM(type->t) && type->ref->c < 0)
|
||||
tcc_error("cast to incomplete type");
|
||||
|
||||
dbt = type->t & (VT_BTYPE | VT_UNSIGNED);
|
||||
sbt = vtop->type.t & (VT_BTYPE | VT_UNSIGNED);
|
||||
if (sbt == VT_FUNC)
|
||||
|
@ -3313,9 +3319,6 @@ error:
|
|||
if (ds == 0 || ss == 0)
|
||||
goto error;
|
||||
|
||||
if (IS_ENUM(type->t) && type->ref->c < 0)
|
||||
tcc_error("cast to incomplete type");
|
||||
|
||||
/* same size and no sign conversion needed */
|
||||
if (ds == ss && ds >= 4)
|
||||
goto done;
|
||||
|
@ -4343,7 +4346,7 @@ static void do_Static_assert(void);
|
|||
static void struct_decl(CType *type, int u)
|
||||
{
|
||||
int v, c, size, align, flexible;
|
||||
int bit_size, bsize, bt;
|
||||
int bit_size, bsize, bt, ut;
|
||||
Sym *s, *ss, **ps;
|
||||
AttributeDef ad, ad1;
|
||||
CType type1, btype;
|
||||
|
@ -4351,28 +4354,43 @@ static void struct_decl(CType *type, int u)
|
|||
memset(&ad, 0, sizeof ad);
|
||||
next();
|
||||
parse_attribute(&ad);
|
||||
if (tok != '{') {
|
||||
v = tok;
|
||||
next();
|
||||
|
||||
v = 0;
|
||||
if (tok >= TOK_IDENT) /* struct/enum tag */
|
||||
v = tok, next();
|
||||
|
||||
bt = ut = 0;
|
||||
if (u == VT_ENUM) {
|
||||
ut = VT_INT;
|
||||
if (tok == ':') { /* C2x enum : <type> ... */
|
||||
next();
|
||||
if (!parse_btype(&btype, &ad1, 0)
|
||||
|| !is_integer_btype(btype.t & VT_BTYPE))
|
||||
expect("enum type");
|
||||
bt = ut = btype.t & (VT_BTYPE|VT_LONG|VT_UNSIGNED|VT_DEFSIGN);
|
||||
}
|
||||
}
|
||||
|
||||
if (v) {
|
||||
/* struct already defined ? return it */
|
||||
if (v < TOK_IDENT)
|
||||
expect("struct/union/enum name");
|
||||
s = struct_find(v);
|
||||
if (s && (s->sym_scope == local_scope || tok != '{')) {
|
||||
if (s && (s->sym_scope == local_scope || (tok != '{' && tok != ';'))) {
|
||||
if (u == s->type.t)
|
||||
goto do_decl;
|
||||
if (u == VT_ENUM && IS_ENUM(s->type.t))
|
||||
if (u == VT_ENUM && IS_ENUM(s->type.t)) /* XXX: check integral types */
|
||||
goto do_decl;
|
||||
tcc_error("redefinition of '%s'", get_tok_str(v, NULL));
|
||||
tcc_error("redeclaration of '%s'", get_tok_str(v, NULL));
|
||||
}
|
||||
} else {
|
||||
if (tok != '{')
|
||||
expect("struct/union/enum name");
|
||||
v = anon_sym++;
|
||||
}
|
||||
/* Record the original enum/struct/union token. */
|
||||
type1.t = u == VT_ENUM ? u | VT_INT | VT_UNSIGNED : u;
|
||||
type1.t = u | ut;
|
||||
type1.ref = NULL;
|
||||
/* we put an undefined size for struct/union */
|
||||
s = sym_push(v | SYM_STRUCT, &type1, 0, -1);
|
||||
s = sym_push(v | SYM_STRUCT, &type1, 0, bt ? 0 : -1);
|
||||
s->r = 0; /* default alignment is zero as gcc */
|
||||
do_decl:
|
||||
type->t = s->type.t;
|
||||
|
@ -4380,7 +4398,8 @@ do_decl:
|
|||
|
||||
if (tok == '{') {
|
||||
next();
|
||||
if (s->c != -1)
|
||||
if (s->c != -1
|
||||
&& !(u == VT_ENUM && s->c == 0)) /* not yet defined typed enum */
|
||||
tcc_error("struct/union/enum already defined");
|
||||
s->c = -2;
|
||||
/* cannot be empty */
|
||||
|
@ -4392,6 +4411,8 @@ do_decl:
|
|||
t.ref = s;
|
||||
/* enum symbols have static storage */
|
||||
t.t = VT_INT|VT_STATIC|VT_ENUM_VAL;
|
||||
if (bt)
|
||||
t.t = bt|VT_STATIC|VT_ENUM_VAL;
|
||||
for(;;) {
|
||||
v = tok;
|
||||
if (v < TOK_UIDENT)
|
||||
|
@ -4421,6 +4442,13 @@ do_decl:
|
|||
break;
|
||||
}
|
||||
skip('}');
|
||||
|
||||
if (bt) {
|
||||
t.t = bt;
|
||||
s->c = 2;
|
||||
goto enum_done;
|
||||
}
|
||||
|
||||
/* set integral type of the enum */
|
||||
t.t = VT_INT;
|
||||
if (nl >= 0) {
|
||||
|
@ -4429,8 +4457,7 @@ do_decl:
|
|||
t.t |= VT_UNSIGNED;
|
||||
} else if (pl != (int)pl || nl != (int)nl)
|
||||
t.t = (LONG_SIZE==8 ? VT_LLONG|VT_LONG : 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;
|
||||
|
@ -4444,6 +4471,10 @@ do_decl:
|
|||
ss->type.t = (ss->type.t & ~VT_BTYPE)
|
||||
| (LONG_SIZE==8 ? VT_LLONG|VT_LONG : VT_LLONG);
|
||||
}
|
||||
s->c = 1;
|
||||
enum_done:
|
||||
s->type.t = type->t = t.t | VT_ENUM;
|
||||
|
||||
} else {
|
||||
c = 0;
|
||||
flexible = 0;
|
||||
|
|
Loading…
Reference in a new issue