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
3312 no_var: ;3312 no_var: ;
3313}3313}
3314 3314
3315static void cast_error(CType *st, CType *dt)3315static 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
3323static void type_incompatibility_warning(CType* st, CType* dt, const char* fmt)
3316{3324{
3317 char buf1[256], buf2[256];3325 char buf1[256], buf2[256];
3318 type_to_str(buf1, sizeof(buf1), st, NULL);3326 type_to_str(buf1, sizeof(buf1), st, NULL);
3319 type_to_str(buf2, sizeof(buf2), dt, NULL);3327 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
3331static void cast_error(CType *st, CType *dt)
3332{
3333 type_incompatibility_error(st, dt, "cannot convert '%s' to '%s'");
3321}3334}
3322 3335
3323/* verify type compatibility to store vtop in 'dt' type */3336/* verify type compatibility to store vtop in 'dt' type */
@@ -5523,8 +5536,11 @@ special_math_val: · 2199 unmodified lines
5523 test_lvalue();5536 test_lvalue();
5524 gaddrof();5537 gaddrof();
5525 /* expect pointer on structure */5538 /* expect pointer on structure */
5526 if ((vtop->type.t & VT_BTYPE) != VT_STRUCT)5539 if ( (vtop->type.t & VT_BTYPE) != VT_STRUCT ) {
5527 expect("struct or union");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 }
5528 if (tok == TOK_CDOUBLE)5544 if (tok == TOK_CDOUBLE)
5529 expect("field name");5545 expect("field name");
5530 next();5546 next();
@@ -6001,7 +6017,13 @@ static void expr_cond(void) · 470 unmodified lines
6001 /* cast operands to correct type according to ISOC rules */6017 /* cast operands to correct type according to ISOC rules */
6002 if (bt1 == VT_VOID || bt2 == VT_VOID) {6018 if (bt1 == VT_VOID || bt2 == VT_VOID) {
6003 type.t = VT_VOID; /* NOTE: as an extension, we accept void on only one side */6019 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)) {
6005 if (bt1 == VT_LDOUBLE || bt2 == VT_LDOUBLE) {6027 if (bt1 == VT_LDOUBLE || bt2 == VT_LDOUBLE) {
6006 type.t = VT_LDOUBLE;6028 type.t = VT_LDOUBLE;
6007 6029
@@ -6010,56 +6032,65 @@ static void expr_cond(void) · 2 unmodified lines
6010 } else {6032 } else {
6011 type.t = VT_FLOAT;6033 type.t = VT_FLOAT;
6012 }6034 }
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))) {
6014 /* cast to biggest op */6037 /* cast to biggest op */
6015 type.t = VT_LLONG | VT_LONG;6038 type.t = VT_LLONG | VT_LONG;
6016 if (bt1 == VT_LLONG)6039 if ( bt1 == VT_LLONG )
6017 type.t &= t1;6040 type.t &= t1;
6018 if (bt2 == VT_LLONG)6041 if ( bt2 == VT_LLONG )
6019 type.t &= t2;6042 type.t &= t2;
6020 /* convert to unsigned if it does not fit in a long long */6043 /* convert to unsigned if it does not fit in a long long */
6021 if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED) ||6044 if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED) ||
6022 (t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED))6045 (t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED))
6023 type.t |= VT_UNSIGNED;6046 type.t |= VT_UNSIGNED;
6024 } else if (bt1 == VT_PTR || bt2 == VT_PTR) {6047 }
6025 /* http://port70.net/~nsz/c/c99/n1256.html#6.5.15p6 */6048 /* http://port70.net/~nsz/c/c99/n1256.html#6.5.15p6 */
6026 /* If one is a null ptr constant the result type6049 /* If one is a null ptr constant the result type
6027 is the other. */6050 is the other. */
6028 if (is_null_pointer (vtop)) type = type1;6051 else if ( bt1 == VT_PTR && is_null_pointer(vtop) ) {
6029 else if (is_null_pointer (&sv)) type = type2;6052 type = type1;
6030 else if (bt1 != bt2)6053 } else if ( is_null_pointer(&sv) && bt2 == VT_PTR ) {
6031 tcc_error("incompatible types in conditional expressions");6054 type = type2;
6032 else {6055 } else if ( bt1 == VT_PTR && is_integer_btype(bt2) ) {
6033 CType *pt1 = pointed_type(&type1);6056 type = type1;
6034 CType *pt2 = pointed_type(&type2);6057 tcc_warning("pointer/integer mismatch");
6035 int pbt1 = pt1->t & VT_BTYPE;6058 } else if ( is_integer_btype(bt1) && bt2 == VT_PTR ) {
6036 int pbt2 = pt2->t & VT_BTYPE;6059 type = type2;
6037 int newquals, copied = 0;6060 tcc_warning("pointer/integer mismatch");
6038 /* pointers to void get preferred, otherwise the6061 } else if ( bt1==VT_PTR && bt2 == VT_PTR ) {
6039 pointed to types minus qualifs should be compatible */6062 CType *pt1 = pointed_type(&type1);
6040 type = (pbt1 == VT_VOID) ? type1 : type2;6063 CType *pt2 = pointed_type(&type2);
6041 if (pbt1 != VT_VOID && pbt2 != VT_VOID) {6064 int pbt1 = pt1->t & VT_BTYPE;
6042 if(!compare_types(pt1, pt2, 1/*unqualif*/))6065 int pbt2 = pt2->t & VT_BTYPE;
6043 tcc_warning("pointer type mismatch in conditional expression\n");6066 int newquals, copied = 0;
6044 }6067 /* pointers to void get preferred, otherwise the
6045 /* combine qualifs */6068 pointed to types minus qualifs should be compatible */
6046 newquals = ((pt1->t | pt2->t) & (VT_CONSTANT | VT_VOLATILE));6069 type = (pbt1 == VT_VOID) ? type1 : type2;
6047 if ((~pointed_type(&type)->t & (VT_CONSTANT | VT_VOLATILE))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))
6048 & newquals)6079 & newquals)
6049 {6080 {
6050 /* copy the pointer target symbol */6081 /* copy the pointer target symbol */
6051 type.ref = sym_push(SYM_FIELD, &type.ref->type,6082 type.ref = sym_push(SYM_FIELD, &type.ref->type,
6052 0, type.ref->c);6083 0, type.ref->c);
6053 copied = 1;6084 copied = 1;
6054 pointed_type(&type)->t |= newquals;6085 pointed_type(&type)->t |= newquals;
6055 }6086 }
6056 /* pointers to incomplete arrays get converted to6087 /* pointers to incomplete arrays get converted to
6057 pointers to completed ones if possible */6088 pointers to completed ones if possible */
6058 if (pt1->t & VT_ARRAY6089 if (pt1->t & VT_ARRAY
6059 && pt2->t & VT_ARRAY6090 && pt2->t & VT_ARRAY
6060 && pointed_type(&type)->ref->c < 06091 && pointed_type(&type)->ref->c < 0
6061 && (pt1->ref->c > 0 || pt2->ref->c > 0))6092 && (pt1->ref->c > 0 || pt2->ref->c > 0))
6062 {6093 {
6063 if (!copied)6094 if (!copied)
6064 type.ref = sym_push(SYM_FIELD, &type.ref->type,6095 type.ref = sym_push(SYM_FIELD, &type.ref->type,
6065 0, type.ref->c);6096 0, type.ref->c);
@@ -6068,19 +6099,25 @@ static void expr_cond(void) · 2 unmodified lines
6068 0, pointed_type(&type)->ref->c);6099 0, pointed_type(&type)->ref->c);
6069 pointed_type(&type)->ref->c =6100 pointed_type(&type)->ref->c =
6070 0 < pt1->ref->c ? pt1->ref->c : pt2->ref->c;6101 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;
6072 }6109 }
6073 } else if (bt1 == VT_STRUCT || bt2 == VT_STRUCT) {6110 } else if ( is_integer_btype(bt1) && is_integer_btype(bt2) ) {
6074 /* XXX: test structure compatibility */
6075 type = bt1 == VT_STRUCT ? type1 : type2;
6076 } else {
6077 /* integer operations */6111 /* integer operations */
6078 type.t = VT_INT | (VT_LONG & (t1 | t2));6112 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 */
6080 if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED) ||6114 if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED) ||
6081 (t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED))6115 (t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED))
6082 type.t |= VT_UNSIGNED;6116 type.t |= VT_UNSIGNED;
6117 } else {
6118 type_incompatibility_error(&type1, &type2, "type '%s' is incompatible to '%s'");
6083 }6119 }
6120
6084 /* keep structs lvalue by transforming `(expr ? a : b)` to `*(expr ? &a : &b)` so6121 /* keep structs lvalue by transforming `(expr ? a : b)` to `*(expr ? &a : &b)` so
6085 that `(expr ? a : b).mem` does not error with "lvalue expected" */6122 that `(expr ? a : b).mem` does not error with "lvalue expected" */
6086 islv = (vtop->r & VT_LVAL) && (sv.r & VT_LVAL) && VT_STRUCT == (type.t & VT_BTYPE);6123 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>
2#include <assert.h>1#include <assert.h>
2extern int printf(const char*, ...);
3 3
4char arr[1];4char arr[1];
5static void f (void){}5static void f (void){}
@@ -22,8 +22,21 @@ void call_fp() · 16 unmodified lines
22 (fp?f:&f)();22 (fp?f:&f)();
23 _Generic((__typeof(fp?0L:(void)0)*){0}, void*: (void)0);23 _Generic((__typeof(fp?0L:(void)0)*){0}, void*: (void)0);
24 24
25 //Should cleanly fail, not segfault:25 /* The following line causes a warning */
26 /*(fp?f:1);*/26 void *xx = fp?f:1;
27}
28
29struct condstruct {
30 int i;
31};
32
33static 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;
27}40}
28 41
29int main()42int main()
@@ -39,12 +52,25 @@ int main() · 9 unmodified lines
39 int c = 0;52 int c = 0;
40 #define ASSERT(X) assert(X)53 #define ASSERT(X) assert(X)
41 static struct stru { int x; } a={'A'},b={'B'};54 static struct stru { int x; } a={'A'},b={'B'};
55 static const struct stru2 { int x; } d = { 'D' };
42 ASSERT('A'==(*(1?&a:&b)).x);56 ASSERT('A'==(*(1?&a:&b)).x);
43 ASSERT('A'==(1?a:b).x);57 ASSERT('A'==(1?a:b).x);
44 ASSERT('A'==(c?b:a).x);58 ASSERT('A'==(c?b:a).x);
45 ASSERT('A'==(0?b:a).x);59 ASSERT('A'==(0?b:a).x);
46 c=1;60 c=1;
47 ASSERT('A'==(c?a:b).x);61 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;
48 }74 }
49 75
50 76
tests/tests2/33_ternary_op.expect+2−0
@@ -1,3 +1,4 @@
133_ternary_op.c:26: warning: pointer/integer mismatch
1020
2131
3444
@@ -8,3 +9,4 @@ · 4 unmodified lines
821921
9241024
10271127
12152

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