@@ -152,6 +152,25 @@ static bool is_assignment_from(
152
152
is_typecast_with_id (rhs, identifier);
153
153
}
154
154
155
+ // / Return whether the instruction is a return, and the rhs is a symbol or
156
+ // / typecast expression with the specified identifier.
157
+ // / \param instr: A goto program instruction.
158
+ // / \param identifier: Some identifier.
159
+ // / \return True if the expression is a typecast with one operand, and the
160
+ // / typecast's identifier matches the specified identifier.
161
+ static bool is_return_with_variable (
162
+ const goto_programt::instructiont &instr,
163
+ const irep_idt &identifier)
164
+ {
165
+ if (!instr.is_return ())
166
+ {
167
+ return false ;
168
+ }
169
+ const auto &rhs = to_code_return (instr.code ).return_value ();
170
+ return is_symbol_with_id (rhs, identifier) ||
171
+ is_typecast_with_id (rhs, identifier);
172
+ }
173
+
155
174
// / Given an iterator into a list of instructions, modify the list to replace
156
175
// / 'nondet' library functions with CBMC-native nondet expressions, and return
157
176
// / an iterator to the next instruction to check. It's important to note that
@@ -166,7 +185,10 @@ static bool is_assignment_from(
166
185
// / obj = (<type-of-obj>)return_tmp0;
167
186
// /
168
187
// / We're going to replace all of these lines with
169
- // / return_tmp0 = NONDET(<type-of-obj>)
188
+ // / obj = NONDET(<type-of-obj>)
189
+ // /
190
+ // / In the situation of a direct return, the end result should be:
191
+ // / return NONDET(<type-of-obj>)
170
192
// / \param goto_program: The goto program to modify.
171
193
// / \param target: A single step of the goto program which may be erased and
172
194
// / replaced.
@@ -225,47 +247,60 @@ static goto_programt::targett check_and_replace_target(
225
247
// Look for the assignment of the temporary return variable into our target
226
248
// variable.
227
249
const auto end = goto_program.instructions .end ();
228
- auto assignment_instruction = std::find_if (
250
+ auto target_instruction = std::find_if (
229
251
next_instr,
230
252
end,
231
253
[&return_identifier](const goto_programt::instructiont &instr) {
232
254
return is_assignment_from (instr, return_identifier);
233
255
});
234
256
235
- INVARIANT (
236
- assignment_instruction != end,
237
- " failed to find assignment of the temporary return variable into our "
238
- " target variable" );
239
-
240
- // Assume that the LHS of *this* assignment is the actual nondet variable
241
- const auto &code_assign = to_code_assign (assignment_instruction->code );
242
- const auto nondet_var = code_assign.lhs ();
243
- const auto source_loc = target->source_location ;
257
+ // If we can't find an assign, it might be a direct return.
258
+ if (target_instruction == end)
259
+ {
260
+ target_instruction = std::find_if (
261
+ next_instr,
262
+ end,
263
+ [&return_identifier](const goto_programt::instructiont &instr) {
264
+ return is_return_with_variable (instr, return_identifier);
265
+ });
266
+ }
244
267
245
- // Erase from the nondet function call to the assignment
246
- const auto after_matching_assignment = std::next (assignment_instruction);
247
268
INVARIANT (
248
- after_matching_assignment != end,
249
- " goto_program missing END_FUNCTION instruction" );
269
+ target_instruction != end,
270
+ " failed to find return of the temporary return variable or assignment of "
271
+ " the temporary return variable into a target variable" );
250
272
251
273
std::for_each (
252
- target, after_matching_assignment , [](goto_programt::instructiont &instr) {
274
+ target, target_instruction , [](goto_programt::instructiont &instr) {
253
275
instr.make_skip ();
254
276
});
255
277
256
- const auto inserted = goto_program.insert_before (after_matching_assignment);
257
- inserted->make_assignment ();
258
- side_effect_expr_nondett inserted_expr (nondet_var.type ());
259
- inserted_expr.set_nullable (
260
- instr_info.get_nullable_type () ==
261
- nondet_instruction_infot::is_nullablet::TRUE );
262
- inserted->code = code_assignt (nondet_var, inserted_expr);
263
- inserted->code .add_source_location () = source_loc;
264
- inserted->source_location = source_loc;
278
+ if (target_instruction->is_return ())
279
+ {
280
+ const auto &nondet_var =
281
+ to_code_return (target_instruction->code ).return_value ();
282
+
283
+ side_effect_expr_nondett inserted_expr (nondet_var.type ());
284
+ inserted_expr.set_nullable (
285
+ instr_info.get_nullable_type () ==
286
+ nondet_instruction_infot::is_nullablet::TRUE );
287
+ target_instruction->code = code_returnt (inserted_expr);
288
+ }
289
+ else if (target_instruction->is_assign ())
290
+ {
291
+ // Assume that the LHS of *this* assignment is the actual nondet variable
292
+ const auto &nondet_var = to_code_assign (target_instruction->code ).lhs ();
293
+
294
+ side_effect_expr_nondett inserted_expr (nondet_var.type ());
295
+ inserted_expr.set_nullable (
296
+ instr_info.get_nullable_type () ==
297
+ nondet_instruction_infot::is_nullablet::TRUE );
298
+ target_instruction->code = code_assignt (nondet_var, inserted_expr);
299
+ }
265
300
266
301
goto_program.update ();
267
302
268
- return after_matching_assignment ;
303
+ return std::next (target_instruction) ;
269
304
}
270
305
271
306
// / Checks each instruction in the goto program to see whether it is a method
0 commit comments