From d72113f5cb150753ee9dfb64c1cbe224e6565529 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 9 Oct 2024 13:33:38 +0900 Subject: [PATCH] [qfcc] Select correct generic function for references When the parameter is a reference, implicit casting is not allowed, but when the parameter is by value and the argument is a reference, the argument is dereferenced and promotion is allowed. However, this covers only the selection of generic functions. It doesn't deal with otherwise overloaded functions, nor does it do the actual dereferencing or address taking. --- tools/qfcc/source/function.c | 44 ++++++++++++++++++++++++++++++------ tools/qfcc/source/type.c | 2 +- 2 files changed, 38 insertions(+), 8 deletions(-) diff --git a/tools/qfcc/source/function.c b/tools/qfcc/source/function.c index 7546ab240..d7d883e0b 100644 --- a/tools/qfcc/source/function.c +++ b/tools/qfcc/source/function.c @@ -685,7 +685,22 @@ static const type_t * __attribute__((pure)) select_type (gentype_t *gentype, const type_t *param_type) { for (auto t = gentype->valid_types; t && *t; t++) { - if (*t == param_type || type_promotes (*t, param_type)) { + if (*t == param_type) { + return *t; + } + if (is_reference (*t) && dereference_type (*t) == param_type) { + // pass value by reference: no promotion + return *t; + } + auto pt = param_type; + if (is_reference (pt)) { + // pass reference by value: promotion ok + pt = dereference_type (pt); + } + if (*t == pt) { + return *t; + } + if (type_promotes (*t, pt)) { return *t; } } @@ -695,13 +710,28 @@ select_type (gentype_t *gentype, const type_t *param_type) static bool check_type (const type_t *type, const type_t *param_type, unsigned *cost) { - if (type != param_type) { - if (type_promotes (type, param_type)) { - *cost += 1; - } else { - return false; - } + if (!type) { + return false; } + if (type == param_type) { + return true; + } + if (is_reference (type)) { + // pass by references is a free conversion, but no promotion + return dereference_type (type) == param_type; + } + if (is_reference (param_type)) { + // dereferencing a reference is free so long as there's no + // promotion, otherwise there's the promotion cost + param_type = dereference_type (param_type); + } + if (type == param_type) { + return true; + } + if (!type_promotes (type, param_type)) { + return false; + } + *cost += 1; return true; } diff --git a/tools/qfcc/source/type.c b/tools/qfcc/source/type.c index e7fe935d4..0edf63526 100644 --- a/tools/qfcc/source/type.c +++ b/tools/qfcc/source/type.c @@ -1003,7 +1003,7 @@ print_type_str (dstring_t *str, const type_t *type) return; } } - dasprintf (str, "(*"); + dasprintf (str, "(%c", type->fldptr.deref ? '&' : '*'); print_type_str (str, type->fldptr.type); dasprintf (str, ")"); return;