History

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

Udo committed 6 years ago

Commit 9272fac1 parent a9e7fe13 files · +112 −47Browse files

Unified · Split

3 files
  1. tccgen.c +81 −44
  2. tests/tests2/33_ternary_op.c +29 −3
  3. tests/tests2/33_ternary_op.expect +2 −0
tccgen.c+81−44
@@ -3312,12 +3312,25 @@ static void type_to_str(char *buf, int buf_size, · 3311 unmodified lines
33123312 no_var: ;
33133313 }
33143314
3315−static void cast_error(CType *st, CType *dt)
3315+static void type_incompatibility_error(CType* st, CType* dt, const char* fmt)
3316+{
3317+ char buf1[256], buf2[256];
3318+ type_to_str(buf1, sizeof(buf1), st, NULL);
3319+ type_to_str(buf2, sizeof(buf2), dt, NULL);
3320+ tcc_error(fmt, buf1, buf2);
3321+}
3322+
3323+static void type_incompatibility_warning(CType* st, CType* dt, const char* fmt)
33163324 {
33173325 char buf1[256], buf2[256];
33183326 type_to_str(buf1, sizeof(buf1), st, NULL);
33193327 type_to_str(buf2, sizeof(buf2), dt, NULL);
3320− tcc_error("cannot convert '%s' to '%s'", buf1, buf2);
3328+ tcc_warning(fmt, buf1, buf2);
3329+}
3330+
3331+static void cast_error(CType *st, CType *dt)
3332+{
3333+ type_incompatibility_error(st, dt, "cannot convert '%s' to '%s'");
33213334 }
33223335
33233336 /* verify type compatibility to store vtop in 'dt' type */
@@ -5523,8 +5536,11 @@ special_math_val: · 2199 unmodified lines
55235536 test_lvalue();
55245537 gaddrof();
55255538 /* expect pointer on structure */
5526− if ((vtop->type.t & VT_BTYPE) != VT_STRUCT)
5527− expect("struct or union");
5539+ if ( (vtop->type.t & VT_BTYPE) != VT_STRUCT ) {
5540+ char got[256];
5541+ type_to_str(got, sizeof got, &vtop->type, NULL);
5542+ tcc_error("expected struct or union but not '%s'", got);
5543+ }
55285544 if (tok == TOK_CDOUBLE)
55295545 expect("field name");
55305546 next();
@@ -6001,7 +6017,13 @@ static void expr_cond(void) · 470 unmodified lines
60016017 /* cast operands to correct type according to ISOC rules */
60026018 if (bt1 == VT_VOID || bt2 == VT_VOID) {
60036019 type.t = VT_VOID; /* NOTE: as an extension, we accept void on only one side */
6004− } else if (is_float(bt1) || is_float(bt2)) {
6020+ } else if ( bt1 == VT_BOOL && bt2 == VT_BOOL ) {
6021+ type = type1;
6022+ } else if ( is_float(bt1) && is_integer_btype(bt2) ) {
6023+ type = type1;
6024+ } else if ( is_integer_btype(bt1) && is_float(bt2) ) {
6025+ type = type2;
6026+ } else if (is_float(bt1) && is_float(bt2)) {
60056027 if (bt1 == VT_LDOUBLE || bt2 == VT_LDOUBLE) {
60066028 type.t = VT_LDOUBLE;
60076029
@@ -6010,56 +6032,65 @@ static void expr_cond(void) · 2 unmodified lines
60106032 } else {
60116033 type.t = VT_FLOAT;
60126034 }
6013− } else if (bt1 == VT_LLONG || bt2 == VT_LLONG) {
6035+ } else if ((bt1 == VT_LLONG && is_integer_btype(bt2)) ||
6036+ (bt2 == VT_LLONG && is_integer_btype(bt1))) {
60146037 /* cast to biggest op */
60156038 type.t = VT_LLONG | VT_LONG;
6016− if (bt1 == VT_LLONG)
6039+ if ( bt1 == VT_LLONG )
60176040 type.t &= t1;
6018− if (bt2 == VT_LLONG)
6041+ if ( bt2 == VT_LLONG )
60196042 type.t &= t2;
60206043 /* convert to unsigned if it does not fit in a long long */
60216044 if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED) ||
60226045 (t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED))
60236046 type.t |= VT_UNSIGNED;
6024− } else if (bt1 == VT_PTR || bt2 == VT_PTR) {
6025− /* http://port70.net/~nsz/c/c99/n1256.html#6.5.15p6 */
6026− /* If one is a null ptr constant the result type
6027− is the other. */
6028− if (is_null_pointer (vtop)) type = type1;
6029− else if (is_null_pointer (&sv)) type = type2;
6030− else if (bt1 != bt2)
6031− tcc_error("incompatible types in conditional expressions");
6032− else {
6033− CType *pt1 = pointed_type(&type1);
6034− CType *pt2 = pointed_type(&type2);
6035− int pbt1 = pt1->t & VT_BTYPE;
6036− int pbt2 = pt2->t & VT_BTYPE;
6037− int newquals, copied = 0;
6038− /* pointers to void get preferred, otherwise the
6039− pointed to types minus qualifs should be compatible */
6040− type = (pbt1 == VT_VOID) ? type1 : type2;
6041− if (pbt1 != VT_VOID && pbt2 != VT_VOID) {
6042− if(!compare_types(pt1, pt2, 1/*unqualif*/))
6043− tcc_warning("pointer type mismatch in conditional expression\n");
6044− }
6045− /* combine qualifs */
6046− newquals = ((pt1->t | pt2->t) & (VT_CONSTANT | VT_VOLATILE));
6047− if ((~pointed_type(&type)->t & (VT_CONSTANT | VT_VOLATILE))
6047+ }
6048+ /* http://port70.net/~nsz/c/c99/n1256.html#6.5.15p6 */
6049+ /* If one is a null ptr constant the result type
6050+ is the other. */
6051+ else if ( bt1 == VT_PTR && is_null_pointer(vtop) ) {
6052+ type = type1;
6053+ } else if ( is_null_pointer(&sv) && bt2 == VT_PTR ) {
6054+ type = type2;
6055+ } else if ( bt1 == VT_PTR && is_integer_btype(bt2) ) {
6056+ type = type1;
6057+ tcc_warning("pointer/integer mismatch");
6058+ } else if ( is_integer_btype(bt1) && bt2 == VT_PTR ) {
6059+ type = type2;
6060+ tcc_warning("pointer/integer mismatch");
6061+ } else if ( bt1==VT_PTR && bt2 == VT_PTR ) {
6062+ CType *pt1 = pointed_type(&type1);
6063+ CType *pt2 = pointed_type(&type2);
6064+ int pbt1 = pt1->t & VT_BTYPE;
6065+ int pbt2 = pt2->t & VT_BTYPE;
6066+ int newquals, copied = 0;
6067+ /* pointers to void get preferred, otherwise the
6068+ pointed to types minus qualifs should be compatible */
6069+ type = (pbt1 == VT_VOID) ? type1 : type2;
6070+ if (pbt1 != VT_VOID && pbt2 != VT_VOID && ! compare_types(pt1, pt2, 1/*unqualif*/) ) {
6071+ type_incompatibility_warning(&type1, &type2, "incompatible pointer types");
6072+ // result is void*
6073+ type.t = VT_VOID;
6074+ mk_pointer(&type);
6075+ }
6076+ /* combine qualifs */
6077+ newquals = ((pt1->t | pt2->t) & (VT_CONSTANT | VT_VOLATILE));
6078+ if ((~pointed_type(&type)->t & (VT_CONSTANT | VT_VOLATILE))
60486079 & newquals)
6049− {
6080+ {
60506081 /* copy the pointer target symbol */
60516082 type.ref = sym_push(SYM_FIELD, &type.ref->type,
60526083 0, type.ref->c);
60536084 copied = 1;
60546085 pointed_type(&type)->t |= newquals;
6055− }
6056− /* pointers to incomplete arrays get converted to
6057− pointers to completed ones if possible */
6058− if (pt1->t & VT_ARRAY
6086+ }
6087+ /* pointers to incomplete arrays get converted to
6088+ pointers to completed ones if possible */
6089+ if (pt1->t & VT_ARRAY
60596090 && pt2->t & VT_ARRAY
60606091 && pointed_type(&type)->ref->c < 0
60616092 && (pt1->ref->c > 0 || pt2->ref->c > 0))
6062− {
6093+ {
60636094 if (!copied)
60646095 type.ref = sym_push(SYM_FIELD, &type.ref->type,
60656096 0, type.ref->c);
@@ -6068,19 +6099,25 @@ static void expr_cond(void) · 2 unmodified lines
60686099 0, pointed_type(&type)->ref->c);
60696100 pointed_type(&type)->ref->c =
60706101 0 < pt1->ref->c ? pt1->ref->c : pt2->ref->c;
6071− }
6102+ }
6103+ } else if (bt1 == VT_STRUCT && bt2 == VT_STRUCT) {
6104+ /* test structure compatibility */
6105+ if ( type1.ref != type2.ref ) {
6106+ type_incompatibility_error(&type1, &type2,"different struct/union types '%s' vs. '%s'");
6107+ } else {
6108+ type = bt1 == VT_STRUCT ? type1 : type2;
60726109 }
6073− } else if (bt1 == VT_STRUCT || bt2 == VT_STRUCT) {
6074− /* XXX: test structure compatibility */
6075− type = bt1 == VT_STRUCT ? type1 : type2;
6076− } else {
6110+ } else if ( is_integer_btype(bt1) && is_integer_btype(bt2) ) {
60776111 /* integer operations */
60786112 type.t = VT_INT | (VT_LONG & (t1 | t2));
6079− /* convert to unsigned if it does not fit in an integer */
6113+ /* convert to unsigned if one of both is unsigned */
60806114 if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED) ||
60816115 (t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED))
60826116 type.t |= VT_UNSIGNED;
6117+ } else {
6118+ type_incompatibility_error(&type1, &type2, "type '%s' is incompatible to '%s'");
60836119 }
6120+
60846121 /* keep structs lvalue by transforming `(expr ? a : b)` to `*(expr ? &a : &b)` so
60856122 that `(expr ? a : b).mem` does not error with "lvalue expected" */
60866123 islv = (vtop->r & VT_LVAL) && (sv.r & VT_LVAL) && VT_STRUCT == (type.t & VT_BTYPE);
tests/tests2/33_ternary_op.c+29−3
@@ -1,5 +1,5 @@
1−#include <stdio.h>
21 #include <assert.h>
2+extern int printf(const char*, ...);
33
44 char arr[1];
55 static void f (void){}
@@ -22,8 +22,21 @@ void call_fp() · 16 unmodified lines
2222 (fp?f:&f)();
2323 _Generic((__typeof(fp?0L:(void)0)*){0}, void*: (void)0);
2424
25− //Should cleanly fail, not segfault:
26− /*(fp?f:1);*/
25+ /* The following line causes a warning */
26+ void *xx = fp?f:1;
27+}
28+
29+struct condstruct {
30+ int i;
31+};
32+
33+static int getme(struct condstruct* s, int i)
34+{
35+ int i1 = (i != 0 ? 0 : s)->i;
36+ int i2 = (i == 0 ? s : 0)->i;
37+ int i3 = (i != 0 ? (void*)0 : s)->i;
38+ int i4 = (i == 0 ? s : (void*)0)->i;
39+ return i1 + i2 + i3 + i4;
2740 }
2841
2942 int main()
@@ -39,12 +52,25 @@ int main() · 9 unmodified lines
3952 int c = 0;
4053 #define ASSERT(X) assert(X)
4154 static struct stru { int x; } a={'A'},b={'B'};
55+ static const struct stru2 { int x; } d = { 'D' };
4256 ASSERT('A'==(*(1?&a:&b)).x);
4357 ASSERT('A'==(1?a:b).x);
4458 ASSERT('A'==(c?b:a).x);
4559 ASSERT('A'==(0?b:a).x);
4660 c=1;
4761 ASSERT('A'==(c?a:b).x);
62+ ASSERT(sizeof(int) == sizeof(0 ? 'a' : c));
63+ ASSERT(sizeof(double) == sizeof(0 ? 'a' : 1.0));
64+ ASSERT(sizeof(double) == sizeof(0 ? 0.0 : 'a'));
65+ ASSERT(sizeof(float) == sizeof(0 ? 'a' : 1.0f));
66+ ASSERT(sizeof(double) == sizeof(0 ? 0.0 : 1.0f));
67+ struct condstruct cs = { 38 };
68+ printf("%d\n", getme(&cs, 0));
69+
70+ // the following lines contain type mismatch errors in every ternary expression
71+ //printf("comparing double with pointer : size = %d\n", sizeof(0 ? &c : 0.0));
72+ //printf("'%c' <> '%c'\n", (0 ? a : d).x, (1 ? a : d).x);
73+ //0 ? a : 0.0;
4874 }
4975
5076
tests/tests2/33_ternary_op.expect+2−0
@@ -1,3 +1,4 @@
1+33_ternary_op.c:26: warning: pointer/integer mismatch
12 0
23 1
34 4
@@ -8,3 +9,4 @@ · 4 unmodified lines
89 21
910 24
1011 27
12+152

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t