]> git.lizzy.rs Git - rust.git/commitdiff
trans: Move rust_try into the compiler
authorAlex Crichton <alex@alexcrichton.com>
Mon, 20 Jul 2015 20:27:38 +0000 (13:27 -0700)
committerAlex Crichton <alex@alexcrichton.com>
Tue, 21 Jul 2015 23:08:11 +0000 (16:08 -0700)
This commit moves the IR files in the distribution, rust_try.ll,
rust_try_msvc_64.ll, and rust_try_msvc_32.ll into the compiler from the main
distribution. There's a few reasons for this change:

* LLVM changes its IR syntax from time to time, so it's very difficult to
  have these files build across many LLVM versions simultaneously. We'll likely
  want to retain this ability for quite some time into the future.
* The implementation of these files is closely tied to the compiler and runtime
  itself, so it makes sense to fold it into a location which can do more
  platform-specific checks for various implementation details (such as MSVC 32
  vs 64-bit).
* This removes LLVM as a build-time dependency of the standard library. This may
  end up becoming very useful if we move towards building the standard library
  with Cargo.

In the immediate future, however, this commit should restore compatibility with
LLVM 3.5 and 3.6.

25 files changed:
mk/rt.mk
src/libcore/intrinsics.rs
src/librustc/middle/lang_items.rs
src/librustc/middle/weak_lang_items.rs
src/librustc_llvm/lib.rs
src/librustc_trans/trans/build.rs
src/librustc_trans/trans/builder.rs
src/librustc_trans/trans/callee.rs
src/librustc_trans/trans/cleanup.rs
src/librustc_trans/trans/closure.rs
src/librustc_trans/trans/common.rs
src/librustc_trans/trans/context.rs
src/librustc_trans/trans/declare.rs
src/librustc_trans/trans/foreign.rs
src/librustc_trans/trans/intrinsic.rs
src/librustc_trans/trans/meth.rs
src/librustc_trans/trans/monomorphize.rs
src/librustc_typeck/check/mod.rs
src/libstd/rt/unwind/gcc.rs
src/libstd/rt/unwind/mod.rs
src/libstd/rt/unwind/seh.rs
src/rt/rust_try.ll [deleted file]
src/rt/rust_try_msvc_32.ll [deleted file]
src/rt/rust_try_msvc_64.ll [deleted file]
src/rustllvm/RustWrapper.cpp

index c70f9e8a37addfd80a78855c85de180943602719..69277e774e43bf99e41f767dfd70a4c1608c53d9 100644 (file)
--- a/mk/rt.mk
+++ b/mk/rt.mk
@@ -54,15 +54,6 @@ NATIVE_DEPS_miniz_$(1) = miniz.c
 NATIVE_DEPS_rust_builtin_$(1) := rust_builtin.c \
                        rust_android_dummy.c
 NATIVE_DEPS_rustrt_native_$(1) := arch/$$(HOST_$(1))/record_sp.S
-ifeq ($$(findstring msvc,$(1)),msvc)
-ifeq ($$(findstring i686,$(1)),i686)
-NATIVE_DEPS_rustrt_native_$(1) += rust_try_msvc_32.ll
-else
-NATIVE_DEPS_rustrt_native_$(1) += rust_try_msvc_64.ll
-endif
-else
-NATIVE_DEPS_rustrt_native_$(1) += rust_try.ll
-endif
 NATIVE_DEPS_rust_test_helpers_$(1) := rust_test_helpers.c
 NATIVE_DEPS_morestack_$(1) := arch/$$(HOST_$(1))/morestack.S
 
@@ -76,14 +67,6 @@ NATIVE_DEPS_morestack_$(1) := arch/$$(HOST_$(1))/morestack.S
 
 RT_OUTPUT_DIR_$(1) := $(1)/rt
 
-$$(RT_OUTPUT_DIR_$(1))/%.o: $(S)src/rt/%.ll $$(MKFILE_DEPS) \
-           $$(LLVM_CONFIG_$$(CFG_BUILD))
-       @mkdir -p $$(@D)
-       @$$(call E, compile: $$@)
-       $$(Q)$$(LLC_$$(CFG_BUILD)) $$(CFG_LLC_FLAGS_$(1)) \
-           -filetype=obj -mtriple=$$(CFG_LLVM_TARGET_$(1)) \
-           -relocation-model=pic -o $$@ $$<
-
 $$(RT_OUTPUT_DIR_$(1))/%.o: $(S)src/rt/%.c $$(MKFILE_DEPS)
        @mkdir -p $$(@D)
        @$$(call E, compile: $$@)
@@ -122,7 +105,6 @@ define THIRD_PARTY_LIB
 OBJS_$(2)_$(1) := $$(NATIVE_DEPS_$(2)_$(1):%=$$(RT_OUTPUT_DIR_$(1))/%)
 OBJS_$(2)_$(1) := $$(OBJS_$(2)_$(1):.c=.o)
 OBJS_$(2)_$(1) := $$(OBJS_$(2)_$(1):.cpp=.o)
-OBJS_$(2)_$(1) := $$(OBJS_$(2)_$(1):.ll=.o)
 OBJS_$(2)_$(1) := $$(OBJS_$(2)_$(1):.S=.o)
 NATIVE_$(2)_$(1) := $$(call CFG_STATIC_LIB_NAME_$(1),$(2))
 $$(RT_OUTPUT_DIR_$(1))/$$(NATIVE_$(2)_$(1)): $$(OBJS_$(2)_$(1))
index 74901553149abce3083c27d6c77262ad0d093b73..ef022179772c4cd4c9a60eb53a143e6d1eca9291 100644 (file)
@@ -602,4 +602,10 @@ pub fn volatile_copy_nonoverlapping_memory<T>(dst: *mut T, src: *const T,
     /// 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;
 }
index cf528e0c8a91423d7363da2f510290009ab75544..f7cd94f30af12e2a30643fbc25df39201109893b 100644 (file)
@@ -326,6 +326,8 @@ pub fn collect_language_items(krate: &ast::Crate,
     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;
index 60a9ffc7d2e13b80a6e1824a55efdb6e02315504..72fda9a7ae06ac236f82eda442dc6f2c4bf42f95 100644 (file)
@@ -119,7 +119,7 @@ fn visit_foreign_item(&mut self, i: &ast::ForeignItem) {
 ) }
 
 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;
 }
index 7734704b021a851a66b5396343acfdbd0671b1c9..83f8619c5eeabd1e2976b976eae81da9891b3adf 100644 (file)
@@ -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 @@ pub enum DLLStorageClassTypes {
         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)
     }
 }
 
index 3e4452a23b9f7c893460421590bb25c506cbfdea..5a3fcc8d27f3cb8bf422c6d6e8dabc579eb89d66 100644 (file)
@@ -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)
 }
index e39fc18dc7bf1140c70c5738f011b4cb37c8be69..107ae378ac4463925e70fd978af74f270b176dcf 100644 (file)
@@ -937,6 +937,12 @@ pub fn landing_pad(&self, ty: Type, pers_fn: ValueRef,
         }
     }
 
+    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 {
index debc8dd59c04c0187547627a39f288646b93e124..7900000d3a9df1d33478acb7ad2b119721182047 100644 (file)
@@ -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,
index 1891320313a851f562a8ffb89e21083cdebfa786..37722d5a549fe7f7a693122ac241b8da0f342f96 100644 (file)
 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 @@ fn get_or_create_landing_pad(&'blk self) -> BasicBlockRef {
                                     &[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);
index d813e9dbf40fab9ca75b4c9d21f04697c9817557..f00029ec2ff932a8d762423017949e92f963ee36 100644 (file)
@@ -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();
index d7d3be699cb902891b396457a94e9ca16179869a..1e87053c2ae63e422e35d86d3fbffbd5e1cdbb9b 100644 (file)
@@ -25,6 +25,7 @@
 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 @@ pub fn monomorphize<T>(&self, value: &T) -> T
     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
index 5a4bd7ff3a18468847b5bcb47ef974c1b7557ad5..760a4ae827aac66ef86adb86d07278e3d26b7f58 100644 (file)
@@ -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 @@ fn new<'a>(shared: &SharedCrateContext<'a, '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 @@ pub fn eh_personality<'a>(&'a self) -> &'a RefCell<Option<ValueRef>> {
         &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 @@ macro_rules! mk_struct {
     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.
index b29da9d560fea89a6eda936982b4ab4f67f341f8..c802de91e38b3da452a8b09f64de196bad07fc1c 100644 (file)
@@ -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(|_|{
index 9e8c0189a9762722a7683480a7bc632c623684cf..e102e3cd062be220dbf886d712cbcecef7c69be7 100644 (file)
@@ -627,9 +627,7 @@ fn build_rust_fn<'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
index b449c3ad060b81a82f67f31657ee0067c5eaf2d5..e78218fd10dd8fab399075745aafb2ae4c117ef9 100644 (file)
@@ -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::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::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
+}
index 1fa996f76b9a28809a2778a3ee2ac2342089abdd..8901361b27976396cfada7ff1c19b21ed4914634 100644 (file)
@@ -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);
 
index 98fe57ec31446f6cfac18a613707bd4f7d6e1fd0..217181da1421aac8ac688d3a52a8091cbbfca8b9 100644 (file)
@@ -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);
index 9042cedccc8571a836648e11159c3b7852c65b75..17140db904f628e4d4f009642e141c1357dfb8e1 100644 (file)
@@ -5096,6 +5096,21 @@ fn param<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, n: u32) -> Ty<'tcx> {
                                                                   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);
index 84c6d6864a9e5d592aee14b45adf29d46daa331c..87941e79b2f7d79e6d2aa87b1454172ea9035be9 100644 (file)
@@ -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 @@ fn __gcc_personality_v0(version: c_int,
             -> 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 @@ fn __gcc_personality_v0(version: c_int,
         }
     }
 
-    #[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 @@ fn __gcc_personality_sj0(version: c_int,
             -> 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 extern "C" fn rust_eh_personality(
         }
     }
 
-    #[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 @@ extern "C" fn rust_eh_personality(
         }
     }
 
-    #[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 enum EXCEPTION_DISPOSITION {
     }
 
     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 enum EXCEPTION_DISPOSITION {
             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 @@ fn _GCC_specific_handler(
         ) -> 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 @@ extern "C" fn rust_eh_personality(
         }
     }
 
-    #[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,
index c403976745aa4769af0e9ad3730d0714ab572a10..db2310ba361b342d9c436f523943e7aa57beef2c 100644 (file)
@@ -69,7 +69,6 @@
 use panicking;
 use fmt;
 use intrinsics;
-use libc::c_void;
 use mem;
 use sync::atomic::{self, Ordering};
 use sys_common::mutex::Mutex;
 ///   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 @@ unsafe fn inner_try(f: extern fn(*mut c_void), data: *mut c_void)
             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 @@ unsafe fn inner_try(f: extern fn(*mut c_void), data: *mut c_void)
         // 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;
     }
 }
 
index 632ab4f8e253750c23028b7d71fe2f1dabfa5ad4..ed44f9a8bda9499b0bfa7835295503afd999eb18 100644 (file)
@@ -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 (file)
index 8643131..0000000
+++ /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 (file)
index bdee53b..0000000
+++ /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 (file)
index c38e608..0000000
+++ /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
index 163e95b890f4b25ab2a513a9d3774cd98e679fbc..5007af0e777b84bc080f71ebb74cf9945edb1895 100644 (file)
@@ -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);