diff options
Diffstat (limited to 'compiler/rustc_middle/src/mir/patch.rs')
-rw-r--r-- | compiler/rustc_middle/src/mir/patch.rs | 68 |
1 files changed, 61 insertions, 7 deletions
diff --git a/compiler/rustc_middle/src/mir/patch.rs b/compiler/rustc_middle/src/mir/patch.rs index 24fe3b472..f62853c3e 100644 --- a/compiler/rustc_middle/src/mir/patch.rs +++ b/compiler/rustc_middle/src/mir/patch.rs @@ -12,6 +12,9 @@ pub struct MirPatch<'tcx> { new_statements: Vec<(Location, StatementKind<'tcx>)>, new_locals: Vec<LocalDecl<'tcx>>, resume_block: Option<BasicBlock>, + // Only for unreachable in cleanup path. + unreachable_cleanup_block: Option<BasicBlock>, + terminate_block: Option<BasicBlock>, body_span: Span, next_local: usize, } @@ -25,14 +28,31 @@ impl<'tcx> MirPatch<'tcx> { new_locals: vec![], next_local: body.local_decls.len(), resume_block: None, + unreachable_cleanup_block: None, + terminate_block: None, body_span: body.span, }; - // Check if we already have a resume block for (bb, block) in body.basic_blocks.iter_enumerated() { + // Check if we already have a resume block if let TerminatorKind::Resume = block.terminator().kind && block.statements.is_empty() { result.resume_block = Some(bb); - break; + continue; + } + + // Check if we already have an unreachable block + if let TerminatorKind::Unreachable = block.terminator().kind + && block.statements.is_empty() + && block.is_cleanup + { + result.unreachable_cleanup_block = Some(bb); + continue; + } + + // Check if we already have a terminate block + if let TerminatorKind::Terminate = block.terminator().kind && block.statements.is_empty() { + result.terminate_block = Some(bb); + continue; } } @@ -56,6 +76,40 @@ impl<'tcx> MirPatch<'tcx> { bb } + pub fn unreachable_cleanup_block(&mut self) -> BasicBlock { + if let Some(bb) = self.unreachable_cleanup_block { + return bb; + } + + let bb = self.new_block(BasicBlockData { + statements: vec![], + terminator: Some(Terminator { + source_info: SourceInfo::outermost(self.body_span), + kind: TerminatorKind::Unreachable, + }), + is_cleanup: true, + }); + self.unreachable_cleanup_block = Some(bb); + bb + } + + pub fn terminate_block(&mut self) -> BasicBlock { + if let Some(bb) = self.terminate_block { + return bb; + } + + let bb = self.new_block(BasicBlockData { + statements: vec![], + terminator: Some(Terminator { + source_info: SourceInfo::outermost(self.body_span), + kind: TerminatorKind::Terminate, + }), + is_cleanup: true, + }); + self.terminate_block = Some(bb); + bb + } + pub fn is_patched(&self, bb: BasicBlock) -> bool { self.patch_map[bb].is_some() } @@ -72,28 +126,28 @@ impl<'tcx> MirPatch<'tcx> { &mut self, ty: Ty<'tcx>, span: Span, - local_info: Option<Box<LocalInfo<'tcx>>>, + local_info: LocalInfo<'tcx>, ) -> Local { let index = self.next_local; self.next_local += 1; let mut new_decl = LocalDecl::new(ty, span).internal(); - new_decl.local_info = local_info; + **new_decl.local_info.as_mut().assert_crate_local() = local_info; self.new_locals.push(new_decl); - Local::new(index as usize) + Local::new(index) } pub fn new_temp(&mut self, ty: Ty<'tcx>, span: Span) -> Local { let index = self.next_local; self.next_local += 1; self.new_locals.push(LocalDecl::new(ty, span)); - Local::new(index as usize) + Local::new(index) } pub fn new_internal(&mut self, ty: Ty<'tcx>, span: Span) -> Local { let index = self.next_local; self.next_local += 1; self.new_locals.push(LocalDecl::new(ty, span).internal()); - Local::new(index as usize) + Local::new(index) } pub fn new_block(&mut self, data: BasicBlockData<'tcx>) -> BasicBlock { |