diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index b829a9c6ec4..079cd9c3757 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -752,7 +752,14 @@ pub fn invoke<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, pub fn need_invoke(bcx: Block) -> bool { if bcx.sess().no_landing_pads() { - return false; + return false + } + + // Currently 32-bit MSVC unwinding is not super well implemented in LLVM, so + // we avoid it entirely. + if bcx.sess().target.target.options.is_like_msvc && + bcx.sess().target.target.arch == "x86" { + return false } // Avoid using invoke if we are already inside a landing pad. diff --git a/src/librustc_trans/trans/cleanup.rs b/src/librustc_trans/trans/cleanup.rs index 588e4cea504..1891320313a 100644 --- a/src/librustc_trans/trans/cleanup.rs +++ b/src/librustc_trans/trans/cleanup.rs @@ -851,8 +851,8 @@ impl<'blk, 'tcx> CleanupHelperMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx // an "exception", but for MSVC we want to force SEH. This means that we // can't actually have the personality function be our standard // `rust_eh_personality` function, but rather we wired it up to the - // CRT's custom `__C_specific_handler` personality funciton, which - // forces LLVM to consider landing pads as "landing pads for SEH". + // CRT's custom personality function, which forces LLVM to consider + // landing pads as "landing pads for SEH". let target = &self.ccx.sess().target.target; let llpersonality = match pad_bcx.tcx().lang_items.eh_personality() { Some(def_id) if !target.options.is_like_msvc => { @@ -864,10 +864,12 @@ impl<'blk, 'tcx> CleanupHelperMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx match *personality { Some(llpersonality) => llpersonality, None => { - let name = if target.options.is_like_msvc { - "__C_specific_handler" - } else { + let name = if !target.options.is_like_msvc { "rust_eh_personality" + } else if target.arch == "x86" { + "_except_handler3" + } else { + "__C_specific_handler" }; let fty = Type::variadic_func(&[], &Type::i32(self.ccx)); let f = declare::declare_cfn(self.ccx, name, fty, diff --git a/src/rt/rust_try_msvc_32.ll b/src/rt/rust_try_msvc_32.ll new file mode 100644 index 00000000000..bdee53b136e --- /dev/null +++ b/src/rt/rust_try_msvc_32.ll @@ -0,0 +1,42 @@ +; 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 or the MIT license +; , at your +; option. This file may not be copied, modified, or distributed +; except according to those terms. + +; For more comments about what's going on here see rust_try_msvc_64.ll. The only +; difference between that and this file is the personality function used as it's +; different for 32-bit MSVC than it is for 64-bit. + +define i8* @rust_try(void (i8*)* %f, i8* %env) + personality i8* bitcast (i32 (...)* @_except_handler3 to i8*) +{ + invoke void %f(i8* %env) + to label %normal + unwind label %catch + +normal: + ret i8* null +catch: + %vals = landingpad { i8*, i32 } + catch i8* bitcast (i32 (i8*, i8*)* @__rust_try_filter to i8*) + %ehptr = extractvalue { i8*, i32 } %vals, 0 + %sel = extractvalue { i8*, i32 } %vals, 1 + %filter_sel = call i32 @llvm.eh.typeid.for(i8* bitcast (i32 (i8*, i8*)* @__rust_try_filter to i8*)) + %is_filter = icmp eq i32 %sel, %filter_sel + br i1 %is_filter, label %catch-return, label %catch-resume + +catch-return: + ret i8* %ehptr + +catch-resume: + resume { i8*, i32 } %vals +} + +declare i32 @_except_handler3(...) +declare i32 @__rust_try_filter(i8*, i8*) +declare i32 @llvm.eh.typeid.for(i8*) readnone nounwind