about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/libcore/intrinsics.rs6
-rw-r--r--src/librustc/middle/lang_items.rs2
-rw-r--r--src/librustc/middle/weak_lang_items.rs2
-rw-r--r--src/librustc_llvm/lib.rs6
-rw-r--r--src/librustc_trans/trans/build.rs4
-rw-r--r--src/librustc_trans/trans/builder.rs6
-rw-r--r--src/librustc_trans/trans/callee.rs17
-rw-r--r--src/librustc_trans/trans/cleanup.rs52
-rw-r--r--src/librustc_trans/trans/closure.rs16
-rw-r--r--src/librustc_trans/trans/common.rs51
-rw-r--r--src/librustc_trans/trans/context.rs7
-rw-r--r--src/librustc_trans/trans/declare.rs21
-rw-r--r--src/librustc_trans/trans/foreign.rs4
-rw-r--r--src/librustc_trans/trans/intrinsic.rs344
-rw-r--r--src/librustc_trans/trans/meth.rs4
-rw-r--r--src/librustc_trans/trans/monomorphize.rs7
-rw-r--r--src/librustc_typeck/check/mod.rs15
-rw-r--r--src/libstd/rt/unwind/gcc.rs62
-rw-r--r--src/libstd/rt/unwind/mod.rs19
-rw-r--r--src/libstd/rt/unwind/seh.rs5
-rw-r--r--src/rt/rust_try.ll54
-rw-r--r--src/rt/rust_try_msvc_32.ll42
-rw-r--r--src/rt/rust_try_msvc_64.ll80
-rw-r--r--src/rustllvm/RustWrapper.cpp3
24 files changed, 519 insertions, 310 deletions
diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs
index 74901553149..ef022179772 100644
--- a/src/libcore/intrinsics.rs
+++ b/src/libcore/intrinsics.rs
@@ -602,4 +602,10 @@ extern "rust-intrinsic" {
     /// Returns the value of the discriminant for the variant in 'v',
     /// cast to a `u64`; if `T` has no discriminant, returns 0.
     pub fn discriminant_value<T>(v: &T) -> u64;
+
+    /// Rust's "try catch" construct which invokes the function pointer `f` with
+    /// the data pointer `data`, returning the exception payload if an exception
+    /// is thrown (aka the thread panics).
+    #[cfg(not(stage0))]
+    pub fn try(f: fn(*mut u8), data: *mut u8) -> *mut u8;
 }
diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs
index cf528e0c8a9..f7cd94f30af 100644
--- a/src/librustc/middle/lang_items.rs
+++ b/src/librustc/middle/lang_items.rs
@@ -326,6 +326,8 @@ lets_do_this! {
     StartFnLangItem,                 "start",                   start_fn;
 
     EhPersonalityLangItem,           "eh_personality",          eh_personality;
+    EhPersonalityCatchLangItem,      "eh_personality_catch",    eh_personality_catch;
+    MSVCTryFilterLangItem,           "msvc_try_filter",         msvc_try_filter;
 
     ExchangeHeapLangItem,            "exchange_heap",           exchange_heap;
     OwnedBoxLangItem,                "owned_box",               owned_box;
diff --git a/src/librustc/middle/weak_lang_items.rs b/src/librustc/middle/weak_lang_items.rs
index 60a9ffc7d2e..72fda9a7ae0 100644
--- a/src/librustc/middle/weak_lang_items.rs
+++ b/src/librustc/middle/weak_lang_items.rs
@@ -119,7 +119,7 @@ impl<'a, 'v> Visitor<'v> for Context<'a> {
 ) }
 
 weak_lang_items! {
-    panic_fmt,          PanicFmtLangItem,            rust_begin_unwind;
+    panic_fmt,          PanicFmtLangItem,           rust_begin_unwind;
     stack_exhausted,    StackExhaustedLangItem,     rust_stack_exhausted;
     eh_personality,     EhPersonalityLangItem,      rust_eh_personality;
 }
diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs
index 7734704b021..83f8619c5ee 100644
--- a/src/librustc_llvm/lib.rs
+++ b/src/librustc_llvm/lib.rs
@@ -134,7 +134,7 @@ pub enum DLLStorageClassTypes {
 }
 
 bitflags! {
-    flags Attribute : u32 {
+    flags Attribute : u64 {
         const ZExt            = 1 << 0,
         const SExt            = 1 << 1,
         const NoReturn        = 1 << 2,
@@ -161,6 +161,7 @@ bitflags! {
         const ReturnsTwice    = 1 << 29,
         const UWTable         = 1 << 30,
         const NonLazyBind     = 1 << 31,
+        const OptimizeNone    = 1 << 42,
     }
 }
 
@@ -2193,7 +2194,8 @@ pub fn ConstFCmp(pred: RealPredicate, v1: ValueRef, v2: ValueRef) -> ValueRef {
 
 pub fn SetFunctionAttribute(fn_: ValueRef, attr: Attribute) {
     unsafe {
-        LLVMAddFunctionAttribute(fn_, FunctionIndex as c_uint, attr.bits() as uint64_t)
+        LLVMAddFunctionAttribute(fn_, FunctionIndex as c_uint,
+                                 attr.bits() as uint64_t)
     }
 }
 
diff --git a/src/librustc_trans/trans/build.rs b/src/librustc_trans/trans/build.rs
index 3e4452a23b9..5a3fcc8d27f 100644
--- a/src/librustc_trans/trans/build.rs
+++ b/src/librustc_trans/trans/build.rs
@@ -1042,6 +1042,10 @@ pub fn LandingPad(cx: Block, ty: Type, pers_fn: ValueRef,
     B(cx).landing_pad(ty, pers_fn, num_clauses, cx.fcx.llfn)
 }
 
+pub fn AddClause(cx: Block, landing_pad: ValueRef, clause: ValueRef) {
+    B(cx).add_clause(landing_pad, clause)
+}
+
 pub fn SetCleanup(cx: Block, landing_pad: ValueRef) {
     B(cx).set_cleanup(landing_pad)
 }
diff --git a/src/librustc_trans/trans/builder.rs b/src/librustc_trans/trans/builder.rs
index e39fc18dc7b..107ae378ac4 100644
--- a/src/librustc_trans/trans/builder.rs
+++ b/src/librustc_trans/trans/builder.rs
@@ -937,6 +937,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         }
     }
 
+    pub fn add_clause(&self, landing_pad: ValueRef, clause: ValueRef) {
+        unsafe {
+            llvm::LLVMAddClause(landing_pad, clause);
+        }
+    }
+
     pub fn set_cleanup(&self, landing_pad: ValueRef) {
         self.count_insn("setcleanup");
         unsafe {
diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs
index debc8dd59c0..7900000d3a9 100644
--- a/src/librustc_trans/trans/callee.rs
+++ b/src/librustc_trans/trans/callee.rs
@@ -620,16 +620,17 @@ pub fn trans_lang_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     }, ArgVals(args), dest)
 }
 
-/// This behemoth of a function translates function calls. Unfortunately, in order to generate more
-/// efficient LLVM output at -O0, it has quite a complex signature (refactoring this into two
-/// functions seems like a good idea).
+/// This behemoth of a function translates function calls. Unfortunately, in
+/// order to generate more efficient LLVM output at -O0, it has quite a complex
+/// signature (refactoring this into two functions seems like a good idea).
 ///
-/// In particular, for lang items, it is invoked with a dest of None, and in that case the return
-/// value contains the result of the fn. The lang item must not return a structural type or else
-/// all heck breaks loose.
+/// In particular, for lang items, it is invoked with a dest of None, and in
+/// that case the return value contains the result of the fn. The lang item must
+/// not return a structural type or else all heck breaks loose.
 ///
-/// For non-lang items, `dest` is always Some, and hence the result is written into memory
-/// somewhere. Nonetheless we return the actual return value of the function.
+/// For non-lang items, `dest` is always Some, and hence the result is written
+/// into memory somewhere. Nonetheless we return the actual return value of the
+/// function.
 pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
                                            debug_loc: DebugLoc,
                                            get_callee: F,
diff --git a/src/librustc_trans/trans/cleanup.rs b/src/librustc_trans/trans/cleanup.rs
index 1891320313a..37722d5a549 100644
--- a/src/librustc_trans/trans/cleanup.rs
+++ b/src/librustc_trans/trans/cleanup.rs
@@ -122,11 +122,9 @@ pub use self::Heap::*;
 use llvm::{BasicBlockRef, ValueRef};
 use trans::base;
 use trans::build;
-use trans::callee;
 use trans::common;
-use trans::common::{Block, FunctionContext, ExprId, NodeIdAndSpan};
+use trans::common::{Block, FunctionContext, NodeIdAndSpan};
 use trans::debuginfo::{DebugLoc, ToDebugLoc};
-use trans::declare;
 use trans::glue;
 use middle::region;
 use trans::type_::Type;
@@ -833,53 +831,7 @@ impl<'blk, 'tcx> CleanupHelperMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx
                                     &[Type::i8p(self.ccx), Type::i32(self.ccx)],
                                     false);
 
-        // The exception handling personality function.
-        //
-        // If our compilation unit has the `eh_personality` lang item somewhere
-        // within it, then we just need to translate that. Otherwise, we're
-        // building an rlib which will depend on some upstream implementation of
-        // this function, so we just codegen a generic reference to it. We don't
-        // specify any of the types for the function, we just make it a symbol
-        // that LLVM can later use.
-        //
-        // Note that MSVC is a little special here in that we don't use the
-        // `eh_personality` lang item at all. Currently LLVM has support for
-        // both Dwarf and SEH unwind mechanisms for MSVC targets and uses the
-        // *name of the personality function* to decide what kind of unwind side
-        // tables/landing pads to emit. It looks like Dwarf is used by default,
-        // injecting a dependency on the `_Unwind_Resume` symbol for resuming
-        // 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 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 => {
-                callee::trans_fn_ref(pad_bcx.ccx(), def_id, ExprId(0),
-                                     pad_bcx.fcx.param_substs).val
-            }
-            _ => {
-                let mut personality = self.ccx.eh_personality().borrow_mut();
-                match *personality {
-                    Some(llpersonality) => llpersonality,
-                    None => {
-                        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,
-                                                     self.ccx.tcx().types.i32);
-                        *personality = Some(f);
-                        f
-                    }
-                }
-            }
-        };
+        let llpersonality = pad_bcx.fcx.eh_personality();
 
         // The only landing pad clause will be 'cleanup'
         let llretval = build::LandingPad(pad_bcx, llretty, llpersonality, 1);
diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs
index d813e9dbf40..f00029ec2ff 100644
--- a/src/librustc_trans/trans/closure.rs
+++ b/src/librustc_trans/trans/closure.rs
@@ -163,11 +163,10 @@ pub fn get_or_create_declaration_if_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tc
         mangle_internal_name_by_path_and_seq(path, "closure")
     });
 
-    // Currently there’s only a single user of get_or_create_declaration_if_closure and it
-    // unconditionally defines the function, therefore we use define_* here.
-    let llfn = declare::define_internal_rust_fn(ccx, &symbol[..], function_type).unwrap_or_else(||{
-        ccx.sess().bug(&format!("symbol `{}` already defined", symbol));
-    });
+    // Currently there’s only a single user of
+    // get_or_create_declaration_if_closure and it unconditionally defines the
+    // function, therefore we use define_* here.
+    let llfn = declare::define_internal_rust_fn(ccx, &symbol[..], function_type);
 
     // set an inline hint for all closures
     attributes::inline(llfn, attributes::InlineAttr::Hint);
@@ -388,11 +387,8 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
 
     // Create the by-value helper.
     let function_name = link::mangle_internal_name_by_type_and_seq(ccx, llonce_fn_ty, "once_shim");
-    let lloncefn = declare::define_internal_rust_fn(ccx, &function_name[..], llonce_fn_ty)
-        .unwrap_or_else(||{
-            ccx.sess().bug(&format!("symbol `{}` already defined", function_name));
-        });
-
+    let lloncefn = declare::define_internal_rust_fn(ccx, &function_name,
+                                                    llonce_fn_ty);
     let sig = tcx.erase_late_bound_regions(&llonce_bare_fn_ty.sig);
     let (block_arena, fcx): (TypedArena<_>, FunctionContext);
     block_arena = TypedArena::new();
diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs
index d7d3be699cb..1e87053c2ae 100644
--- a/src/librustc_trans/trans/common.rs
+++ b/src/librustc_trans/trans/common.rs
@@ -25,6 +25,7 @@ use middle::lang_items::LangItem;
 use middle::subst::{self, Substs};
 use trans::base;
 use trans::build;
+use trans::callee;
 use trans::cleanup;
 use trans::consts;
 use trans::datum;
@@ -479,6 +480,56 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> {
     pub fn type_needs_drop(&self, ty: Ty<'tcx>) -> bool {
         type_needs_drop_given_env(self.ccx.tcx(), ty, &self.param_env)
     }
+
+    pub fn eh_personality(&self) -> ValueRef {
+        // The exception handling personality function.
+        //
+        // If our compilation unit has the `eh_personality` lang item somewhere
+        // within it, then we just need to translate that. Otherwise, we're
+        // building an rlib which will depend on some upstream implementation of
+        // this function, so we just codegen a generic reference to it. We don't
+        // specify any of the types for the function, we just make it a symbol
+        // that LLVM can later use.
+        //
+        // Note that MSVC is a little special here in that we don't use the
+        // `eh_personality` lang item at all. Currently LLVM has support for
+        // both Dwarf and SEH unwind mechanisms for MSVC targets and uses the
+        // *name of the personality function* to decide what kind of unwind side
+        // tables/landing pads to emit. It looks like Dwarf is used by default,
+        // injecting a dependency on the `_Unwind_Resume` symbol for resuming
+        // 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 personality function, which forces LLVM to consider
+        // landing pads as "landing pads for SEH".
+        let target = &self.ccx.sess().target.target;
+        match self.ccx.tcx().lang_items.eh_personality() {
+            Some(def_id) if !target.options.is_like_msvc => {
+                callee::trans_fn_ref(self.ccx, def_id, ExprId(0),
+                                     self.param_substs).val
+            }
+            _ => {
+                let mut personality = self.ccx.eh_personality().borrow_mut();
+                match *personality {
+                    Some(llpersonality) => llpersonality,
+                    None => {
+                        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,
+                                                     self.ccx.tcx().types.i32);
+                        *personality = Some(f);
+                        f
+                    }
+                }
+            }
+        }
+    }
 }
 
 // Basic block context.  We create a block context for each basic block
diff --git a/src/librustc_trans/trans/context.rs b/src/librustc_trans/trans/context.rs
index 5a4bd7ff3a1..760a4ae827a 100644
--- a/src/librustc_trans/trans/context.rs
+++ b/src/librustc_trans/trans/context.rs
@@ -142,6 +142,7 @@ pub struct LocalCrateContext<'tcx> {
     dbg_cx: Option<debuginfo::CrateDebugContext<'tcx>>,
 
     eh_personality: RefCell<Option<ValueRef>>,
+    rust_try_fn: RefCell<Option<ValueRef>>,
 
     intrinsics: RefCell<FnvHashMap<&'static str, ValueRef>>,
 
@@ -461,6 +462,7 @@ impl<'tcx> LocalCrateContext<'tcx> {
                 closure_vals: RefCell::new(FnvHashMap()),
                 dbg_cx: dbg_cx,
                 eh_personality: RefCell::new(None),
+                rust_try_fn: RefCell::new(None),
                 intrinsics: RefCell::new(FnvHashMap()),
                 n_llvm_insns: Cell::new(0),
                 trait_cache: RefCell::new(FnvHashMap()),
@@ -726,6 +728,10 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
         &self.local.eh_personality
     }
 
+    pub fn rust_try_fn<'a>(&'a self) -> &'a RefCell<Option<ValueRef>> {
+        &self.local.rust_try_fn
+    }
+
     fn intrinsics<'a>(&'a self) -> &'a RefCell<FnvHashMap<&'static str, ValueRef>> {
         &self.local.intrinsics
     }
@@ -923,6 +929,7 @@ fn declare_intrinsic(ccx: &CrateContext, key: & &'static str) -> Option<ValueRef
     ifn!("llvm.lifetime.end", fn(t_i64, i8p) -> void);
 
     ifn!("llvm.expect.i1", fn(i1, i1) -> i1);
+    ifn!("llvm.eh.typeid.for", fn(i8p) -> t_i32);
 
     // Some intrinsics were introduced in later versions of LLVM, but they have
     // fallbacks in libc or libm and such.
diff --git a/src/librustc_trans/trans/declare.rs b/src/librustc_trans/trans/declare.rs
index b29da9d560f..c802de91e38 100644
--- a/src/librustc_trans/trans/declare.rs
+++ b/src/librustc_trans/trans/declare.rs
@@ -176,8 +176,8 @@ pub fn define_global(ccx: &CrateContext, name: &str, ty: Type) -> Option<ValueRe
 /// return None if the name already has a definition associated with it. In that
 /// case an error should be reported to the user, because it usually happens due
 /// to user’s fault (e.g. misuse of #[no_mangle] or #[export_name] attributes).
-pub fn define_fn(ccx: &CrateContext, name: &str, callconv: llvm::CallConv, fn_type: Type,
-                 output: ty::FnOutput) -> Option<ValueRef> {
+pub fn define_fn(ccx: &CrateContext, name: &str, callconv: llvm::CallConv,
+                 fn_type: Type, output: ty::FnOutput) -> Option<ValueRef> {
     if get_defined_value(ccx, name).is_some() {
         None
     } else {
@@ -224,20 +224,21 @@ pub fn define_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str,
 /// Declare a Rust function with an intention to define it.
 ///
 /// Use this function when you intend to define a function. This function will
-/// return None if the name already has a definition associated with it. In that
-/// case an error should be reported to the user, because it usually happens due
-/// to user’s fault (e.g. misuse of #[no_mangle] or #[export_name] attributes).
-pub fn define_internal_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str,
-                                         fn_type: ty::Ty<'tcx>) -> Option<ValueRef> {
+/// return panic if the name already has a definition associated with it. This
+/// can happen with #[no_mangle] or #[export_name], for example.
+pub fn define_internal_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+                                         name: &str,
+                                         fn_type: ty::Ty<'tcx>) -> ValueRef {
     if get_defined_value(ccx, name).is_some() {
-        None
+        ccx.sess().fatal(&format!("symbol `{}` already defined", name))
     } else {
-        Some(declare_internal_rust_fn(ccx, name, fn_type))
+        declare_internal_rust_fn(ccx, name, fn_type)
     }
 }
 
 
-/// Get defined or externally defined (AvailableExternally linkage) value by name.
+/// Get defined or externally defined (AvailableExternally linkage) value by
+/// name.
 fn get_defined_value(ccx: &CrateContext, name: &str) -> Option<ValueRef> {
     debug!("get_defined_value(name={:?})", name);
     let namebuf = CString::new(name).unwrap_or_else(|_|{
diff --git a/src/librustc_trans/trans/foreign.rs b/src/librustc_trans/trans/foreign.rs
index 9e8c0189a97..e102e3cd062 100644
--- a/src/librustc_trans/trans/foreign.rs
+++ b/src/librustc_trans/trans/foreign.rs
@@ -627,9 +627,7 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                ccx.tcx().map.path_to_string(id),
                id, t);
 
-        let llfn = declare::define_internal_rust_fn(ccx, &ps[..], t).unwrap_or_else(||{
-            ccx.sess().bug(&format!("symbol `{}` already defined", ps));
-        });
+        let llfn = declare::define_internal_rust_fn(ccx, &ps, t);
         attributes::from_fn_attrs(ccx, attrs, llfn);
         base::trans_fn(ccx, decl, body, llfn, param_substs, id, &[]);
         llfn
diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs
index b449c3ad060..e78218fd10d 100644
--- a/src/librustc_trans/trans/intrinsic.rs
+++ b/src/librustc_trans/trans/intrinsic.rs
@@ -10,6 +10,7 @@
 
 #![allow(non_upper_case_globals)]
 
+use arena::TypedArena;
 use llvm;
 use llvm::{SequentiallyConsistent, Acquire, Release, AtomicXchg, ValueRef, TypeKind};
 use middle::subst;
@@ -23,6 +24,7 @@ use trans::cleanup::CleanupMethods;
 use trans::common::*;
 use trans::datum::*;
 use trans::debuginfo::DebugLoc;
+use trans::declare;
 use trans::expr;
 use trans::glue;
 use trans::type_of::*;
@@ -31,7 +33,8 @@ use trans::machine;
 use trans::machine::llsize_of;
 use trans::type_::Type;
 use middle::ty::{self, Ty, HasTypeFlags};
-use syntax::abi::RustIntrinsic;
+use middle::subst::Substs;
+use syntax::abi::{self, RustIntrinsic};
 use syntax::ast;
 use syntax::parse::token;
 
@@ -302,6 +305,42 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
         }
     }
 
+    let call_debug_location = DebugLoc::At(call_info.id, call_info.span);
+
+    // For `try` we need some custom control flow
+    if &name[..] == "try" {
+        if let callee::ArgExprs(ref exprs) = args {
+            let (func, data) = if exprs.len() != 2 {
+                ccx.sess().bug("expected two exprs as arguments for \
+                                `try` intrinsic");
+            } else {
+                (&exprs[0], &exprs[1])
+            };
+
+            // translate arguments
+            let func = unpack_datum!(bcx, expr::trans(bcx, func));
+            let func = unpack_datum!(bcx, func.to_rvalue_datum(bcx, "func"));
+            let data = unpack_datum!(bcx, expr::trans(bcx, data));
+            let data = unpack_datum!(bcx, data.to_rvalue_datum(bcx, "data"));
+
+            let dest = match dest {
+                expr::SaveIn(d) => d,
+                expr::Ignore => alloc_ty(bcx, tcx.mk_mut_ptr(tcx.types.i8),
+                                         "try_result"),
+            };
+
+            // do the invoke
+            bcx = try_intrinsic(bcx, func.val, data.val, dest,
+                                call_debug_location);
+
+            fcx.pop_and_trans_custom_cleanup_scope(bcx, cleanup_scope);
+            return Result::new(bcx, dest);
+        } else {
+            ccx.sess().bug("expected two exprs as arguments for \
+                            `try` intrinsic");
+        }
+    }
+
     // Push the arguments.
     let mut llargs = Vec::new();
     bcx = callee::trans_args(bcx,
@@ -314,8 +353,6 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
 
     fcx.scopes.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean();
 
-    let call_debug_location = DebugLoc::At(call_info.id, call_info.span);
-
     // These are the only intrinsic functions that diverge.
     if &name[..] == "abort" {
         let llfn = ccx.get_intrinsic(&("llvm.trap"));
@@ -989,3 +1026,304 @@ fn with_overflow_intrinsic<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         ret
     }
 }
+
+fn try_intrinsic<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+                             func: ValueRef,
+                             data: ValueRef,
+                             dest: ValueRef,
+                             dloc: DebugLoc) -> Block<'blk, 'tcx> {
+    if bcx.sess().no_landing_pads() {
+        Call(bcx, func, &[data], None, dloc);
+        Store(bcx, C_null(Type::i8p(bcx.ccx())), dest);
+        bcx
+    } else if bcx.sess().target.target.options.is_like_msvc {
+        trans_msvc_try(bcx, func, data, dest, dloc)
+    } else {
+        trans_gnu_try(bcx, func, data, dest, dloc)
+    }
+}
+
+// MSVC's definition of the `rust_try` function. The exact implementation here
+// is a little different than the GNU (standard) version below, not only because
+// of the personality function but also because of the other fiddly bits about
+// SEH. LLVM also currently requires us to structure this a very particular way
+// as explained below.
+//
+// Like with the GNU version we generate a shim wrapper
+fn trans_msvc_try<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+                              func: ValueRef,
+                              data: ValueRef,
+                              dest: ValueRef,
+                              dloc: DebugLoc) -> Block<'blk, 'tcx> {
+    let llfn = get_rust_try_fn(bcx.fcx, &mut |try_fn_ty, output| {
+        let ccx = bcx.ccx();
+        let dloc = DebugLoc::None;
+        let rust_try = declare::define_internal_rust_fn(ccx, "__rust_try",
+                                                         try_fn_ty);
+        let (fcx, block_arena);
+        block_arena = TypedArena::new();
+        fcx = new_fn_ctxt(ccx, rust_try, ast::DUMMY_NODE_ID, false,
+                          output, ccx.tcx().mk_substs(Substs::trans_empty()),
+                          None, &block_arena);
+        let bcx = init_function(&fcx, true, output);
+        let then = fcx.new_temp_block("then");
+        let catch = fcx.new_temp_block("catch");
+        let catch_return = fcx.new_temp_block("catch-return");
+        let catch_resume = fcx.new_temp_block("catch-resume");
+        let personality = fcx.eh_personality();
+
+        let eh_typeid_for = ccx.get_intrinsic(&"llvm.eh.typeid.for");
+        let rust_try_filter = match bcx.tcx().lang_items.msvc_try_filter() {
+            Some(did) => callee::trans_fn_ref(ccx, did, ExprId(0),
+                                              bcx.fcx.param_substs).val,
+            None => bcx.sess().bug("msvc_try_filter not defined"),
+        };
+
+        // Type indicator for the exception being thrown, not entirely sure
+        // what's going on here but it's what all the examples in LLVM use.
+        let lpad_ty = Type::struct_(ccx, &[Type::i8p(ccx), Type::i32(ccx)],
+                                    false);
+
+        llvm::SetFunctionAttribute(rust_try, llvm::Attribute::NoInline);
+        llvm::SetFunctionAttribute(rust_try, llvm::Attribute::OptimizeNone);
+        let func = llvm::get_param(rust_try, 0);
+        let data = llvm::get_param(rust_try, 1);
+
+        // Invoke the function, specifying our two temporary landing pads as the
+        // ext point. After the invoke we've terminated our basic block.
+        Invoke(bcx, func, &[data], then.llbb, catch.llbb, None, dloc);
+
+        // All the magic happens in this landing pad, and this is basically the
+        // only landing pad in rust tagged with "catch" to indicate that we're
+        // catching an exception. The other catch handlers in the GNU version
+        // below just catch *all* exceptions, but that's because most exceptions
+        // are already filtered out by the gnu personality function.
+        //
+        // For MSVC we're just using a standard personality function that we
+        // can't customize (e.g. _except_handler3 or __C_specific_handler), so
+        // we need to do the exception filtering ourselves. This is currently
+        // performed by the `__rust_try_filter` function. This function,
+        // specified in the landingpad instruction, will be invoked by Windows
+        // SEH routines and will return whether the exception in question can be
+        // caught (aka the Rust runtime is the one that threw the exception).
+        //
+        // To get this to compile (currently LLVM segfaults if it's not in this
+        // particular structure), when the landingpad is executing we test to
+        // make sure that the ID of the exception being thrown is indeed the one
+        // that we were expecting. If it's not, we resume the exception, and
+        // otherwise we return the pointer that we got Full disclosure: It's not
+        // clear to me what this `llvm.eh.typeid` stuff is doing *other* then
+        // just allowing LLVM to compile this file without segfaulting. I would
+        // expect the entire landing pad to just be:
+        //
+        //     %vals = landingpad ...
+        //     %ehptr = extractvalue { i8*, i32 } %vals, 0
+        //     ret i8* %ehptr
+        //
+        // but apparently LLVM chokes on this, so we do the more complicated
+        // thing to placate it.
+        let vals = LandingPad(catch, lpad_ty, personality, 1);
+        let rust_try_filter = BitCast(catch, rust_try_filter, Type::i8p(ccx));
+        AddClause(catch, vals, rust_try_filter);
+        let ehptr = ExtractValue(catch, vals, 0);
+        let sel = ExtractValue(catch, vals, 1);
+        let filter_sel = Call(catch, eh_typeid_for, &[rust_try_filter], None,
+                              dloc);
+        let is_filter = ICmp(catch, llvm::IntEQ, sel, filter_sel, dloc);
+        CondBr(catch, is_filter, catch_return.llbb, catch_resume.llbb, dloc);
+
+        // Our "catch-return" basic block is where we've determined that we
+        // actually need to catch this exception, in which case we just return
+        // the exception pointer.
+        Ret(catch_return, ehptr, dloc);
+
+        // The "catch-resume" block is where we're running this landing pad but
+        // we actually need to not catch the exception, so just resume the
+        // exception to return.
+        Resume(catch_resume, vals);
+
+        // On the successful branch we just return null.
+        Ret(then, C_null(Type::i8p(ccx)), dloc);
+
+        return rust_try
+    });
+
+    // Note that no invoke is used here because by definition this function
+    // can't panic (that's what it's catching).
+    let ret = Call(bcx, llfn, &[func, data], None, dloc);
+    Store(bcx, ret, dest);
+    return bcx;
+}
+
+// Definition of the standard "try" function for Rust using the GNU-like model
+// of exceptions (e.g. the normal semantics of LLVM's landingpad and invoke
+// instructions).
+//
+// This translation is a little surprising for two reasons:
+//
+// 1. We always call a shim function instead of inlining the call to `invoke`
+//    manually here. This is done because in LLVM we're only allowed to have one
+//    personality per function definition. The call to the `try` intrinsic is
+//    being inlined into the function calling it, and that function may already
+//    have other personality functions in play. By calling a shim we're
+//    guaranteed that our shim will have the right personality function.
+//
+// 2. Instead of making one shim (explained above), we make two shims! The
+//    reason for this has to do with the technical details about the
+//    implementation of unwinding in the runtime, but the tl;dr; is that the
+//    outer shim's personality function says "catch rust exceptions" and the
+//    inner shim's landing pad will not `resume` the exception being thrown.
+//    This means that the outer shim's landing pad is never run and the inner
+//    shim's return value is the return value of the whole call.
+//
+// The double-shim aspect is currently done for implementation ease on the
+// runtime side of things, and more info can be found in
+// src/libstd/rt/unwind/gcc.rs.
+fn trans_gnu_try<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+                             func: ValueRef,
+                             data: ValueRef,
+                             dest: ValueRef,
+                             dloc: DebugLoc) -> Block<'blk, 'tcx> {
+    let llfn = get_rust_try_fn(bcx.fcx, &mut |try_fn_ty, output| {
+        let ccx = bcx.ccx();
+        let dloc = DebugLoc::None;
+
+        // Type indicator for the exception being thrown, not entirely sure
+        // what's going on here but it's what all the examples in LLVM use.
+        let lpad_ty = Type::struct_(ccx, &[Type::i8p(ccx), Type::i32(ccx)],
+                                    false);
+
+        // Define the "inner try" shim
+        let rust_try_inner = declare::define_internal_rust_fn(ccx,
+                                                              "__rust_try_inner",
+                                                              try_fn_ty);
+        trans_rust_try(ccx, rust_try_inner, lpad_ty, bcx.fcx.eh_personality(),
+                       output, dloc, &mut |bcx, then, catch| {
+            let func = llvm::get_param(rust_try_inner, 0);
+            let data = llvm::get_param(rust_try_inner, 1);
+            Invoke(bcx, func, &[data], then.llbb, catch.llbb, None, dloc);
+            C_null(Type::i8p(ccx))
+        });
+
+        // Define the "outer try" shim.
+        let rust_try = declare::define_internal_rust_fn(ccx, "__rust_try",
+                                                        try_fn_ty);
+        let catch_pers = match bcx.tcx().lang_items.eh_personality_catch() {
+            Some(did) => callee::trans_fn_ref(ccx, did, ExprId(0),
+                                              bcx.fcx.param_substs).val,
+            None => bcx.tcx().sess.bug("eh_personality_catch not defined"),
+        };
+        trans_rust_try(ccx, rust_try, lpad_ty, catch_pers, output, dloc,
+                       &mut |bcx, then, catch| {
+            let func = llvm::get_param(rust_try, 0);
+            let data = llvm::get_param(rust_try, 1);
+            Invoke(bcx, rust_try_inner, &[func, data], then.llbb, catch.llbb,
+                   None, dloc)
+        });
+        return rust_try
+    });
+
+    // Note that no invoke is used here because by definition this function
+    // can't panic (that's what it's catching).
+    let ret = Call(bcx, llfn, &[func, data], None, dloc);
+    Store(bcx, ret, dest);
+    return bcx;
+
+    // Translates both the inner and outer shims described above. The only
+    // difference between these two is the function invoked and the personality
+    // involved, so a common routine is shared.
+    //
+    //   bcx:
+    //      invoke %func(%args...) normal %normal unwind %unwind
+    //
+    //   normal:
+    //      ret null
+    //
+    //   unwind:
+    //      (ptr, _) = landingpad
+    //      br (ptr != null), done, reraise
+    //
+    //   done:
+    //      ret ptr
+    //
+    //   reraise:
+    //      resume
+    //
+    // Note that the branch checking for `null` here isn't actually necessary,
+    // it's just an unfortunate hack to make sure that LLVM doesn't optimize too
+    // much. If this were not present, then LLVM would correctly deduce that our
+    // inner shim should be tagged with `nounwind` (as it catches all
+    // exceptions) and then the outer shim's `invoke` will be translated to just
+    // a simple call, destroying that entry for the personality function.
+    //
+    // To ensure that both shims always have an `invoke` this check against null
+    // confuses LLVM enough to the point that it won't infer `nounwind` and
+    // we'll proceed as normal.
+    fn trans_rust_try<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+                                llfn: ValueRef,
+                                lpad_ty: Type,
+                                personality: ValueRef,
+                                output: ty::FnOutput<'tcx>,
+                                dloc: DebugLoc,
+                                invoke: &mut FnMut(Block, Block, Block) -> ValueRef) {
+        let (fcx, block_arena);
+        block_arena = TypedArena::new();
+        fcx = new_fn_ctxt(ccx, llfn, ast::DUMMY_NODE_ID, false,
+                          output, ccx.tcx().mk_substs(Substs::trans_empty()),
+                          None, &block_arena);
+        let bcx = init_function(&fcx, true, output);
+        let then = bcx.fcx.new_temp_block("then");
+        let catch = bcx.fcx.new_temp_block("catch");
+        let reraise = bcx.fcx.new_temp_block("reraise");
+        let catch_return = bcx.fcx.new_temp_block("catch-return");
+
+        let invoke_ret = invoke(bcx, then, catch);
+        Ret(then, invoke_ret, dloc);
+        let vals = LandingPad(catch, lpad_ty, personality, 1);
+        AddClause(catch, vals, C_null(Type::i8p(ccx)));
+        let ptr = ExtractValue(catch, vals, 0);
+        let valid = ICmp(catch, llvm::IntNE, ptr, C_null(Type::i8p(ccx)), dloc);
+        CondBr(catch, valid, catch_return.llbb, reraise.llbb, dloc);
+        Ret(catch_return, ptr, dloc);
+        Resume(reraise, vals);
+    }
+}
+
+// Helper to generate the `Ty` associated with `rust_Try`
+fn get_rust_try_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>,
+                             f: &mut FnMut(Ty<'tcx>,
+                                           ty::FnOutput<'tcx>) -> ValueRef)
+                             -> ValueRef {
+    let ccx = fcx.ccx;
+    if let Some(llfn) = *ccx.rust_try_fn().borrow() {
+        return llfn
+    }
+
+    // Define the types up front for the signatures of the rust_try and
+    // rust_try_inner functions.
+    let tcx = ccx.tcx();
+    let i8p = tcx.mk_mut_ptr(tcx.types.i8);
+    let fn_ty = tcx.mk_bare_fn(ty::BareFnTy {
+        unsafety: ast::Unsafety::Unsafe,
+        abi: abi::Rust,
+        sig: ty::Binder(ty::FnSig {
+            inputs: vec![i8p],
+            output: ty::FnOutput::FnConverging(tcx.mk_nil()),
+            variadic: false,
+        }),
+    });
+    let fn_ty = tcx.mk_fn(None, fn_ty);
+    let output = ty::FnOutput::FnConverging(i8p);
+    let try_fn_ty  = tcx.mk_bare_fn(ty::BareFnTy {
+        unsafety: ast::Unsafety::Unsafe,
+        abi: abi::Rust,
+        sig: ty::Binder(ty::FnSig {
+            inputs: vec![fn_ty, i8p],
+            output: output,
+            variadic: false,
+        }),
+    });
+    let rust_try = f(tcx.mk_fn(None, try_fn_ty), output);
+    *ccx.rust_try_fn().borrow_mut() = Some(rust_try);
+    return rust_try
+}
diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs
index 1fa996f76b9..8901361b279 100644
--- a/src/librustc_trans/trans/meth.rs
+++ b/src/librustc_trans/trans/meth.rs
@@ -550,9 +550,7 @@ fn trans_object_shim<'a, 'tcx>(
     let shim_fn_ty = tcx.mk_fn(None, fty);
     let method_bare_fn_ty = tcx.mk_fn(None, method_ty);
     let function_name = link::mangle_internal_name_by_type_and_seq(ccx, shim_fn_ty, "object_shim");
-    let llfn = declare::define_internal_rust_fn(ccx, &function_name, shim_fn_ty).unwrap_or_else(||{
-        ccx.sess().bug(&format!("symbol `{}` already defined", function_name));
-    });
+    let llfn = declare::define_internal_rust_fn(ccx, &function_name, shim_fn_ty);
 
     let sig = ccx.tcx().erase_late_bound_regions(&fty.sig);
 
diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs
index 98fe57ec314..217181da142 100644
--- a/src/librustc_trans/trans/monomorphize.rs
+++ b/src/librustc_trans/trans/monomorphize.rs
@@ -137,10 +137,9 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         let lldecl = if abi != abi::Rust {
             foreign::decl_rust_fn_with_foreign_abi(ccx, mono_ty, &s[..])
         } else {
-            // FIXME(nagisa): perhaps needs a more fine grained selection? See setup_lldecl below.
-            declare::define_internal_rust_fn(ccx, &s[..], mono_ty).unwrap_or_else(||{
-                ccx.sess().bug(&format!("symbol `{}` already defined", s));
-            })
+            // FIXME(nagisa): perhaps needs a more fine grained selection? See
+            // setup_lldecl below.
+            declare::define_internal_rust_fn(ccx, &s, mono_ty)
         };
 
         ccx.monomorphized().borrow_mut().insert(hash_id.take().unwrap(), lldecl);
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 9042cedccc8..17140db904f 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -5096,6 +5096,21 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) {
                                                                   ty::BrAnon(0))),
                                     param(ccx, 0))], tcx.types.u64),
 
+            "try" => {
+                let mut_u8 = tcx.mk_mut_ptr(tcx.types.u8);
+                let fn_ty = ty::BareFnTy {
+                    unsafety: ast::Unsafety::Normal,
+                    abi: abi::Rust,
+                    sig: ty::Binder(FnSig {
+                        inputs: vec![mut_u8],
+                        output: ty::FnOutput::FnConverging(tcx.mk_nil()),
+                        variadic: false,
+                    }),
+                };
+                let fn_ty = tcx.mk_bare_fn(fn_ty);
+                (0, vec![tcx.mk_fn(None, fn_ty), mut_u8], mut_u8)
+            }
+
             ref other => {
                 span_err!(tcx.sess, it.span, E0093,
                     "unrecognized intrinsic function: `{}`", *other);
diff --git a/src/libstd/rt/unwind/gcc.rs b/src/libstd/rt/unwind/gcc.rs
index 84c6d6864a9..87941e79b2f 100644
--- a/src/libstd/rt/unwind/gcc.rs
+++ b/src/libstd/rt/unwind/gcc.rs
@@ -8,10 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![allow(private_no_mangle_fns)]
+
 use prelude::v1::*;
 
 use any::Any;
-use libc::c_void;
 use rt::libunwind as uw;
 
 struct Exception {
@@ -41,7 +42,7 @@ pub unsafe fn panic(data: Box<Any + Send + 'static>) -> ! {
     }
 }
 
-pub unsafe fn cleanup(ptr: *mut c_void) -> Box<Any + Send + 'static> {
+pub unsafe fn cleanup(ptr: *mut u8) -> Box<Any + Send + 'static> {
     let my_ep = ptr as *mut Exception;
     rtdebug!("caught {}", (*my_ep).uwe.exception_class);
     let cause = (*my_ep).cause.take();
@@ -89,7 +90,7 @@ pub mod eabi {
     use rt::libunwind as uw;
     use libc::c_int;
 
-    extern "C" {
+    extern {
         fn __gcc_personality_v0(version: c_int,
                                 actions: uw::_Unwind_Action,
                                 exception_class: uw::_Unwind_Exception_Class,
@@ -98,9 +99,8 @@ pub mod eabi {
             -> uw::_Unwind_Reason_Code;
     }
 
-    #[lang="eh_personality"]
-    #[no_mangle] // referenced from rust_try.ll
-    #[allow(private_no_mangle_fns)]
+    #[lang = "eh_personality"]
+    #[no_mangle]
     extern fn rust_eh_personality(
         version: c_int,
         actions: uw::_Unwind_Action,
@@ -115,8 +115,9 @@ pub mod eabi {
         }
     }
 
-    #[no_mangle] // referenced from rust_try.ll
-    pub extern "C" fn rust_eh_personality_catch(
+    #[cfg_attr(not(stage0), lang = "eh_personality_catch")]
+    #[no_mangle]
+    pub extern fn rust_eh_personality_catch(
         _version: c_int,
         actions: uw::_Unwind_Action,
         _exception_class: uw::_Unwind_Exception_Class,
@@ -142,7 +143,7 @@ pub mod eabi {
     use rt::libunwind as uw;
     use libc::c_int;
 
-    extern "C" {
+    extern {
         fn __gcc_personality_sj0(version: c_int,
                                 actions: uw::_Unwind_Action,
                                 exception_class: uw::_Unwind_Exception_Class,
@@ -151,9 +152,9 @@ pub mod eabi {
             -> uw::_Unwind_Reason_Code;
     }
 
-    #[lang="eh_personality"]
-    #[no_mangle] // referenced from rust_try.ll
-    pub extern "C" fn rust_eh_personality(
+    #[lang = "eh_personality"]
+    #[no_mangle]
+    pub extern fn rust_eh_personality(
         version: c_int,
         actions: uw::_Unwind_Action,
         exception_class: uw::_Unwind_Exception_Class,
@@ -167,8 +168,9 @@ pub mod eabi {
         }
     }
 
-    #[no_mangle] // referenced from rust_try.ll
-    pub extern "C" fn rust_eh_personality_catch(
+    #[cfg_attr(not(stage0), lang = "eh_personality_catch")]
+    #[no_mangle]
+    pub extern fn rust_eh_personality_catch(
         _version: c_int,
         actions: uw::_Unwind_Action,
         _exception_class: uw::_Unwind_Exception_Class,
@@ -196,17 +198,16 @@ pub mod eabi {
     use rt::libunwind as uw;
     use libc::c_int;
 
-    extern "C" {
+    extern {
         fn __gcc_personality_v0(state: uw::_Unwind_State,
                                 ue_header: *mut uw::_Unwind_Exception,
                                 context: *mut uw::_Unwind_Context)
             -> uw::_Unwind_Reason_Code;
     }
 
-    #[lang="eh_personality"]
-    #[no_mangle] // referenced from rust_try.ll
-    #[allow(private_no_mangle_fns)]
-    extern "C" fn rust_eh_personality(
+    #[lang = "eh_personality"]
+    #[no_mangle]
+    extern fn rust_eh_personality(
         state: uw::_Unwind_State,
         ue_header: *mut uw::_Unwind_Exception,
         context: *mut uw::_Unwind_Context
@@ -217,8 +218,9 @@ pub mod eabi {
         }
     }
 
-    #[no_mangle] // referenced from rust_try.ll
-    pub extern "C" fn rust_eh_personality_catch(
+    #[cfg_attr(not(stage0), lang = "eh_personality_catch")]
+    #[no_mangle]
+    pub extern fn rust_eh_personality_catch(
         state: uw::_Unwind_State,
         _ue_header: *mut uw::_Unwind_Exception,
         _context: *mut uw::_Unwind_Context
@@ -266,7 +268,7 @@ pub mod eabi {
     }
 
     type _Unwind_Personality_Fn =
-        extern "C" fn(
+        extern fn(
             version: c_int,
             actions: uw::_Unwind_Action,
             exception_class: uw::_Unwind_Exception_Class,
@@ -274,7 +276,7 @@ pub mod eabi {
             context: *mut uw::_Unwind_Context
         ) -> uw::_Unwind_Reason_Code;
 
-    extern "C" {
+    extern {
         fn __gcc_personality_seh0(
             exceptionRecord: *mut EXCEPTION_RECORD,
             establisherFrame: *mut c_void,
@@ -291,10 +293,9 @@ pub mod eabi {
         ) -> EXCEPTION_DISPOSITION;
     }
 
-    #[lang="eh_personality"]
-    #[no_mangle] // referenced from rust_try.ll
-    #[allow(private_no_mangle_fns)]
-    extern "C" fn rust_eh_personality(
+    #[lang = "eh_personality"]
+    #[no_mangle]
+    extern fn rust_eh_personality(
         exceptionRecord: *mut EXCEPTION_RECORD,
         establisherFrame: *mut c_void,
         contextRecord: *mut CONTEXT,
@@ -307,15 +308,16 @@ pub mod eabi {
         }
     }
 
-    #[no_mangle] // referenced from rust_try.ll
-    pub extern "C" fn rust_eh_personality_catch(
+    #[cfg_attr(not(stage0), lang = "eh_personality_catch")]
+    #[no_mangle]
+    pub extern fn rust_eh_personality_catch(
         exceptionRecord: *mut EXCEPTION_RECORD,
         establisherFrame: *mut c_void,
         contextRecord: *mut CONTEXT,
         dispatcherContext: *mut DISPATCHER_CONTEXT
     ) -> EXCEPTION_DISPOSITION
     {
-        extern "C" fn inner(
+        extern fn inner(
                 _version: c_int,
                 actions: uw::_Unwind_Action,
                 _exception_class: uw::_Unwind_Exception_Class,
diff --git a/src/libstd/rt/unwind/mod.rs b/src/libstd/rt/unwind/mod.rs
index c403976745a..db2310ba361 100644
--- a/src/libstd/rt/unwind/mod.rs
+++ b/src/libstd/rt/unwind/mod.rs
@@ -69,7 +69,6 @@ use cmp;
 use panicking;
 use fmt;
 use intrinsics;
-use libc::c_void;
 use mem;
 use sync::atomic::{self, Ordering};
 use sys_common::mutex::Mutex;
@@ -127,7 +126,7 @@ extern {}
 ///   run.
 pub unsafe fn try<F: FnOnce()>(f: F) -> Result<(), Box<Any + Send>> {
     let mut f = Some(f);
-    return inner_try(try_fn::<F>, &mut f as *mut _ as *mut c_void);
+    return inner_try(try_fn::<F>, &mut f as *mut _ as *mut u8);
 
     // If an inner function were not used here, then this generic function `try`
     // uses the native symbol `rust_try`, for which the code is statically
@@ -140,11 +139,12 @@ pub unsafe fn try<F: FnOnce()>(f: F) -> Result<(), Box<Any + Send>> {
     // `dllexport`, but it's easier to not have conditional `src/rt/rust_try.ll`
     // files and instead just have this non-generic shim the compiler can take
     // care of exposing correctly.
-    unsafe fn inner_try(f: extern fn(*mut c_void), data: *mut c_void)
+    #[cfg(not(stage0))]
+    unsafe fn inner_try(f: fn(*mut u8), data: *mut u8)
                         -> Result<(), Box<Any + Send>> {
         let prev = PANICKING.with(|s| s.get());
         PANICKING.with(|s| s.set(false));
-        let ep = rust_try(f, data);
+        let ep = intrinsics::try(f, data);
         PANICKING.with(|s| s.set(prev));
         if ep.is_null() {
             Ok(())
@@ -152,8 +152,13 @@ pub unsafe fn try<F: FnOnce()>(f: F) -> Result<(), Box<Any + Send>> {
             Err(imp::cleanup(ep))
         }
     }
+    #[cfg(stage0)]
+    unsafe fn inner_try(f: fn(*mut u8), data: *mut u8)
+                        -> Result<(), Box<Any + Send>> {
+        Ok(f(data))
+    }
 
-    extern fn try_fn<F: FnOnce()>(opt_closure: *mut c_void) {
+    fn try_fn<F: FnOnce()>(opt_closure: *mut u8) {
         let opt_closure = opt_closure as *mut Option<F>;
         unsafe { (*opt_closure).take().unwrap()(); }
     }
@@ -163,8 +168,8 @@ pub unsafe fn try<F: FnOnce()>(f: F) -> Result<(), Box<Any + Send>> {
         // When f(...) returns normally, the return value is null.
         // When f(...) throws, the return value is a pointer to the caught
         // exception object.
-        fn rust_try(f: extern fn(*mut c_void),
-                    data: *mut c_void) -> *mut c_void;
+        fn rust_try(f: extern fn(*mut u8),
+                    data: *mut u8) -> *mut u8;
     }
 }
 
diff --git a/src/libstd/rt/unwind/seh.rs b/src/libstd/rt/unwind/seh.rs
index 632ab4f8e25..ed44f9a8bda 100644
--- a/src/libstd/rt/unwind/seh.rs
+++ b/src/libstd/rt/unwind/seh.rs
@@ -102,7 +102,7 @@ pub unsafe fn panic(data: Box<Any + Send + 'static>) -> ! {
     rtabort!("could not unwind stack");
 }
 
-pub unsafe fn cleanup(ptr: *mut c_void) -> Box<Any + Send + 'static> {
+pub unsafe fn cleanup(ptr: *mut u8) -> Box<Any + Send + 'static> {
     // The `ptr` here actually corresponds to the code of the exception, and our
     // real data is stored in our thread local.
     rtassert!(ptr as DWORD == RUST_PANIC);
@@ -135,8 +135,9 @@ fn rust_eh_personality() {
 // to ensure that it's code is RUST_PANIC, which was set by the call to
 // `RaiseException` above in the `panic` function.
 #[no_mangle]
+#[lang = "msvc_try_filter"]
 pub extern fn __rust_try_filter(eh_ptrs: *mut EXCEPTION_POINTERS,
-                                _rbp: *mut c_void) -> i32 {
+                                _rbp: *mut u8) -> i32 {
     unsafe {
         ((*(*eh_ptrs).ExceptionRecord).ExceptionCode == RUST_PANIC) as i32
     }
diff --git a/src/rt/rust_try.ll b/src/rt/rust_try.ll
deleted file mode 100644
index 8643131d0fb..00000000000
--- a/src/rt/rust_try.ll
+++ /dev/null
@@ -1,54 +0,0 @@
-; Copyright 2013 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.
-
-; Rust's try-catch
-; When f(...) returns normally, the return value is null.
-; When f(...) throws, the return value is a pointer to the caught exception object.
-
-; See also: libstd/rt/unwind/mod.rs
-
-define i8* @rust_try(void (i8*)* %f, i8* %env)
-    personality i8* bitcast (i32 (...)* @rust_eh_personality_catch to i8*)
-{
-
-    %1 = invoke i8* @rust_try_inner(void (i8*)* %f, i8* %env)
-        to label %normal
-        unwind label %catch
-
-normal:
-    ret i8* %1
-
-catch:
-    landingpad { i8*, i32 } catch i8* null
-    ; rust_try_inner's landing pad does not resume unwinds, so execution will
-    ; never reach here
-    ret i8* null
-}
-
-define internal i8* @rust_try_inner(void (i8*)* %f, i8* %env)
-    personality i8* bitcast (i32 (...)* @rust_eh_personality to i8*)
-{
-
-    invoke void %f(i8* %env)
-        to label %normal
-        unwind label %catch
-
-normal:
-    ret i8* null
-
-catch:
-    %1 = landingpad { i8*, i32 } catch i8* null
-    ; extract and return pointer to the exception object
-    %2 = extractvalue { i8*, i32 } %1, 0
-    ret i8* %2
-}
-
-declare i32 @rust_eh_personality(...)
-declare i32 @rust_eh_personality_catch(...)
diff --git a/src/rt/rust_try_msvc_32.ll b/src/rt/rust_try_msvc_32.ll
deleted file mode 100644
index bdee53b136e..00000000000
--- a/src/rt/rust_try_msvc_32.ll
+++ /dev/null
@@ -1,42 +0,0 @@
-; 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.
-
-; 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
diff --git a/src/rt/rust_try_msvc_64.ll b/src/rt/rust_try_msvc_64.ll
deleted file mode 100644
index c38e6081bf2..00000000000
--- a/src/rt/rust_try_msvc_64.ll
+++ /dev/null
@@ -1,80 +0,0 @@
-; 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.
-
-; 64-bit MSVC's definition of the `rust_try` function. This function can't be
-; defined in Rust as it's a "try-catch" block that's not expressible in Rust's
-; syntax, so we're using LLVM to produce an object file with the associated
-; handler.
-;
-; To use the correct system implementation details, this file is separate from
-; the standard rust_try.ll as we need specifically use the __C_specific_handler
-; personality function or otherwise LLVM doesn't emit SEH handling tables.
-; There's also a few fiddly bits about SEH right now in LLVM that require us to
-; structure this a fairly particular way!
-;
-; See also: src/libstd/rt/unwind/seh.rs
-
-define i8* @rust_try(void (i8*)* %f, i8* %env)
-    personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
-{
-    invoke void %f(i8* %env)
-        to label %normal
-        unwind label %catch
-
-normal:
-    ret i8* null
-
-; Here's where most of the magic happens, this is the only landing pad in rust
-; tagged with "catch" to indicate that we're catching an exception. The other
-; catch handlers in rust_try.ll just catch *all* exceptions, but that's because
-; most exceptions are already filtered out by their personality function.
-;
-; For MSVC we're just using a standard personality function that we can't
-; customize, so we need to do the exception filtering ourselves, and this is
-; currently performed by the `__rust_try_filter` function. This function,
-; specified in the landingpad instruction, will be invoked by Windows SEH
-; routines and will return whether the exception in question can be caught (aka
-; the Rust runtime is the one that threw the exception).
-;
-; To get this to compile (currently LLVM segfaults if it's not in this
-; particular structure), when the landingpad is executing we test to make sure
-; that the ID of the exception being thrown is indeed the one that we were
-; expecting. If it's not, we resume the exception, and otherwise we return the
-; pointer that we got
-;
-; Full disclosure: It's not clear to me what this `llvm.eh.typeid` stuff is
-; doing *other* then just allowing LLVM to compile this file without
-; segfaulting. I would expect the entire landing pad to just be:
-;
-;     %vals = landingpad ...
-;     %ehptr = extractvalue { i8*, i32 } %vals, 0
-;     ret i8* %ehptr
-;
-; but apparently LLVM chokes on this, so we do the more complicated thing to
-; placate it.
-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 @__C_specific_handler(...)
-declare i32 @__rust_try_filter(i8*, i8*)
-declare i32 @llvm.eh.typeid.for(i8*) readnone nounwind
diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp
index 163e95b890f..5007af0e777 100644
--- a/src/rustllvm/RustWrapper.cpp
+++ b/src/rustllvm/RustWrapper.cpp
@@ -120,7 +120,8 @@ extern "C" void LLVMAddDereferenceableCallSiteAttr(LLVMValueRef Instr, unsigned
                                                          idx, B)));
 }
 
-extern "C" void LLVMAddFunctionAttribute(LLVMValueRef Fn, unsigned index, uint64_t Val) {
+extern "C" void LLVMAddFunctionAttribute(LLVMValueRef Fn, unsigned index,
+                                         uint64_t Val) {
   Function *A = unwrap<Function>(Fn);
   AttrBuilder B;
   B.addRawValue(Val);