@@ -51,9 +51,6 @@ pub const START_BLOCK: BasicBlock = BasicBlock(0);
5151/// where execution ends, on normal return
5252pub const END_BLOCK : BasicBlock = BasicBlock ( 1 ) ;
5353
54- /// where execution ends, on panic
55- pub const DIVERGE_BLOCK : BasicBlock = BasicBlock ( 2 ) ;
56-
5754impl < ' tcx > Mir < ' tcx > {
5855 pub fn all_basic_blocks ( & self ) -> Vec < BasicBlock > {
5956 ( 0 ..self . basic_blocks . len ( ) )
@@ -194,7 +191,8 @@ impl Debug for BasicBlock {
194191#[ derive( Debug , RustcEncodable , RustcDecodable ) ]
195192pub struct BasicBlockData < ' tcx > {
196193 pub statements : Vec < Statement < ' tcx > > ,
197- pub terminator : Terminator < ' tcx > ,
194+ pub terminator : Option < Terminator < ' tcx > > ,
195+ pub is_cleanup : bool ,
198196}
199197
200198#[ derive( RustcEncodable , RustcDecodable ) ]
@@ -204,12 +202,6 @@ pub enum Terminator<'tcx> {
204202 target : BasicBlock ,
205203 } ,
206204
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-
213205 /// jump to branch 0 if this lvalue evaluates to true
214206 If {
215207 cond : Operand < ' tcx > ,
@@ -243,77 +235,125 @@ pub enum Terminator<'tcx> {
243235 targets : Vec < BasicBlock > ,
244236 } ,
245237
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 ,
253241
254242 /// Indicates a normal return. The ReturnPointer lvalue should
255243 /// have been filled in by now. This should only occur in the
256244 /// `END_BLOCK`.
257245 Return ,
258246
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
262248 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 > ,
265255 } ,
266256}
267257
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+
268309impl < ' tcx > Terminator < ' tcx > {
269310 pub fn successors ( & self ) -> & [ BasicBlock ] {
270311 use self :: Terminator :: * ;
271312 match * self {
272313 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 ( ) ,
275315 Switch { targets : ref b, .. } => b,
276316 SwitchInt { targets : ref b, .. } => b,
277- Diverge => & [ ] ,
317+ Resume => & [ ] ,
278318 Return => & [ ] ,
279- Call { data : _ , targets : ref b } => b . as_slice ( ) ,
319+ Call { ref kind , .. } => kind . successors ( ) ,
280320 }
281321 }
282322
283323 pub fn successors_mut ( & mut self ) -> & mut [ BasicBlock ] {
284324 use self :: Terminator :: * ;
285325 match * self {
286326 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 ( ) ,
289328 Switch { targets : ref mut b, .. } => b,
290329 SwitchInt { targets : ref mut b, .. } => b,
291- Diverge => & mut [ ] ,
330+ Resume => & mut [ ] ,
292331 Return => & mut [ ] ,
293- Call { data : _ , targets : ref mut b } => b . as_mut_slice ( ) ,
332+ Call { ref mut kind , .. } => kind . successors_mut ( ) ,
294333 }
295334 }
296335}
297336
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-
310337impl < ' tcx > BasicBlockData < ' tcx > {
311- pub fn new ( terminator : Terminator < ' tcx > ) -> BasicBlockData < ' tcx > {
338+ pub fn new ( terminator : Option < Terminator < ' tcx > > ) -> BasicBlockData < ' tcx > {
312339 BasicBlockData {
313340 statements : vec ! [ ] ,
314341 terminator : terminator,
342+ is_cleanup : false ,
315343 }
316344 }
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+ }
317357}
318358
319359impl < ' tcx > Debug for Terminator < ' tcx > {
@@ -351,15 +391,17 @@ impl<'tcx> Terminator<'tcx> {
351391 use self :: Terminator :: * ;
352392 match * self {
353393 Goto { .. } => write ! ( fmt, "goto" ) ,
354- Panic { .. } => write ! ( fmt, "panic" ) ,
355394 If { cond : ref lv, .. } => write ! ( fmt, "if({:?})" , lv) ,
356395 Switch { discr : ref lv, .. } => write ! ( fmt, "switch({:?})" , lv) ,
357396 SwitchInt { discr : ref lv, .. } => write ! ( fmt, "switchInt({:?})" , lv) ,
358- Diverge => write ! ( fmt, "diverge" ) ,
359397 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 ( ) {
363405 if index > 0 {
364406 try!( write ! ( fmt, ", " ) ) ;
365407 }
@@ -374,10 +416,9 @@ impl<'tcx> Terminator<'tcx> {
374416 pub fn fmt_successor_labels ( & self ) -> Vec < Cow < ' static , str > > {
375417 use self :: Terminator :: * ;
376418 match * self {
377- Diverge | Return => vec ! [ ] ,
378- Goto { .. } | Panic { .. } => vec ! [ "" . into_cow( ) ] ,
419+ Return | Resume => vec ! [ ] ,
420+ Goto { .. } => vec ! [ "" . into_cow( ) ] ,
379421 If { .. } => vec ! [ "true" . into_cow( ) , "false" . into_cow( ) ] ,
380- Call { .. } => vec ! [ "return" . into_cow( ) , "unwind" . into_cow( ) ] ,
381422 Switch { ref adt_def, .. } => {
382423 adt_def. variants
383424 . iter ( )
@@ -394,6 +435,16 @@ impl<'tcx> Terminator<'tcx> {
394435 . chain ( iter:: once ( String :: from ( "otherwise" ) . into_cow ( ) ) )
395436 . collect ( )
396437 }
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+ } ,
397448 }
398449 }
399450}
0 commit comments