From 0cd015b4ed36f8b794b33f1c66c1946255f1ac22 Mon Sep 17 00:00:00 2001 From: Christopher Bazley Date: Mon, 7 Sep 2026 08:39:41 +0100 Subject: [PATCH] tccgen: combine qualifiers through array types Conditional expressions combine the qualifiers of their pointer target types. TCC only examines the outer array node, although array qualifiers are stored on the element type. This makes the result depend on operand order. Collect and apply qualifiers through array layers. --- tccgen.c | 17 +++++++++++++---- tests/tcctest.c | 8 ++++++++ tests/tests2/60_errors_and_warnings.c | 18 ++++++++++++++++++ tests/tests2/60_errors_and_warnings.expect | 6 ++++++ 4 files changed, 45 insertions(+), 4 deletions(-) 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