aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Matz <matz@suse.de>2016-08-07 02:15:34 +0200
committerMichael Matz <matz@suse.de>2016-12-15 17:47:10 +0100
commit34fc6435ee17e6d2bbfffc367532cf340cf730a2 (patch)
tree03f510ee2a18fa2e32d2c4026eee5fab0a811127
parentb1a906b970e1f55c1a3e6786cddb08719216ade3 (diff)
downloadtinycc-34fc6435ee17e6d2bbfffc367532cf340cf730a2.tar.gz
tinycc-34fc6435ee17e6d2bbfffc367532cf340cf730a2.tar.bz2
enums and ints are compatible
But like GCC do warn about changes in signedness. The latter leads to some changes in gen_assign_cast to not also warn about unsigned* = int* (where GCC warns, but only with extra warnings).
-rw-r--r--tcc.h3
-rw-r--r--tccasm.c2
-rw-r--r--tccgen.c42
-rw-r--r--tests/tcctest.c2
4 files changed, 35 insertions, 14 deletions
diff --git a/tcc.h b/tcc.h
index 470b8dc..f990f8f 100644
--- a/tcc.h
+++ b/tcc.h
@@ -387,7 +387,8 @@ struct Attribute {
mode : 4,
weak : 1,
visibility : 2,
- fill : 8; // 8 bits left to fit well in union below
+ unsigned_enum : 1,
+ fill : 7; // 7 bits left to fit well in union below
};
/* GNUC attribute definition */
diff --git a/tccasm.c b/tccasm.c
index ea65171..cef3f1c 100644
--- a/tccasm.c
+++ b/tccasm.c
@@ -612,7 +612,7 @@ static void asm_parse_directive(TCCState *s1)
case TOK_ASMDIR_global:
case TOK_ASMDIR_weak:
case TOK_ASMDIR_hidden:
- tok1 = tok;
+ tok1 = tok;
do {
Sym *sym;
diff --git a/tccgen.c b/tccgen.c
index 7c8bc32..eefa1b4 100644
--- a/tccgen.c
+++ b/tccgen.c
@@ -2565,13 +2565,20 @@ 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.<some_bit> 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) {
- /* An enum is compatible with (unsigned) int. */
- t1 = VT_INT | (t1 & ~VT_BTYPE);
+ t1 = VT_INT;
+ if (type1->ref->a.unsigned_enum)
+ t1 |= VT_UNSIGNED;
}
if ((t2 & VT_BTYPE) == VT_ENUM) {
- /* An enum is compatible with (unsigned) int. */
- t2 = VT_INT | (t2 & ~VT_BTYPE);
+ t2 = VT_INT;
+ if (type2->ref->a.unsigned_enum)
+ t2 |= VT_UNSIGNED;
}
/* XXX: bitfields ? */
if (t1 != t2)
@@ -2766,15 +2773,23 @@ static void gen_assign_cast(CType *dt)
(type2->t & VT_BTYPE) == VT_VOID) {
/* void * can match anything */
} else {
- /* exact type match, except for unsigned */
+ /* exact type match, except for qualifiers */
tmp_type1 = *type1;
tmp_type2 = *type2;
- tmp_type1.t &= ~(VT_DEFSIGN | VT_UNSIGNED | VT_CONSTANT |
- VT_VOLATILE);
- tmp_type2.t &= ~(VT_DEFSIGN | VT_UNSIGNED | VT_CONSTANT |
- VT_VOLATILE);
- if (!is_compatible_types(&tmp_type1, &tmp_type2))
- tcc_warning("assignment from incompatible pointer type");
+ tmp_type1.t &= ~(VT_CONSTANT | VT_VOLATILE);
+ tmp_type2.t &= ~(VT_CONSTANT | VT_VOLATILE);
+ if (!is_compatible_types(&tmp_type1, &tmp_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
+ tcc_warning("assignment from incompatible pointer type");
+ }
}
/* check const and volatile */
if ((!(type1->t & VT_CONSTANT) && (type2->t & VT_CONSTANT)) ||
@@ -3252,6 +3267,7 @@ static void struct_decl(CType *type, AttributeDef *ad, int u)
c = 0;
/* non empty enums are not allowed */
if (a == TOK_ENUM) {
+ int seen_neg = 0;
for(;;) {
v = tok;
if (v < TOK_UIDENT)
@@ -3265,6 +3281,8 @@ static void struct_decl(CType *type, AttributeDef *ad, int u)
next();
c = expr_const();
}
+ if (c < 0)
+ seen_neg = 1;
/* enum symbols have static storage */
ss = sym_push(v, &int_type, VT_CONST, c);
ss->type.t |= VT_STATIC;
@@ -3276,6 +3294,8 @@ static void struct_decl(CType *type, AttributeDef *ad, int u)
if (tok == '}')
break;
}
+ if (!seen_neg)
+ s->a.unsigned_enum = 1;
s->c = type_size(&int_type, &align);
skip('}');
} else {
diff --git a/tests/tcctest.c b/tests/tcctest.c
index a604c4a..d8c8bcf 100644
--- a/tests/tcctest.c
+++ b/tests/tcctest.c
@@ -591,7 +591,7 @@ void enum_test()
{
enum test b1;
/* The following should give no warning */
- int *p = &b1;
+ unsigned *p = &b1;
printf("enum:\n%d %d %d %d %d %d\n",
E0, E1, E2, E3, E4, E5);
b1 = 1;