From 137892bd8b04f9a5bd680b5a7739fd9d7465a27d Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 1 Mar 2024 22:05:48 +0000 Subject: [PATCH] Refactor resolving of subprogram names --- src/names.c | 160 +++++++++++++++++++++++++++++----------- src/names.h | 5 +- src/parse.c | 17 ++--- test/parse/issue654.vhd | 13 +++- test/test_parse.c | 6 +- test/test_sem.c | 7 +- 6 files changed, 148 insertions(+), 60 deletions(-) diff --git a/src/names.c b/src/names.c index fa740f89..5cc49a04 100644 --- a/src/names.c +++ b/src/names.c @@ -1458,7 +1458,7 @@ static void hint_for_typo(scope_t *top_scope, diag_t *d, ident_t name, for (int i = 0; i < chunk->count; i++) { if (chunk->symbols[i].mask & filter) { const int d = ident_distance(chunk->symbols[i].name, name); - if (d < bestd) { + if (d > 0 && d < bestd) { best = &(chunk->symbols[i]); bestd = d; } @@ -1791,24 +1791,16 @@ tree_t resolve_name(nametab_t *tab, const loc_t *loc, ident_t name) return NULL; } -tree_t resolve_subprogram_name(nametab_t *tab, tree_t ref, type_t constraint) +static tree_t resolve_method_name(nametab_t *tab, tree_t ref, type_t constraint) { - const bool is_protected = tree_kind(ref) == T_PROT_REF; - assert(is_protected || tree_kind(ref) == T_REF); + assert(tree_kind(ref) == T_PROT_REF); + assert(constraint != NULL); - const bool allow_enum = - constraint != NULL && type_kind(constraint) == T_FUNC - && type_params(constraint) == 0 - && !is_protected; + type_t ptype = tree_type(tree_value(ref)); + assert(type_is_protected(ptype)); - const symbol_t *sym; - if (is_protected) { - type_t ptype = tree_type(tree_value(ref)); - assert(type_is_protected(ptype)); - sym = symbol_for(scope_for_type(tab, ptype), tree_ident(ref)); - } - else - sym = iterate_symbol_for(tab, tree_ident(ref)); + scope_t *scope = scope_for_type(tab, ptype); + const symbol_t *sym = symbol_for(scope, tree_ident(ref)); SCOPED_A(tree_t) matching = AINIT; if (sym != NULL) { @@ -1817,47 +1809,90 @@ tree_t resolve_subprogram_name(nametab_t *tab, tree_t ref, type_t constraint) if (dd->visibility == HIDDEN) continue; else if (dd->mask & N_SUBPROGRAM) { - if (constraint == NULL) + type_t signature = tree_type(dd->tree); + if (type_eq_map(constraint, signature, tab->top_scope->gmap)) APUSH(matching, dd->tree); + } + } + } + + assert(matching.count <= 1); + + if (matching.count == 1) + return matching.items[0]; + else if (tab->top_scope->suppress) + return NULL; + else { + const char *signature = strchr(type_pp(constraint), '['); + error_at(tree_loc(ref), "no visible method %s in protected type %s " + "matches signature %s", istr(tree_ident(ref)), type_pp(ptype), + signature); + return NULL; + } +} + +tree_t resolve_uninstantiated_subprogram(nametab_t *tab, const loc_t *loc, + ident_t name, type_t constraint) +{ + const symbol_t *sym = iterate_symbol_for(tab, name); + + SCOPED_A(tree_t) m = AINIT; + if (sym != NULL) { + for (int i = 0; i < sym->ndecls; i++) { + const decl_t *dd = get_decl(sym, i); + if (dd->visibility == HIDDEN) + continue; + else if (dd->mask & N_SUBPROGRAM) { + if (constraint == NULL) + APUSH(m, dd->tree); else { type_t signature = tree_type(dd->tree); if (type_eq_map(constraint, signature, tab->top_scope->gmap)) - APUSH(matching, dd->tree); + APUSH(m, dd->tree); } } - else if (allow_enum && dd->kind == T_ENUM_LIT - && type_eq(type_result(constraint), tree_type(dd->tree))) - APUSH(matching, dd->tree); } } - if (matching.count == 1) - return matching.items[0]; + if (m.count > 1) { + unsigned wptr = 0; + for (unsigned i = 0; i < m.count; i++) { + if (is_uninstantiated_subprogram(m.items[i])) + m.items[wptr++] = m.items[i]; + } + ATRIM(m, wptr); + } + + if (m.count == 1) { + if (is_uninstantiated_subprogram(m.items[0])) + return m.items[0]; + else { + error_at(loc, "%s %s is not an uninstantiated subprogram", + class_str(class_of(m.items[0])), istr(name)); + return NULL; + } + } else if (tab->top_scope->suppress) return NULL; else if (constraint != NULL) { const char *signature = strchr(type_pp(constraint), '['); - error_at(tree_loc(ref), "no visible subprogram%s %s matches " - "signature %s", allow_enum ? " or enumeration literal" : "", - istr(tree_ident(ref)), signature); + error_at(loc, "no visible uninstantiated subprogram %s matches " + "signature %s", istr(name), signature); return NULL; } - else if (matching.count == 0) { - diag_t *d = diag_new(DIAG_ERROR, tree_loc(ref)); - diag_printf(d, "no visible subprogram declaration for %s", - istr(tree_ident(ref))); - hint_for_typo(tab->top_scope, d, tree_ident(ref), N_SUBPROGRAM); - diag_emit(d); + else if (m.count == 0) { + error_at(loc,"no visible uninstantiated subprogram declaration for %s", + istr(name)); return NULL; } else { - diag_t *d = diag_new(DIAG_ERROR, tree_loc(ref)); - diag_printf(d, "multiple visible subprograms with name %s", - istr(tree_ident(ref))); - for (int i = 0; i < matching.count; i++) - diag_hint(d, tree_loc(matching.items[i]), "visible declaration of %s", - type_pp(tree_type(matching.items[i]))); - diag_hint(d, tree_loc(ref), "use of name %s here", istr(tree_ident(ref))); + diag_t *d = diag_new(DIAG_ERROR, loc); + diag_printf(d, "multiple visible uninstantiated subprograms with " + "name %s", istr(name)); + for (int i = 0; i < m.count; i++) + diag_hint(d, tree_loc(m.items[i]), "visible declaration of %s", + type_pp(tree_type(m.items[i]))); + diag_hint(d, loc, "use of name %s here", istr(name)); diag_hint(d, NULL, "use an explicit subprogram signature to select " "a particular overload"); diag_emit(d); @@ -1865,16 +1900,57 @@ tree_t resolve_subprogram_name(nametab_t *tab, tree_t ref, type_t constraint) } } +tree_t resolve_subprogram_name(nametab_t *tab, const loc_t *loc, ident_t name, + type_t constraint) +{ + const bool allow_enum = + type_kind(constraint) == T_FUNC && type_params(constraint) == 0; + + const symbol_t *sym = iterate_symbol_for(tab, name); + + SCOPED_A(tree_t) matching = AINIT; + if (sym != NULL) { + for (int i = 0; i < sym->ndecls; i++) { + const decl_t *dd = get_decl(sym, i); + if (dd->visibility == HIDDEN) + continue; + else if (dd->mask & N_SUBPROGRAM) { + type_t signature = tree_type(dd->tree); + if (type_eq_map(constraint, signature, tab->top_scope->gmap)) + APUSH(matching, dd->tree); + } + else if (allow_enum && dd->kind == T_ENUM_LIT + && type_eq(type_result(constraint), tree_type(dd->tree))) + APUSH(matching, dd->tree); + } + } + + if (matching.count == 1) + return matching.items[0]; + else if (tab->top_scope->suppress) + return NULL; + else { + const char *signature = strchr(type_pp(constraint), '['); + error_at(loc, "no visible subprogram%s %s matches signature %s", + allow_enum ? " or enumeration literal" : "", + istr(name), signature); + return NULL; + } +} + static tree_t resolve_ref(nametab_t *tab, tree_t ref) { + const loc_t *loc = tree_loc(ref); + ident_t name = tree_ident(ref); + type_t constraint; if (type_set_uniq(tab, &constraint) && type_is_subprogram(constraint)) { // Reference to subprogram or enumeration literal with signature - return resolve_subprogram_name(tab, ref, constraint); + return resolve_subprogram_name(tab, loc, name, constraint); } else { // Ordinary reference - return resolve_name(tab, tree_loc(ref), tree_ident(ref)); + return resolve_name(tab, loc, name); } } @@ -3798,7 +3874,7 @@ static type_t solve_prot_ref(nametab_t *tab, tree_t pref) type_t constraint; if (type_set_uniq(tab, &constraint) && type_is_subprogram(constraint)) { // Reference to protected type subprogram with signature - tree_t decl = resolve_subprogram_name(tab, pref, constraint); + tree_t decl = resolve_method_name(tab, pref, constraint); type_t type = decl ? tree_type(decl) : type_new(T_NONE); tree_set_type(pref, type); tree_set_ref(pref, decl); diff --git a/src/names.h b/src/names.h index b6ae09c1..e1a4afe1 100644 --- a/src/names.h +++ b/src/names.h @@ -102,7 +102,10 @@ void continue_proc_labelling_from(tree_t t, nametab_t *tab); tree_t resolve_name(nametab_t *tab, const loc_t *loc, ident_t name); type_t resolve_type(nametab_t *tab, type_t incomplete); -tree_t resolve_subprogram_name(nametab_t *tab, tree_t ref, type_t constraint); +tree_t resolve_subprogram_name(nametab_t *tab, const loc_t *loc, ident_t name, + type_t constraint); +tree_t resolve_uninstantiated_subprogram(nametab_t *tab, const loc_t *loc, + ident_t name, type_t constraint); void resolve_resolution(nametab_t *tab, tree_t rname, type_t type); name_mask_t query_name(nametab_t *tab, ident_t name, tree_t *p_decl); tree_t query_spec(nametab_t *tab, tree_t object); diff --git a/src/parse.c b/src/parse.c index 1e8414df..5df84f0a 100644 --- a/src/parse.c +++ b/src/parse.c @@ -5805,11 +5805,8 @@ static void p_attribute_specification(tree_t parent, add_func_t addf) tree_set_type(t, type); if (it->signature != NULL) { - tree_t tmp = tree_new(T_REF); - tree_set_ident(tmp, it->ident); - tree_set_loc(tmp, &(it->loc)); - - tree_t d = resolve_subprogram_name(nametab, tmp, it->signature); + tree_t d = resolve_subprogram_name(nametab, &(it->loc), it->ident, + it->signature); tree_set_ref(t, d); } else if (class != C_LITERAL && class != C_LABEL) @@ -6907,13 +6904,8 @@ static tree_t p_subprogram_instantiation_declaration(void) if (tree_kind(name) != T_REF) parse_error(CURRENT_LOC, "expecting uninstantiated subprogram name"); else { - decl = resolve_subprogram_name(nametab, name, constraint); - - if (decl != NULL && !is_uninstantiated_subprogram(decl)) { - parse_error(CURRENT_LOC, "%s %s is not an uninstantiated subprogram", - class_str(class_of(decl)), istr(tree_ident(name))); - decl = NULL; - } + decl = resolve_uninstantiated_subprogram(nametab, tree_loc(name), + tree_ident(name), constraint); } tree_t body = NULL; @@ -6948,6 +6940,7 @@ static tree_t p_subprogram_instantiation_declaration(void) else { // Create a dummy subprogram type to avoid later errors type_t type = type_new(kind == T_FUNC_INST ? T_FUNC : T_PROC); + type_set_ident(type, tree_ident(name)); if (kind == T_FUNC_INST) type_set_result(type, type_new(T_NONE)); tree_set_type(inst, type); diff --git a/test/parse/issue654.vhd b/test/parse/issue654.vhd index 2b294455..41cbadb0 100644 --- a/test/parse/issue654.vhd +++ b/test/parse/issue654.vhd @@ -16,6 +16,17 @@ package frequency is function "not"(x : t) return t is <> ) parameter (signal clock : inout t ; freq : frequency ; count : natural := 0) ; - procedure generate_clock is new generate_clock generic map(t => bit) ; + procedure generate_clock is new generate_clock -- OK + generic map(t => bit) ; + + procedure bad1 is new generate_clock [return integer]; -- Error + procedure bad2 is new "+"; -- Error + + procedure generate_clock generic ( + type t ; + function "not"(x : t) return t is <> + ) parameter (signal clock : inout t) ; + + procedure bad3 is new generate_clock; -- Error end package ; diff --git a/test/test_parse.c b/test/test_parse.c index 57e12cbb..0ee4b69f 100644 --- a/test/test_parse.c +++ b/test/test_parse.c @@ -5411,7 +5411,11 @@ START_TEST(test_issue654) const error_t expect[] = { { 19, "subprogram GENERATE_CLOCK cannot be instantiated until its body " "has been analysed" }, - { 19, "GENERATE_CLOCK has no generic named T" }, + { 20, "GENERATE_CLOCK has no generic named T" }, + { 22, "no visible uninstantiated subprogram GENERATE_CLOCK matches " + "signature [return INTEGER]" }, + { 23, "no visible uninstantiated subprogram declaration for \"+\"" }, + { 30, "multiple visible uninstantiated subprograms with name GENE" }, { -1, NULL } }; expect_errors(expect); diff --git a/test/test_sem.c b/test/test_sem.c index f5dcb729..53ad582b 100644 --- a/test/test_sem.c +++ b/test/test_sem.c @@ -2822,9 +2822,9 @@ START_TEST(test_gensub) { 60, "actual associated with generic Y must be a globally static" }, { 69, "subtype of generic X does not match type INTEGER in spec" }, { 75, "subprogram TEST2 declaration has 1 generic but body has 2" }, - { 93, "multiple visible subprograms with name TEST1" }, + { 93, "multiple visible uninstantiated subprograms with name TEST1" }, { 93, "TEST_ERROR has no generic named T" }, - { 94, "no visible subprogram declaration for TEST444" }, + { 94, "no visible uninstantiated subprogram declaration for TEST444" }, { 94, "TEST_ERROR2 has no generic named T" }, { -1, NULL } }; @@ -3350,7 +3350,8 @@ START_TEST(test_alias2) input_from_file(TESTDIR "/sem/alias2.vhd"); const error_t expect[] = { - { 39, "no visible subprogram FOOBAR matches signature []" }, + { 39, "no visible method FOOBAR in protected type T_TEST matches " + "signature []" }, { 40, "no visible declaration for XX" }, { 42, "invalid use of name INCREMENT" }, { 42, "aliased name is not static" }, -- 2.39.2