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.
This commit is contained in:
Christopher Bazley 2026-09-26 09:13:48 +01:00
parent 3dc99dbc82
commit 5f1425ef21
5 changed files with 82 additions and 5 deletions

View File

@ -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)

View File

@ -0,0 +1,11 @@
void defined_const(int *pointer);
void defined_const(int *const pointer)
{
pointer = 0;
}
int main(void)
{
return 0;
}

View File

@ -0,0 +1 @@
149_parameter_qualifier_errors.c:5: warning: assignment of read-only location

View File

@ -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;
}