diff --git a/tccgen.c b/tccgen.c index fa190597..a4a3e640 100644 --- a/tccgen.c +++ b/tccgen.c @@ -136,6 +136,8 @@ static void block(int flags); static void gen_cast(CType *type); static void gen_cast_s(int t); static inline CType *pointed_type(CType *type); +static int type_qualifiers(CType *type); +static void parse_btype_qualify(CType *type, int qualifiers); static int is_compatible_types(CType *type1, CType *type2); static int parse_btype(CType *type, AttributeDef *ad, int ignore_label); static CType *type_decl(CType *type, AttributeDef *ad, int *v, int td); @@ -2972,15 +2974,14 @@ static int combine_types(CType *dest, SValue *op1, SValue *op2, int op) pointed to types minus qualifs should be compatible */ type = *((pbt1 == VT_VOID) ? type1 : type2); /* combine qualifs */ - newquals = ((pt1->t | pt2->t) & (VT_CONSTANT | VT_VOLATILE)); - if ((~pointed_type(&type)->t & (VT_CONSTANT | VT_VOLATILE)) - & newquals) + newquals = type_qualifiers(pt1) | type_qualifiers(pt2); + if ((~type_qualifiers(pointed_type(&type))) & 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; + parse_btype_qualify(pointed_type(&type), newquals); } /* pointers to incomplete arrays get converted to pointers to completed ones if possible */ @@ -3567,6 +3568,14 @@ static inline CType *pointed_type(CType *type) return &type->ref->type; } +/* Array qualifiers are represented on the element type. */ +static int type_qualifiers(CType *type) +{ + while (type->t & VT_ARRAY) + type = pointed_type(type); + return type->t & (VT_CONSTANT | VT_VOLATILE); +} + /* modify type so that its it is a pointer to type. */ ST_FUNC void mk_pointer(CType *type) { diff --git a/tests/tcctest.c b/tests/tcctest.c index e275bf6c..0d36b049 100644 --- a/tests/tcctest.c +++ b/tests/tcctest.c @@ -3956,6 +3956,14 @@ void builtin_test(void) COMPAT_TYPE(int[2], const int[2]); COMPAT_TYPE(int[2][3], volatile int[][3]); COMPAT_TYPE(int (*)[], const int (*)[]); + COMPAT_TYPE(__typeof__(1 ? (const int (*)[2])0 : (int (*)[2])0), + const int (*)[2]); + COMPAT_TYPE(__typeof__(1 ? (const int (*)[2][3])0 : + (volatile int (*)[2][3])0), + const volatile int (*)[2][3]); + COMPAT_TYPE(__typeof__(1 ? (volatile int (*)[2][3])0 : + (const int (*)[2][3])0), + const volatile int (*)[2][3]); COMPAT_TYPE(int *, int *); COMPAT_TYPE(int *, void *); COMPAT_TYPE(int *, const int *); diff --git a/tests/tests2/60_errors_and_warnings.c b/tests/tests2/60_errors_and_warnings.c index c3eda13f..c13aed83 100644 --- a/tests/tests2/60_errors_and_warnings.c +++ b/tests/tests2/60_errors_and_warnings.c @@ -661,4 +661,22 @@ void good_volatile_write(volatile my_struct *s) s->arr[0] = 1; } +#elif defined test_conditional_array_qualifiers + +typedef int Array2[2]; +typedef int Array2x3[2][3]; + +Array2 *p; +const Array2 *cp; +const Array2x3 *cap; +volatile Array2x3 *vap; + +void test(void) +{ + (1 ? p : cp)[0][0] = 1; + (1 ? cp : p)[0][0] = 2; + (1 ? cap : vap)[0][0][0] = 3; + (1 ? vap : cap)[0][0][0] = 4; +} + #endif diff --git a/tests/tests2/60_errors_and_warnings.expect b/tests/tests2/60_errors_and_warnings.expect index 5f7be4ba..63aa9912 100644 --- a/tests/tests2/60_errors_and_warnings.expect +++ b/tests/tests2/60_errors_and_warnings.expect @@ -290,3 +290,9 @@ bar 15 12 34 60_errors_and_warnings.c:651: warning: assignment discards qualifiers from pointer target type [test_volatile_array_member_write_ok] + +[test_conditional_array_qualifiers] +60_errors_and_warnings.c:676: warning: assignment of read-only location +60_errors_and_warnings.c:677: warning: assignment of read-only location +60_errors_and_warnings.c:678: warning: assignment of read-only location +60_errors_and_warnings.c:679: warning: assignment of read-only location