mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-28 01:34:21 +00:00
Remove diverge terminator
Unreachable terminator can be contained all within the trans.
This commit is contained in:
parent
5b34690842
commit
4e86dcdb72
@ -51,9 +51,6 @@ pub const START_BLOCK: BasicBlock = BasicBlock(0);
|
|||||||
/// where execution ends, on normal return
|
/// where execution ends, on normal return
|
||||||
pub const END_BLOCK: BasicBlock = BasicBlock(1);
|
pub const END_BLOCK: BasicBlock = BasicBlock(1);
|
||||||
|
|
||||||
/// where execution ends, on panic
|
|
||||||
pub const DIVERGE_BLOCK: BasicBlock = BasicBlock(2);
|
|
||||||
|
|
||||||
impl<'tcx> Mir<'tcx> {
|
impl<'tcx> Mir<'tcx> {
|
||||||
pub fn all_basic_blocks(&self) -> Vec<BasicBlock> {
|
pub fn all_basic_blocks(&self) -> Vec<BasicBlock> {
|
||||||
(0..self.basic_blocks.len())
|
(0..self.basic_blocks.len())
|
||||||
@ -194,7 +191,7 @@ impl Debug for BasicBlock {
|
|||||||
#[derive(Debug, RustcEncodable, RustcDecodable)]
|
#[derive(Debug, RustcEncodable, RustcDecodable)]
|
||||||
pub struct BasicBlockData<'tcx> {
|
pub struct BasicBlockData<'tcx> {
|
||||||
pub statements: Vec<Statement<'tcx>>,
|
pub statements: Vec<Statement<'tcx>>,
|
||||||
pub terminator: Terminator<'tcx>,
|
pub terminator: Option<Terminator<'tcx>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(RustcEncodable, RustcDecodable)]
|
#[derive(RustcEncodable, RustcDecodable)]
|
||||||
@ -237,14 +234,6 @@ pub enum Terminator<'tcx> {
|
|||||||
targets: Vec<BasicBlock>,
|
targets: Vec<BasicBlock>,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Indicates that the last statement in the block panics, aborts,
|
|
||||||
/// etc. No successors. This terminator appears on exactly one
|
|
||||||
/// basic block which we create in advance. However, during
|
|
||||||
/// construction, we use this value as a sentinel for "terminator
|
|
||||||
/// not yet assigned", and assert at the end that only the
|
|
||||||
/// well-known diverging block actually diverges.
|
|
||||||
Diverge,
|
|
||||||
|
|
||||||
/// Indicates that the landing pad is finished and unwinding should
|
/// Indicates that the landing pad is finished and unwinding should
|
||||||
/// continue. Emitted by build::scope::diverge_cleanup.
|
/// continue. Emitted by build::scope::diverge_cleanup.
|
||||||
Resume,
|
Resume,
|
||||||
@ -317,7 +306,6 @@ impl<'tcx> Terminator<'tcx> {
|
|||||||
If { targets: ref b, .. } => b.as_slice(),
|
If { targets: ref b, .. } => b.as_slice(),
|
||||||
Switch { targets: ref b, .. } => b,
|
Switch { targets: ref b, .. } => b,
|
||||||
SwitchInt { targets: ref b, .. } => b,
|
SwitchInt { targets: ref b, .. } => b,
|
||||||
Diverge => &[],
|
|
||||||
Resume => &[],
|
Resume => &[],
|
||||||
Return => &[],
|
Return => &[],
|
||||||
Call { targets: ref b, .. } => b.as_slice(),
|
Call { targets: ref b, .. } => b.as_slice(),
|
||||||
@ -336,7 +324,6 @@ impl<'tcx> Terminator<'tcx> {
|
|||||||
If { targets: ref mut b, .. } => b.as_mut_slice(),
|
If { targets: ref mut b, .. } => b.as_mut_slice(),
|
||||||
Switch { targets: ref mut b, .. } => b,
|
Switch { targets: ref mut b, .. } => b,
|
||||||
SwitchInt { targets: ref mut b, .. } => b,
|
SwitchInt { targets: ref mut b, .. } => b,
|
||||||
Diverge => &mut [],
|
|
||||||
Resume => &mut [],
|
Resume => &mut [],
|
||||||
Return => &mut [],
|
Return => &mut [],
|
||||||
Call { targets: ref mut b, .. } => b.as_mut_slice(),
|
Call { targets: ref mut b, .. } => b.as_mut_slice(),
|
||||||
@ -350,12 +337,24 @@ impl<'tcx> Terminator<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> BasicBlockData<'tcx> {
|
impl<'tcx> BasicBlockData<'tcx> {
|
||||||
pub fn new(terminator: Terminator<'tcx>) -> BasicBlockData<'tcx> {
|
pub fn new(terminator: Option<Terminator<'tcx>>) -> BasicBlockData<'tcx> {
|
||||||
BasicBlockData {
|
BasicBlockData {
|
||||||
statements: vec![],
|
statements: vec![],
|
||||||
terminator: terminator,
|
terminator: terminator,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Accessor for terminator.
|
||||||
|
///
|
||||||
|
/// Terminator may not be None after construction of the basic block is complete. This accessor
|
||||||
|
/// provides a convenience way to reach the terminator.
|
||||||
|
pub fn terminator(&self) -> &Terminator<'tcx> {
|
||||||
|
self.terminator.as_ref().expect("invalid terminator state")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn terminator_mut(&mut self) -> &mut Terminator<'tcx> {
|
||||||
|
self.terminator.as_mut().expect("invalid terminator state")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Debug for Terminator<'tcx> {
|
impl<'tcx> Debug for Terminator<'tcx> {
|
||||||
@ -396,7 +395,6 @@ impl<'tcx> Terminator<'tcx> {
|
|||||||
If { cond: ref lv, .. } => write!(fmt, "if({:?})", lv),
|
If { cond: ref lv, .. } => write!(fmt, "if({:?})", lv),
|
||||||
Switch { discr: ref lv, .. } => write!(fmt, "switch({:?})", lv),
|
Switch { discr: ref lv, .. } => write!(fmt, "switch({:?})", lv),
|
||||||
SwitchInt { discr: ref lv, .. } => write!(fmt, "switchInt({:?})", lv),
|
SwitchInt { discr: ref lv, .. } => write!(fmt, "switchInt({:?})", lv),
|
||||||
Diverge => write!(fmt, "diverge"),
|
|
||||||
Return => write!(fmt, "return"),
|
Return => write!(fmt, "return"),
|
||||||
Resume => write!(fmt, "resume"),
|
Resume => write!(fmt, "resume"),
|
||||||
Call { .. } => {
|
Call { .. } => {
|
||||||
@ -414,7 +412,7 @@ impl<'tcx> Terminator<'tcx> {
|
|||||||
pub fn fmt_successor_labels(&self) -> Vec<Cow<'static, str>> {
|
pub fn fmt_successor_labels(&self) -> Vec<Cow<'static, str>> {
|
||||||
use self::Terminator::*;
|
use self::Terminator::*;
|
||||||
match *self {
|
match *self {
|
||||||
Diverge | Return | Resume => vec![],
|
Return | Resume => vec![],
|
||||||
Goto { .. } => vec!["".into_cow()],
|
Goto { .. } => vec!["".into_cow()],
|
||||||
If { .. } => vec!["true".into_cow(), "false".into_cow()],
|
If { .. } => vec!["true".into_cow(), "false".into_cow()],
|
||||||
Call { .. } => vec!["return".into_cow(), "unwind".into_cow()],
|
Call { .. } => vec!["return".into_cow(), "unwind".into_cow()],
|
||||||
|
@ -84,7 +84,7 @@ pub trait Visitor<'tcx> {
|
|||||||
for statement in &data.statements {
|
for statement in &data.statements {
|
||||||
self.visit_statement(block, statement);
|
self.visit_statement(block, statement);
|
||||||
}
|
}
|
||||||
self.visit_terminator(block, &data.terminator);
|
data.terminator.as_ref().map(|r| self.visit_terminator(block, r));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn super_statement(&mut self, block: BasicBlock, statement: &Statement<'tcx>) {
|
fn super_statement(&mut self, block: BasicBlock, statement: &Statement<'tcx>) {
|
||||||
@ -132,7 +132,6 @@ pub trait Visitor<'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Terminator::Diverge |
|
|
||||||
Terminator::Resume |
|
Terminator::Resume |
|
||||||
Terminator::Return => {
|
Terminator::Return => {
|
||||||
}
|
}
|
||||||
@ -374,7 +373,7 @@ pub trait MutVisitor<'tcx> {
|
|||||||
for statement in &mut data.statements {
|
for statement in &mut data.statements {
|
||||||
self.visit_statement(block, statement);
|
self.visit_statement(block, statement);
|
||||||
}
|
}
|
||||||
self.visit_terminator(block, &mut data.terminator);
|
data.terminator.as_mut().map(|r| self.visit_terminator(block, r));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn super_statement(&mut self,
|
fn super_statement(&mut self,
|
||||||
@ -429,7 +428,6 @@ pub trait MutVisitor<'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Terminator::Diverge |
|
|
||||||
Terminator::Resume |
|
Terminator::Resume |
|
||||||
Terminator::Return => {
|
Terminator::Return => {
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ impl<'tcx> CFG<'tcx> {
|
|||||||
|
|
||||||
pub fn start_new_block(&mut self) -> BasicBlock {
|
pub fn start_new_block(&mut self) -> BasicBlock {
|
||||||
let node_index = self.basic_blocks.len();
|
let node_index = self.basic_blocks.len();
|
||||||
self.basic_blocks.push(BasicBlockData::new(Terminator::Diverge));
|
self.basic_blocks.push(BasicBlockData::new(None));
|
||||||
BasicBlock::new(node_index)
|
BasicBlock::new(node_index)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,15 +67,9 @@ impl<'tcx> CFG<'tcx> {
|
|||||||
pub fn terminate(&mut self,
|
pub fn terminate(&mut self,
|
||||||
block: BasicBlock,
|
block: BasicBlock,
|
||||||
terminator: Terminator<'tcx>) {
|
terminator: Terminator<'tcx>) {
|
||||||
// Check whether this block has already been terminated. For
|
debug_assert!(self.block_data(block).terminator.is_none(),
|
||||||
// this, we rely on the fact that the initial state is to have
|
|
||||||
// a Diverge terminator and an empty list of targets (which
|
|
||||||
// is not a valid state).
|
|
||||||
debug_assert!(match self.block_data(block).terminator { Terminator::Diverge => true,
|
|
||||||
_ => false },
|
|
||||||
"terminate: block {:?} already has a terminator set", block);
|
"terminate: block {:?} already has a terminator set", block);
|
||||||
|
self.block_data_mut(block).terminator = Some(terminator);
|
||||||
self.block_data_mut(block).terminator = terminator;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,7 +107,6 @@ pub fn construct<'a,'tcx>(mut hir: Cx<'a,'tcx>,
|
|||||||
|
|
||||||
assert_eq!(builder.cfg.start_new_block(), START_BLOCK);
|
assert_eq!(builder.cfg.start_new_block(), START_BLOCK);
|
||||||
assert_eq!(builder.cfg.start_new_block(), END_BLOCK);
|
assert_eq!(builder.cfg.start_new_block(), END_BLOCK);
|
||||||
assert_eq!(builder.cfg.start_new_block(), DIVERGE_BLOCK);
|
|
||||||
|
|
||||||
let mut block = START_BLOCK;
|
let mut block = START_BLOCK;
|
||||||
let arg_decls = unpack!(block = builder.args_and_body(block,
|
let arg_decls = unpack!(block = builder.args_and_body(block,
|
||||||
|
@ -62,7 +62,7 @@ fn write_node<W: Write>(block: BasicBlock, mir: &Mir, w: &mut W) -> io::Result<(
|
|||||||
// Terminator head at the bottom, not including the list of successor blocks. Those will be
|
// Terminator head at the bottom, not including the list of successor blocks. Those will be
|
||||||
// displayed as labels on the edges between blocks.
|
// displayed as labels on the edges between blocks.
|
||||||
let mut terminator_head = String::new();
|
let mut terminator_head = String::new();
|
||||||
data.terminator.fmt_head(&mut terminator_head).unwrap();
|
data.terminator().fmt_head(&mut terminator_head).unwrap();
|
||||||
try!(write!(w, r#"<tr><td align="left">{}</td></tr>"#, dot::escape_html(&terminator_head)));
|
try!(write!(w, r#"<tr><td align="left">{}</td></tr>"#, dot::escape_html(&terminator_head)));
|
||||||
|
|
||||||
// Close the table, node label, and the node itself.
|
// Close the table, node label, and the node itself.
|
||||||
@ -71,7 +71,7 @@ fn write_node<W: Write>(block: BasicBlock, mir: &Mir, w: &mut W) -> io::Result<(
|
|||||||
|
|
||||||
/// Write graphviz DOT edges with labels between the given basic block and all of its successors.
|
/// Write graphviz DOT edges with labels between the given basic block and all of its successors.
|
||||||
fn write_edges<W: Write>(source: BasicBlock, mir: &Mir, w: &mut W) -> io::Result<()> {
|
fn write_edges<W: Write>(source: BasicBlock, mir: &Mir, w: &mut W) -> io::Result<()> {
|
||||||
let terminator = &mir.basic_block_data(source).terminator;
|
let terminator = &mir.basic_block_data(source).terminator();
|
||||||
let labels = terminator.fmt_successor_labels();
|
let labels = terminator.fmt_successor_labels();
|
||||||
|
|
||||||
for (&target, label) in terminator.successors().iter().zip(labels) {
|
for (&target, label) in terminator.successors().iter().zip(labels) {
|
||||||
|
@ -59,7 +59,7 @@ impl<'a, 'tcx> EraseRegions<'a, 'tcx> {
|
|||||||
self.erase_regions_statement(statement);
|
self.erase_regions_statement(statement);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.erase_regions_terminator(&mut basic_block.terminator);
|
self.erase_regions_terminator(basic_block.terminator_mut());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn erase_regions_statement(&mut self,
|
fn erase_regions_statement(&mut self,
|
||||||
@ -79,7 +79,6 @@ impl<'a, 'tcx> EraseRegions<'a, 'tcx> {
|
|||||||
terminator: &mut Terminator<'tcx>) {
|
terminator: &mut Terminator<'tcx>) {
|
||||||
match *terminator {
|
match *terminator {
|
||||||
Terminator::Goto { .. } |
|
Terminator::Goto { .. } |
|
||||||
Terminator::Diverge |
|
|
||||||
Terminator::Resume |
|
Terminator::Resume |
|
||||||
Terminator::Return => {
|
Terminator::Return => {
|
||||||
/* nothing to do */
|
/* nothing to do */
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
|
|
||||||
use rustc::middle::const_eval::ConstVal;
|
use rustc::middle::const_eval::ConstVal;
|
||||||
use rustc::mir::repr::*;
|
use rustc::mir::repr::*;
|
||||||
use std::mem;
|
|
||||||
use transform::util;
|
use transform::util;
|
||||||
use transform::MirPass;
|
use transform::MirPass;
|
||||||
|
|
||||||
@ -27,11 +26,10 @@ impl SimplifyCfg {
|
|||||||
// These blocks are always required.
|
// These blocks are always required.
|
||||||
seen[START_BLOCK.index()] = true;
|
seen[START_BLOCK.index()] = true;
|
||||||
seen[END_BLOCK.index()] = true;
|
seen[END_BLOCK.index()] = true;
|
||||||
seen[DIVERGE_BLOCK.index()] = true;
|
|
||||||
|
|
||||||
let mut worklist = vec![START_BLOCK];
|
let mut worklist = vec![START_BLOCK];
|
||||||
while let Some(bb) = worklist.pop() {
|
while let Some(bb) = worklist.pop() {
|
||||||
for succ in mir.basic_block_data(bb).terminator.successors() {
|
for succ in mir.basic_block_data(bb).terminator().successors() {
|
||||||
if !seen[succ.index()] {
|
if !seen[succ.index()] {
|
||||||
seen[succ.index()] = true;
|
seen[succ.index()] = true;
|
||||||
worklist.push(*succ);
|
worklist.push(*succ);
|
||||||
@ -51,7 +49,7 @@ impl SimplifyCfg {
|
|||||||
|
|
||||||
while mir.basic_block_data(target).statements.is_empty() {
|
while mir.basic_block_data(target).statements.is_empty() {
|
||||||
match mir.basic_block_data(target).terminator {
|
match mir.basic_block_data(target).terminator {
|
||||||
Terminator::Goto { target: next } => {
|
Some(Terminator::Goto { target: next }) => {
|
||||||
if seen.contains(&next) {
|
if seen.contains(&next) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@ -67,9 +65,9 @@ impl SimplifyCfg {
|
|||||||
|
|
||||||
let mut changed = false;
|
let mut changed = false;
|
||||||
for bb in mir.all_basic_blocks() {
|
for bb in mir.all_basic_blocks() {
|
||||||
// Temporarily swap out the terminator we're modifying to keep borrowck happy
|
// Temporarily take ownership of the terminator we're modifying to keep borrowck happy
|
||||||
let mut terminator = Terminator::Diverge;
|
let mut terminator = mir.basic_block_data_mut(bb).terminator.take()
|
||||||
mem::swap(&mut terminator, &mut mir.basic_block_data_mut(bb).terminator);
|
.expect("invalid terminator state");
|
||||||
|
|
||||||
for target in terminator.successors_mut() {
|
for target in terminator.successors_mut() {
|
||||||
let new_target = match final_target(mir, *target) {
|
let new_target = match final_target(mir, *target) {
|
||||||
@ -80,10 +78,8 @@ impl SimplifyCfg {
|
|||||||
changed |= *target != new_target;
|
changed |= *target != new_target;
|
||||||
*target = new_target;
|
*target = new_target;
|
||||||
}
|
}
|
||||||
|
mir.basic_block_data_mut(bb).terminator = Some(terminator);
|
||||||
mir.basic_block_data_mut(bb).terminator = terminator;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
changed
|
changed
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,11 +87,10 @@ impl SimplifyCfg {
|
|||||||
let mut changed = false;
|
let mut changed = false;
|
||||||
|
|
||||||
for bb in mir.all_basic_blocks() {
|
for bb in mir.all_basic_blocks() {
|
||||||
// Temporarily swap out the terminator we're modifying to keep borrowck happy
|
let basic_block = mir.basic_block_data_mut(bb);
|
||||||
let mut terminator = Terminator::Diverge;
|
let mut terminator = basic_block.terminator_mut();
|
||||||
mem::swap(&mut terminator, &mut mir.basic_block_data_mut(bb).terminator);
|
|
||||||
|
|
||||||
mir.basic_block_data_mut(bb).terminator = match terminator {
|
*terminator = match *terminator {
|
||||||
Terminator::If { ref targets, .. } if targets.0 == targets.1 => {
|
Terminator::If { ref targets, .. } if targets.0 == targets.1 => {
|
||||||
changed = true;
|
changed = true;
|
||||||
Terminator::Goto { target: targets.0 }
|
Terminator::Goto { target: targets.0 }
|
||||||
@ -115,7 +110,7 @@ impl SimplifyCfg {
|
|||||||
Terminator::SwitchInt { ref targets, .. } if targets.len() == 1 => {
|
Terminator::SwitchInt { ref targets, .. } if targets.len() == 1 => {
|
||||||
Terminator::Goto { target: targets[0] }
|
Terminator::Goto { target: targets[0] }
|
||||||
}
|
}
|
||||||
_ => terminator
|
_ => continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,7 +126,6 @@ impl<'tcx> MirPass<'tcx> for SimplifyCfg {
|
|||||||
changed |= self.remove_goto_chains(mir);
|
changed |= self.remove_goto_chains(mir);
|
||||||
self.remove_dead_blocks(mir);
|
self.remove_dead_blocks(mir);
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Should probably be moved into some kind of pass manager
|
// FIXME: Should probably be moved into some kind of pass manager
|
||||||
mir.basic_blocks.shrink_to_fit();
|
mir.basic_blocks.shrink_to_fit();
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ use rustc::mir::repr::*;
|
|||||||
/// in a single pass
|
/// in a single pass
|
||||||
pub fn update_basic_block_ids(mir: &mut Mir, replacements: &[BasicBlock]) {
|
pub fn update_basic_block_ids(mir: &mut Mir, replacements: &[BasicBlock]) {
|
||||||
for bb in mir.all_basic_blocks() {
|
for bb in mir.all_basic_blocks() {
|
||||||
for target in mir.basic_block_data_mut(bb).terminator.successors_mut() {
|
for target in mir.basic_block_data_mut(bb).terminator_mut().successors_mut() {
|
||||||
*target = replacements[target.index()];
|
*target = replacements[target.index()];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,9 +33,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||||||
bcx = self.trans_statement(bcx, statement);
|
bcx = self.trans_statement(bcx, statement);
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("trans_block: terminator: {:?}", data.terminator);
|
debug!("trans_block: terminator: {:?}", data.terminator());
|
||||||
|
|
||||||
match data.terminator {
|
match *data.terminator() {
|
||||||
mir::Terminator::Goto { target } => {
|
mir::Terminator::Goto { target } => {
|
||||||
build::Br(bcx, self.llblock(target), DebugLoc::None)
|
build::Br(bcx, self.llblock(target), DebugLoc::None)
|
||||||
}
|
}
|
||||||
@ -82,10 +82,6 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mir::Terminator::Diverge => {
|
|
||||||
build::Unreachable(bcx);
|
|
||||||
}
|
|
||||||
|
|
||||||
mir::Terminator::Resume => {
|
mir::Terminator::Resume => {
|
||||||
if let Some(llpersonalityslot) = self.llpersonalityslot {
|
if let Some(llpersonalityslot) = self.llpersonalityslot {
|
||||||
let lp = build::Load(bcx, llpersonalityslot);
|
let lp = build::Load(bcx, llpersonalityslot);
|
||||||
|
@ -125,16 +125,11 @@ pub fn trans_mir<'bcx, 'tcx>(bcx: Block<'bcx, 'tcx>) {
|
|||||||
|
|
||||||
// Translate the body of each block
|
// Translate the body of each block
|
||||||
for &bb in &mir_blocks {
|
for &bb in &mir_blocks {
|
||||||
if bb != mir::DIVERGE_BLOCK {
|
// NB that we do not handle the Resume terminator specially, because a block containing
|
||||||
|
// that terminator will have a higher block number than a function call which should take
|
||||||
|
// care of filling in that information.
|
||||||
mircx.trans_block(bb);
|
mircx.trans_block(bb);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Total hack: translate DIVERGE_BLOCK last. This is so that any
|
|
||||||
// panics which the fn may do can initialize the
|
|
||||||
// `llpersonalityslot` cell. We don't do this up front because the
|
|
||||||
// LLVM type of it is (frankly) annoying to compute.
|
|
||||||
mircx.trans_block(mir::DIVERGE_BLOCK);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Produce, for each argument, a `ValueRef` pointing at the
|
/// Produce, for each argument, a `ValueRef` pointing at the
|
||||||
|
Loading…
Reference in New Issue
Block a user