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

View File

@ -48,4 +48,74 @@ enum rgb3 c = 42;
#elif defined test_74_non_const_init
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

View File

@ -26,3 +26,21 @@
[test_74_non_const_init]
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'