@@ -51,9 +51,6 @@ pub const START_BLOCK: BasicBlock = BasicBlock(0);
51
51
/// where execution ends, on normal return
52
52
pub const END_BLOCK : BasicBlock = BasicBlock ( 1 ) ;
53
53
54
- /// where execution ends, on panic
55
- pub const DIVERGE_BLOCK : BasicBlock = BasicBlock ( 2 ) ;
56
-
57
54
impl < ' tcx > Mir < ' tcx > {
58
55
pub fn all_basic_blocks ( & self ) -> Vec < BasicBlock > {
59
56
( 0 ..self . basic_blocks . len ( ) )
@@ -194,7 +191,8 @@ impl Debug for BasicBlock {
194
191
#[ derive( Debug , RustcEncodable , RustcDecodable ) ]
195
192
pub struct BasicBlockData < ' tcx > {
196
193
pub statements : Vec < Statement < ' tcx > > ,
197
- pub terminator : Terminator < ' tcx > ,
194
+ pub terminator : Option < Terminator < ' tcx > > ,
195
+ pub is_cleanup : bool ,
198
196
}
199
197
200
198
#[ derive( RustcEncodable , RustcDecodable ) ]
@@ -204,12 +202,6 @@ pub enum Terminator<'tcx> {
204
202
target : BasicBlock ,
205
203
} ,
206
204
207
- /// block should initiate unwinding; should be one successor
208
- /// that does cleanup and branches to DIVERGE_BLOCK
209
- Panic {
210
- target : BasicBlock ,
211
- } ,
212
-
213
205
/// jump to branch 0 if this lvalue evaluates to true
214
206
If {
215
207
cond : Operand < ' tcx > ,
@@ -243,77 +235,125 @@ pub enum Terminator<'tcx> {
243
235
targets : Vec < BasicBlock > ,
244
236
} ,
245
237
246
- /// Indicates that the last statement in the block panics, aborts,
247
- /// etc. No successors. This terminator appears on exactly one
248
- /// basic block which we create in advance. However, during
249
- /// construction, we use this value as a sentinel for "terminator
250
- /// not yet assigned", and assert at the end that only the
251
- /// well-known diverging block actually diverges.
252
- Diverge ,
238
+ /// Indicates that the landing pad is finished and unwinding should
239
+ /// continue. Emitted by build::scope::diverge_cleanup.
240
+ Resume ,
253
241
254
242
/// Indicates a normal return. The ReturnPointer lvalue should
255
243
/// have been filled in by now. This should only occur in the
256
244
/// `END_BLOCK`.
257
245
Return ,
258
246
259
- /// block ends with a call; it should have two successors. The
260
- /// first successor indicates normal return. The second indicates
261
- /// unwinding.
247
+ /// Block ends with a call of a converging function
262
248
Call {
263
- data : CallData < ' tcx > ,
264
- targets : ( BasicBlock , BasicBlock ) ,
249
+ /// The function that’s being called
250
+ func : Operand < ' tcx > ,
251
+ /// Arguments the function is called with
252
+ args : Vec < Operand < ' tcx > > ,
253
+ /// The kind of call with associated information
254
+ kind : CallKind < ' tcx > ,
265
255
} ,
266
256
}
267
257
258
+ #[ derive( Clone , RustcEncodable , RustcDecodable ) ]
259
+ pub enum CallKind < ' tcx > {
260
+ /// Diverging function without associated cleanup
261
+ Diverging ,
262
+ /// Diverging function with associated cleanup
263
+ DivergingCleanup ( BasicBlock ) ,
264
+ /// Converging function without associated cleanup
265
+ Converging {
266
+ /// Destination where the call result is written
267
+ destination : Lvalue < ' tcx > ,
268
+ /// Block to branch into on successful return
269
+ target : BasicBlock ,
270
+ } ,
271
+ ConvergingCleanup {
272
+ /// Destination where the call result is written
273
+ destination : Lvalue < ' tcx > ,
274
+ /// First target is branched to on successful return.
275
+ /// Second block contains the cleanups to do on unwind.
276
+ targets : ( BasicBlock , BasicBlock )
277
+ }
278
+ }
279
+
280
+ impl < ' tcx > CallKind < ' tcx > {
281
+ pub fn successors ( & self ) -> & [ BasicBlock ] {
282
+ match * self {
283
+ CallKind :: Diverging => & [ ] ,
284
+ CallKind :: DivergingCleanup ( ref b) |
285
+ CallKind :: Converging { target : ref b, .. } => slice:: ref_slice ( b) ,
286
+ CallKind :: ConvergingCleanup { ref targets, .. } => targets. as_slice ( ) ,
287
+ }
288
+ }
289
+
290
+ pub fn successors_mut ( & mut self ) -> & mut [ BasicBlock ] {
291
+ match * self {
292
+ CallKind :: Diverging => & mut [ ] ,
293
+ CallKind :: DivergingCleanup ( ref mut b) |
294
+ CallKind :: Converging { target : ref mut b, .. } => slice:: mut_ref_slice ( b) ,
295
+ CallKind :: ConvergingCleanup { ref mut targets, .. } => targets. as_mut_slice ( ) ,
296
+ }
297
+ }
298
+
299
+ pub fn destination ( & self ) -> Option < Lvalue < ' tcx > > {
300
+ match * self {
301
+ CallKind :: Converging { ref destination, .. } |
302
+ CallKind :: ConvergingCleanup { ref destination, .. } => Some ( destination. clone ( ) ) ,
303
+ CallKind :: Diverging |
304
+ CallKind :: DivergingCleanup ( _) => None
305
+ }
306
+ }
307
+ }
308
+
268
309
impl < ' tcx > Terminator < ' tcx > {
269
310
pub fn successors ( & self ) -> & [ BasicBlock ] {
270
311
use self :: Terminator :: * ;
271
312
match * self {
272
313
Goto { target : ref b } => slice:: ref_slice ( b) ,
273
- Panic { target : ref b } => slice:: ref_slice ( b) ,
274
- If { cond : _, targets : ref b } => b. as_slice ( ) ,
314
+ If { targets : ref b, .. } => b. as_slice ( ) ,
275
315
Switch { targets : ref b, .. } => b,
276
316
SwitchInt { targets : ref b, .. } => b,
277
- Diverge => & [ ] ,
317
+ Resume => & [ ] ,
278
318
Return => & [ ] ,
279
- Call { data : _ , targets : ref b } => b . as_slice ( ) ,
319
+ Call { ref kind , .. } => kind . successors ( ) ,
280
320
}
281
321
}
282
322
283
323
pub fn successors_mut ( & mut self ) -> & mut [ BasicBlock ] {
284
324
use self :: Terminator :: * ;
285
325
match * self {
286
326
Goto { target : ref mut b } => slice:: mut_ref_slice ( b) ,
287
- Panic { target : ref mut b } => slice:: mut_ref_slice ( b) ,
288
- If { cond : _, targets : ref mut b } => b. as_mut_slice ( ) ,
327
+ If { targets : ref mut b, .. } => b. as_mut_slice ( ) ,
289
328
Switch { targets : ref mut b, .. } => b,
290
329
SwitchInt { targets : ref mut b, .. } => b,
291
- Diverge => & mut [ ] ,
330
+ Resume => & mut [ ] ,
292
331
Return => & mut [ ] ,
293
- Call { data : _ , targets : ref mut b } => b . as_mut_slice ( ) ,
332
+ Call { ref mut kind , .. } => kind . successors_mut ( ) ,
294
333
}
295
334
}
296
335
}
297
336
298
- #[ derive( Debug , RustcEncodable , RustcDecodable ) ]
299
- pub struct CallData < ' tcx > {
300
- /// where the return value is written to
301
- pub destination : Lvalue < ' tcx > ,
302
-
303
- /// the fn being called
304
- pub func : Operand < ' tcx > ,
305
-
306
- /// the arguments
307
- pub args : Vec < Operand < ' tcx > > ,
308
- }
309
-
310
337
impl < ' tcx > BasicBlockData < ' tcx > {
311
- pub fn new ( terminator : Terminator < ' tcx > ) -> BasicBlockData < ' tcx > {
338
+ pub fn new ( terminator : Option < Terminator < ' tcx > > ) -> BasicBlockData < ' tcx > {
312
339
BasicBlockData {
313
340
statements : vec ! [ ] ,
314
341
terminator : terminator,
342
+ is_cleanup : false ,
315
343
}
316
344
}
345
+
346
+ /// Accessor for terminator.
347
+ ///
348
+ /// Terminator may not be None after construction of the basic block is complete. This accessor
349
+ /// provides a convenience way to reach the terminator.
350
+ pub fn terminator ( & self ) -> & Terminator < ' tcx > {
351
+ self . terminator . as_ref ( ) . expect ( "invalid terminator state" )
352
+ }
353
+
354
+ pub fn terminator_mut ( & mut self ) -> & mut Terminator < ' tcx > {
355
+ self . terminator . as_mut ( ) . expect ( "invalid terminator state" )
356
+ }
317
357
}
318
358
319
359
impl < ' tcx > Debug for Terminator < ' tcx > {
@@ -351,15 +391,17 @@ impl<'tcx> Terminator<'tcx> {
351
391
use self :: Terminator :: * ;
352
392
match * self {
353
393
Goto { .. } => write ! ( fmt, "goto" ) ,
354
- Panic { .. } => write ! ( fmt, "panic" ) ,
355
394
If { cond : ref lv, .. } => write ! ( fmt, "if({:?})" , lv) ,
356
395
Switch { discr : ref lv, .. } => write ! ( fmt, "switch({:?})" , lv) ,
357
396
SwitchInt { discr : ref lv, .. } => write ! ( fmt, "switchInt({:?})" , lv) ,
358
- Diverge => write ! ( fmt, "diverge" ) ,
359
397
Return => write ! ( fmt, "return" ) ,
360
- Call { data : ref c, .. } => {
361
- try!( write ! ( fmt, "{:?} = {:?}(" , c. destination, c. func) ) ;
362
- for ( index, arg) in c. args . iter ( ) . enumerate ( ) {
398
+ Resume => write ! ( fmt, "resume" ) ,
399
+ Call { ref kind, ref func, ref args } => {
400
+ if let Some ( destination) = kind. destination ( ) {
401
+ try!( write ! ( fmt, "{:?} = " , destination) ) ;
402
+ }
403
+ try!( write ! ( fmt, "{:?}(" , func) ) ;
404
+ for ( index, arg) in args. iter ( ) . enumerate ( ) {
363
405
if index > 0 {
364
406
try!( write ! ( fmt, ", " ) ) ;
365
407
}
@@ -374,10 +416,9 @@ impl<'tcx> Terminator<'tcx> {
374
416
pub fn fmt_successor_labels ( & self ) -> Vec < Cow < ' static , str > > {
375
417
use self :: Terminator :: * ;
376
418
match * self {
377
- Diverge | Return => vec ! [ ] ,
378
- Goto { .. } | Panic { .. } => vec ! [ "" . into_cow( ) ] ,
419
+ Return | Resume => vec ! [ ] ,
420
+ Goto { .. } => vec ! [ "" . into_cow( ) ] ,
379
421
If { .. } => vec ! [ "true" . into_cow( ) , "false" . into_cow( ) ] ,
380
- Call { .. } => vec ! [ "return" . into_cow( ) , "unwind" . into_cow( ) ] ,
381
422
Switch { ref adt_def, .. } => {
382
423
adt_def. variants
383
424
. iter ( )
@@ -394,6 +435,16 @@ impl<'tcx> Terminator<'tcx> {
394
435
. chain ( iter:: once ( String :: from ( "otherwise" ) . into_cow ( ) ) )
395
436
. collect ( )
396
437
}
438
+ Call { ref kind, .. } => match * kind {
439
+ CallKind :: Diverging =>
440
+ vec ! [ ] ,
441
+ CallKind :: DivergingCleanup ( ..) =>
442
+ vec ! [ "unwind" . into_cow( ) ] ,
443
+ CallKind :: Converging { .. } =>
444
+ vec ! [ "return" . into_cow( ) ] ,
445
+ CallKind :: ConvergingCleanup { .. } =>
446
+ vec ! [ "return" . into_cow( ) , "unwind" . into_cow( ) ] ,
447
+ } ,
397
448
}
398
449
}
399
450
}
0 commit comments