@@ -152,6 +152,25 @@ static bool is_assignment_from(
152152 is_typecast_with_id (rhs, identifier);
153153}
154154
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+
155174// / Given an iterator into a list of instructions, modify the list to replace
156175// / 'nondet' library functions with CBMC-native nondet expressions, and return
157176// / an iterator to the next instruction to check. It's important to note that
@@ -166,7 +185,10 @@ static bool is_assignment_from(
166185// / obj = (<type-of-obj>)return_tmp0;
167186// /
168187// / 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>)
170192// / \param goto_program: The goto program to modify.
171193// / \param target: A single step of the goto program which may be erased and
172194// / replaced.
@@ -225,47 +247,60 @@ static goto_programt::targett check_and_replace_target(
225247 // Look for the assignment of the temporary return variable into our target
226248 // variable.
227249 const auto end = goto_program.instructions .end ();
228- auto assignment_instruction = std::find_if (
250+ auto target_instruction = std::find_if (
229251 next_instr,
230252 end,
231253 [&return_identifier](const goto_programt::instructiont &instr) {
232254 return is_assignment_from (instr, return_identifier);
233255 });
234256
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+ }
244267
245- // Erase from the nondet function call to the assignment
246- const auto after_matching_assignment = std::next (assignment_instruction);
247268 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" );
250272
251273 std::for_each (
252- target, after_matching_assignment , [](goto_programt::instructiont &instr) {
274+ target, target_instruction , [](goto_programt::instructiont &instr) {
253275 instr.make_skip ();
254276 });
255277
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+ }
265300
266301 goto_program.update ();
267302
268- return after_matching_assignment ;
303+ return std::next (target_instruction) ;
269304}
270305
271306// / Checks each instruction in the goto program to see whether it is a method
0 commit comments