diff --git a/src/dump.c b/src/dump.c index e9d830f7a..a2f666057 100644 --- a/src/dump.c +++ b/src/dump.c @@ -569,7 +569,8 @@ static void dump_binding(tree_t t, int indent) print_syntax("#use %s", istr(tree_ident(t))); if (tree_has_ident2(t)) print_syntax("(%s)", istr(tree_ident2(t))); - print_syntax("\n"); + if (tree_genmaps(t) > 0 || tree_params(t) > 0) + print_syntax("\n"); dump_generic_map(t, indent + 2, tree_params(t) > 0 ? "\n" : ""); dump_port_map(t, indent + 2, ""); print_syntax(";\n"); diff --git a/src/sem.c b/src/sem.c index c5f0eb30c..2a3998c5f 100644 --- a/src/sem.c +++ b/src/sem.c @@ -5525,20 +5525,157 @@ static bool sem_check_binding(tree_t t, nametab_t *tab) static bool sem_check_block_config(tree_t t, nametab_t *tab) { - bool ok = true; - const int ndecls = tree_decls(t); - for (int i = 0; i < ndecls; i++) - ok &= sem_check(tree_decl(t, i), tab); - - return ok; + return true; } static bool sem_check_spec(tree_t t, nametab_t *tab) { - if (tree_has_value(t)) - return sem_check(tree_value(t), tab); - else + if (!tree_has_ref(t)) + return false; + + tree_t comp = tree_ref(t); + assert(tree_kind(comp) == T_COMPONENT); + + if (!tree_has_value(t)) return true; + + tree_t bind = tree_value(t); + assert(tree_kind(bind) == T_BINDING); + + if (!sem_check(bind, tab)) + return false; + + tree_t entity = primary_unit_of(tree_ref(bind)); + 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); + + for (int i = 0; i < c_ngenerics; i++) { + tree_t cg = tree_generic(comp, i); + + 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; + } + + if (rebind != NULL) + continue; // Ignore for now + + 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) { + if (!tree_has_value(cg)) { + 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", + 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; + } + + 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); + + ok = false; + continue; + } + } + + const int c_nports = tree_ports(comp); + const int e_nports = tree_ports(entity); + const int b_nparams = tree_params(bind); + + for (int i = 0; i < c_nports; i++) { + tree_t cp = tree_port(comp, i); + + 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; + } + + if (rebind != NULL) + continue; // Ignore for now + + 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) { + const bool open_ok = + tree_has_value(cp) + || (tree_subkind(cp) == PORT_OUT + && !type_is_unconstrained(tree_type(cp))); + + if (!open_ok) { + 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", + 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); + } + + ok = false; + continue; + } + + 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); + + ok = false; + continue; + } + } + + return ok; } static bool sem_check_configuration(tree_t t, nametab_t *tab) diff --git a/test/sem/config2.vhd b/test/sem/config2.vhd new file mode 100644 index 000000000..98d70ffb6 --- /dev/null +++ b/test/sem/config2.vhd @@ -0,0 +1,62 @@ +entity sub is + generic ( g : integer; g2 : bit ); + port ( i : in bit_vector; + o : out bit_vector ); +end entity; + +architecture test of sub is +begin +end architecture; + +------------------------------------------------------------------------------- + +entity other is + generic ( gg : integer; g2 : real ); + port ( ii : in bit_vector; + oo : out bit_vector; + zz : out integer ); +end entity; + +architecture test of other is +begin +end architecture; + +------------------------------------------------------------------------------- + +entity top is +end entity; + +architecture test of top is + component comp is + generic ( g : integer; g2 : bit ); + port ( i : in bit_vector; + o : out bit_vector; + k : out bit; + zz : out real ); + end component; + + signal x, y : bit_vector(3 downto 0); +begin + + u1: component comp -- Error + generic map (5, '1') + port map (x, y); + + u2: component comp -- OK + generic map (5, '1') + port map (x, y); + +end architecture; + +------------------------------------------------------------------------------- + +configuration conf of top is + for test + for u1 : comp + use entity work.other(test); + end for; + for u2 : comp + use entity work.sub(test); + end for; + end for; +end configuration; diff --git a/test/test_sem.c b/test/test_sem.c index 822439ab2..a148c7604 100644 --- a/test/test_sem.c +++ b/test/test_sem.c @@ -3202,6 +3202,32 @@ START_TEST(test_lcs2016_23) } END_TEST +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 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, "port ZZ in component COMP has type REAL which is incompatible " + "with type INTEGER in entity WORK.OTHER" }, + { -1, NULL } + }; + expect_errors(expect); + + parse_and_check(T_ENTITY, T_ARCH, T_ENTITY, T_ARCH, T_ENTITY, + T_ARCH, T_CONFIGURATION); + + check_expected_errors(); +} +END_TEST + Suite *get_sem_tests(void) { Suite *s = suite_create("sem"); @@ -3357,6 +3383,7 @@ Suite *get_sem_tests(void) tcase_add_test(tc_core, test_lcs2016_19); tcase_add_test(tc_core, test_lcs2016_07); tcase_add_loop_test(tc_core, test_lcs2016_23, STD_08, STD_19 + 1); + tcase_add_test(tc_core, test_config2); suite_add_tcase(s, tc_core); return s;