From 78772e8248a599db238cbcd96a7b0a2541b13709 Mon Sep 17 00:00:00 2001 From: NikLeberg <39563554+NikLeberg@users.noreply.github.com> Date: Mon, 16 Dec 2024 22:48:29 -1000 Subject: [PATCH] Fix crash with missing choices in aggregate. (#1104) --- src/eval.c | 59 +++++++++++++++++++++++++++++++++++++++ test/bounds/issue1091.vhd | 17 +++++++++++ test/test_bounds.c | 22 +++++++++++++++ 3 files changed, 98 insertions(+) create mode 100644 test/bounds/issue1091.vhd diff --git a/src/eval.c b/src/eval.c index f8e2d3be0..fd200f10d 100644 --- a/src/eval.c +++ b/src/eval.c @@ -364,6 +364,65 @@ bool eval_possible(tree_t t, unit_registry_t *ur) return false; } + // Check for missing choices in constrained array aggregates + type_t composite_type = tree_type(t); + if (type_is_array(composite_type) + && !type_is_unconstrained(composite_type)) { + int64_t count = 0, elem_count = 0; + bool known_elem_count = false; + bool has_others = false; + bool has_range = false; + for (int i = 0; i < nassocs; i++) { + tree_t a = tree_assoc(t, i); + const assoc_kind_t akind = tree_subkind(a); + + switch (akind) { + + case A_NAMED: + case A_POS: + known_elem_count = true; + elem_count = 1; + break; + + case A_RANGE: + known_elem_count = false; + has_range = true; + break; + + case A_OTHERS: + known_elem_count = false; + has_others = true; + break; + + case A_SLICE: + case A_CONCAT: + { + type_t v_type = tree_type(tree_value(a)); + known_elem_count = true; + if (type_is_unconstrained(v_type)) + known_elem_count = false; + else if (!folded_length(range_of(v_type, 0), &elem_count)) + known_elem_count = false; + break; + } + } + + if (known_elem_count) + count += elem_count; + } + + if (has_range) + // Range could overlap, defer to bounds check + return eval_not_possible(t, "range as choice"); + + if (!has_others) { + int64_t type_count; + if (folded_length(range_of(composite_type, 0), &type_count)) + if (count != type_count) + return eval_not_possible(t, "missing choice"); + } + } + return true; } diff --git a/test/bounds/issue1091.vhd b/test/bounds/issue1091.vhd new file mode 100644 index 000000000..3f5e80be9 --- /dev/null +++ b/test/bounds/issue1091.vhd @@ -0,0 +1,17 @@ +package pkg is + type vec is array(0 to 3) of integer; +end pkg; + +use work.pkg.all; + +entity ent is + port ( + p0 : boolean := vec'(0=>0, 1=>0) = vec'(3=>0); + p1 : boolean := vec'(0=>0, 1=>1, 1 to 2=>1) = vec'(others=>0); + p2 : boolean := vec'(0=>0, 1=>1, 2 to 3=>1) = vec'(others=>0) + ); +end ent; + +architecture arch of ent is +begin +end architecture arch; diff --git a/test/test_bounds.c b/test/test_bounds.c index 06feb2a8c..77f4c81f4 100644 --- a/test/test_bounds.c +++ b/test/test_bounds.c @@ -860,6 +860,27 @@ START_TEST(test_issue1021) } END_TEST +START_TEST(test_issue1091) +{ + input_from_file(TESTDIR "/bounds/issue1091.vhd"); + + const error_t expect[] = { + { 9, "missing choices for elements 2 to 3 of VEC" }, + { 9, "missing choices for elements 0 to 2 of VEC" }, + { 10, "value 1 is already covered" }, + { 10, "missing choice for element 3 of VEC" }, + { -1, NULL } + }; + expect_errors(expect); + + parse_check_and_simplify(T_PACKAGE, T_ENTITY, T_ARCH); + + fail_unless(parse() == NULL); + + check_expected_errors(); +} +END_TEST + Suite *get_bounds_tests(void) { Suite *s = suite_create("bounds"); @@ -905,6 +926,7 @@ Suite *get_bounds_tests(void) tcase_add_test(tc_core, test_issue975); tcase_add_test(tc_core, test_issue1040); tcase_add_test(tc_core, test_issue1021); + tcase_add_test(tc_core, test_issue1091); suite_add_tcase(s, tc_core); return s;