From b3603d06f2a3d712a55bdab63fcd885cb193c0d2 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 15 Nov 2022 19:22:02 +0000 Subject: [PATCH] Allow selected name in component instantiation statement. Fixes #569 --- src/names.c | 25 +++++++++++--- src/parse.c | 76 +++++++++++++++++------------------------ test/parse/issue569.vhd | 22 ++++++++++++ test/test_parse.c | 36 +++++++++++++++++-- test/test_sem.c | 10 +++--- 5 files changed, 114 insertions(+), 55 deletions(-) create mode 100644 test/parse/issue569.vhd diff --git a/src/names.c b/src/names.c index 5c405c00..f812c588 100644 --- a/src/names.c +++ b/src/names.c @@ -159,6 +159,7 @@ static bool can_call_no_args(nametab_t *tab, tree_t decl); static bool is_forward_decl(tree_t decl, tree_t existing); static bool denotes_same_object(tree_t a, tree_t b); static void make_visible_slow(scope_t *s, ident_t name, tree_t decl); +static const symbol_t *iterate_symbol_for(nametab_t *tab, ident_t name); static void begin_overload_resolution(overload_t *o); static tree_t finish_overload_resolution(overload_t *o); @@ -892,8 +893,9 @@ static symbol_t *lazy_lib_cb(scope_t *s, ident_t name, void *context) { lib_t lib = context; - tree_t unit = lib_get(lib, name); - if (unit == NULL) + bool error; + tree_t unit = lib_get_allow_error(lib, name, &error); + if (unit == NULL || error) return NULL; return make_visible(s, name, unit, DIRECT, s); @@ -1229,7 +1231,7 @@ type_t resolve_type(nametab_t *tab, type_t incomplete) name_mask_t query_name(nametab_t *tab, ident_t name, tree_t *p_decl) { - const symbol_t *sym = symbol_for(tab->top_scope, name); + const symbol_t *sym = iterate_symbol_for(tab, name); if (sym == NULL) return 0; @@ -1400,7 +1402,22 @@ tree_t resolve_name(nametab_t *tab, const loc_t *loc, ident_t name) ; // Was earlier error else if (tab->top_scope->overload == NULL) { diag_t *d = diag_new(DIAG_ERROR, loc); - diag_printf(d, "no visible declaration for %s", istr(name)); + + ident_t prefix = ident_until(name, '.'); + const symbol_t *psym = prefix ? iterate_symbol_for(tab, prefix) : NULL; + if (psym != NULL && psym->ndecls == 1) { + const char *container = "object", *what = "name"; + switch (psym->decls[0].kind) { + case T_LIBRARY: container = "library"; what = "design unit"; break; + default: break; + } + diag_printf(d, "%s %s not found in %s %s", what, + istr(ident_rfrom(name, '.')), container, + istr(psym->name)); + } + else + diag_printf(d, "no visible declaration for %s", istr(name)); + hint_for_typo(tab, d, name, N_OBJECT | N_TYPE); diag_emit(d); } diff --git a/src/parse.c b/src/parse.c index 6e0c55cc..3e8e6fef 100644 --- a/src/parse.c +++ b/src/parse.c @@ -605,6 +605,8 @@ static tree_t error_expr(void) static tree_t find_unit(const loc_t *where, ident_t name, const char *hint) { + // TODO: should be able to replace this with resolve_name + ident_t lname = ident_until(name, '.'); lib_t lib = lib_loaded(lname); if (lib != NULL) { @@ -647,59 +649,45 @@ static tree_t find_binding(tree_t inst) name = tree_ident(inst); if (tree_has_ident2(inst)) name = ident_prefix(name, tree_ident2(inst), '-'); - query_name(nametab, name, &unit); } else { name = tree_ident2(inst); if (tree_has_ref(inst)) unit = tree_ref(inst); - else - query_name(nametab, name, &unit); } - if (unit != NULL) { - const char *what = is_design_unit(unit) ? "design unit" : "object"; - switch (tree_class(inst)) { - case C_COMPONENT: - if (tree_kind(unit) != T_COMPONENT) { - parse_error(tree_loc(inst), "%s %s is not a component declaration", - what, istr(name)); - return NULL; - } - break; - case C_ENTITY: - if (tree_kind(unit) != T_ENTITY) { - parse_error(tree_loc(inst), "%s %s is not an entity", - what, istr(name)); - return NULL; - } - break; - case C_CONFIGURATION: - if (tree_kind(unit) != T_CONFIGURATION) { - parse_error(tree_loc(inst), "%s %s is not a configuration", - what, istr(name)); - return NULL; - } - break; - default: - break; + if (unit == NULL) + unit = resolve_name(nametab, tree_loc(inst), name); + + if (unit == NULL) + return NULL; + + const char *what = is_design_unit(unit) ? "design unit" : "object"; + const tree_kind_t kind = tree_kind(unit); + switch (tree_class(inst)) { + case C_COMPONENT: + if (kind != T_COMPONENT) { + parse_error(tree_loc(inst), "%s %s is not a component declaration", + what, istr(name)); + return NULL; } - } - else { - unit = find_unit(tree_loc(inst), name, NULL); - if (unit != NULL) { - tree_kind_t kind = tree_kind(unit); - if (kind != T_ENTITY && kind != T_CONFIGURATION && kind != T_ARCH) { - parse_error(tree_loc(inst), "unit %s cannot be instantiated", - istr(name)); - unit = NULL; - } - else if ((kind == T_CONFIGURATION || kind == T_ARCH) - && !tree_has_primary(unit)) { - // Was an earlier parse error - unit = NULL; - } + break; + case C_ENTITY: + if (kind != T_ENTITY && kind != T_ARCH) { + parse_error(tree_loc(inst), "%s %s is not an entity", + what, istr(name)); + return NULL; } + break; + case C_CONFIGURATION: + if (kind != T_CONFIGURATION) { + parse_error(tree_loc(inst), "%s %s is not a configuration", + what, istr(name)); + return NULL; + } + break; + default: + break; } return unit; diff --git a/test/parse/issue569.vhd b/test/parse/issue569.vhd new file mode 100644 index 00000000..455b19ca --- /dev/null +++ b/test/parse/issue569.vhd @@ -0,0 +1,22 @@ +-- library foo + +package pack is + component comp is + port ( p : in bit ); + end component; +end package; + +-- library bar + +library foo; + +entity e is +end entity; + +architecture a of e is +begin + + u: component foo.pack.comp -- OK + port map ( '1' ); + +end architecture; diff --git a/test/test_parse.c b/test/test_parse.c index 20a923a4..bd697219 100644 --- a/test/test_parse.c +++ b/test/test_parse.c @@ -2908,7 +2908,6 @@ START_TEST(test_error) { 50, "B1 already declared in this region" }, { 53, "declaration of constant X hides signal X" }, { 56, "C1 already declared in this region" }, - { 59, "NOT_A_LIBRARY does not name a visible component or design unit" }, { 64, "missing declaration for entity WORK.NOT_HERE" }, { -1, NULL } }; @@ -3873,6 +3872,7 @@ START_TEST(test_badprimary) const error_t expect[] = { { 17, "missing declaration for entity WORK.NOT_HERE" }, + { 26, "design unit NOT_HERE-BAD not found in library WORK" }, { -1, NULL } }; expect_errors(expect); @@ -3891,7 +3891,7 @@ START_TEST(test_badprimary) fail_if(bad == NULL); fail_unless(tree_kind(bad) == T_ARCH); fail_if(tree_has_primary(bad)); - lib_put(lib_work(), bad); + lib_put_error(lib_work(), bad); tree_t cfg = parse(); fail_if(cfg == NULL); @@ -4994,6 +4994,37 @@ START_TEST(test_issue568) } END_TEST +START_TEST(test_issue569) +{ + input_from_file(TESTDIR "/parse/issue569.vhd"); + + lib_t foo = lib_tmp("foo"); + lib_t bar = lib_tmp("bar"); + + lib_set_work(foo); + + tree_t p = parse(); + fail_if(p == NULL); + fail_unless(tree_kind(p) == T_PACKAGE); + lib_put(foo, p); + + lib_set_work(bar); + + tree_t e = parse(); + fail_if(e == NULL); + fail_unless(tree_kind(e) == T_ENTITY); + lib_put(bar, e); + + tree_t a = parse(); + fail_if(a == NULL); + fail_unless(tree_kind(a) == T_ARCH); + + fail_unless(parse() == NULL); + + fail_if_errors(); +} +END_TEST + Suite *get_parse_tests(void) { Suite *s = suite_create("parse"); @@ -5091,6 +5122,7 @@ Suite *get_parse_tests(void) tcase_add_test(tc_core, test_issue532); tcase_add_test(tc_core, test_issue539); tcase_add_test(tc_core, test_issue568); + tcase_add_test(tc_core, test_issue569); suite_add_tcase(s, tc_core); return s; diff --git a/test/test_sem.c b/test/test_sem.c index ecf2dd48..9b15b121 100644 --- a/test/test_sem.c +++ b/test/test_sem.c @@ -108,7 +108,7 @@ START_TEST(test_ports) { 85, "formal port I already has an actual" }, { 89, "at least 3 positional actuals but WORK.FOO has only 2 ports" }, { 92, "WORK.FOO has no port named CAKE" }, - { 94, "cannot find unit WORK.BAD" }, + { 94, "design unit BAD not found in library WORK" }, { 103, "unconnected port I with mode IN must have a default value" }, { 116, "object X is not a component declaration" }, { 122, "declaration of signal X hides signal X" }, @@ -908,8 +908,8 @@ START_TEST(test_entity) input_from_file(TESTDIR "/sem/entity.vhd"); const error_t expect[] = { - { 23, "cannot find unit WORK.E-INVALID" }, - { 26, "unit WORK.PACK cannot be instantiated" }, + { 23, "design unit E-INVALID not found in library WORK" }, + { 26, "design unit WORK.PACK is not an entity" }, { 30, "unit WORK.PACK is not an entity" }, { 61, "signal assignment statement not allowed inside passive process" }, { -1, NULL } @@ -1067,8 +1067,8 @@ START_TEST(test_spec) { 24, "E does not name a component" }, { 24, "duplicate specification for instance I1" }, { 32, "duplicate specification for instance I1" }, - { 34, "cannot find unit WORK.NOT_HERE" }, - { 36, "unit WORK.P cannot be instantiated" }, + { 34, "design unit NOT_HERE not found in library WORK" }, + { 36, "design unit WORK.P is not an entity" }, { 36, "duplicate specification for instance I3" }, { 22, "component mismatch for instance I1: expected C1" }, { 30, "specification may only be used with component instances" }, -- 2.39.2