From c4787e3626904fc542bd640cc368a9d306347008 Mon Sep 17 00:00:00 2001 From: Michael Matz Date: Fri, 30 Nov 2018 23:43:30 +0100 Subject: [PATCH] Fix type completion for array types as well like qualifier merging the array sizes are merged as well for the operands of ?:, and they must not statically influence the types of decls. Also fix some style problems, spaces aren't stinky :) --- tccgen.c | 81 +++++++++++++++++++++++---------------- tests/tests2/94_generic.c | 9 +++++ 2 files changed, 56 insertions(+), 34 deletions(-) diff --git a/tccgen.c b/tccgen.c index dda46a7..ce0bdb5 100644 --- a/tccgen.c +++ b/tccgen.c @@ -2097,8 +2097,8 @@ static inline int is_null_pointer(SValue *p) ((p->type.t & VT_BTYPE) == VT_LLONG && p->c.i == 0) || ((p->type.t & VT_BTYPE) == VT_PTR && (PTR_SIZE == 4 ? (uint32_t)p->c.i == 0 : p->c.i == 0) && - ((pointed_type(&p->type)->t&VT_BTYPE)==VT_VOID) && - 0==(pointed_type(&p->type)->t&(VT_CONSTANT|VT_VOLATILE)) + ((pointed_type(&p->type)->t & VT_BTYPE) == VT_VOID) && + 0 == (pointed_type(&p->type)->t & (VT_CONSTANT | VT_VOLATILE)) ); } static inline int is_integer_btype(int bt) @@ -2823,7 +2823,7 @@ static int compare_types(CType *type1, CType *type2, int unqualified) if (t1 != t2) return 0; /* test more complicated cases */ - bt1 = t1 & (VT_BTYPE | (unqualified ? 0 : VT_ARRAY) ); + bt1 = t1 & (VT_BTYPE | VT_ARRAY); if (bt1 == VT_PTR) { type1 = pointed_type(type1); type2 = pointed_type(type2); @@ -5565,10 +5565,9 @@ static void expr_cond(void) if (!g) gexpr(); - if ( ((type1=vtop->type).t&VT_BTYPE)==VT_FUNC ) { + if ((vtop->type.t & VT_BTYPE) == VT_FUNC) mk_pointer(&vtop->type); - type1=vtop->type; - } + type1 = vtop->type; sv = *vtop; /* save value to handle it later */ vtop--; /* no vpop so that FP stack is not flushed */ skip(':'); @@ -5586,10 +5585,9 @@ static void expr_cond(void) if (c == 1) nocode_wanted--; - if ( ((type2=vtop->type).t&VT_BTYPE)==VT_FUNC ) { + if ((vtop->type.t & VT_BTYPE) == VT_FUNC) mk_pointer(&vtop->type); - type2=vtop->type; - } + type2=vtop->type; t1 = type1.t; bt1 = t1 & VT_BTYPE; t2 = type2.t; @@ -5600,7 +5598,7 @@ 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 (is_float(bt1) || is_float(bt2)) { if (bt1 == VT_LDOUBLE || bt2 == VT_LDOUBLE) { type.t = VT_LDOUBLE; @@ -5626,33 +5624,48 @@ static void expr_cond(void) is the other. */ if (is_null_pointer (vtop)) type = type1; else if (is_null_pointer (&sv)) type = type2; - else{ - 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){ - if(!compare_types(pointed_type(&type1), pointed_type(&type2),1/*unqualif*/)) + 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"); } - { /*copy the pointer target symbol*/ - Sym *s; - s = sym_push(SYM_FIELD, pointed_type(&type), 0, -1); - type.t = VT_PTR | (type.t & VT_STORAGE); - type.ref = s; - } - /*qualifs combine*/ - pointed_type(&type)->t |= 0 - |(pointed_type(&type1)->t&(VT_CONSTANT|VT_VOLATILE)) - |(pointed_type(&type2)->t&(VT_CONSTANT|VT_VOLATILE)); - /*pointers to incomplete arrays get converted to pointers to completed ones if possible*/ - if ( (pointed_type(&type1)->t&VT_ARRAY) ) + /* 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 + && 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); + pointed_type(&type)->ref = + sym_push(SYM_FIELD, &pointed_type(&type)->ref->type, + 0, pointed_type(&type)->ref->c); pointed_type(&type)->ref->c = - 0ref->c ? - pointed_type(&type1)->ref->c : pointed_type(&type2)->ref->c; + 0 < pt1->ref->c ? pt1->ref->c : pt2->ref->c; + } } } else if (bt1 == VT_STRUCT || bt2 == VT_STRUCT) { /* XXX: test structure compatibility */ diff --git a/tests/tests2/94_generic.c b/tests/tests2/94_generic.c index ac36650..6e85c02 100644 --- a/tests/tests2/94_generic.c +++ b/tests/tests2/94_generic.c @@ -96,11 +96,20 @@ int main() (void)(sizeof(struct { int x:_Generic( 0?(int (*)[])0 : (int (*)[4])0, int (*)[4]:+1, int (*)[5]:(void)0); })); { + /* completion shouldn't affect the type of decl */ char **argv; _Generic(argv, char**: (void)0); _Generic(0?(char const*)0:argv[0], char const*: (void)0); _Generic(argv, char**: (void)0); } + { + extern int (*ar)[]; + (void)(sizeof(struct { int x:_Generic( 0?(int (*)[4])0 : (int (*)[])0, int (*)[4]:+1, int (*)[5]:(void)0); })); + (void)(sizeof(struct { int x:_Generic( 0?(int (*)[])0 : (int (*)[4])0, int (*)[4]:+1, int (*)[5]:(void)0); })); + (void)(sizeof(struct { int x:_Generic( 0?ar : (int (*)[4])0, int (*)[4]:+1, int (*)[5]:(void)0); })); + (void)(sizeof(struct { int x:_Generic( 0?(int (*)[4])0 : ar, int (*)[4]:+1, int (*)[5]:(void)0); })); + (void)(sizeof(struct { int x:_Generic( 0?(int (*)[5])0 : ar, int (*)[5]:+1, int (*)[4]:(void)0); })); + } return 0; }