@@ -57,11 +57,11 @@ Function: goto_convertt::finish_gotos
57
57
58
58
\*******************************************************************/
59
59
60
- void goto_convertt::finish_gotos ()
60
+ void goto_convertt::finish_gotos (goto_programt &dest )
61
61
{
62
62
for (const auto &g_it : targets.gotos )
63
63
{
64
- goto_programt::instructiont &i=*g_it;
64
+ goto_programt::instructiont &i=*( g_it. first ) ;
65
65
66
66
if (i.code .get_statement ()==" non-deterministic-goto" )
67
67
{
@@ -81,7 +81,7 @@ void goto_convertt::finish_gotos()
81
81
throw 0 ;
82
82
}
83
83
84
- i.targets .push_back (l_it->second );
84
+ i.targets .push_back (l_it->second . first );
85
85
}
86
86
}
87
87
else if (i.is_start_thread ())
@@ -98,7 +98,7 @@ void goto_convertt::finish_gotos()
98
98
throw 0 ;
99
99
}
100
100
101
- i.targets .push_back (l_it->second );
101
+ i.targets .push_back (l_it->second . first );
102
102
}
103
103
else if (i.code .get_statement ()==ID_goto)
104
104
{
@@ -114,7 +114,48 @@ void goto_convertt::finish_gotos()
114
114
}
115
115
116
116
i.targets .clear ();
117
- i.targets .push_back (l_it->second );
117
+ i.targets .push_back (l_it->second .first );
118
+
119
+ // If the goto recorded a destructor stack, execute as much as is
120
+ // appropriate for however many automatic variables leave scope.
121
+ // We don't currently handle variables *entering* scope.
122
+ auto goto_stack=g_it.second ;
123
+ const auto & label_stack=l_it->second .second ;
124
+ bool stack_is_prefix=true ;
125
+ if (label_stack.size ()>goto_stack.size ())
126
+ stack_is_prefix=false ;
127
+ for (unsigned i=0 , ilim=label_stack.size ();
128
+ i!=ilim && stack_is_prefix;
129
+ ++i)
130
+ {
131
+ if (goto_stack[i]!=label_stack[i])
132
+ stack_is_prefix=false ;
133
+ }
134
+
135
+ if (!stack_is_prefix)
136
+ {
137
+ warning () << " Encountered goto (" << goto_label <<
138
+ " ) that enters one or more lexical blocks;" <<
139
+ " omitting constructors and destructors." << eom;
140
+ }
141
+ else
142
+ {
143
+ auto unwind_to_size=label_stack.size ();
144
+ if (unwind_to_size<goto_stack.size ())
145
+ {
146
+ status () << " Adding goto-destructor code on jump to " <<
147
+ goto_label << eom;
148
+ goto_programt destructor_code;
149
+ unwind_destructor_stack (
150
+ i.code .add_source_location (),
151
+ unwind_to_size,
152
+ destructor_code,
153
+ goto_stack);
154
+ dest.destructive_insert (g_it.first , destructor_code);
155
+ // This should leave iterators intact, as long as
156
+ // goto_programt::instructionst is std::list.
157
+ }
158
+ }
118
159
}
119
160
else
120
161
{
@@ -169,7 +210,7 @@ void goto_convertt::finish_computed_gotos(goto_programt &goto_program)
169
210
goto_programt::targett t=
170
211
goto_program.insert_after (g_it);
171
212
172
- t->make_goto (label.second );
213
+ t->make_goto (label.second . first );
173
214
t->source_location =i.source_location ;
174
215
t->guard =guard;
175
216
}
@@ -213,7 +254,7 @@ void goto_convertt::goto_convert_rec(
213
254
{
214
255
convert (code, dest);
215
256
216
- finish_gotos ();
257
+ finish_gotos (dest );
217
258
finish_computed_gotos (dest);
218
259
}
219
260
@@ -282,8 +323,7 @@ void goto_convertt::convert_label(
282
323
goto_programt::targett target=tmp.instructions .begin ();
283
324
dest.destructive_append (tmp);
284
325
285
- targets.labels .insert (std::pair<irep_idt, goto_programt::targett>
286
- (label, target));
326
+ targets.labels .insert ({label, {target, targets.destructor_stack }});
287
327
target->labels .push_front (label);
288
328
}
289
329
@@ -1622,13 +1662,21 @@ void goto_convertt::convert_goto(
1622
1662
const codet &code,
1623
1663
goto_programt &dest)
1624
1664
{
1665
+ // Precede with a 'skip', which will be replaced by any pre-departure
1666
+ // destructor code if appropriate. Without this the goto can be amalgamated
1667
+ // into a control-flow structure, such as IF x THEN GOTO 1;, leaving
1668
+ // nowhere for the destructors to go.
1669
+ goto_programt::targett skip=dest.add_instruction (SKIP);
1670
+ skip->source_location =code.source_location ();
1671
+ skip->code =code_skipt ();
1672
+
1625
1673
goto_programt::targett t=dest.add_instruction ();
1626
1674
t->make_goto ();
1627
1675
t->source_location =code.source_location ();
1628
1676
t->code =code;
1629
1677
1630
1678
// remember it to do target later
1631
- targets.gotos .push_back (t );
1679
+ targets.gotos .push_back (std::make_pair (t,targets. destructor_stack ) );
1632
1680
}
1633
1681
1634
1682
/* ******************************************************************\
0 commit comments