[qfcc] Add reference_expr() to create references

`address_expr()` wasn't enough because it returns pointers instead of
references (quite correct) which messes with checks for references
elsewhere (also quite correct). It seems I've finally got reference
parameters working.
This commit is contained in:
Bill Currie 2025-01-22 14:59:03 +09:00
parent 9c3dc555a3
commit 5b9d241177
3 changed files with 56 additions and 34 deletions

View file

@ -1094,6 +1094,7 @@ const expr_t *deref_pointer_expr (const expr_t *pointer);
const expr_t *pointer_deref (const expr_t *pointer);
const expr_t *offset_pointer_expr (const expr_t *pointer, const expr_t *offset);
const expr_t *address_expr (const expr_t *e1, const type_t *t);
const expr_t *reference_expr (const expr_t *e1, const type_t *t);
const expr_t *build_if_statement (bool not, const expr_t *test,
const expr_t *s1, const expr_t *els,
const expr_t *s2);

View file

@ -2528,14 +2528,11 @@ offset_pointer_expr (const expr_t *pointer, const expr_t *offset)
return cast_expr (ptr_type, ptr);
}
const expr_t *
address_expr (const expr_t *e1, const type_t *t)
static expr_t *
core_address_expr (const expr_t *e1, const type_t *t)
{
expr_t *e;
if (e1->type == ex_error)
return e1;
if (!t)
t = get_type (e1);
@ -2553,9 +2550,9 @@ address_expr (const expr_t *e1, const type_t *t)
}
if (is_array (type)) {
auto ptrval = new_pointer_val (0, t, def, 0);
return new_value_expr (ptrval, false);
return (expr_t *) new_value_expr (ptrval, false);
} else {
return new_pointer_expr (0, t, def);
return (expr_t *) new_pointer_expr (0, t, def);
}
}
break;
@ -2572,13 +2569,13 @@ address_expr (const expr_t *e1, const type_t *t)
if (is_array (type)) {
auto ptrval = new_pointer_val (0, t, def, 0);
return new_value_expr (ptrval, false);
return (expr_t *) new_value_expr (ptrval, false);
} else {
return new_pointer_expr (0, t, def);
return (expr_t *) new_pointer_expr (0, t, def);
}
break;
}
return error (e1, "invalid type for unary &");
return (expr_t *) error (e1, "invalid type for unary &");
case ex_field:
e = new_address_expr (e1->field.type, e1, nullptr);
break;
@ -2588,16 +2585,16 @@ address_expr (const expr_t *e1, const type_t *t)
e1->expr.e1, e1->expr.e2);
break;
}
return error (e1, "invalid type for unary &");
return (expr_t *) error (e1, "invalid type for unary &");
case ex_uexpr:
if (e1->expr.op == '.') {
auto p = e1->expr.e1;
auto p = (expr_t *) e1->expr.e1;
if (p->type == ex_expr && p->expr.op == '.') {
p = new_address_expr (p->expr.type, p->expr.e1, p->expr.e2);
}
return p;
}
return error (e1, "invalid type for unary &");
return (expr_t *) error (e1, "invalid type for unary &");
case ex_label:
return new_label_ref (&e1->label);
case ex_temp:
@ -2609,11 +2606,40 @@ address_expr (const expr_t *e1, const type_t *t)
}
return new_address_expr (t, e1, 0);
default:
return error (e1, "invalid type for unary &");
return (expr_t *) error (e1, "invalid type for unary &");
}
return e;
}
const expr_t *
address_expr (const expr_t *e1, const type_t *t)
{
if (is_error (e1)) {
return e1;
}
return core_address_expr (e1, t);
}
const expr_t *
reference_expr (const expr_t *e, const type_t *t)
{
if (is_error (e)) {
return e;
}
auto ref = core_address_expr (e, t);
if (is_error (ref)) {
return ref;
}
if (ref->type != ex_address) {
internal_error (ref, "expected address expression");
}
auto type = get_type (ref);
type = dereference_type (type);
type = reference_type (type);
ref->address.type = type;
return ref;
}
const expr_t *
build_if_statement (bool not, const expr_t *test, const expr_t *s1,
const expr_t *els, const expr_t *s2)

View file

@ -205,6 +205,18 @@ check_arg_types (const expr_t **arguments, const type_t **arg_types,
return err;
}
static const expr_t *
reference_param (const type_t *ptype, const expr_t *arg)
{
auto arg_type = get_type (arg);
if (is_reference (ptype) && !is_reference (arg_type)) {
arg = reference_expr (arg, nullptr);
} else if (!is_reference (ptype) && is_reference (arg_type)) {
arg = pointer_deref (arg);
}
return arg;
}
static void
build_call_scope (symbol_t *fsym, const expr_t **arguments)
{
@ -236,14 +248,7 @@ build_call_scope (symbol_t *fsym, const expr_t **arguments)
}
auto psym = new_symbol (p->name);
psym->sy_type = sy_expr;
auto arg_type = get_type (arguments[i]);
if (is_reference (p->type) && !is_reference (arg_type)) {
psym->expr = address_expr (arguments[i], nullptr);
} else if (!is_reference (p->type) && is_reference (arg_type)) {
psym->expr = pointer_deref (arguments[i]);
} else {
psym->expr = arguments[i];
}
psym->expr = reference_param (p->type, arguments[i]);
symtab_addsymbol (params, psym);
}
}
@ -280,23 +285,13 @@ build_intrinsic_call (const expr_t *expr, symbol_t *fsym, const type_t *ftype,
current_symtab = func->locals;
for (int i = 0; i < extra_count; i++) {
extra_args[i] = expr_process (extra_args[i], ctx);
if (is_reference (get_type (extra_args[i]))) {
extra_args[i] = pointer_deref (extra_args[i]);
}
}
current_symtab = scope;
list_gather (&call->intrinsic.operands, extra_args, extra_count);
} else {
auto p = fsym->params;
for (int i = 0; i < arg_count; i++, p = p->next) {
auto arg_type = get_type (arguments[i]);
if (is_reference (p->type) && !is_reference (arg_type)) {
arguments[i] = address_expr (arguments[i], nullptr);
} else if (!is_reference (p->type) && is_reference (arg_type)) {
arguments[i] = pointer_deref (arguments[i]);
} else {
arguments[i] = arguments[i];
}
arguments[i] = reference_param (p->type, arguments[i]);
}
list_gather (&call->intrinsic.operands, arguments, arg_count);
}
@ -416,7 +411,7 @@ build_args (const expr_t *(*arg_exprs)[2], int *arg_expr_count,
if (is_reference (get_type (e))) {
// just copy the param, so no op
} else {
e = address_expr (e, nullptr);
e = reference_expr (e, nullptr);
}
} else {
if (is_reference (get_type (e))) {