@@ -93,6 +93,141 @@ static void finish_catch_push_targets(goto_programt &dest)
93
93
}
94
94
}
95
95
96
+ struct build_declaration_hops_inputst
97
+ {
98
+ irep_idt mode;
99
+ irep_idt label;
100
+ goto_programt::targett goto_instruction;
101
+ goto_programt::targett label_instruction;
102
+ node_indext label_scope_index = 0 ;
103
+ node_indext end_scope_index = 0 ;
104
+ };
105
+
106
+ void goto_convertt::build_declaration_hops (
107
+ goto_programt &program,
108
+ std::unordered_map<irep_idt, symbolt, irep_id_hash> &label_flags,
109
+ const build_declaration_hops_inputst &inputs)
110
+ {
111
+ // In the case of a goto jumping into a scope, the declarations (but not the
112
+ // initialisations) need to be executed. This function performs a
113
+ // transformation from code that looks like -
114
+ // {
115
+ // statement_block_a();
116
+ // if(...)
117
+ // goto user_label;
118
+ // statement_block_b();
119
+ // int x;
120
+ // x = 0;
121
+ // statement_block_c();
122
+ // int y;
123
+ // y = 0;
124
+ // statement_block_d();
125
+ // user_label:
126
+ // statement_block_e();
127
+ // }
128
+ // to code which looks like -
129
+ // {
130
+ // __CPROVER_bool going_to::user_label;
131
+ // going_to::user_label = false;
132
+ // statement_block_a();
133
+ // if(...)
134
+ // {
135
+ // going_to::user_label = true;
136
+ // goto scope_x_label;
137
+ // }
138
+ // statement_block_b();
139
+ // scope_x_label:
140
+ // int x;
141
+ // if going_to::user_label goto scope_y_label:
142
+ // x = 0;
143
+ // statement_block_c();
144
+ // scope_y_label:
145
+ // int y;
146
+ // if going_to::user_label goto user_label:
147
+ // y = 0;
148
+ // statement_block_d();
149
+ // user_label:
150
+ // going_to::user_label = false;
151
+ // statement_block_e();
152
+ // }
153
+
154
+ PRECONDITION (inputs.label_scope_index != inputs.end_scope_index );
155
+
156
+ const auto flag = [&]() -> symbolt {
157
+ const auto existing_flag = label_flags.find (inputs.label );
158
+ if (existing_flag != label_flags.end ())
159
+ return existing_flag->second ;
160
+ source_locationt label_location =
161
+ inputs.label_instruction ->source_location ();
162
+ label_location.set_hide ();
163
+ const symbolt &new_flag = get_fresh_aux_symbol (
164
+ bool_typet{},
165
+ " going_to" ,
166
+ id2string (inputs.label ),
167
+ label_location,
168
+ inputs.mode ,
169
+ symbol_table);
170
+ label_flags.emplace (inputs.label , new_flag);
171
+
172
+ // Create and initialise flag.
173
+ goto_programt flag_creation;
174
+ flag_creation.instructions .push_back (
175
+ goto_programt::make_decl (new_flag.symbol_expr (), label_location));
176
+ const auto make_clear_flag = [&]() -> goto_programt::instructiont {
177
+ return goto_programt::make_assignment (
178
+ new_flag.symbol_expr (), false_exprt{}, label_location);
179
+ };
180
+ flag_creation.instructions .push_back (make_clear_flag ());
181
+ program.destructive_insert (program.instructions .begin (), flag_creation);
182
+
183
+ // Clear flag on arrival at label.
184
+ auto clear_on_arrival = make_clear_flag ();
185
+ program.insert_before_swap (inputs.label_instruction , clear_on_arrival);
186
+ return new_flag;
187
+ }();
188
+
189
+ auto goto_instruction = inputs.goto_instruction ;
190
+ {
191
+ // Set flag before the goto.
192
+ auto goto_location = goto_instruction->source_location ();
193
+ goto_location.set_hide ();
194
+ auto set_flag = goto_programt::make_assignment (
195
+ flag.symbol_expr (), true_exprt{}, goto_location);
196
+ program.insert_before_swap (goto_instruction, set_flag);
197
+ // Keep this iterator referring to the goto instruction, not the assignment.
198
+ ++goto_instruction;
199
+ }
200
+
201
+ auto target = inputs.label_instruction ;
202
+ targets.scope_stack .set_current_node (inputs.label_scope_index );
203
+ while (targets.scope_stack .get_current_node () > inputs.end_scope_index )
204
+ {
205
+ node_indext current_node = targets.scope_stack .get_current_node ();
206
+ auto &declaration = targets.scope_stack .get_declaration (current_node);
207
+ targets.scope_stack .descend_tree ();
208
+ if (!declaration)
209
+ continue ;
210
+
211
+ bool add_if = declaration->if_conditions_added .find (flag.name ) ==
212
+ declaration->if_conditions_added .end ();
213
+ if (add_if)
214
+ {
215
+ auto declaration_location = declaration->instruction ->source_location ();
216
+ declaration_location.set_hide ();
217
+ auto if_goto = goto_programt::make_goto (
218
+ target, flag.symbol_expr (), declaration_location);
219
+ program.instructions .insert (
220
+ std::next (declaration->instruction ), std::move (if_goto));
221
+ declaration->if_conditions_added .insert (flag.name );
222
+ }
223
+ target = declaration->instruction ;
224
+ }
225
+
226
+ // Update the goto so that it goes to the first declaration rather than its
227
+ // original/final destination.
228
+ goto_instruction->set_target (target);
229
+ }
230
+
96
231
/* ****************************************************************** \
97
232
98
233
Function: goto_convertt::finish_gotos
@@ -107,6 +242,8 @@ Function: goto_convertt::finish_gotos
107
242
108
243
void goto_convertt::finish_gotos (goto_programt &dest, const irep_idt &mode)
109
244
{
245
+ std::unordered_map<irep_idt, symbolt, irep_id_hash> label_flags;
246
+
110
247
for (const auto &g_it : targets.gotos )
111
248
{
112
249
goto_programt::instructiont &i=*(g_it.first );
@@ -174,17 +311,29 @@ void goto_convertt::finish_gotos(goto_programt &dest, const irep_idt &mode)
174
311
// goto_programt::instructionst is std::list.
175
312
}
176
313
177
- // We don't currently handle variables *entering* scope, which
178
- // is illegal for C++ non-pod types and impossible in Java in any case.
179
- // This is however valid C .
314
+ // Variables *entering* scope on goto, is illegal for C++ non-pod types
315
+ // and impossible in Java. This is however valid C and should be taken
316
+ // into account .
180
317
const bool variables_added_to_scope =
181
318
intersection_result.right_depth_below_common_ancestor > 0 ;
182
319
if (variables_added_to_scope)
183
320
{
321
+ // If the goto recorded a destructor stack, execute as much as is
322
+ // appropriate for however many automatic variables leave scope.
184
323
debug ().source_location = i.source_location ();
185
324
debug () << " encountered goto '" << goto_label
186
325
<< " ' that enters one or more lexical blocks; "
187
- << " omitting constructors." << eom;
326
+ << " adding declaration code on jump to '" << goto_label << " '"
327
+ << eom;
328
+
329
+ build_declaration_hops_inputst inputs;
330
+ inputs.mode = mode;
331
+ inputs.label = l_it->first ;
332
+ inputs.goto_instruction = g_it.first ;
333
+ inputs.label_instruction = l_it->second .first ;
334
+ inputs.label_scope_index = label_target;
335
+ inputs.end_scope_index = intersection_result.common_ancestor ;
336
+ build_declaration_hops (dest, label_flags, inputs);
188
337
}
189
338
}
190
339
else
0 commit comments