[qfcc] Handle type expressions when merging specifiers

The type expressions no longer get lost along the way to the function
return type and parameter types.
This commit is contained in:
Bill Currie 2024-05-01 10:58:01 +09:00
parent aff70aa243
commit 1567f29668
3 changed files with 48 additions and 19 deletions

View file

@ -136,16 +136,18 @@ extern function_t *current_func;
typedef struct param_s {
struct param_s *next;
const char *selector;
const struct type_s *type;
const type_t *type;
const expr_t *type_expr;
const char *name;
} param_t;
struct expr_s;
struct symbol_s;
struct symtab_s;
typedef struct expr_s expr_t;
typedef struct symbol_s symbol_t;
typedef struct symtab_s symtab_t;
param_t *new_param (const char *selector, const struct type_s *type,
const char *name);
param_t *new_generic_param (const expr_t *type_expr, const char *name);
param_t *param_append_identifiers (param_t *params, struct symbol_s *idents,
const struct type_s *type);
param_t *reverse_params (param_t *params);

View file

@ -98,11 +98,24 @@ new_param (const char *selector, const type_t *type, const char *name)
param_t *param;
ALLOC (4096, param_t, params, param);
param->next = 0;
param->selector = selector;
param->type = find_type (type);
param->name = name;
*param = (param_t) {
.selector = selector,
.type = find_type (type),
.name = name,
};
return param;
}
param_t *
new_generic_param (const expr_t *type_expr, const char *name)
{
param_t *param;
ALLOC (4096, param_t, params, param);
*param = (param_t) {
.type_expr = type_expr,
.name = name,
};
return param;
}

View file

@ -285,15 +285,22 @@ storage_auto (specifier_t spec)
return spec.storage == sc_global || spec.storage == sc_local;
}
static bool
spec_type (specifier_t spec)
{
return spec.type || spec.type_expr;
}
static specifier_t
spec_merge (specifier_t spec, specifier_t new)
{
if (new.type) {
if (spec_type (new)) {
// deal with "type <type_name>"
if (!spec.type || new.sym) {
if (!spec_type (spec) || new.sym) {
spec.sym = new.sym;
if (!spec.type) {
if (!spec_type (spec)) {
spec.type = new.type;
spec.type_expr = new.type_expr;
}
} else if (!spec.multi_type) {
error (0, "two or more data types in declaration specifiers");
@ -419,13 +426,14 @@ static param_t *
make_param (specifier_t spec)
{
if (spec.type_expr) {
if (!(spec.type = resolve_type (spec.type_expr))) {
}
auto param = new_generic_param (spec.type_expr, spec.sym->name);
return param;
} else {
spec = default_type (spec, spec.sym);
spec.type = find_type (append_type (spec.sym->type, spec.type));
auto param = new_param (0, spec.type, spec.sym->name);
return param;
}
spec = default_type (spec, spec.sym);
spec.type = find_type (append_type (spec.sym->type, spec.type));
param_t *param = new_param (0, spec.type, spec.sym->name);
return param;
}
static param_t *
@ -922,8 +930,14 @@ typespec_reserved
: TYPE_SPEC
| type_function
{
auto type = resolve_type ($1);
$$ = make_spec (type, 0, 0, 0);
if (generic_scope) {
$$ = (specifier_t) {
.type_expr = $1,
};
} else {
auto type = resolve_type ($1);
$$ = make_spec (type, 0, 0, 0);
}
}
| algebra_specifier %prec LOW
| algebra_specifier '.' attribute