Fix incorrect one-sided void handling in ?:

Also make the case when one side in ?: is a ptr
and the other is neither a ptr nor a null-ptr constant
fail cleanly instead of segfaulting.
This commit is contained in:
Petr Skocik 2018-11-29 13:40:48 +01:00
parent 49dfb5755a
commit f7779efe58
2 changed files with 26 additions and 20 deletions

View File

@ -5598,7 +5598,9 @@ static void expr_cond(void)
/* cast operands to correct type according to ISOC rules */
if (is_float(bt1) || is_float(bt2)) {
if (bt1 == VT_VOID || bt2 == VT_VOID) {
type.t = VT_VOID; /* NOTE: as an extension, we accept void on only one side */
}else if (is_float(bt1) || is_float(bt2)) {
if (bt1 == VT_LDOUBLE || bt2 == VT_LDOUBLE) {
type.t = VT_LDOUBLE;
@ -5625,8 +5627,11 @@ static void expr_cond(void)
if (is_null_pointer (vtop)) type = type1;
else if (is_null_pointer (&sv)) type = type2;
else{
int pbt1 = (pointed_type(&type1)->t&VT_BTYPE);
int pbt2 = (pointed_type(&type2)->t&VT_BTYPE);
int pbt1, pbt2;
if (bt1!=bt2)
tcc_error("incompatible types in conditional expressions");
pbt1 = (pointed_type(&type1)->t&VT_BTYPE);
pbt2 = (pointed_type(&type2)->t&VT_BTYPE);
/*pointers to void get preferred, otherwise the pointed to types minus qualifs should be compatible*/
type = (pbt1==VT_VOID) ? type1 : type2;
if (pbt1!=VT_VOID && pbt2!=VT_VOID){
@ -5652,9 +5657,6 @@ static void expr_cond(void)
} else if (bt1 == VT_STRUCT || bt2 == VT_STRUCT) {
/* XXX: test structure compatibility */
type = bt1 == VT_STRUCT ? type1 : type2;
} else if (bt1 == VT_VOID || bt2 == VT_VOID) {
/* NOTE: as an extension, we accept void on only one side */
type.t = VT_VOID;
} else {
/* integer operations */
type.t = VT_INT | (VT_LONG & (t1 | t2));

View File

@ -6,20 +6,24 @@ static void f (void){}
void (*fp)(void) = f;
void call_fp()
{
(fp?f:f)();
(fp?fp:fp)();
(fp?fp:&f)();
(fp?&f:fp)();
(fp?&f:&f)();
_Generic(0?arr:arr, char*: (void)0);
_Generic(0?&arr[0]:arr, char*: (void)0);
_Generic(0?arr:&arr[0], char*: (void)0);
_Generic(1?arr:arr, char*: (void)0);
_Generic(1?&arr[0]:arr, char*: (void)0);
_Generic(1?arr:&arr[0], char*: (void)0);
_Generic((__typeof(1?f:f)*){0}, void (**)(void): (void)0);
(fp?&f:f)();
(fp?f:&f)();
(fp?f:f)();
(fp?fp:fp)();
(fp?fp:&f)();
(fp?&f:fp)();
(fp?&f:&f)();
_Generic(0?arr:arr, char*: (void)0);
_Generic(0?&arr[0]:arr, char*: (void)0);
_Generic(0?arr:&arr[0], char*: (void)0);
_Generic(1?arr:arr, char*: (void)0);
_Generic(1?&arr[0]:arr, char*: (void)0);
_Generic(1?arr:&arr[0], char*: (void)0);
_Generic((__typeof(1?f:f)*){0}, void (**)(void): (void)0);
(fp?&f:f)();
(fp?f:&f)();
_Generic((__typeof(fp?0L:(void)0)*){0}, void*: (void)0);
//Should cleanly fail, not segfault:
/*(fp?f:1);*/
}
int main()