From 5f1425ef219158b150e904f120781932378b63f0 Mon Sep 17 00:00:00 2001 From: Christopher Bazley Date: Sat, 26 Sep 2026 09:13:48 +0100 Subject: [PATCH] tccgen: preserve adjusted parameter qualifiers Previously, TCC wrongly discarded the const and volatile qualifiers from parameter types when adjusting them. - convert_parameter_type() will no longer remove the const and volatile qualifiers from a CType. - a new function, convert_expression_type(), will remove the const and volatile qualifiers before tail-calling convert_parameter_type(). - unary() and gexpr() will call convert_expression_type() instead of convert_parameter_type() to ensure that expression semantics are unchanged. The new tests for restrict also pass, but only because the restrict keyword is ignored. --- tccgen.c | 14 +++-- tests/tests2/149_parameter_qualifier_errors.c | 11 ++++ .../149_parameter_qualifier_errors.expect | 1 + tests/tests2/149_parameter_qualifiers.c | 61 +++++++++++++++++++ tests/tests2/149_parameter_qualifiers.expect | 0 5 files changed, 82 insertions(+), 5 deletions(-) create mode 100644 tests/tests2/149_parameter_qualifier_errors.c create mode 100644 tests/tests2/149_parameter_qualifier_errors.expect create mode 100644 tests/tests2/149_parameter_qualifiers.c create mode 100644 tests/tests2/149_parameter_qualifiers.expect diff --git a/tccgen.c b/tccgen.c index a4a3e640..a899444c 100644 --- a/tccgen.c +++ b/tccgen.c @@ -5006,9 +5006,6 @@ the_end: function pointer) */ static inline void convert_parameter_type(CType *pt) { - /* remove const and volatile qualifiers (XXX: const could be used - to indicate a const function parameter */ - pt->t &= ~(VT_CONSTANT | VT_VOLATILE); /* array must be transformed to pointer according to ANSI C */ pt->t &= ~(VT_ARRAY | VT_VLA); if ((pt->t & VT_BTYPE) == VT_FUNC) { @@ -5016,6 +5013,13 @@ static inline void convert_parameter_type(CType *pt) } } +/* apply the conversions required for an expression value */ +static inline void convert_expression_type(CType *pt) +{ + pt->t &= ~(VT_CONSTANT | VT_VOLATILE); + convert_parameter_type(pt); +} + ST_FUNC CString* parse_asm_str(void) { skip('('); @@ -6063,7 +6067,7 @@ ST_FUNC void unary(void) next(); skip('('); expr_type(&controlling_type, expr_eq); - convert_parameter_type (&controlling_type); + convert_expression_type(&controlling_type); nocode_wanted = saved_nocode_wanted; @@ -6774,7 +6778,7 @@ ST_FUNC void gexpr(void) } while (tok == ','); /* convert array & function to pointer */ - convert_parameter_type(&vtop->type); + convert_expression_type(&vtop->type); /* make builtin_constant_p((1,2)) return 0 (like on gcc) */ if ((vtop->r & VT_VALMASK) == VT_CONST && nocode_wanted && !CONST_WANTED) diff --git a/tests/tests2/149_parameter_qualifier_errors.c b/tests/tests2/149_parameter_qualifier_errors.c new file mode 100644 index 00000000..93c853e2 --- /dev/null +++ b/tests/tests2/149_parameter_qualifier_errors.c @@ -0,0 +1,11 @@ +void defined_const(int *pointer); + +void defined_const(int *const pointer) +{ + pointer = 0; +} + +int main(void) +{ + return 0; +} diff --git a/tests/tests2/149_parameter_qualifier_errors.expect b/tests/tests2/149_parameter_qualifier_errors.expect new file mode 100644 index 00000000..dbcdbd0a --- /dev/null +++ b/tests/tests2/149_parameter_qualifier_errors.expect @@ -0,0 +1 @@ +149_parameter_qualifier_errors.c:5: warning: assignment of read-only location diff --git a/tests/tests2/149_parameter_qualifiers.c b/tests/tests2/149_parameter_qualifiers.c new file mode 100644 index 00000000..663592c0 --- /dev/null +++ b/tests/tests2/149_parameter_qualifiers.c @@ -0,0 +1,61 @@ +void pointer_parameters(int *const cp, int *volatile vp, int *restrict rp) +{ + _Static_assert(_Generic(&cp, int *const *: 1, default: 0), + "const pointer parameter remains qualified"); + _Static_assert(_Generic(&vp, int *volatile *: 1, default: 0), + "volatile pointer parameter remains qualified"); + _Static_assert(_Generic(&rp, int *restrict *: 1, default: 0), + "restrict pointer parameter remains qualified"); +} + +void declared_const(int *const pointer); +void declared_const(int *pointer) +{ + _Static_assert(_Generic(&pointer, int **: 1, default: 0), + "declaration qualifier does not affect definition"); + pointer = 0; +} + +void defined_const(int *pointer); +void defined_const(int *const pointer) +{ + _Static_assert(_Generic(&pointer, int *const *: 1, default: 0), + "definition retains const"); +} + +void declared_volatile(int *volatile pointer); +void declared_volatile(int *pointer) +{ + _Static_assert(_Generic(&pointer, int **: 1, default: 0), + "declaration qualifier does not affect definition"); + pointer = 0; +} + +void defined_volatile(int *pointer); +void defined_volatile(int *volatile pointer) +{ + _Static_assert(_Generic(&pointer, int *volatile *: 1, default: 0), + "definition retains volatile"); + pointer = 0; +} + +void declared_restrict(int *restrict pointer); +void declared_restrict(int *pointer) +{ + _Static_assert(_Generic(&pointer, int **: 1, default: 0), + "declaration qualifier does not affect definition"); + pointer = 0; +} + +void defined_restrict(int *pointer); +void defined_restrict(int *restrict pointer) +{ + _Static_assert(_Generic(&pointer, int *restrict *: 1, default: 0), + "definition retains restrict"); + pointer = 0; +} + +int main(void) +{ + return 0; +} diff --git a/tests/tests2/149_parameter_qualifiers.expect b/tests/tests2/149_parameter_qualifiers.expect new file mode 100644 index 00000000..e69de29b