Skip to content

Commit

Permalink
Fix crash with missing choices in aggregate. (#1104)
Browse files Browse the repository at this point in the history
  • Loading branch information
NikLeberg authored Dec 17, 2024
1 parent f18aed1 commit 78772e8
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 0 deletions.
59 changes: 59 additions & 0 deletions src/eval.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
17 changes: 17 additions & 0 deletions test/bounds/issue1091.vhd
Original file line number Diff line number Diff line change
@@ -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;
22 changes: 22 additions & 0 deletions test/test_bounds.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 78772e8

Please sign in to comment.