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;
|
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;
|
t1 = type1->t & VT_TYPE;
|
||||||
t2 = type2->t & VT_TYPE;
|
t2 = type2->t & VT_TYPE;
|
||||||
if (unqualified) {
|
if (unqualified) {
|
||||||
|
@ -2824,10 +2831,6 @@ static int compare_types(CType *type1, CType *type2, int unqualified)
|
||||||
return (type1->ref == type2->ref);
|
return (type1->ref == type2->ref);
|
||||||
} else if (bt1 == VT_FUNC) {
|
} else if (bt1 == VT_FUNC) {
|
||||||
return is_compatible_func(type1, type2);
|
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 {
|
} else {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -3191,6 +3194,9 @@ static void gen_cast(CType *type)
|
||||||
if (vtop->type.t & VT_BITFIELD)
|
if (vtop->type.t & VT_BITFIELD)
|
||||||
gv(RC_INT);
|
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);
|
dbt = type->t & (VT_BTYPE | VT_UNSIGNED);
|
||||||
sbt = vtop->type.t & (VT_BTYPE | VT_UNSIGNED);
|
sbt = vtop->type.t & (VT_BTYPE | VT_UNSIGNED);
|
||||||
if (sbt == VT_FUNC)
|
if (sbt == VT_FUNC)
|
||||||
|
@ -3313,9 +3319,6 @@ error:
|
||||||
if (ds == 0 || ss == 0)
|
if (ds == 0 || ss == 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (IS_ENUM(type->t) && type->ref->c < 0)
|
|
||||||
tcc_error("cast to incomplete type");
|
|
||||||
|
|
||||||
/* same size and no sign conversion needed */
|
/* same size and no sign conversion needed */
|
||||||
if (ds == ss && ds >= 4)
|
if (ds == ss && ds >= 4)
|
||||||
goto done;
|
goto done;
|
||||||
|
@ -4343,7 +4346,7 @@ static void do_Static_assert(void);
|
||||||
static void struct_decl(CType *type, int u)
|
static void struct_decl(CType *type, int u)
|
||||||
{
|
{
|
||||||
int v, c, size, align, flexible;
|
int v, c, size, align, flexible;
|
||||||
int bit_size, bsize, bt;
|
int bit_size, bsize, bt, ut;
|
||||||
Sym *s, *ss, **ps;
|
Sym *s, *ss, **ps;
|
||||||
AttributeDef ad, ad1;
|
AttributeDef ad, ad1;
|
||||||
CType type1, btype;
|
CType type1, btype;
|
||||||
|
@ -4351,28 +4354,43 @@ static void struct_decl(CType *type, int u)
|
||||||
memset(&ad, 0, sizeof ad);
|
memset(&ad, 0, sizeof ad);
|
||||||
next();
|
next();
|
||||||
parse_attribute(&ad);
|
parse_attribute(&ad);
|
||||||
if (tok != '{') {
|
|
||||||
v = tok;
|
v = 0;
|
||||||
next();
|
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 */
|
/* struct already defined ? return it */
|
||||||
if (v < TOK_IDENT)
|
|
||||||
expect("struct/union/enum name");
|
|
||||||
s = struct_find(v);
|
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)
|
if (u == s->type.t)
|
||||||
goto do_decl;
|
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;
|
goto do_decl;
|
||||||
tcc_error("redefinition of '%s'", get_tok_str(v, NULL));
|
tcc_error("redeclaration of '%s'", get_tok_str(v, NULL));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if (tok != '{')
|
||||||
|
expect("struct/union/enum name");
|
||||||
v = anon_sym++;
|
v = anon_sym++;
|
||||||
}
|
}
|
||||||
/* Record the original enum/struct/union token. */
|
/* 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;
|
type1.ref = NULL;
|
||||||
/* we put an undefined size for struct/union */
|
/* 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 */
|
s->r = 0; /* default alignment is zero as gcc */
|
||||||
do_decl:
|
do_decl:
|
||||||
type->t = s->type.t;
|
type->t = s->type.t;
|
||||||
|
@ -4380,7 +4398,8 @@ do_decl:
|
||||||
|
|
||||||
if (tok == '{') {
|
if (tok == '{') {
|
||||||
next();
|
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");
|
tcc_error("struct/union/enum already defined");
|
||||||
s->c = -2;
|
s->c = -2;
|
||||||
/* cannot be empty */
|
/* cannot be empty */
|
||||||
|
@ -4392,6 +4411,8 @@ do_decl:
|
||||||
t.ref = s;
|
t.ref = s;
|
||||||
/* enum symbols have static storage */
|
/* enum symbols have static storage */
|
||||||
t.t = VT_INT|VT_STATIC|VT_ENUM_VAL;
|
t.t = VT_INT|VT_STATIC|VT_ENUM_VAL;
|
||||||
|
if (bt)
|
||||||
|
t.t = bt|VT_STATIC|VT_ENUM_VAL;
|
||||||
for(;;) {
|
for(;;) {
|
||||||
v = tok;
|
v = tok;
|
||||||
if (v < TOK_UIDENT)
|
if (v < TOK_UIDENT)
|
||||||
|
@ -4421,6 +4442,13 @@ do_decl:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
skip('}');
|
skip('}');
|
||||||
|
|
||||||
|
if (bt) {
|
||||||
|
t.t = bt;
|
||||||
|
s->c = 2;
|
||||||
|
goto enum_done;
|
||||||
|
}
|
||||||
|
|
||||||
/* set integral type of the enum */
|
/* set integral type of the enum */
|
||||||
t.t = VT_INT;
|
t.t = VT_INT;
|
||||||
if (nl >= 0) {
|
if (nl >= 0) {
|
||||||
|
@ -4429,8 +4457,7 @@ do_decl:
|
||||||
t.t |= VT_UNSIGNED;
|
t.t |= VT_UNSIGNED;
|
||||||
} else if (pl != (int)pl || nl != (int)nl)
|
} else if (pl != (int)pl || nl != (int)nl)
|
||||||
t.t = (LONG_SIZE==8 ? VT_LLONG|VT_LONG : VT_LLONG);
|
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 */
|
/* set type for enum members */
|
||||||
for (ss = s->next; ss; ss = ss->next) {
|
for (ss = s->next; ss; ss = ss->next) {
|
||||||
ll = ss->enum_val;
|
ll = ss->enum_val;
|
||||||
|
@ -4444,6 +4471,10 @@ do_decl:
|
||||||
ss->type.t = (ss->type.t & ~VT_BTYPE)
|
ss->type.t = (ss->type.t & ~VT_BTYPE)
|
||||||
| (LONG_SIZE==8 ? VT_LLONG|VT_LONG : VT_LLONG);
|
| (LONG_SIZE==8 ? VT_LLONG|VT_LONG : VT_LLONG);
|
||||||
}
|
}
|
||||||
|
s->c = 1;
|
||||||
|
enum_done:
|
||||||
|
s->type.t = type->t = t.t | VT_ENUM;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
c = 0;
|
c = 0;
|
||||||
flexible = 0;
|
flexible = 0;
|
||||||
|
|
Loading…
Reference in a new issue