@@ -11,6 +11,11 @@ use rustc_middle::{
1111} ;
1212use rustc_span:: def_id:: DefId ;
1313
14+ enum EdgeKind {
15+ Unwind ,
16+ Other ,
17+ }
18+
1419pub struct Validator {
1520 /// Describes at which point in the pipeline this validation is happening.
1621 pub when : String ,
@@ -49,8 +54,25 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
4954 ) ;
5055 }
5156
52- fn check_bb ( & self , location : Location , bb : BasicBlock ) {
53- if self . body . basic_blocks ( ) . get ( bb) . is_none ( ) {
57+ fn check_bb ( & self , location : Location , bb : BasicBlock , edge_kind : EdgeKind ) {
58+ if let Some ( bb) = self . body . basic_blocks ( ) . get ( bb) {
59+ let src = self . body . basic_blocks ( ) . get ( location. block ) . unwrap ( ) ;
60+ match ( src. is_cleanup , bb. is_cleanup , edge_kind) {
61+ // Non-cleanup blocks can jump to non-cleanup blocks along non-unwind edges
62+ ( false , false , EdgeKind :: Other )
63+ // Non-cleanup blocks can jump to cleanup blocks along unwind edges
64+ | ( false , true , EdgeKind :: Unwind )
65+ // Cleanup blocks can jump to cleanup blocks along unwind edges
66+ | ( true , true , EdgeKind :: Unwind ) => { }
67+ // All other jumps are invalid
68+ _ => {
69+ self . fail (
70+ location,
71+ format ! ( "encountered jump that does not respect unwind invariants {:?}" , bb)
72+ )
73+ }
74+ }
75+ } else {
5476 self . fail ( location, format ! ( "encountered jump to invalid basic block {:?}" , bb) )
5577 }
5678 }
@@ -92,7 +114,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
92114 fn visit_terminator ( & mut self , terminator : & Terminator < ' tcx > , location : Location ) {
93115 match & terminator. kind {
94116 TerminatorKind :: Goto { target } => {
95- self . check_bb ( location, * target) ;
117+ self . check_bb ( location, * target, EdgeKind :: Other ) ;
96118 }
97119 TerminatorKind :: SwitchInt { targets, values, .. } => {
98120 if targets. len ( ) != values. len ( ) + 1 {
@@ -106,19 +128,19 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
106128 ) ;
107129 }
108130 for target in targets {
109- self . check_bb ( location, * target) ;
131+ self . check_bb ( location, * target, EdgeKind :: Other ) ;
110132 }
111133 }
112134 TerminatorKind :: Drop { target, unwind, .. } => {
113- self . check_bb ( location, * target) ;
135+ self . check_bb ( location, * target, EdgeKind :: Other ) ;
114136 if let Some ( unwind) = unwind {
115- self . check_bb ( location, * unwind) ;
137+ self . check_bb ( location, * unwind, EdgeKind :: Unwind ) ;
116138 }
117139 }
118140 TerminatorKind :: DropAndReplace { target, unwind, .. } => {
119- self . check_bb ( location, * target) ;
141+ self . check_bb ( location, * target, EdgeKind :: Other ) ;
120142 if let Some ( unwind) = unwind {
121- self . check_bb ( location, * unwind) ;
143+ self . check_bb ( location, * unwind, EdgeKind :: Unwind ) ;
122144 }
123145 }
124146 TerminatorKind :: Call { func, destination, cleanup, .. } => {
@@ -131,10 +153,10 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
131153 ) ,
132154 }
133155 if let Some ( ( _, target) ) = destination {
134- self . check_bb ( location, * target) ;
156+ self . check_bb ( location, * target, EdgeKind :: Other ) ;
135157 }
136158 if let Some ( cleanup) = cleanup {
137- self . check_bb ( location, * cleanup) ;
159+ self . check_bb ( location, * cleanup, EdgeKind :: Unwind ) ;
138160 }
139161 }
140162 TerminatorKind :: Assert { cond, target, cleanup, .. } => {
@@ -148,30 +170,30 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
148170 ) ,
149171 ) ;
150172 }
151- self . check_bb ( location, * target) ;
173+ self . check_bb ( location, * target, EdgeKind :: Other ) ;
152174 if let Some ( cleanup) = cleanup {
153- self . check_bb ( location, * cleanup) ;
175+ self . check_bb ( location, * cleanup, EdgeKind :: Unwind ) ;
154176 }
155177 }
156178 TerminatorKind :: Yield { resume, drop, .. } => {
157- self . check_bb ( location, * resume) ;
179+ self . check_bb ( location, * resume, EdgeKind :: Other ) ;
158180 if let Some ( drop) = drop {
159- self . check_bb ( location, * drop) ;
181+ self . check_bb ( location, * drop, EdgeKind :: Other ) ;
160182 }
161183 }
162184 TerminatorKind :: FalseEdge { real_target, imaginary_target } => {
163- self . check_bb ( location, * real_target) ;
164- self . check_bb ( location, * imaginary_target) ;
185+ self . check_bb ( location, * real_target, EdgeKind :: Other ) ;
186+ self . check_bb ( location, * imaginary_target, EdgeKind :: Other ) ;
165187 }
166188 TerminatorKind :: FalseUnwind { real_target, unwind } => {
167- self . check_bb ( location, * real_target) ;
189+ self . check_bb ( location, * real_target, EdgeKind :: Other ) ;
168190 if let Some ( unwind) = unwind {
169- self . check_bb ( location, * unwind) ;
191+ self . check_bb ( location, * unwind, EdgeKind :: Unwind ) ;
170192 }
171193 }
172194 TerminatorKind :: InlineAsm { destination, .. } => {
173195 if let Some ( destination) = destination {
174- self . check_bb ( location, * destination) ;
196+ self . check_bb ( location, * destination, EdgeKind :: Other ) ;
175197 }
176198 }
177199 // Nothing to validate for these.
0 commit comments