Skip to content

Commit 2a10285

Browse files
committed
Verilog: enum constants may depend on elaboration-time constants
This postpones the conversion of enum base types and enum initializers to enable them to depend on other elaboration-time constants.
1 parent 3a3cb95 commit 2a10285

11 files changed

+77
-31
lines changed

regression/verilog/enums/enum1.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@ enum1.sv
33
--bound 3
44
^EXIT=10$
55
^SIGNAL=0$
6-
^\[main\.property\.p1\] always main\.my_light != 0 \+ 1 \+ 1 \+ 1: REFUTED$
6+
^\[main\.property\.p1\] always main\.my_light != 3: REFUTED$
77
--

regression/verilog/enums/enum2.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
CORE
22
enum2.sv
33

4-
^file .* line 4: assignment to enum requires enum of the same type$
4+
^file .* line 4: assignment to enum requires enum of the same type, but got signed \[0:31\]$
55
^EXIT=2$
66
^SIGNAL=0$
77
--
Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
KNOWNBUG
1+
CORE
22
enum_base_type2.sv
33
--bound 0
44
^EXIT=0$
55
^SIGNAL=0$
66
^\[.*\] always 8 == 8: PROVED up to bound 0$
77
--
8-
--
9-
The base type of an enum may depend on an elaboration-time constant.

regression/verilog/enums/enum_initializers1.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ CORE
22
enum_initializers1.sv
33
--bound 0
44
^\[main\.property\.pA\] always 1 == 1: PROVED up to bound 0$
5-
^\[main\.property\.pB\] always 1 \+ 10 == 11: PROVED up to bound 0$
5+
^\[main\.property\.pB\] always 11 == 11: PROVED up to bound 0$
66
^EXIT=0$
77
^SIGNAL=0$
88
--
Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
1-
KNOWNBUG
1+
CORE
22
enum_initializers2.sv
33

4-
^EXIT=10$
4+
^EXIT=0$
55
^SIGNAL=0$
66
--
7-
--
8-
Crashes with missing identifier
9-

regression/verilog/enums/enum_initializers2.sv

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ module main;
22

33
parameter B = A + 1;
44

5-
enum { A = 1, C = my_parameter + 1 } my_enum;
5+
enum { A = 1, C = B + 1 } my_enum;
66

77
// expected to pass
88
pA: assert property (A == 1);
99
pB: assert property (B == 2);
10-
pC: assert property (B == 3);
10+
pC: assert property (C == 3);
1111

1212
endmodule
Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
KNOWNBUG
1+
CORE
22
enum_initializers3.sv
33

4-
^EXIT=10$
4+
^file .* line 4: cyclic dependency when elaborating main\.B$
5+
^EXIT=2$
56
^SIGNAL=0$
67
--
7-
--
8-
Cycle not detected.

src/verilog/verilog_elaborate.cpp

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -102,37 +102,37 @@ void verilog_typecheckt::collect_symbols(const typet &type)
102102
if(enum_type.has_base_type())
103103
collect_symbols(enum_type.base_type());
104104

105-
// convert the type now
106-
auto converted_type = convert_type(enum_type);
105+
// The type needs to be converted later, as it may
106+
// depend on other elaboration-time constants.
107+
auto tbd_type = to_be_elaborated_typet(enum_type);
107108

108109
// Add the enum names to the symbol table for subsequent elaboration.
109110
// Values are given, or the previous plus one, starting with value '0'.
110111
exprt initializer = from_integer(0, integer_typet());
111112

112113
for(auto &enum_name : enum_type.enum_names())
113114
{
115+
// The initializer will also be converted later.
114116
if(enum_name.value().is_not_nil())
115-
{
116-
exprt tmp = enum_name.value();
117-
convert_expr(tmp);
118-
initializer = std::move(tmp);
119-
}
117+
initializer = enum_name.value();
120118

121-
exprt value = typecast_exprt(initializer, converted_type);
119+
exprt value = typecast_exprt(initializer, tbd_type);
120+
value.add_source_location() = enum_name.source_location();
122121

123122
const auto base_name = enum_name.base_name();
124123
const auto identifier = hierarchical_identifier(base_name);
125-
symbolt enum_name_symbol(identifier, converted_type, mode);
124+
symbolt enum_name_symbol(identifier, tbd_type, mode);
126125
enum_name_symbol.module = module_identifier;
127126
enum_name_symbol.base_name = base_name;
128127
enum_name_symbol.value = std::move(value);
129128
enum_name_symbol.is_macro = true;
130129
enum_name_symbol.is_file_local = true;
130+
enum_name_symbol.location = enum_name.source_location();
131131
add_symbol(std::move(enum_name_symbol));
132132

133133
initializer = plus_exprt(
134-
typecast_exprt(initializer, converted_type),
135-
typecast_exprt(from_integer(1, integer_typet()), converted_type));
134+
typecast_exprt(initializer, tbd_type),
135+
typecast_exprt(from_integer(1, integer_typet()), tbd_type));
136136
}
137137
}
138138
}
@@ -831,8 +831,10 @@ void verilog_typecheckt::elaborate_symbol_rec(irep_idt identifier)
831831
// Now elaborate the value, possibly recursively, if any.
832832
if(symbol.value.is_not_nil())
833833
{
834+
auto location = symbol.value.source_location();
834835
convert_expr(symbol.value);
835836
symbol.value = elaborate_constant_expression(symbol.value);
837+
symbol.value.add_source_location() = location;
836838

837839
// Cast to the given type.
838840
propagate_type(symbol.value, symbol.type);

src/verilog/verilog_typecheck_expr.cpp

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,8 @@ void verilog_typecheck_exprt::propagate_type(
105105
expr.type().get(ID_C_identifier) != type.get(ID_C_identifier))
106106
{
107107
throw errort().with_location(expr.source_location())
108-
<< "assignment to enum requires enum of the same type";
108+
<< "assignment to enum requires enum of the same type, but got "
109+
<< to_string(expr.type());
109110
}
110111
}
111112

@@ -1319,6 +1320,10 @@ exprt verilog_typecheck_exprt::elaborate_constant_expression(exprt expr)
13191320
}
13201321
else
13211322
{
1323+
// Remember the Verilog type.
1324+
auto expr_verilog_type = expr.type().get(ID_C_verilog_type);
1325+
auto expr_identifier = expr.type().get(ID_C_identifier);
1326+
13221327
// Do any operands first.
13231328
bool operands_are_constant = true;
13241329

@@ -1344,7 +1349,16 @@ exprt verilog_typecheck_exprt::elaborate_constant_expression(exprt expr)
13441349

13451350
// We fall back to the simplifier to approximate
13461351
// the standard's definition of 'constant expression'.
1347-
return simplify_expr(expr, ns);
1352+
auto simplified_expr = simplify_expr(expr, ns);
1353+
1354+
// Restore the Verilog type, if any.
1355+
if(expr_verilog_type != irep_idt())
1356+
simplified_expr.type().set(ID_C_verilog_type, expr_verilog_type);
1357+
1358+
if(expr_identifier != irep_idt())
1359+
simplified_expr.type().set(ID_C_identifier, expr_identifier);
1360+
1361+
return simplified_expr;
13481362
}
13491363
}
13501364

@@ -1479,7 +1493,8 @@ void verilog_typecheck_exprt::implicit_typecast(
14791493
expr.type().get(ID_C_identifier) != dest_type.get(ID_C_identifier))
14801494
{
14811495
throw errort().with_location(expr.source_location())
1482-
<< "assignment to enum requires enum of the same type";
1496+
<< "assignment to enum requires enum of the same type, but got "
1497+
<< to_string(expr.type());
14831498
}
14841499
}
14851500

src/verilog/verilog_typecheck_type.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,11 @@ typet verilog_typecheck_exprt::convert_type(const typet &src)
175175
else
176176
return convert_type(type_reference.type_op());
177177
}
178+
else if(src.id() == ID_to_be_elaborated)
179+
{
180+
// recursive call
181+
return convert_type(to_to_be_elaborated_type(src).subtype());
182+
}
178183
else
179184
{
180185
error().source_location = source_location;

0 commit comments

Comments
 (0)