mirror of
https://github.com/frida/tinycc
synced 2024-12-24 22:16:49 +03:00
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
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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'
|
||||
|
Loading…
Reference in New Issue
Block a user