@@ -41,16 +41,143 @@ void verilog_typecheckt::assignment_conversion(
41
41
exprt &rhs,
42
42
const typet &lhs_type)
43
43
{
44
- // Implements 1800-2017 10.7
45
- // If the RHS is smaller than the LHS:
46
- // * if the RHS is unsigned, it is zero-padded
47
- // * if the RHS is signed, it is sign-extended
48
- // If the RHS is larger than the LHS, it is truncated.
49
-
50
- // This matches our typecast, but differs from the steps taken
51
- // when evaluating binary expressions (11.8.2), where sign
52
- // extension only happens when the propagated type is signed.
53
- implicit_typecast (rhs, lhs_type);
44
+ if (rhs.type ().id () == ID_verilog_assignment_pattern)
45
+ {
46
+ DATA_INVARIANT (
47
+ rhs.id () == ID_verilog_assignment_pattern,
48
+ " verilog_assignment_pattern expression expected" );
49
+
50
+ if (lhs_type.id () == ID_struct)
51
+ {
52
+ auto &struct_type = to_struct_type (lhs_type);
53
+ auto &components = struct_type.components ();
54
+
55
+ if (
56
+ !rhs.operands ().empty () &&
57
+ rhs.operands ().front ().id () == ID_member_initializer)
58
+ {
59
+ exprt::operandst initializers{components.size (), nil_exprt{}};
60
+
61
+ for (auto &op : rhs.operands ())
62
+ {
63
+ PRECONDITION (op.id () == ID_member_initializer);
64
+ auto member_name = op.get (ID_member_name);
65
+ if (!struct_type.has_component (member_name))
66
+ {
67
+ throw errort ().with_location (op.source_location ())
68
+ << " struct does not have a member `" << member_name << " '" ;
69
+ }
70
+ auto nr = struct_type.component_number (member_name);
71
+ auto value = to_unary_expr (op).op ();
72
+ // rec. call
73
+ assignment_conversion (value, components[nr].type ());
74
+ initializers[nr] = std::move (value);
75
+ }
76
+
77
+ // Is every member covered?
78
+ for (std::size_t i = 0 ; i < components.size (); i++)
79
+ if (initializers[i].is_nil ())
80
+ {
81
+ throw errort ().with_location (rhs.source_location ())
82
+ << " assignment pattern does not assign member `"
83
+ << components[i].get_name () << " '" ;
84
+ }
85
+
86
+ rhs = struct_exprt{std::move (initializers), struct_type}
87
+ .with_source_location (rhs.source_location ());
88
+ }
89
+ else
90
+ {
91
+ if (rhs.operands ().size () != components.size ())
92
+ {
93
+ throw errort ().with_location (rhs.source_location ())
94
+ << " number of expressions does not match number of struct members" ;
95
+ }
96
+
97
+ for (std::size_t i = 0 ; i < components.size (); i++)
98
+ {
99
+ // rec. call
100
+ assignment_conversion (rhs.operands ()[i], components[i].type ());
101
+ }
102
+
103
+ // turn into struct expression
104
+ rhs.id (ID_struct);
105
+ rhs.type () = lhs_type;
106
+ }
107
+
108
+ return ;
109
+ }
110
+ else if (lhs_type.id () == ID_array)
111
+ {
112
+ auto &array_type = to_array_type (lhs_type);
113
+ auto &element_type = array_type.element_type ();
114
+ auto array_size =
115
+ numeric_cast_v<mp_integer>(to_constant_expr (array_type.size ()));
116
+
117
+ if (array_size != rhs.operands ().size ())
118
+ {
119
+ throw errort ().with_location (rhs.source_location ())
120
+ << " number of expressions does not match number of array elements" ;
121
+ }
122
+
123
+ for (std::size_t i = 0 ; i < array_size; i++)
124
+ {
125
+ // rec. call
126
+ assignment_conversion (rhs.operands ()[i], element_type);
127
+ }
128
+
129
+ // turn into array expression
130
+ rhs.id (ID_array);
131
+ rhs.type () = lhs_type;
132
+ return ;
133
+ }
134
+ else
135
+ {
136
+ throw errort ().with_location (rhs.source_location ())
137
+ << " cannot convert assignment pattern to '" << to_string (lhs_type)
138
+ << ' \' ' ;
139
+ }
140
+ }
141
+
142
+ // Implements 1800-2017 10.7 and 1800-2017 11.8.3.
143
+ //
144
+ // "The size of the left-hand side of an assignment forms
145
+ // the context for the right-hand expression."
146
+
147
+ // Get the width of LHS and RHS
148
+ auto lhs_width = get_width (lhs_type);
149
+ auto rhs_width = get_width (rhs.type ());
150
+
151
+ if (lhs_width > rhs_width)
152
+ {
153
+ // Need to enlarge the RHS.
154
+ //
155
+ // "If needed, extend the size of the right-hand side,
156
+ // performing sign extension if, and only if, the type
157
+ // of the right-hand side is signed.
158
+ if (
159
+ (rhs.type ().id () == ID_signedbv ||
160
+ rhs.type ().id () == ID_verilog_signedbv) &&
161
+ (lhs_type.id () == ID_unsignedbv ||
162
+ lhs_type.id () == ID_verilog_unsignedbv))
163
+ {
164
+ // LHS is unsigned, RHS is signed. Must sign-extend.
165
+ auto new_rhs_type = to_bitvector_type (rhs.type ());
166
+ new_rhs_type.set_width (numeric_cast_v<std::size_t >(lhs_width));
167
+
168
+ downwards_type_propagation (rhs, new_rhs_type);
169
+
170
+ // then cast
171
+ rhs = typecast_exprt::conditional_cast (rhs, lhs_type);
172
+ }
173
+ else
174
+ downwards_type_propagation (rhs, lhs_type);
175
+ }
176
+ else
177
+ {
178
+ // no need to enlarge
179
+ rhs = typecast_exprt::conditional_cast (rhs, lhs_type);
180
+ }
54
181
}
55
182
56
183
/* ******************************************************************\
0 commit comments