mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-26 08:44:35 +00:00
Auto merge of #31600 - nagisa:mir-msvc-seh-2, r=nikomatsakis
r? @alexcrichton for the translator changes and @nikomatsakis for the no-landing-pads pass.
This commit is contained in:
commit
de366b5218
@ -22,7 +22,7 @@ extern crate rustc_front;
|
|||||||
use build;
|
use build;
|
||||||
use graphviz;
|
use graphviz;
|
||||||
use pretty;
|
use pretty;
|
||||||
use transform::simplify_cfg;
|
use transform::{simplify_cfg, no_landing_pads};
|
||||||
use rustc::dep_graph::DepNode;
|
use rustc::dep_graph::DepNode;
|
||||||
use rustc::mir::repr::Mir;
|
use rustc::mir::repr::Mir;
|
||||||
use hair::cx::Cx;
|
use hair::cx::Cx;
|
||||||
@ -148,6 +148,7 @@ impl<'a, 'm, 'tcx> Visitor<'tcx> for InnerDump<'a,'m,'tcx> {
|
|||||||
|
|
||||||
match build_mir(Cx::new(&infcx), implicit_arg_tys, id, span, decl, body) {
|
match build_mir(Cx::new(&infcx), implicit_arg_tys, id, span, decl, body) {
|
||||||
Ok(mut mir) => {
|
Ok(mut mir) => {
|
||||||
|
no_landing_pads::NoLandingPads.run_on_mir(&mut mir, self.tcx);
|
||||||
simplify_cfg::SimplifyCfg::new().run_on_mir(&mut mir, self.tcx);
|
simplify_cfg::SimplifyCfg::new().run_on_mir(&mut mir, self.tcx);
|
||||||
|
|
||||||
let meta_item_list = self.attr
|
let meta_item_list = self.attr
|
||||||
|
@ -10,4 +10,5 @@
|
|||||||
|
|
||||||
pub mod simplify_cfg;
|
pub mod simplify_cfg;
|
||||||
pub mod erase_regions;
|
pub mod erase_regions;
|
||||||
|
pub mod no_landing_pads;
|
||||||
mod util;
|
mod util;
|
||||||
|
49
src/librustc_mir/transform/no_landing_pads.rs
Normal file
49
src/librustc_mir/transform/no_landing_pads.rs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
//! This pass removes the unwind branch of all the terminators when the no-landing-pads option is
|
||||||
|
//! specified.
|
||||||
|
|
||||||
|
use rustc::middle::ty;
|
||||||
|
use rustc::mir::repr::*;
|
||||||
|
use rustc::mir::visit::MutVisitor;
|
||||||
|
use rustc::mir::transform::MirPass;
|
||||||
|
|
||||||
|
pub struct NoLandingPads;
|
||||||
|
|
||||||
|
impl<'tcx> MutVisitor<'tcx> for NoLandingPads {
|
||||||
|
fn visit_terminator(&mut self, bb: BasicBlock, terminator: &mut Terminator<'tcx>) {
|
||||||
|
match *terminator {
|
||||||
|
Terminator::Goto { .. } |
|
||||||
|
Terminator::Resume |
|
||||||
|
Terminator::Return |
|
||||||
|
Terminator::If { .. } |
|
||||||
|
Terminator::Switch { .. } |
|
||||||
|
Terminator::SwitchInt { .. } => {
|
||||||
|
/* nothing to do */
|
||||||
|
},
|
||||||
|
Terminator::Drop { ref mut unwind, .. } => {
|
||||||
|
unwind.take();
|
||||||
|
},
|
||||||
|
Terminator::Call { ref mut cleanup, .. } => {
|
||||||
|
cleanup.take();
|
||||||
|
},
|
||||||
|
}
|
||||||
|
self.super_terminator(bb, terminator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MirPass for NoLandingPads {
|
||||||
|
fn run_on_mir<'tcx>(&mut self, mir: &mut Mir<'tcx>, tcx: &ty::ctxt<'tcx>) {
|
||||||
|
if tcx.sess.no_landing_pads() {
|
||||||
|
self.visit_mir(mir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -767,6 +767,10 @@ impl<'blk, 'tcx> BlockAndBuilder<'blk, 'tcx> {
|
|||||||
{
|
{
|
||||||
self.bcx.monomorphize(value)
|
self.bcx.monomorphize(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_lpad(&self, lpad: Option<LandingPad>) {
|
||||||
|
self.bcx.lpad.set(lpad.map(|p| &*self.fcx().lpad_arena.alloc(p)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'blk, 'tcx> Deref for BlockAndBuilder<'blk, 'tcx> {
|
impl<'blk, 'tcx> Deref for BlockAndBuilder<'blk, 'tcx> {
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use llvm::{BasicBlockRef, ValueRef};
|
use llvm::{BasicBlockRef, ValueRef, OperandBundleDef};
|
||||||
use rustc::middle::ty;
|
use rustc::middle::ty;
|
||||||
use rustc::mir::repr as mir;
|
use rustc::mir::repr as mir;
|
||||||
use syntax::abi::Abi;
|
use syntax::abi::Abi;
|
||||||
@ -34,6 +34,18 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||||||
let mut bcx = self.bcx(bb);
|
let mut bcx = self.bcx(bb);
|
||||||
let data = self.mir.basic_block_data(bb);
|
let data = self.mir.basic_block_data(bb);
|
||||||
|
|
||||||
|
// MSVC SEH bits
|
||||||
|
let (cleanup_pad, cleanup_bundle) = if let Some((cp, cb)) = self.make_cleanup_pad(bb) {
|
||||||
|
(Some(cp), Some(cb))
|
||||||
|
} else {
|
||||||
|
(None, None)
|
||||||
|
};
|
||||||
|
let funclet_br = |bcx: BlockAndBuilder, llbb: BasicBlockRef| if let Some(cp) = cleanup_pad {
|
||||||
|
bcx.cleanup_ret(cp, Some(llbb));
|
||||||
|
} else {
|
||||||
|
bcx.br(llbb);
|
||||||
|
};
|
||||||
|
|
||||||
for statement in &data.statements {
|
for statement in &data.statements {
|
||||||
bcx = self.trans_statement(bcx, statement);
|
bcx = self.trans_statement(bcx, statement);
|
||||||
}
|
}
|
||||||
@ -41,8 +53,21 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||||||
debug!("trans_block: terminator: {:?}", data.terminator());
|
debug!("trans_block: terminator: {:?}", data.terminator());
|
||||||
|
|
||||||
match *data.terminator() {
|
match *data.terminator() {
|
||||||
|
mir::Terminator::Resume => {
|
||||||
|
if let Some(cleanup_pad) = cleanup_pad {
|
||||||
|
bcx.cleanup_ret(cleanup_pad, None);
|
||||||
|
} else {
|
||||||
|
let ps = self.get_personality_slot(&bcx);
|
||||||
|
let lp = bcx.load(ps);
|
||||||
|
bcx.with_block(|bcx| {
|
||||||
|
base::call_lifetime_end(bcx, ps);
|
||||||
|
base::trans_unwind_resume(bcx, lp);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mir::Terminator::Goto { target } => {
|
mir::Terminator::Goto { target } => {
|
||||||
bcx.br(self.llblock(target));
|
funclet_br(bcx, self.llblock(target));
|
||||||
}
|
}
|
||||||
|
|
||||||
mir::Terminator::If { ref cond, targets: (true_bb, false_bb) } => {
|
mir::Terminator::If { ref cond, targets: (true_bb, false_bb) } => {
|
||||||
@ -85,19 +110,10 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mir::Terminator::Resume => {
|
|
||||||
let ps = self.get_personality_slot(&bcx);
|
|
||||||
let lp = bcx.load(ps);
|
|
||||||
bcx.with_block(|bcx| {
|
|
||||||
base::call_lifetime_end(bcx, ps);
|
|
||||||
base::trans_unwind_resume(bcx, lp);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
mir::Terminator::Return => {
|
mir::Terminator::Return => {
|
||||||
let return_ty = bcx.monomorphize(&self.mir.return_ty);
|
let return_ty = bcx.monomorphize(&self.mir.return_ty);
|
||||||
bcx.with_block(|bcx| {
|
bcx.with_block(|bcx| {
|
||||||
base::build_return_block(bcx.fcx, bcx, return_ty, DebugLoc::None);
|
base::build_return_block(self.fcx, bcx, return_ty, DebugLoc::None);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,7 +122,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||||||
let ty = lvalue.ty.to_ty(bcx.tcx());
|
let ty = lvalue.ty.to_ty(bcx.tcx());
|
||||||
// Double check for necessity to drop
|
// Double check for necessity to drop
|
||||||
if !glue::type_needs_drop(bcx.tcx(), ty) {
|
if !glue::type_needs_drop(bcx.tcx(), ty) {
|
||||||
bcx.br(self.llblock(target));
|
funclet_br(bcx, self.llblock(target));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let drop_fn = glue::get_drop_glue(bcx.ccx(), ty);
|
let drop_fn = glue::get_drop_glue(bcx.ccx(), ty);
|
||||||
@ -123,11 +139,11 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||||||
&[llvalue],
|
&[llvalue],
|
||||||
self.llblock(target),
|
self.llblock(target),
|
||||||
unwind.llbb(),
|
unwind.llbb(),
|
||||||
None,
|
cleanup_bundle.as_ref(),
|
||||||
None);
|
None);
|
||||||
} else {
|
} else {
|
||||||
bcx.call(drop_fn, &[llvalue], None, None);
|
bcx.call(drop_fn, &[llvalue], cleanup_bundle.as_ref(), None);
|
||||||
bcx.br(self.llblock(target));
|
funclet_br(bcx, self.llblock(target));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,11 +196,10 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let avoid_invoke = bcx.with_block(|bcx| base::avoid_invoke(bcx));
|
|
||||||
// Many different ways to call a function handled here
|
// Many different ways to call a function handled here
|
||||||
match (is_foreign, avoid_invoke, cleanup, destination) {
|
match (is_foreign, cleanup, destination) {
|
||||||
// The two cases below are the only ones to use LLVM’s `invoke`.
|
// The two cases below are the only ones to use LLVM’s `invoke`.
|
||||||
(false, false, &Some(cleanup), &None) => {
|
(false, &Some(cleanup), &None) => {
|
||||||
let cleanup = self.bcx(cleanup);
|
let cleanup = self.bcx(cleanup);
|
||||||
let landingpad = self.make_landing_pad(cleanup);
|
let landingpad = self.make_landing_pad(cleanup);
|
||||||
let unreachable_blk = self.unreachable_block();
|
let unreachable_blk = self.unreachable_block();
|
||||||
@ -192,14 +207,14 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||||||
&llargs[..],
|
&llargs[..],
|
||||||
unreachable_blk.llbb,
|
unreachable_blk.llbb,
|
||||||
landingpad.llbb(),
|
landingpad.llbb(),
|
||||||
None,
|
cleanup_bundle.as_ref(),
|
||||||
Some(attrs));
|
Some(attrs));
|
||||||
},
|
},
|
||||||
(false, false, &Some(cleanup), &Some((_, success))) => {
|
(false, &Some(cleanup), &Some((_, success))) => {
|
||||||
let cleanup = self.bcx(cleanup);
|
let cleanup = self.bcx(cleanup);
|
||||||
let landingpad = self.make_landing_pad(cleanup);
|
let landingpad = self.make_landing_pad(cleanup);
|
||||||
let (target, postinvoke) = if must_copy_dest {
|
let (target, postinvoke) = if must_copy_dest {
|
||||||
(bcx.fcx().new_block("", None).build(), Some(self.bcx(success)))
|
(self.fcx.new_block("", None).build(), Some(self.bcx(success)))
|
||||||
} else {
|
} else {
|
||||||
(self.bcx(success), None)
|
(self.bcx(success), None)
|
||||||
};
|
};
|
||||||
@ -207,7 +222,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||||||
&llargs[..],
|
&llargs[..],
|
||||||
target.llbb(),
|
target.llbb(),
|
||||||
landingpad.llbb(),
|
landingpad.llbb(),
|
||||||
None,
|
cleanup_bundle.as_ref(),
|
||||||
Some(attrs));
|
Some(attrs));
|
||||||
if let Some(postinvoketarget) = postinvoke {
|
if let Some(postinvoketarget) = postinvoke {
|
||||||
// We translate the copy into a temporary block. The temporary block is
|
// We translate the copy into a temporary block. The temporary block is
|
||||||
@ -242,14 +257,17 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||||||
target.br(postinvoketarget.llbb());
|
target.br(postinvoketarget.llbb());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
(false, _, _, &None) => {
|
(false, _, &None) => {
|
||||||
bcx.call(callee.immediate(), &llargs[..], None, Some(attrs));
|
bcx.call(callee.immediate(),
|
||||||
|
&llargs[..],
|
||||||
|
cleanup_bundle.as_ref(),
|
||||||
|
Some(attrs));
|
||||||
bcx.unreachable();
|
bcx.unreachable();
|
||||||
}
|
}
|
||||||
(false, _, _, &Some((_, target))) => {
|
(false, _, &Some((_, target))) => {
|
||||||
let llret = bcx.call(callee.immediate(),
|
let llret = bcx.call(callee.immediate(),
|
||||||
&llargs[..],
|
&llargs[..],
|
||||||
None,
|
cleanup_bundle.as_ref(),
|
||||||
Some(attrs));
|
Some(attrs));
|
||||||
if must_copy_dest {
|
if must_copy_dest {
|
||||||
let (ret_dest, ret_ty) = ret_dest_ty
|
let (ret_dest, ret_ty) = ret_dest_ty
|
||||||
@ -258,10 +276,10 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||||||
base::store_ty(bcx, llret, ret_dest.llval, ret_ty);
|
base::store_ty(bcx, llret, ret_dest.llval, ret_ty);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
bcx.br(self.llblock(target));
|
funclet_br(bcx, self.llblock(target));
|
||||||
}
|
}
|
||||||
// Foreign functions
|
// Foreign functions
|
||||||
(true, _, _, destination) => {
|
(true, _, destination) => {
|
||||||
let (dest, _) = ret_dest_ty
|
let (dest, _) = ret_dest_ty
|
||||||
.expect("return destination is not set");
|
.expect("return destination is not set");
|
||||||
bcx = bcx.map_block(|bcx| {
|
bcx = bcx.map_block(|bcx| {
|
||||||
@ -274,7 +292,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||||||
debugloc)
|
debugloc)
|
||||||
});
|
});
|
||||||
if let Some((_, target)) = *destination {
|
if let Some((_, target)) = *destination {
|
||||||
bcx.br(self.llblock(target));
|
funclet_br(bcx, self.llblock(target));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -297,11 +315,16 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a landingpad wrapper around the given Block.
|
||||||
|
///
|
||||||
|
/// No-op in MSVC SEH scheme.
|
||||||
fn make_landing_pad(&mut self,
|
fn make_landing_pad(&mut self,
|
||||||
cleanup: BlockAndBuilder<'bcx, 'tcx>)
|
cleanup: BlockAndBuilder<'bcx, 'tcx>)
|
||||||
-> BlockAndBuilder<'bcx, 'tcx>
|
-> BlockAndBuilder<'bcx, 'tcx>
|
||||||
{
|
{
|
||||||
// FIXME(#30941) this doesn't handle msvc-style exceptions
|
if base::wants_msvc_seh(cleanup.sess()) {
|
||||||
|
return cleanup;
|
||||||
|
}
|
||||||
let bcx = self.fcx.new_block("cleanup", None).build();
|
let bcx = self.fcx.new_block("cleanup", None).build();
|
||||||
let ccx = bcx.ccx();
|
let ccx = bcx.ccx();
|
||||||
let llpersonality = self.fcx.eh_personality();
|
let llpersonality = self.fcx.eh_personality();
|
||||||
@ -314,6 +337,31 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||||||
bcx
|
bcx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create prologue cleanuppad instruction under MSVC SEH handling scheme.
|
||||||
|
///
|
||||||
|
/// Also handles setting some state for the original trans and creating an operand bundle for
|
||||||
|
/// function calls.
|
||||||
|
fn make_cleanup_pad(&mut self, bb: mir::BasicBlock) -> Option<(ValueRef, OperandBundleDef)> {
|
||||||
|
let bcx = self.bcx(bb);
|
||||||
|
let data = self.mir.basic_block_data(bb);
|
||||||
|
let use_funclets = base::wants_msvc_seh(bcx.sess()) && data.is_cleanup;
|
||||||
|
let cleanup_pad = if use_funclets {
|
||||||
|
bcx.set_personality_fn(self.fcx.eh_personality());
|
||||||
|
Some(bcx.cleanup_pad(None, &[]))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
// Set the landingpad global-state for old translator, so it knows about the SEH used.
|
||||||
|
bcx.set_lpad(if let Some(cleanup_pad) = cleanup_pad {
|
||||||
|
Some(common::LandingPad::msvc(cleanup_pad))
|
||||||
|
} else if data.is_cleanup {
|
||||||
|
Some(common::LandingPad::gnu())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
});
|
||||||
|
cleanup_pad.map(|f| (f, OperandBundleDef::new("funclet", &[f])))
|
||||||
|
}
|
||||||
|
|
||||||
fn unreachable_block(&mut self) -> Block<'bcx, 'tcx> {
|
fn unreachable_block(&mut self) -> Block<'bcx, 'tcx> {
|
||||||
self.unreachable_block.unwrap_or_else(|| {
|
self.unreachable_block.unwrap_or_else(|| {
|
||||||
let bl = self.fcx.new_block("unreachable", None);
|
let bl = self.fcx.new_block("unreachable", None);
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
#![feature(rustc_attrs)]
|
#![feature(rustc_attrs)]
|
||||||
|
|
||||||
// ignore-msvc: FIXME(#30941)
|
|
||||||
// error-pattern:panic 1
|
// error-pattern:panic 1
|
||||||
// error-pattern:drop 2
|
// error-pattern:drop 2
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
|
|
||||||
#![feature(rustc_attrs)]
|
#![feature(rustc_attrs)]
|
||||||
|
|
||||||
// ignore-msvc: FIXME(#30941)
|
|
||||||
// error-pattern:converging_fn called
|
// error-pattern:converging_fn called
|
||||||
// error-pattern:0 dropped
|
// error-pattern:0 dropped
|
||||||
// error-pattern:exit
|
// error-pattern:exit
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
|
|
||||||
#![feature(rustc_attrs)]
|
#![feature(rustc_attrs)]
|
||||||
|
|
||||||
// ignore-msvc: FIXME(#30941)
|
|
||||||
// error-pattern:complex called
|
// error-pattern:complex called
|
||||||
// error-pattern:dropped
|
// error-pattern:dropped
|
||||||
// error-pattern:exit
|
// error-pattern:exit
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
|
|
||||||
#![feature(rustc_attrs)]
|
#![feature(rustc_attrs)]
|
||||||
|
|
||||||
// ignore-msvc: FIXME(#30941)
|
|
||||||
// error-pattern:diverging_fn called
|
// error-pattern:diverging_fn called
|
||||||
// error-pattern:0 dropped
|
// error-pattern:0 dropped
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user