summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_middle/src/mir/patch.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_middle/src/mir/patch.rs')
-rw-r--r--compiler/rustc_middle/src/mir/patch.rs68
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 {