tccgen.c: fix warning for incompatible struct- and function pointers

see tests2/60_errors_and_warnings.c
This commit is contained in:
grischka 2018-05-31 23:52:07 +02:00
parent ace1225492
commit 2b155a8c16
3 changed files with 124 additions and 39 deletions

View File

@ -2795,8 +2795,6 @@ static int is_compatible_func(CType *type1, CType *type2)
/* return true if type1 and type2 are the same. If unqualified is /* return true if type1 and type2 are the same. If unqualified is
true, qualifiers on the types are ignored. true, qualifiers on the types are ignored.
- enums are not checked as gcc __builtin_types_compatible_p ()
*/ */
static int compare_types(CType *type1, CType *type2, int unqualified) static int compare_types(CType *type1, CType *type2, int unqualified)
{ {
@ -2828,6 +2826,8 @@ 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)) {
return type1->ref == type2->ref;
} else { } else {
return 1; return 1;
} }
@ -2988,22 +2988,14 @@ static void gen_assign_cast(CType *dt)
{ {
CType *st, *type1, *type2; CType *st, *type1, *type2;
char buf1[256], buf2[256]; char buf1[256], buf2[256];
int dbt, sbt; int dbt, sbt, qualwarn, lvl;
st = &vtop->type; /* source type */ st = &vtop->type; /* source type */
dbt = dt->t & VT_BTYPE; dbt = dt->t & VT_BTYPE;
sbt = st->t & VT_BTYPE; sbt = st->t & VT_BTYPE;
if (sbt == VT_VOID || dbt == VT_VOID) { if (sbt == VT_VOID || dbt == VT_VOID) {
if (sbt == VT_VOID && dbt == VT_VOID) if (sbt == VT_VOID && dbt == VT_VOID)
; /* ; /* It is Ok if both are void */
It is Ok if both are void
A test program:
void func1() {}
void func2() {
return func1();
}
gcc accepts this program
*/
else else
tcc_error("cannot cast from/to void"); tcc_error("cannot cast from/to void");
} }
@ -3014,43 +3006,49 @@ static void gen_assign_cast(CType *dt)
/* special cases for pointers */ /* special cases for pointers */
/* '0' can also be a pointer */ /* '0' can also be a pointer */
if (is_null_pointer(vtop)) if (is_null_pointer(vtop))
goto type_ok; break;
/* accept implicit pointer to integer cast with warning */ /* accept implicit pointer to integer cast with warning */
if (is_integer_btype(sbt)) { if (is_integer_btype(sbt)) {
tcc_warning("assignment makes pointer from integer without a cast"); tcc_warning("assignment makes pointer from integer without a cast");
goto type_ok; break;
} }
type1 = pointed_type(dt); type1 = pointed_type(dt);
/* a function is implicitly a function pointer */ if (sbt == VT_PTR)
if (sbt == VT_FUNC) { type2 = pointed_type(st);
if ((type1->t & VT_BTYPE) != VT_VOID && else if (sbt == VT_FUNC)
!is_compatible_types(pointed_type(dt), st)) type2 = st; /* a function is implicitly a function pointer */
tcc_warning("assignment from incompatible pointer type"); else
goto type_ok;
}
if (sbt != VT_PTR)
goto error; goto error;
type2 = pointed_type(st); if (is_compatible_types(type1, type2))
if ((type1->t & VT_BTYPE) == VT_VOID || break;
(type2->t & VT_BTYPE) == VT_VOID) { for (qualwarn = lvl = 0;; ++lvl) {
/* void * can match anything */ if (((type2->t & VT_CONSTANT) && !(type1->t & VT_CONSTANT)) ||
} else { ((type2->t & VT_VOLATILE) && !(type1->t & VT_VOLATILE)))
//printf("types %08x %08x\n", type1->t, type2->t); qualwarn = 1;
/* exact type match, except for qualifiers */ dbt = type1->t & (VT_BTYPE|VT_LONG);
if (!is_compatible_unqualified_types(type1, type2)) { sbt = type2->t & (VT_BTYPE|VT_LONG);
if (dbt != VT_PTR || sbt != VT_PTR)
break;
type1 = pointed_type(type1);
type2 = pointed_type(type2);
}
if (!is_compatible_unqualified_types(type1, type2)) {
if ((dbt == VT_VOID || sbt == VT_VOID) && lvl == 0) {
/* void * can match anything */
} else if (dbt == sbt
&& is_integer_btype(sbt & VT_BTYPE)
&& IS_ENUM(type1->t) + IS_ENUM(type2->t)
+ !!((type1->t ^ type2->t) & VT_UNSIGNED) < 2) {
/* Like GCC don't warn by default for merely changes /* Like GCC don't warn by default for merely changes
in pointer target signedness. Do warn for different in pointer target signedness. Do warn for different
base types, though, in particular for unsigned enums base types, though, in particular for unsigned enums
and signed int targets. */ and signed int targets. */
if ((type1->t & (VT_BTYPE|VT_LONG)) != (type2->t & (VT_BTYPE|VT_LONG)) } else {
|| IS_ENUM(type1->t) || IS_ENUM(type2->t) tcc_warning("assignment from incompatible pointer type");
) break;
tcc_warning("assignment from incompatible pointer type"); }
}
} }
/* check const and volatile */ if (qualwarn)
if ((!(type1->t & VT_CONSTANT) && (type2->t & VT_CONSTANT)) ||
(!(type1->t & VT_VOLATILE) && (type2->t & VT_VOLATILE)))
tcc_warning("assignment discards qualifiers from pointer target type"); tcc_warning("assignment discards qualifiers from pointer target type");
break; break;
case VT_BYTE: case VT_BYTE:
@ -3074,7 +3072,6 @@ static void gen_assign_cast(CType *dt)
} }
break; break;
} }
type_ok:
gen_cast(dt); gen_cast(dt);
} }

View File

@ -48,4 +48,74 @@ enum rgb3 c = 42;
#elif defined test_74_non_const_init #elif defined test_74_non_const_init
int i = i++; int i = i++;
#elif defined test_pointer_assignment
void (*f1)(void);
void f2(void) {}
struct s1 *ps1;
struct s2 *ps2;
void *v1, **v2, ***v3;
enum e1 { a = 4 } e10, *e11, *e12;
enum e2 { b = -4 } e20, *e21;
enum e3 { c = 5000000000LL } e30;
int *ip;
unsigned int *up;
long *lp;
long long *llp;
char **c1;
char const **c2;
unsigned char **u1;
int no_main ()
{
// function
f1 = f2;
// struct
ps1 = ps2;
// void*
v1 = v3;
v2 = v3;
// enum
e11 = e12;
e11 = e21;
e11 = &e10;
ip = &e10;
ip = &e20;
up = &e10;
up = &e20;
up = &e30;
lp = ip;
lp = llp;
// constness
c1 = c2;
*c1 = *c2;
**c1 = **c2;
// unsigned = signed
u1 = c2;
*u1 = *c2;
**u1 = **c2;
c2 = c1;
*c2 = *c1;
**c2 = **c1;
return 0;
}
#elif defined test_enum_compat
enum e4;
enum e5;
void f3(enum e4 e);
void f3(enum e5 e);
#endif #endif

View File

@ -26,3 +26,21 @@
[test_74_non_const_init] [test_74_non_const_init]
60_errors_and_warnings.c:49: error: initializer element is not constant 60_errors_and_warnings.c:49: error: initializer element is not constant
[test_pointer_assignment]
60_errors_and_warnings.c:79: warning: assignment from incompatible pointer type
60_errors_and_warnings.c:82: warning: assignment from incompatible pointer type
60_errors_and_warnings.c:86: warning: assignment from incompatible pointer type
60_errors_and_warnings.c:88: warning: assignment from incompatible pointer type
60_errors_and_warnings.c:91: warning: assignment from incompatible pointer type
60_errors_and_warnings.c:92: warning: assignment from incompatible pointer type
60_errors_and_warnings.c:94: warning: assignment from incompatible pointer type
60_errors_and_warnings.c:95: warning: assignment from incompatible pointer type
60_errors_and_warnings.c:98: warning: assignment discards qualifiers from pointer target type
60_errors_and_warnings.c:99: warning: assignment discards qualifiers from pointer target type
60_errors_and_warnings.c:103: warning: assignment discards qualifiers from pointer target type
60_errors_and_warnings.c:104: warning: assignment discards qualifiers from pointer target type
60_errors_and_warnings.c:109: warning: assignment of read-only location
[test_enum_compat]
60_errors_and_warnings.c:119: error: incompatible types for redefinition of 'f3'