rework type coercion in ternary expr (a bit) and uncomment previously failing test. Be more explicit in diagnostic messages.

This commit is contained in:
Udo 2020-02-17 18:25:43 +01:00
parent a9e7fe19c7
commit 9272fac7c4
3 changed files with 112 additions and 47 deletions

125
tccgen.c
View File

@ -3312,12 +3312,25 @@ static void type_to_str(char *buf, int buf_size,
no_var: ;
}
static void cast_error(CType *st, CType *dt)
static void type_incompatibility_error(CType* st, CType* dt, const char* fmt)
{
char buf1[256], buf2[256];
type_to_str(buf1, sizeof(buf1), st, NULL);
type_to_str(buf2, sizeof(buf2), dt, NULL);
tcc_error("cannot convert '%s' to '%s'", buf1, buf2);
tcc_error(fmt, buf1, buf2);
}
static void type_incompatibility_warning(CType* st, CType* dt, const char* fmt)
{
char buf1[256], buf2[256];
type_to_str(buf1, sizeof(buf1), st, NULL);
type_to_str(buf2, sizeof(buf2), dt, NULL);
tcc_warning(fmt, buf1, buf2);
}
static void cast_error(CType *st, CType *dt)
{
type_incompatibility_error(st, dt, "cannot convert '%s' to '%s'");
}
/* verify type compatibility to store vtop in 'dt' type */
@ -5523,8 +5536,11 @@ special_math_val:
test_lvalue();
gaddrof();
/* expect pointer on structure */
if ((vtop->type.t & VT_BTYPE) != VT_STRUCT)
expect("struct or union");
if ( (vtop->type.t & VT_BTYPE) != VT_STRUCT ) {
char got[256];
type_to_str(got, sizeof got, &vtop->type, NULL);
tcc_error("expected struct or union but not '%s'", got);
}
if (tok == TOK_CDOUBLE)
expect("field name");
next();
@ -6001,7 +6017,13 @@ static void expr_cond(void)
/* cast operands to correct type according to ISOC rules */
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)) {
} else if ( bt1 == VT_BOOL && bt2 == VT_BOOL ) {
type = type1;
} else if ( is_float(bt1) && is_integer_btype(bt2) ) {
type = type1;
} else if ( is_integer_btype(bt1) && is_float(bt2) ) {
type = type2;
} else if (is_float(bt1) && is_float(bt2)) {
if (bt1 == VT_LDOUBLE || bt2 == VT_LDOUBLE) {
type.t = VT_LDOUBLE;
@ -6010,56 +6032,65 @@ static void expr_cond(void)
} else {
type.t = VT_FLOAT;
}
} else if (bt1 == VT_LLONG || bt2 == VT_LLONG) {
} else if ((bt1 == VT_LLONG && is_integer_btype(bt2)) ||
(bt2 == VT_LLONG && is_integer_btype(bt1))) {
/* cast to biggest op */
type.t = VT_LLONG | VT_LONG;
if (bt1 == VT_LLONG)
if ( bt1 == VT_LLONG )
type.t &= t1;
if (bt2 == VT_LLONG)
if ( bt2 == VT_LLONG )
type.t &= t2;
/* convert to unsigned if it does not fit in a long long */
if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED) ||
(t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED))
type.t |= VT_UNSIGNED;
} else if (bt1 == VT_PTR || bt2 == VT_PTR) {
/* http://port70.net/~nsz/c/c99/n1256.html#6.5.15p6 */
/* If one is a null ptr constant the result type
is the other. */
if (is_null_pointer (vtop)) type = type1;
else if (is_null_pointer (&sv)) type = type2;
else if (bt1 != bt2)
tcc_error("incompatible types in conditional expressions");
else {
CType *pt1 = pointed_type(&type1);
CType *pt2 = pointed_type(&type2);
int pbt1 = pt1->t & VT_BTYPE;
int pbt2 = pt2->t & VT_BTYPE;
int newquals, copied = 0;
/* 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) {
if(!compare_types(pt1, pt2, 1/*unqualif*/))
tcc_warning("pointer type mismatch in conditional expression\n");
}
/* combine qualifs */
newquals = ((pt1->t | pt2->t) & (VT_CONSTANT | VT_VOLATILE));
if ((~pointed_type(&type)->t & (VT_CONSTANT | VT_VOLATILE))
}
/* http://port70.net/~nsz/c/c99/n1256.html#6.5.15p6 */
/* If one is a null ptr constant the result type
is the other. */
else if ( bt1 == VT_PTR && is_null_pointer(vtop) ) {
type = type1;
} else if ( is_null_pointer(&sv) && bt2 == VT_PTR ) {
type = type2;
} else if ( bt1 == VT_PTR && is_integer_btype(bt2) ) {
type = type1;
tcc_warning("pointer/integer mismatch");
} else if ( is_integer_btype(bt1) && bt2 == VT_PTR ) {
type = type2;
tcc_warning("pointer/integer mismatch");
} else if ( bt1==VT_PTR && bt2 == VT_PTR ) {
CType *pt1 = pointed_type(&type1);
CType *pt2 = pointed_type(&type2);
int pbt1 = pt1->t & VT_BTYPE;
int pbt2 = pt2->t & VT_BTYPE;
int newquals, copied = 0;
/* 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 && ! compare_types(pt1, pt2, 1/*unqualif*/) ) {
type_incompatibility_warning(&type1, &type2, "incompatible pointer types");
// result is void*
type.t = VT_VOID;
mk_pointer(&type);
}
/* combine qualifs */
newquals = ((pt1->t | pt2->t) & (VT_CONSTANT | VT_VOLATILE));
if ((~pointed_type(&type)->t & (VT_CONSTANT | VT_VOLATILE))
& newquals)
{
{
/* copy the pointer target symbol */
type.ref = sym_push(SYM_FIELD, &type.ref->type,
0, type.ref->c);
copied = 1;
pointed_type(&type)->t |= newquals;
}
/* pointers to incomplete arrays get converted to
pointers to completed ones if possible */
if (pt1->t & VT_ARRAY
}
/* pointers to incomplete arrays get converted to
pointers to completed ones if possible */
if (pt1->t & VT_ARRAY
&& pt2->t & VT_ARRAY
&& pointed_type(&type)->ref->c < 0
&& (pt1->ref->c > 0 || pt2->ref->c > 0))
{
{
if (!copied)
type.ref = sym_push(SYM_FIELD, &type.ref->type,
0, type.ref->c);
@ -6068,19 +6099,25 @@ static void expr_cond(void)
0, pointed_type(&type)->ref->c);
pointed_type(&type)->ref->c =
0 < pt1->ref->c ? pt1->ref->c : pt2->ref->c;
}
}
} else if (bt1 == VT_STRUCT && bt2 == VT_STRUCT) {
/* test structure compatibility */
if ( type1.ref != type2.ref ) {
type_incompatibility_error(&type1, &type2,"different struct/union types '%s' vs. '%s'");
} else {
type = bt1 == VT_STRUCT ? type1 : type2;
}
} else if (bt1 == VT_STRUCT || bt2 == VT_STRUCT) {
/* XXX: test structure compatibility */
type = bt1 == VT_STRUCT ? type1 : type2;
} else {
} else if ( is_integer_btype(bt1) && is_integer_btype(bt2) ) {
/* integer operations */
type.t = VT_INT | (VT_LONG & (t1 | t2));
/* convert to unsigned if it does not fit in an integer */
/* convert to unsigned if one of both is unsigned */
if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED) ||
(t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED))
type.t |= VT_UNSIGNED;
} else {
type_incompatibility_error(&type1, &type2, "type '%s' is incompatible to '%s'");
}
/* keep structs lvalue by transforming `(expr ? a : b)` to `*(expr ? &a : &b)` so
that `(expr ? a : b).mem` does not error with "lvalue expected" */
islv = (vtop->r & VT_LVAL) && (sv.r & VT_LVAL) && VT_STRUCT == (type.t & VT_BTYPE);

View File

@ -1,5 +1,5 @@
#include <stdio.h>
#include <assert.h>
extern int printf(const char*, ...);
char arr[1];
static void f (void){}
@ -22,8 +22,21 @@ void call_fp()
(fp?f:&f)();
_Generic((__typeof(fp?0L:(void)0)*){0}, void*: (void)0);
//Should cleanly fail, not segfault:
/*(fp?f:1);*/
/* The following line causes a warning */
void *xx = fp?f:1;
}
struct condstruct {
int i;
};
static int getme(struct condstruct* s, int i)
{
int i1 = (i != 0 ? 0 : s)->i;
int i2 = (i == 0 ? s : 0)->i;
int i3 = (i != 0 ? (void*)0 : s)->i;
int i4 = (i == 0 ? s : (void*)0)->i;
return i1 + i2 + i3 + i4;
}
int main()
@ -39,12 +52,25 @@ int main()
int c = 0;
#define ASSERT(X) assert(X)
static struct stru { int x; } a={'A'},b={'B'};
static const struct stru2 { int x; } d = { 'D' };
ASSERT('A'==(*(1?&a:&b)).x);
ASSERT('A'==(1?a:b).x);
ASSERT('A'==(c?b:a).x);
ASSERT('A'==(0?b:a).x);
c=1;
ASSERT('A'==(c?a:b).x);
ASSERT(sizeof(int) == sizeof(0 ? 'a' : c));
ASSERT(sizeof(double) == sizeof(0 ? 'a' : 1.0));
ASSERT(sizeof(double) == sizeof(0 ? 0.0 : 'a'));
ASSERT(sizeof(float) == sizeof(0 ? 'a' : 1.0f));
ASSERT(sizeof(double) == sizeof(0 ? 0.0 : 1.0f));
struct condstruct cs = { 38 };
printf("%d\n", getme(&cs, 0));
// the following lines contain type mismatch errors in every ternary expression
//printf("comparing double with pointer : size = %d\n", sizeof(0 ? &c : 0.0));
//printf("'%c' <> '%c'\n", (0 ? a : d).x, (1 ? a : d).x);
//0 ? a : 0.0;
}

View File

@ -1,3 +1,4 @@
33_ternary_op.c:26: warning: pointer/integer mismatch
0
1
4
@ -8,3 +9,4 @@
21
24
27
152