Skip to content

Commit de366b5

Browse files
committed
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.
2 parents 6b076c2 + 1752615 commit de366b5

File tree

9 files changed

+135
-36
lines changed

9 files changed

+135
-36
lines changed

src/librustc_mir/mir_map.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ extern crate rustc_front;
2222
use build;
2323
use graphviz;
2424
use pretty;
25-
use transform::simplify_cfg;
25+
use transform::{simplify_cfg, no_landing_pads};
2626
use rustc::dep_graph::DepNode;
2727
use rustc::mir::repr::Mir;
2828
use hair::cx::Cx;
@@ -148,6 +148,7 @@ impl<'a, 'm, 'tcx> Visitor<'tcx> for InnerDump<'a,'m,'tcx> {
148148

149149
match build_mir(Cx::new(&infcx), implicit_arg_tys, id, span, decl, body) {
150150
Ok(mut mir) => {
151+
no_landing_pads::NoLandingPads.run_on_mir(&mut mir, self.tcx);
151152
simplify_cfg::SimplifyCfg::new().run_on_mir(&mut mir, self.tcx);
152153

153154
let meta_item_list = self.attr

src/librustc_mir/transform/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@
1010

1111
pub mod simplify_cfg;
1212
pub mod erase_regions;
13+
pub mod no_landing_pads;
1314
mod util;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
//! This pass removes the unwind branch of all the terminators when the no-landing-pads option is
12+
//! specified.
13+
14+
use rustc::middle::ty;
15+
use rustc::mir::repr::*;
16+
use rustc::mir::visit::MutVisitor;
17+
use rustc::mir::transform::MirPass;
18+
19+
pub struct NoLandingPads;
20+
21+
impl<'tcx> MutVisitor<'tcx> for NoLandingPads {
22+
fn visit_terminator(&mut self, bb: BasicBlock, terminator: &mut Terminator<'tcx>) {
23+
match *terminator {
24+
Terminator::Goto { .. } |
25+
Terminator::Resume |
26+
Terminator::Return |
27+
Terminator::If { .. } |
28+
Terminator::Switch { .. } |
29+
Terminator::SwitchInt { .. } => {
30+
/* nothing to do */
31+
},
32+
Terminator::Drop { ref mut unwind, .. } => {
33+
unwind.take();
34+
},
35+
Terminator::Call { ref mut cleanup, .. } => {
36+
cleanup.take();
37+
},
38+
}
39+
self.super_terminator(bb, terminator);
40+
}
41+
}
42+
43+
impl MirPass for NoLandingPads {
44+
fn run_on_mir<'tcx>(&mut self, mir: &mut Mir<'tcx>, tcx: &ty::ctxt<'tcx>) {
45+
if tcx.sess.no_landing_pads() {
46+
self.visit_mir(mir);
47+
}
48+
}
49+
}

src/librustc_trans/trans/common.rs

+4
Original file line numberDiff line numberDiff line change
@@ -767,6 +767,10 @@ impl<'blk, 'tcx> BlockAndBuilder<'blk, 'tcx> {
767767
{
768768
self.bcx.monomorphize(value)
769769
}
770+
771+
pub fn set_lpad(&self, lpad: Option<LandingPad>) {
772+
self.bcx.lpad.set(lpad.map(|p| &*self.fcx().lpad_arena.alloc(p)))
773+
}
770774
}
771775

772776
impl<'blk, 'tcx> Deref for BlockAndBuilder<'blk, 'tcx> {

src/librustc_trans/trans/mir/block.rs

+79-31
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use llvm::{BasicBlockRef, ValueRef};
11+
use llvm::{BasicBlockRef, ValueRef, OperandBundleDef};
1212
use rustc::middle::ty;
1313
use rustc::mir::repr as mir;
1414
use syntax::abi::Abi;
@@ -34,15 +34,40 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
3434
let mut bcx = self.bcx(bb);
3535
let data = self.mir.basic_block_data(bb);
3636

37+
// MSVC SEH bits
38+
let (cleanup_pad, cleanup_bundle) = if let Some((cp, cb)) = self.make_cleanup_pad(bb) {
39+
(Some(cp), Some(cb))
40+
} else {
41+
(None, None)
42+
};
43+
let funclet_br = |bcx: BlockAndBuilder, llbb: BasicBlockRef| if let Some(cp) = cleanup_pad {
44+
bcx.cleanup_ret(cp, Some(llbb));
45+
} else {
46+
bcx.br(llbb);
47+
};
48+
3749
for statement in &data.statements {
3850
bcx = self.trans_statement(bcx, statement);
3951
}
4052

4153
debug!("trans_block: terminator: {:?}", data.terminator());
4254

4355
match *data.terminator() {
56+
mir::Terminator::Resume => {
57+
if let Some(cleanup_pad) = cleanup_pad {
58+
bcx.cleanup_ret(cleanup_pad, None);
59+
} else {
60+
let ps = self.get_personality_slot(&bcx);
61+
let lp = bcx.load(ps);
62+
bcx.with_block(|bcx| {
63+
base::call_lifetime_end(bcx, ps);
64+
base::trans_unwind_resume(bcx, lp);
65+
});
66+
}
67+
}
68+
4469
mir::Terminator::Goto { target } => {
45-
bcx.br(self.llblock(target));
70+
funclet_br(bcx, self.llblock(target));
4671
}
4772

4873
mir::Terminator::If { ref cond, targets: (true_bb, false_bb) } => {
@@ -85,19 +110,10 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
85110
}
86111
}
87112

88-
mir::Terminator::Resume => {
89-
let ps = self.get_personality_slot(&bcx);
90-
let lp = bcx.load(ps);
91-
bcx.with_block(|bcx| {
92-
base::call_lifetime_end(bcx, ps);
93-
base::trans_unwind_resume(bcx, lp);
94-
});
95-
}
96-
97113
mir::Terminator::Return => {
98114
let return_ty = bcx.monomorphize(&self.mir.return_ty);
99115
bcx.with_block(|bcx| {
100-
base::build_return_block(bcx.fcx, bcx, return_ty, DebugLoc::None);
116+
base::build_return_block(self.fcx, bcx, return_ty, DebugLoc::None);
101117
})
102118
}
103119

@@ -106,7 +122,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
106122
let ty = lvalue.ty.to_ty(bcx.tcx());
107123
// Double check for necessity to drop
108124
if !glue::type_needs_drop(bcx.tcx(), ty) {
109-
bcx.br(self.llblock(target));
125+
funclet_br(bcx, self.llblock(target));
110126
return;
111127
}
112128
let drop_fn = glue::get_drop_glue(bcx.ccx(), ty);
@@ -123,11 +139,11 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
123139
&[llvalue],
124140
self.llblock(target),
125141
unwind.llbb(),
126-
None,
142+
cleanup_bundle.as_ref(),
127143
None);
128144
} else {
129-
bcx.call(drop_fn, &[llvalue], None, None);
130-
bcx.br(self.llblock(target));
145+
bcx.call(drop_fn, &[llvalue], cleanup_bundle.as_ref(), None);
146+
funclet_br(bcx, self.llblock(target));
131147
}
132148
}
133149

@@ -180,34 +196,33 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
180196
}
181197
}
182198

183-
let avoid_invoke = bcx.with_block(|bcx| base::avoid_invoke(bcx));
184199
// Many different ways to call a function handled here
185-
match (is_foreign, avoid_invoke, cleanup, destination) {
200+
match (is_foreign, cleanup, destination) {
186201
// The two cases below are the only ones to use LLVM’s `invoke`.
187-
(false, false, &Some(cleanup), &None) => {
202+
(false, &Some(cleanup), &None) => {
188203
let cleanup = self.bcx(cleanup);
189204
let landingpad = self.make_landing_pad(cleanup);
190205
let unreachable_blk = self.unreachable_block();
191206
bcx.invoke(callee.immediate(),
192207
&llargs[..],
193208
unreachable_blk.llbb,
194209
landingpad.llbb(),
195-
None,
210+
cleanup_bundle.as_ref(),
196211
Some(attrs));
197212
},
198-
(false, false, &Some(cleanup), &Some((_, success))) => {
213+
(false, &Some(cleanup), &Some((_, success))) => {
199214
let cleanup = self.bcx(cleanup);
200215
let landingpad = self.make_landing_pad(cleanup);
201216
let (target, postinvoke) = if must_copy_dest {
202-
(bcx.fcx().new_block("", None).build(), Some(self.bcx(success)))
217+
(self.fcx.new_block("", None).build(), Some(self.bcx(success)))
203218
} else {
204219
(self.bcx(success), None)
205220
};
206221
let invokeret = bcx.invoke(callee.immediate(),
207222
&llargs[..],
208223
target.llbb(),
209224
landingpad.llbb(),
210-
None,
225+
cleanup_bundle.as_ref(),
211226
Some(attrs));
212227
if let Some(postinvoketarget) = postinvoke {
213228
// We translate the copy into a temporary block. The temporary block is
@@ -242,14 +257,17 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
242257
target.br(postinvoketarget.llbb());
243258
}
244259
},
245-
(false, _, _, &None) => {
246-
bcx.call(callee.immediate(), &llargs[..], None, Some(attrs));
260+
(false, _, &None) => {
261+
bcx.call(callee.immediate(),
262+
&llargs[..],
263+
cleanup_bundle.as_ref(),
264+
Some(attrs));
247265
bcx.unreachable();
248266
}
249-
(false, _, _, &Some((_, target))) => {
267+
(false, _, &Some((_, target))) => {
250268
let llret = bcx.call(callee.immediate(),
251269
&llargs[..],
252-
None,
270+
cleanup_bundle.as_ref(),
253271
Some(attrs));
254272
if must_copy_dest {
255273
let (ret_dest, ret_ty) = ret_dest_ty
@@ -258,10 +276,10 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
258276
base::store_ty(bcx, llret, ret_dest.llval, ret_ty);
259277
});
260278
}
261-
bcx.br(self.llblock(target));
279+
funclet_br(bcx, self.llblock(target));
262280
}
263281
// Foreign functions
264-
(true, _, _, destination) => {
282+
(true, _, destination) => {
265283
let (dest, _) = ret_dest_ty
266284
.expect("return destination is not set");
267285
bcx = bcx.map_block(|bcx| {
@@ -274,7 +292,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
274292
debugloc)
275293
});
276294
if let Some((_, target)) = *destination {
277-
bcx.br(self.llblock(target));
295+
funclet_br(bcx, self.llblock(target));
278296
}
279297
},
280298
}
@@ -297,11 +315,16 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
297315
}
298316
}
299317

318+
/// Create a landingpad wrapper around the given Block.
319+
///
320+
/// No-op in MSVC SEH scheme.
300321
fn make_landing_pad(&mut self,
301322
cleanup: BlockAndBuilder<'bcx, 'tcx>)
302323
-> BlockAndBuilder<'bcx, 'tcx>
303324
{
304-
// FIXME(#30941) this doesn't handle msvc-style exceptions
325+
if base::wants_msvc_seh(cleanup.sess()) {
326+
return cleanup;
327+
}
305328
let bcx = self.fcx.new_block("cleanup", None).build();
306329
let ccx = bcx.ccx();
307330
let llpersonality = self.fcx.eh_personality();
@@ -314,6 +337,31 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
314337
bcx
315338
}
316339

340+
/// Create prologue cleanuppad instruction under MSVC SEH handling scheme.
341+
///
342+
/// Also handles setting some state for the original trans and creating an operand bundle for
343+
/// function calls.
344+
fn make_cleanup_pad(&mut self, bb: mir::BasicBlock) -> Option<(ValueRef, OperandBundleDef)> {
345+
let bcx = self.bcx(bb);
346+
let data = self.mir.basic_block_data(bb);
347+
let use_funclets = base::wants_msvc_seh(bcx.sess()) && data.is_cleanup;
348+
let cleanup_pad = if use_funclets {
349+
bcx.set_personality_fn(self.fcx.eh_personality());
350+
Some(bcx.cleanup_pad(None, &[]))
351+
} else {
352+
None
353+
};
354+
// Set the landingpad global-state for old translator, so it knows about the SEH used.
355+
bcx.set_lpad(if let Some(cleanup_pad) = cleanup_pad {
356+
Some(common::LandingPad::msvc(cleanup_pad))
357+
} else if data.is_cleanup {
358+
Some(common::LandingPad::gnu())
359+
} else {
360+
None
361+
});
362+
cleanup_pad.map(|f| (f, OperandBundleDef::new("funclet", &[f])))
363+
}
364+
317365
fn unreachable_block(&mut self) -> Block<'bcx, 'tcx> {
318366
self.unreachable_block.unwrap_or_else(|| {
319367
let bl = self.fcx.new_block("unreachable", None);

src/test/run-fail/mir_drop_panics.rs

-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
// except according to those terms.
1010
#![feature(rustc_attrs)]
1111

12-
// ignore-msvc: FIXME(#30941)
1312
// error-pattern:panic 1
1413
// error-pattern:drop 2
1514
use std::io::{self, Write};

src/test/run-fail/mir_trans_calls_converging_drops.rs

-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010

1111
#![feature(rustc_attrs)]
1212

13-
// ignore-msvc: FIXME(#30941)
1413
// error-pattern:converging_fn called
1514
// error-pattern:0 dropped
1615
// error-pattern:exit

src/test/run-fail/mir_trans_calls_converging_drops_2.rs

-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010

1111
#![feature(rustc_attrs)]
1212

13-
// ignore-msvc: FIXME(#30941)
1413
// error-pattern:complex called
1514
// error-pattern:dropped
1615
// error-pattern:exit

src/test/run-fail/mir_trans_calls_diverging_drops.rs

-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010

1111
#![feature(rustc_attrs)]
1212

13-
// ignore-msvc: FIXME(#30941)
1413
// error-pattern:diverging_fn called
1514
// error-pattern:0 dropped
1615

0 commit comments

Comments
 (0)