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

Diff for: regression/verilog/enums/enum1.desc

+1-1
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
--

Diff for: regression/verilog/enums/enum2.desc

+1-1
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
--

Diff for: regression/verilog/enums/enum_base_type2.desc

+1-3
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.

Diff for: regression/verilog/enums/enum_initializers1.desc

+1-1
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
--

Diff for: regression/verilog/enums/enum_initializers2.desc

+2-5
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-

Diff for: regression/verilog/enums/enum_initializers2.sv

+2-2
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

Diff for: regression/verilog/enums/enum_initializers3.desc

+3-4
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.

Diff for: src/verilog/verilog_elaborate.cpp

+13-11
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);

Diff for: src/verilog/verilog_typecheck_expr.cpp

+18-3
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

Diff for: src/verilog/verilog_typecheck_type.cpp

+5
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;

Diff for: src/verilog/verilog_types.h

+30
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,31 @@ class to_be_elaborated_typet : public type_with_subtypet
2222
}
2323
};
2424

25+
/*! \brief Cast a generic typet to a \ref to_be_elaborated_typet
26+
*
27+
* This is an unchecked conversion. \a type must be known to be \ref
28+
* to_be_elaborated_typet.
29+
*
30+
* \param type Source type
31+
* \return Object of type \ref to_be_elaborated_typet
32+
*
33+
* \ingroup gr_std_types
34+
*/
35+
inline const to_be_elaborated_typet &to_to_be_elaborated_type(const typet &type)
36+
{
37+
PRECONDITION(type.id() == ID_to_be_elaborated);
38+
return static_cast<const to_be_elaborated_typet &>(type);
39+
}
40+
41+
/*! \copydoc to_to_be_elaborated_type(const typet &)
42+
* \ingroup gr_std_types
43+
*/
44+
inline to_be_elaborated_typet &to_to_be_elaborated_type(typet &type)
45+
{
46+
PRECONDITION(type.id() == ID_to_be_elaborated);
47+
return static_cast<to_be_elaborated_typet &>(type);
48+
}
49+
2550
/// Used during elaboration only,
2651
/// to signal that the type of the symbol is going to be the
2752
/// type of the value (default for parameters).
@@ -336,6 +361,11 @@ class verilog_enum_typet : public type_with_subtypet
336361
{
337362
set(ID_base_name, _base_name);
338363
}
364+
365+
const source_locationt &source_location() const
366+
{
367+
return static_cast<const source_locationt &>(find(ID_C_source_location));
368+
}
339369
};
340370

341371
using enum_namest = std::vector<enum_namet>;

0 commit comments

Comments
 (0)