@@ -10,6 +10,7 @@ use std::iter;
1010use std:: slice;
1111
1212pub use super :: query:: * ;
13+ use super :: * ;
1314
1415#[ derive( Debug , Clone , TyEncodable , TyDecodable , Hash , HashStable , PartialEq ) ]
1516pub struct SwitchTargets {
@@ -430,3 +431,108 @@ impl<'tcx> TerminatorKind<'tcx> {
430431 }
431432 }
432433}
434+
435+ #[ derive( Copy , Clone , Debug ) ]
436+ pub enum TerminatorEdges < ' mir , ' tcx > {
437+ /// For terminators that have no successor, like `return`.
438+ None ,
439+ /// For terminators that a single successor, like `goto`, and `assert` without cleanup block.
440+ Single ( BasicBlock ) ,
441+ /// For terminators that two successors, `assert` with cleanup block and `falseEdge`.
442+ Double ( BasicBlock , BasicBlock ) ,
443+ /// Special action for `Yield`, `Call` and `InlineAsm` terminators.
444+ AssignOnReturn {
445+ return_ : Option < BasicBlock > ,
446+ unwind : UnwindAction ,
447+ place : CallReturnPlaces < ' mir , ' tcx > ,
448+ } ,
449+ /// Special edge for `SwitchInt`.
450+ SwitchInt { targets : & ' mir SwitchTargets , discr : & ' mir Operand < ' tcx > } ,
451+ }
452+
453+ /// List of places that are written to after a successful (non-unwind) return
454+ /// from a `Call`, `Yield` or `InlineAsm`.
455+ #[ derive( Copy , Clone , Debug ) ]
456+ pub enum CallReturnPlaces < ' a , ' tcx > {
457+ Call ( Place < ' tcx > ) ,
458+ Yield ( Place < ' tcx > ) ,
459+ InlineAsm ( & ' a [ InlineAsmOperand < ' tcx > ] ) ,
460+ }
461+
462+ impl < ' tcx > CallReturnPlaces < ' _ , ' tcx > {
463+ pub fn for_each ( & self , mut f : impl FnMut ( Place < ' tcx > ) ) {
464+ match * self {
465+ Self :: Call ( place) | Self :: Yield ( place) => f ( place) ,
466+ Self :: InlineAsm ( operands) => {
467+ for op in operands {
468+ match * op {
469+ InlineAsmOperand :: Out { place : Some ( place) , .. }
470+ | InlineAsmOperand :: InOut { out_place : Some ( place) , .. } => f ( place) ,
471+ _ => { }
472+ }
473+ }
474+ }
475+ }
476+ }
477+ }
478+
479+ impl < ' tcx > Terminator < ' tcx > {
480+ pub fn edges ( & self ) -> TerminatorEdges < ' _ , ' tcx > {
481+ self . kind . edges ( )
482+ }
483+ }
484+
485+ impl < ' tcx > TerminatorKind < ' tcx > {
486+ pub fn edges ( & self ) -> TerminatorEdges < ' _ , ' tcx > {
487+ use TerminatorKind :: * ;
488+ match * self {
489+ Return | Resume | Terminate | GeneratorDrop | Unreachable => TerminatorEdges :: None ,
490+
491+ Goto { target } => TerminatorEdges :: Single ( target) ,
492+
493+ Assert { target, unwind, expected : _, msg : _, cond : _ }
494+ | Drop { target, unwind, place : _, replace : _ }
495+ | FalseUnwind { real_target : target, unwind } => match unwind {
496+ UnwindAction :: Cleanup ( unwind) => TerminatorEdges :: Double ( target, unwind) ,
497+ UnwindAction :: Continue | UnwindAction :: Terminate | UnwindAction :: Unreachable => {
498+ TerminatorEdges :: Single ( target)
499+ }
500+ } ,
501+
502+ FalseEdge { real_target, imaginary_target } => {
503+ TerminatorEdges :: Double ( real_target, imaginary_target)
504+ }
505+
506+ Yield { resume : target, drop, resume_arg, value : _ } => {
507+ TerminatorEdges :: AssignOnReturn {
508+ return_ : Some ( target) ,
509+ unwind : drop. map_or ( UnwindAction :: Terminate , UnwindAction :: Cleanup ) ,
510+ place : CallReturnPlaces :: Yield ( resume_arg) ,
511+ }
512+ }
513+
514+ Call { unwind, destination, target, func : _, args : _, fn_span : _, call_source : _ } => {
515+ TerminatorEdges :: AssignOnReturn {
516+ return_ : target,
517+ unwind,
518+ place : CallReturnPlaces :: Call ( destination) ,
519+ }
520+ }
521+
522+ InlineAsm {
523+ template : _,
524+ ref operands,
525+ options : _,
526+ line_spans : _,
527+ destination,
528+ unwind,
529+ } => TerminatorEdges :: AssignOnReturn {
530+ return_ : destination,
531+ unwind,
532+ place : CallReturnPlaces :: InlineAsm ( operands) ,
533+ } ,
534+
535+ SwitchInt { ref targets, ref discr } => TerminatorEdges :: SwitchInt { targets, discr } ,
536+ }
537+ }
538+ }
0 commit comments