From 997cbfce5b3d955ec49883fbc41b0049d61ac333 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sun, 28 Jan 2024 21:04:01 +0000 Subject: [PATCH] Improve checking for configuration specification --- src/sem.c | 244 +++++++++++++++++++------------ test/parse/spec.vhd | 4 +- test/parse/vests1.vhd | 2 +- test/sem/config2.vhd | 4 +- test/sem/{spec.vhd => spec1.vhd} | 0 test/sem/spec2.vhd | 92 ++++++++++++ test/test_sem.c | 49 +++++-- 7 files changed, 287 insertions(+), 108 deletions(-) rename test/sem/{spec.vhd => spec1.vhd} (100%) create mode 100644 test/sem/spec2.vhd diff --git a/src/sem.c b/src/sem.c index 29e49dde..a08e9269 100644 --- a/src/sem.c +++ b/src/sem.c @@ -4864,9 +4864,6 @@ static bool sem_check_generic_map(tree_t t, tree_t unit, nametab_t *tab) break; // Prevent useless repeated errors } - if (tree_kind(t) == T_BINDING) - return ok; - for (int i = 0; i < nformals; i++) { if (formals[i].have) continue; @@ -5979,10 +5976,10 @@ static bool sem_check_binding(tree_t t, nametab_t *tab) tree_t unit = primary_unit_of(tree_ref(t)); if (tree_kind(unit) == T_ENTITY) { - if (!sem_check_generic_map(t, unit, tab)) + if (tree_genmaps(t) > 0 && !sem_check_generic_map(t, unit, tab)) return false; - if (!sem_check_port_map(t, unit, tab)) + if (tree_params(t) > 0 && !sem_check_port_map(t, unit, tab)) return false; } @@ -6011,133 +6008,192 @@ static bool sem_check_spec(tree_t t, nametab_t *tab) if (!sem_check(bind, tab)) return false; - tree_t entity = primary_unit_of(tree_ref(bind)); + tree_t unit = tree_ref(bind); + if (tree_kind(unit) == T_CONFIGURATION) + return true; + + tree_t entity = primary_unit_of(unit); assert(tree_kind(entity) == T_ENTITY); bool ok = true; - const int c_ngenerics = tree_generics(comp); - const int e_ngenerics = tree_generics(entity); - const int b_genmaps = tree_genmaps(bind); + if (tree_genmaps(bind) == 0) { + const int c_ngenerics = tree_generics(comp); + const int e_ngenerics = tree_generics(entity); - for (int i = 0; i < c_ngenerics; i++) { - tree_t cg = tree_generic(comp, i); + bit_mask_t have; + mask_init(&have, e_ngenerics); - tree_t rebind = NULL; - for (int j = 0; rebind == NULL && j < b_genmaps; j++) { - tree_t value = tree_value(tree_genmap(bind, j)); - if (tree_kind(value) == T_REF && tree_ref(value) == cg) - rebind = value; - } + bool have_named = false; + for (int i = 0; i < c_ngenerics; i++) { + tree_t cg = tree_generic(comp, i); - if (rebind != NULL) - continue; // Ignore for now + int epos = 0; + tree_t match = NULL; + for (; epos < e_ngenerics; epos++) { + tree_t eg = tree_generic(entity, epos); + if (tree_ident(eg) == tree_ident(cg)) { + match = eg; + mask_set(&have, epos); + break; + } + } - tree_t match = NULL; - for (int j = 0; match == NULL && j < e_ngenerics; j++) { - tree_t eg = tree_generic(entity, j); - if (tree_ident(eg) == tree_ident(cg)) - match = eg; - } + if (match == NULL) { + diag_t *d = diag_new(DIAG_ERROR, tree_loc(t)); + diag_printf(d, "generic %s in component %s has no corresponding " + "generic in entity %s", istr(tree_ident(cg)), + istr(tree_ident(comp)), istr(tree_ident(entity))); + diag_hint(d, tree_loc(cg), "generic %s declared here", + istr(tree_ident(cg))); + diag_emit(d); + + ok = false; + continue; + } - if (match == NULL) { - if (!tree_has_value(cg)) { + type_t ctype = tree_type(cg); + type_t etype = tree_type(match); + if (!type_eq(ctype, etype)) { diag_t *d = diag_new(DIAG_ERROR, tree_loc(t)); - diag_printf(d, "generic %s in component %s without a default value " - "has no corresponding generic in entity %s", + diag_printf(d, "generic %s in component %s has type %s which is " + "incompatible with type %s in entity %s", istr(tree_ident(cg)), istr(tree_ident(comp)), + type_pp2(ctype, etype), type_pp2(etype, ctype), istr(tree_ident(entity))); - diag_hint(d, tree_loc(cg), "generic %s declared here", + diag_hint(d, tree_loc(cg), "declaration of generic %s in component", istr(tree_ident(cg))); + diag_hint(d, tree_loc(match), "declaration of generic %s in entity", + istr(tree_ident(match))); diag_emit(d); + + ok = false; + continue; } - ok = false; - continue; + tree_t map = tree_new(T_PARAM); + tree_set_loc(map, tree_loc(t)); + tree_set_value(map, make_ref(cg)); + + if (!have_named && epos == i) { + tree_set_subkind(map, P_POS); + tree_set_pos(map, epos); + } + else { + tree_set_subkind(map, P_NAMED); + tree_set_name(map, make_ref(match)); + have_named = true; + } + + tree_add_genmap(bind, map); } - type_t ctype = tree_type(cg); - type_t etype = tree_type(match); - if (!type_eq(ctype, etype)) { - diag_t *d = diag_new(DIAG_ERROR, tree_loc(t)); - diag_printf(d, "generic %s in component %s has type %s which is " - "incompatible with type %s in entity %s", - istr(tree_ident(cg)), istr(tree_ident(comp)), - type_pp2(ctype, etype), type_pp2(etype, ctype), - istr(tree_ident(entity))); - diag_hint(d, tree_loc(cg), "declaration of generic %s in component", - istr(tree_ident(cg))); - diag_hint(d, tree_loc(match), "declaration of generic %s in entity", - istr(tree_ident(match))); - diag_emit(d); + for (int i = 0; i < e_ngenerics; i++) { + tree_t eg = tree_generic(entity, i); + if (!mask_test(&have, i) && !tree_has_value(eg)) { + diag_t *d = diag_new(DIAG_ERROR, tree_loc(t)); + diag_printf(d, "generic %s in entity %s without a default value " + "has no corresponding generic in component %s", + istr(tree_ident(eg)), istr(tree_ident(entity)), + istr(tree_ident(comp))); + diag_hint(d, tree_loc(eg), "generic %s declared here", + istr(tree_ident(eg))); + diag_emit(d); - ok = false; - continue; + ok = false; + continue; + } } + + mask_free(&have); } - const int c_nports = tree_ports(comp); - const int e_nports = tree_ports(entity); - const int b_nparams = tree_params(bind); + if (tree_params(bind) == 0) { + const int c_nports = tree_ports(comp); + const int e_nports = tree_ports(entity); - for (int i = 0; i < c_nports; i++) { - tree_t cp = tree_port(comp, i); + bit_mask_t have; + mask_init(&have, e_nports); - tree_t rebind = NULL; - for (int j = 0; rebind == NULL && j < b_nparams; j++) { - tree_t value = tree_value(tree_param(bind, j)); - if (tree_kind(value) == T_REF && tree_ref(value) == cp) - rebind = value; - } + bool have_named = false; + for (int i = 0; i < c_nports; i++) { + tree_t cp = tree_port(comp, i); - if (rebind != NULL) - continue; // Ignore for now + int epos = 0; + tree_t match = NULL; + for (; match == NULL && epos < e_nports; epos++) { + tree_t ep = tree_port(entity, epos); + if (tree_ident(ep) == tree_ident(cp)) { + match = ep; + mask_set(&have, epos); + break; + } + } - tree_t match = NULL; - for (int j = 0; match == NULL && j < e_nports; j++) { - tree_t ep = tree_port(entity, j); - if (tree_ident(ep) == tree_ident(cp)) - match = ep; - } + if (match == NULL) { + diag_t *d = diag_new(DIAG_ERROR, tree_loc(t)); + diag_printf(d, "port %s in component %s has no corresponding port " + "in entity %s", istr(tree_ident(cp)), + istr(tree_ident(comp)), istr(tree_ident(entity))); + diag_hint(d, tree_loc(cp), "port %s declared here", + istr(tree_ident(cp))); + diag_emit(d); - if (match == NULL) { - const bool open_ok = - tree_has_value(cp) - || (tree_subkind(cp) == PORT_OUT - && !type_is_unconstrained(tree_type(cp))); + ok = false; + continue; + } - if (!open_ok) { + type_t ctype = tree_type(cp); + type_t etype = tree_type(match); + if (!type_eq(ctype, etype)) { diag_t *d = diag_new(DIAG_ERROR, tree_loc(t)); - diag_printf(d, "port %s in component %s without a default value " - "has no corresponding port in entity %s", + diag_printf(d, "port %s in component %s has type %s which is " + "incompatible with type %s in entity %s", istr(tree_ident(cp)), istr(tree_ident(comp)), + type_pp2(ctype, etype), type_pp2(etype, ctype), istr(tree_ident(entity))); - diag_hint(d, tree_loc(cp), "port %s declared here", + diag_hint(d, tree_loc(cp), "declaration of port %s in component", istr(tree_ident(cp))); + diag_hint(d, tree_loc(match), "declaration of port %s in entity", + istr(tree_ident(match))); diag_emit(d); + + ok = false; + continue; } - ok = false; - continue; + if (!have_named && epos == i) + add_param(bind, make_ref(cp), P_POS, NULL); + else { + add_param(bind, make_ref(cp), P_NAMED, make_ref(match)); + have_named = true; + } } - type_t ctype = tree_type(cp); - type_t etype = tree_type(match); - if (!type_eq(ctype, etype)) { - diag_t *d = diag_new(DIAG_ERROR, tree_loc(t)); - diag_printf(d, "port %s in component %s has type %s which is " - "incompatible with type %s in entity %s", - istr(tree_ident(cp)), istr(tree_ident(comp)), - type_pp2(ctype, etype), type_pp2(etype, ctype), - istr(tree_ident(entity))); - diag_hint(d, tree_loc(cp), "declaration of port %s in component", - istr(tree_ident(cp))); - diag_hint(d, tree_loc(match), "declaration of port %s in entity", - istr(tree_ident(match))); - diag_emit(d); + for (int i = 0; i < e_nports; i++) { + if (mask_test(&have, i)) + continue; - ok = false; - continue; + tree_t ep = tree_port(entity, i); + + const bool open_ok = + tree_has_value(ep) + || (tree_subkind(ep) == PORT_OUT + && !type_is_unconstrained(tree_type(ep))); + + if (!open_ok) { + diag_t *d = diag_new(DIAG_ERROR, tree_loc(t)); + diag_printf(d, "port %s in entity %s without a default value " + "has no corresponding port in component %s", + istr(tree_ident(ep)), istr(tree_ident(entity)), + istr(tree_ident(comp))); + diag_hint(d, tree_loc(ep), "port %s declared here", + istr(tree_ident(ep))); + diag_emit(d); + + ok = false; + continue; + } } } diff --git a/test/parse/spec.vhd b/test/parse/spec.vhd index 04127586..14cfcc22 100644 --- a/test/parse/spec.vhd +++ b/test/parse/spec.vhd @@ -1,8 +1,8 @@ entity b is end entity; entity foo is - generic ( a : integer ); - port ( b : in integer ); + generic ( a : integer := 2 ); + port ( b : in integer := 5 ); end entity; architecture arch of foo is diff --git a/test/parse/vests1.vhd b/test/parse/vests1.vhd index 2224e3ad..a4e77a08 100644 --- a/test/parse/vests1.vhd +++ b/test/parse/vests1.vhd @@ -33,7 +33,7 @@ begin sigout7 : out time ; sigin8 : in natural := 0 ; sigout8 : out natural ; - sigin9 : in positive := 0 ; + sigin9 : in positive := 1 ; sigout9 : out positive ); end component; diff --git a/test/sem/config2.vhd b/test/sem/config2.vhd index 98d70ffb..063e4ba0 100644 --- a/test/sem/config2.vhd +++ b/test/sem/config2.vhd @@ -44,7 +44,7 @@ begin u2: component comp -- OK generic map (5, '1') - port map (x, y); + port map (y, x); end architecture; @@ -53,7 +53,7 @@ end architecture; configuration conf of top is for test for u1 : comp - use entity work.other(test); + use entity work.other(test); -- Error end for; for u2 : comp use entity work.sub(test); diff --git a/test/sem/spec.vhd b/test/sem/spec1.vhd similarity index 100% rename from test/sem/spec.vhd rename to test/sem/spec1.vhd diff --git a/test/sem/spec2.vhd b/test/sem/spec2.vhd new file mode 100644 index 00000000..9105df9e --- /dev/null +++ b/test/sem/spec2.vhd @@ -0,0 +1,92 @@ +entity ent1 is + generic ( g1 : integer; g2 : boolean := true ); + port ( p1 : in bit; + p2 : out bit; + p3 : in integer := 0 ); +end entity; + +architecture dummy of ent1 is +begin + +end architecture; + +configuration ent1cfg of ent1 is + for dummy + end for; +end configuration; + +------------------------------------------------------------------------------- + +entity test is +end entity; + +architecture test of test is + component comp1 is + port ( p1 : in bit; + p2 : out bit; + p3 : in integer := 0 ); + end component; + + for u1 : comp1 use entity work.ent1 -- OK + generic map ( g1 => 5 ); + + for u2 : comp1 use entity work.ent1; -- Error + + component comp2 is + generic ( g3 : integer ); + port ( p4 : out bit ); + end component; + + for u3 : comp2 use entity work.ent1 -- OK + generic map ( g1 => g3 ) + port map ( p1 => '0', p2 => p4 ); + + for u4 : comp2 use entity work.ent1 -- Error + port map ( p1 => '0', p2 => p4 ); + + component comp3 is + generic ( g2 : boolean := true; g1 : integer ); + port ( p2 : out bit; + p1 : in bit; + p3 : in integer := 0 ); + end component; + + for u5 : comp3 use entity work.ent1; -- OK + + for u6 : comp3 use configuration work.ent1cfg; -- OK + + for u7 : comp3 use configuration work.ent1cfg + generic map ( g1 => 5 ); -- OK (?) +begin + + u1: component comp1 + port map ( '1', open ); + + u2: component comp1 + port map ( '1', open ); + + u3: component comp2 + generic map ( g3 => 5 ) + port map ( open ); + + u4: component comp2 + generic map ( g3 => 5 ) + port map ( open ); + + u5: component comp3 + generic map ( g1 => 2 ) + port map ( open, '1' ); + + u6: component comp3 + generic map ( g1 => 2 ) + port map ( open, '1' ); + + u7: component comp3 + generic map ( g1 => 2 ) + port map ( open, '1' ); + + u8: component comp3 + generic map ( g1 => 2 ) + port map ( open, '1' ); + +end architecture; diff --git a/test/test_sem.c b/test/test_sem.c index 83f23893..d5cfd7dc 100644 --- a/test/test_sem.c +++ b/test/test_sem.c @@ -1046,9 +1046,9 @@ START_TEST(test_issue58) } END_TEST -START_TEST(test_spec) +START_TEST(test_spec1) { - input_from_file(TESTDIR "/sem/spec.vhd"); + input_from_file(TESTDIR "/sem/spec1.vhd"); const error_t expect[] = { { 24, "E does not name a component" }, @@ -3253,16 +3253,25 @@ START_TEST(test_config2) input_from_file(TESTDIR "/sem/config2.vhd"); const error_t expect[] = { - { 55, "generic G in component COMP without a default value has no " - "corresponding generic in entity WORK.OTHER" }, + { 55, "generic G in component COMP has no corresponding generic in " + "entity WORK.OTHER" }, { 55, "generic G2 in component COMP has type BIT which is incompatible " "with type REAL in entity WORK.OTHER" }, - { 55, "port I in component COMP without a default value has no " - "corresponding port in entity WORK.OTHER" }, - { 55, "port O in component COMP without a default value has no " - "corresponding port in entity WORK.OTHER" }, + { 55, "generic GG in entity WORK.OTHER without a default value has no " + "corresponding generic in component COMP" }, + { 55, "port I in component COMP has no corresponding port in entity " + "WORK.OTHER" }, + { 55, "port O in component COMP has no corresponding port in entity " }, + { 55, "port K in component COMP has no corresponding port in entity " }, { 55, "port ZZ in component COMP has type REAL which is incompatible " "with type INTEGER in entity WORK.OTHER" }, + { 55, "port II in entity WORK.OTHER without a default value has no " + "corresponding port in component COMP" }, + { 55, "port OO in entity WORK.OTHER without a default value has no " + "corresponding port in component COMP" }, + { 58, "port K in component COMP has no corresponding port in entity " + "WORK.SUB" }, + { 58, "port ZZ in component COMP has no corresponding port in entity " }, { -1, NULL } }; expect_errors(expect); @@ -3483,6 +3492,27 @@ START_TEST(test_lcs2016_16) } END_TEST +START_TEST(test_spec2) +{ + input_from_file(TESTDIR "/sem/spec2.vhd"); + + const error_t expect[] = { + { 33, "generic G1 in entity WORK.ENT1 without a default value has no " + "corresponding generic in component COMP1" }, + { 44, "generic G3 in component COMP2 has no corresponding generic in " + "entity WORK.ENT1" }, + { 44, "generic G1 in entity WORK.ENT1 without a default value has no " + "corresponding generic in component COMP2" }, + { -1, NULL } + }; + expect_errors(expect); + + parse_and_check(T_ENTITY, T_ARCH, T_CONFIGURATION, T_ENTITY, T_ARCH); + + check_expected_errors(); +} +END_TEST + Suite *get_sem_tests(void) { Suite *s = suite_create("sem"); @@ -3518,7 +3548,7 @@ Suite *get_sem_tests(void) tcase_add_test(tc_core, test_universal); tcase_add_test(tc_core, test_issue52); tcase_add_test(tc_core, test_issue58); - tcase_add_test(tc_core, test_spec); + tcase_add_test(tc_core, test_spec1); tcase_add_test(tc_core, test_issue53); tcase_add_test(tc_core, test_supersede); tcase_add_test(tc_core, test_implicit); @@ -3647,6 +3677,7 @@ Suite *get_sem_tests(void) tcase_add_test(tc_core, test_issue770); tcase_add_test(tc_core, test_genpack4); tcase_add_test(tc_core, test_lcs2016_16); + tcase_add_test(tc_core, test_spec2); suite_add_tcase(s, tc_core); return s; -- 2.39.2