tccgen.c: fix warning for incompatible struct- and function pointers
see tests2/60_errors_and_warnings.c
This commit is contained in:
parent
ace1225492
commit
2b155a8c16
75
tccgen.c
75
tccgen.c
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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'
|
||||||
|
|
Loading…
Reference in New Issue