From ae1588579f9df54bb329643cd2c9d5de3c8528ff Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 2 Dec 2022 12:42:26 +0000 Subject: [PATCH] Fix type mismatch with instantiated generic package --- src/dump.c | 8 +++-- src/names.c | 29 +++++++++------ src/names.h | 2 +- src/object.c | 2 +- src/parse.c | 47 +++++++++++++++++------- src/sem.c | 43 +++++++++++----------- test/sem/genpack.vhd | 2 +- test/sem/genpack2.vhd | 83 +++++++++++++++++++++++++++++++++++++++++++ test/test_sem.c | 17 +++++++-- 9 files changed, 181 insertions(+), 52 deletions(-) create mode 100644 test/sem/genpack2.vhd diff --git a/src/dump.c b/src/dump.c index 6197d90e..96ebe4da 100644 --- a/src/dump.c +++ b/src/dump.c @@ -780,7 +780,9 @@ static void dump_decl(tree_t t, int indent) syntax("#function %s", istr(tree_ident(t))); dump_generics(t, indent + 2, ""); dump_arguments(t, indent, ""); - syntax(" #return %s;\n", type_pp(type_result(tree_type(t)))); + syntax(" #return "); + dump_type(type_result(tree_type(t))); + printf(";\n"); if (tree_has_ident2(t)) { tab(indent + 2); syntax("-- %s\n", istr(tree_ident2(t))); @@ -796,7 +798,9 @@ static void dump_decl(tree_t t, int indent) if (tree_kind(t) == T_FUNC_INST) dump_generic_map(t, indent + 2, tree_ports(t) > 0 ? "\n" : ""); dump_arguments(t, indent, ""); - syntax(" #return %s #is\n", type_pp(type_result(tree_type(t)))); + syntax(" #return "); + dump_type(type_result(tree_type(t))); + syntax(" #is\n"); if (tree_has_ident2(t)) { tab(indent + 2); syntax("-- %s\n", istr(tree_ident2(t))); diff --git a/src/names.c b/src/names.c index 2e4ff23a..42f51080 100644 --- a/src/names.c +++ b/src/names.c @@ -444,23 +444,29 @@ void map_generic_subprogram(nametab_t *tab, tree_t decl, tree_t actual) hash_put(tab->top_scope->gmap, decl, actual); } -void map_generic_package(nametab_t *tab, tree_t inst) +void map_generic_package(nametab_t *tab, tree_t generic, tree_t actual) { - assert(tree_kind(inst) == T_PACK_INST); + assert(tree_kind(actual) == T_PACK_INST); if (tab->top_scope->gmap == NULL) tab->top_scope->gmap = hash_new(128); - tree_t pack = tree_ref(inst); + const int ndecls = tree_decls(generic); + for (int i = 0; i < ndecls; i++) { + tree_t gd = tree_decl(generic, i); + tree_t ad = tree_decl(actual, i); + assert(tree_kind(gd) == tree_kind(ad)); - const int ndecls = tree_decls(pack); - for (int i = 0; i < ndecls; i++) - hash_put(tab->top_scope->gmap, tree_decl(pack, i), tree_decl(inst, i)); + hash_put(tab->top_scope->gmap, gd, ad); - const int ngenerics = tree_generics(pack); + if (is_type_decl(gd)) + hash_put(tab->top_scope->gmap, tree_type(gd), tree_type(ad)); + } + + const int ngenerics = tree_generics(generic); for (int i = 0; i < ngenerics; i++) - hash_put(tab->top_scope->gmap, tree_generic(pack, i), - tree_generic(inst, i)); + hash_put(tab->top_scope->gmap, tree_generic(generic, i), + tree_generic(actual, i)); } hash_t *get_generic_map(nametab_t *tab) @@ -1687,9 +1693,10 @@ void insert_names_from_use(nametab_t *tab, tree_t use) if (tree_kind(unit) == T_GENERIC_DECL) { assert(tree_class(unit) == C_PACKAGE); - if ((unit = lib_get_qualified(type_ident(tree_type(unit)))) == NULL) - return; + tree_t ref = tree_value(unit); + assert(tree_kind(ref) == T_REF); + unit = tree_ref(ref); assert(is_uninstantiated_package(unit)); } diff --git a/src/names.h b/src/names.h index 00e540b5..448cee37 100644 --- a/src/names.h +++ b/src/names.h @@ -71,7 +71,7 @@ tree_t find_enclosing(nametab_t *tab, scope_kind_t kind); void suppress_errors(nametab_t *tab); void map_generic_type(nametab_t *tab, type_t generic, type_t actual); -void map_generic_package(nametab_t *tab, tree_t inst); +void map_generic_package(nametab_t *tab, tree_t generic, tree_t actual); void map_generic_box(nametab_t *tab, tree_t inst, tree_t g, unsigned pos); void map_generic_subprogram(nametab_t *tab, tree_t generic, tree_t actual); hash_t *get_generic_map(nametab_t *tab); diff --git a/src/object.c b/src/object.c index daa6b2d9..2132b661 100644 --- a/src/object.c +++ b/src/object.c @@ -357,7 +357,7 @@ void object_one_time_init(void) // Increment this each time a incompatible change is made to the // on-disk format not expressed in the object items table - const uint32_t format_fudge = 27; + const uint32_t format_fudge = 28; format_digest += format_fudge * UINT32_C(2654435761); diff --git a/src/parse.c b/src/parse.c index ac96aba1..f4849506 100644 --- a/src/parse.c +++ b/src/parse.c @@ -1932,6 +1932,21 @@ static void instantiate_helper(tree_t new, tree_t *pdecl, tree_t *pbody) if (copy_ctx.body != NULL) APUSH(roots, copy_ctx.body); + // If the uninstantiated unit has any package generics then we need + // to copy those too in order to fix up the types + const int ngenerics = tree_generics(*pdecl); + for (int i = 0; i < ngenerics; i++) { + tree_t g = tree_generic(*pdecl, i); + if (tree_class(g) == C_PACKAGE) { + tree_t ref = tree_value(g); + if (tree_has_ref(ref)) { + tree_t pack = tree_ref(ref); + assert(is_uninstantiated_package(pack)); + APUSH(roots, pack); + } + } + } + tree_copy(roots.items, roots.count, instantiate_should_copy_tree, instantiate_should_copy_type, @@ -2065,11 +2080,7 @@ static void instantiate_package(tree_t new, tree_t pack, tree_t body) static type_t rewrite_generic_types_cb(type_t type, void *__ctx) { hash_t *map = __ctx; - - if (type_kind(type) == T_GENERIC) - return hash_get(map, type) ?: type; - else - return type; + return hash_get(map, type) ?: type; } static tree_t rewrite_generic_refs_cb(tree_t t, void *__ctx) @@ -2998,10 +3009,8 @@ static void p_association_element(tree_t map, int pos, tree_t unit, break; } - if (formal != NULL) { + if (formal != NULL && (class = tree_class(formal)) != C_PACKAGE) type = tree_type(formal); - class = tree_class(formal); - } } tree_t value = p_actual_part(class); @@ -4977,7 +4986,7 @@ static void p_interface_subprogram_declaration(tree_t parent, tree_kind_t kind) insert_name(nametab, d, NULL); } -static void p_interface_package_generic_map_aspect(type_t type) +static void p_interface_package_generic_map_aspect(void) { // generic_map_aspect | generic map ( <> ) | generic map ( default ) @@ -5011,12 +5020,24 @@ static void p_interface_package_declaration(tree_t parent, tree_kind_t kind) consume(tIS); consume(tNEW); - type_t type = type_new(T_GENERIC); - type_set_ident(type, p_selected_identifier()); + ident_t unit_name = p_selected_identifier(); + + tree_t pack = find_unit(CURRENT_LOC, unit_name, "package"); + if (pack != NULL && !is_uninstantiated_package(pack)) { + parse_error(CURRENT_LOC, "unit %s is not an uninstantiated package", + istr(unit_name)); + pack = NULL; + } - p_interface_package_generic_map_aspect(type); + tree_t ref = tree_new(T_REF); + tree_set_ident(ref, unit_name); + tree_set_loc(ref, CURRENT_LOC); + tree_set_ref(ref, pack); + + tree_set_value(d, ref); + + p_interface_package_generic_map_aspect(); - tree_set_type(d, type); tree_set_loc(d, CURRENT_LOC); add_interface(parent, d, kind); diff --git a/src/sem.c b/src/sem.c index 512a85f9..4d8df531 100644 --- a/src/sem.c +++ b/src/sem.c @@ -1068,23 +1068,28 @@ static bool sem_check_port_decl(tree_t t, nametab_t *tab) static bool sem_check_generic_decl(tree_t t, nametab_t *tab) { - type_t type = tree_type(t); - - if (!sem_check_subtype(t, type, tab)) - return false; - else if (type_is_none(type)) - return false; - const class_t class = tree_class(t); switch (class) { - case C_CONSTANT: case C_TYPE: case C_FUNCTION: - case C_PROCEDURE: case C_PACKAGE: + case C_CONSTANT: + case C_TYPE: + case C_FUNCTION: + case C_PROCEDURE: break; + + case C_PACKAGE: + return true; // No further checking required default: sem_error(t, "invalid object class %s for generic %s", class_str(tree_class(t)), istr(tree_ident(t))); } + type_t type = tree_type(t); + + if (!sem_check_subtype(t, type, tab)) + return false; + else if (type_is_none(type)) + return false; + if (!sem_no_access_file_or_protected(t, type, "generics")) return false; @@ -1099,14 +1104,6 @@ static bool sem_check_generic_decl(tree_t t, nametab_t *tab) type_pp(type)); } - if (class == C_PACKAGE) { - ident_t name = type_ident(tree_type(t)); - tree_t pack = lib_get_qualified(name); - if (pack == NULL || !is_uninstantiated_package(pack)) - sem_error(t, "name %s does not denote an uninstantiated package", - istr(name)); - } - return true; } @@ -4038,15 +4035,19 @@ static bool sem_check_generic_actual(formal_map_t *formals, int nformals, else if (!tree_has_ref(pack)) return false; // Was parse error + tree_t ref = tree_value(decl); + if (!tree_has_ref(ref)) + return false; // Was earlier error + tree_t base = tree_ref(pack); - ident_t expect = type_ident(tree_type(decl)); + tree_t expect = tree_ref(ref); - if (tree_ident(base) != expect) + if (tree_ident(base) != tree_ident(expect)) sem_error(value, "expected an instance of package %s but have " - "instance of %s for generic %s", istr(expect), + "instance of %s for generic %s", istr(tree_ident(expect)), istr(tree_ident(base)), istr(tree_ident(decl))); - map_generic_package(tab, pack); + map_generic_package(tab, expect, pack); } break; diff --git a/test/sem/genpack.vhd b/test/sem/genpack.vhd index 8bb023de..d37ebef1 100644 --- a/test/sem/genpack.vhd +++ b/test/sem/genpack.vhd @@ -94,7 +94,7 @@ architecture test2 of ent is generic map ( fixed_pkg => std.standard ); -- Error package p4 is new work.bad - generic map ( bad_std => work.myfixed_4_8 ); -- Error + generic map ( bad_std => work.myfixed_4_8 ); -- Error (suppressed) begin end architecture; diff --git a/test/sem/genpack2.vhd b/test/sem/genpack2.vhd new file mode 100644 index 00000000..5a4a041d --- /dev/null +++ b/test/sem/genpack2.vhd @@ -0,0 +1,83 @@ +package fixed_generic_pkg is + generic (g : integer); + + type UNRESOLVED_ufixed is array (INTEGER range <>) of bit; + + subtype ufixed is UNRESOLVED_ufixed; + + function to_ufixed ( + arg : NATURAL) + return UNRESOLVED_ufixed; + +end package; + +package body fixed_generic_pkg is + + function to_ufixed ( + arg : NATURAL) + return UNRESOLVED_ufixed is + begin + return (1 to 1 => '0'); + end function; +end package body; + +------------------------------------------------------------------------------- + +package fixed_pkg is new work.fixed_generic_pkg generic map (4); + +------------------------------------------------------------------------------- + +package float_generic_pkg is + generic ( + package fixed_pkg is new work.fixed_generic_pkg + generic map (<>) ); + + use fixed_pkg.all; + + type UNRESOLVED_float is array (INTEGER range <>) of bit; + + subtype float is UNRESOLVED_float; + + subtype UNRESOLVED_float32 is UNRESOLVED_float (8 downto -23); + alias U_float32 is UNRESOLVED_float32; + subtype float32 is float (8 downto -23); + + function to_ufixed ( + arg : UNRESOLVED_float) + return UNRESOLVED_ufixed; +end package; + +package body float_generic_pkg is + function to_ufixed ( + arg : UNRESOLVED_float) + return UNRESOLVED_ufixed is + begin + return (1 to 1 => '0'); + end function; +end package body; + +------------------------------------------------------------------------------- + +package float_pkg is new work.float_generic_pkg generic map (work.fixed_pkg); + +------------------------------------------------------------------------------- + +entity genpack13 is +end entity; + +use work.fixed_pkg.all; +use work.float_pkg.all; + +architecture test of genpack13 is +begin + + main: process is + subtype ufixed7 is ufixed (3 downto -3); -- 7 bit + variable checknum : float32; + variable check7uf1, check7uf : ufixed7; + begin + check7uf1 := to_ufixed (checknum); + wait; + end process; + +end architecture; diff --git a/test/test_sem.c b/test/test_sem.c index 9b15b121..fe721ec1 100644 --- a/test/test_sem.c +++ b/test/test_sem.c @@ -2567,12 +2567,11 @@ START_TEST(test_genpack) { 46, "unit STD.STANDARD is not an uninstantiated package" }, { 47, "missing declaration for package WORK.NOT_HERE" }, { 48, "missing actual for generic FRAC without a default expression" }, - { 77, "name STD.STANDARD does not denote an uninstantiated package" }, + { 77, "unit STD.STANDARD is not an uninstantiated package" }, { 82, "actual for generic FIXED_PKG is not an instantiated package " }, { 91, "expected an instance of package WORK.MYFIXED but have instance " "of WORK.MYFLOAT for generic FIXED_PKG" }, { 94, "actual for generic FIXED_PKG is not an instantiated package" }, - { 97, "expected an instance of package STD.STANDARD but" }, { -1, NULL } }; expect_errors(expect); @@ -2912,6 +2911,19 @@ START_TEST(test_issue509) } END_TEST +START_TEST(test_genpack2) +{ + set_standard(STD_08); + + input_from_file(TESTDIR "/sem/genpack2.vhd"); + + parse_and_check(T_PACKAGE, T_PACK_BODY, T_PACK_INST, T_PACKAGE, T_PACK_BODY, + T_PACK_INST, T_ENTITY, T_ARCH); + + fail_if_errors(); +} +END_TEST + Suite *get_sem_tests(void) { Suite *s = suite_create("sem"); @@ -3051,6 +3063,7 @@ Suite *get_sem_tests(void) tcase_add_test(tc_core, test_vhdl2019); tcase_add_test(tc_core, test_altera1); tcase_add_test(tc_core, test_issue509); + tcase_add_test(tc_core, test_genpack2); suite_add_tcase(s, tc_core); return s; -- 2.39.2