Skip to content

std: Move pc-windows-gnu to SEH-based unwinding #31313

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions mk/cfg/i686-pc-windows-gnu.mk
Original file line number Diff line number Diff line change
@@ -22,6 +22,5 @@ CFG_LDPATH_i686-pc-windows-gnu :=
CFG_RUN_i686-pc-windows-gnu=$(2)
CFG_RUN_TARG_i686-pc-windows-gnu=$(call CFG_RUN_i686-pc-windows-gnu,,$(2))
CFG_GNU_TRIPLE_i686-pc-windows-gnu := i686-w64-mingw32
CFG_THIRD_PARTY_OBJECTS_i686-pc-windows-gnu := crt2.o dllcrt2.o
CFG_INSTALLED_OBJECTS_i686-pc-windows-gnu := crt2.o dllcrt2.o rsbegin.o rsend.o
CFG_RUSTRT_HAS_STARTUP_OBJS_i686-pc-windows-gnu := 1
CFG_THIRD_PARTY_OBJECTS_i686-pc-windows-gnu :=
CFG_INSTALLED_OBJECTS_i686-pc-windows-gnu :=
5 changes: 2 additions & 3 deletions mk/cfg/x86_64-pc-windows-gnu.mk
Original file line number Diff line number Diff line change
@@ -22,6 +22,5 @@ CFG_LDPATH_x86_64-pc-windows-gnu :=
CFG_RUN_x86_64-pc-windows-gnu=$(2)
CFG_RUN_TARG_x86_64-pc-windows-gnu=$(call CFG_RUN_x86_64-pc-windows-gnu,,$(2))
CFG_GNU_TRIPLE_x86_64-pc-windows-gnu := x86_64-w64-mingw32
CFG_THIRD_PARTY_OBJECTS_x86_64-pc-windows-gnu := crt2.o dllcrt2.o
CFG_INSTALLED_OBJECTS_x86_64-pc-windows-gnu := crt2.o dllcrt2.o rsbegin.o rsend.o
CFG_RUSTRT_HAS_STARTUP_OBJS_x86_64-pc-windows-gnu := 1
CFG_THIRD_PARTY_OBJECTS_x86_64-pc-windows-gnu :=
CFG_INSTALLED_OBJECTS_x86_64-pc-windows-gnu :=
1 change: 0 additions & 1 deletion mk/dist.mk
Original file line number Diff line number Diff line change
@@ -58,7 +58,6 @@ PKG_FILES := \
libcoretest \
libbacktrace \
rt \
rtstartup \
rustllvm \
snapshots.txt \
rust-installer \
12 changes: 3 additions & 9 deletions mk/rt.mk
Original file line number Diff line number Diff line change
@@ -291,10 +291,8 @@ BACKTRACE_NAME_$(1) := $$(call CFG_STATIC_LIB_NAME_$(1),backtrace)
BACKTRACE_LIB_$(1) := $$(RT_OUTPUT_DIR_$(1))/$$(BACKTRACE_NAME_$(1))
BACKTRACE_BUILD_DIR_$(1) := $$(RT_OUTPUT_DIR_$(1))/libbacktrace

# We don't use this on platforms that aren't linux-based (with the exception of
# msys2/mingw builds on windows, which use it to read the dwarf debug
# information) so just make the file available, the compilation of libstd won't
# actually build it.
# We don't use this on platforms that aren't linux-based so just make the file
# available, the compilation of libstd won't actually build it.
ifeq ($$(findstring darwin,$$(OSTYPE_$(1))),darwin)
# See comment above
$$(BACKTRACE_LIB_$(1)):
@@ -307,7 +305,7 @@ $$(BACKTRACE_LIB_$(1)):
touch $$@
else

ifeq ($$(findstring msvc,$(1)),msvc)
ifeq ($$(findstring windows,$(1)),windows)
# See comment above
$$(BACKTRACE_LIB_$(1)):
touch $$@
@@ -382,10 +380,6 @@ endif # endif for darwin
ifeq ($$(findstring musl,$(1)),musl)
$$(RT_OUTPUT_DIR_$(1))/%: $$(CFG_MUSL_ROOT)/lib/%
cp $$^ $$@
else
# Ask gcc where it is
$$(RT_OUTPUT_DIR_$(1))/%:
cp $$(shell $$(CC_$(1)) -print-file-name=$$(@F)) $$@
endif

endef
64 changes: 32 additions & 32 deletions mk/target.mk
Original file line number Diff line number Diff line change
@@ -126,34 +126,6 @@ $$(TBIN$(1)_T_$(2)_H_$(3))/$(4)$$(X_$(2)): \

endef

# Macro for building runtime startup/shutdown object files;
# these are Rust's equivalent of crti.o, crtn.o
#
# $(1) - stage
# $(2) - target triple
# $(3) - host triple
# $(4) - object basename
define TARGET_RUSTRT_STARTUP_OBJ

$$(TLIB$(1)_T_$(2)_H_$(3))/$(4).o: \
$(S)src/rtstartup/$(4).rs \
$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.core \
$$(HSREQ$(1)_T_$(2)_H_$(3)) \
| $$(TBIN$(1)_T_$(2)_H_$(3))/
@$$(call E, rustc: $$@)
$$(STAGE$(1)_T_$(2)_H_$(3)) --emit=obj -o $$@ $$<

ifeq ($$(CFG_RUSTRT_HAS_STARTUP_OBJS_$(2)), 1)
# Add dependencies on Rust startup objects to all crates that depend on core.
# This ensures that they are built after core (since they depend on it),
# but before everything else (since they are needed for linking dylib crates).
$$(foreach crate, $$(TARGET_CRATES), \
$$(if $$(findstring core,$$(DEPS_$$(crate))), \
$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$$(crate))) : $$(TLIB$(1)_T_$(2)_H_$(3))/$(4).o
endif

endef

# Every recipe in RUST_TARGET_STAGE_N outputs to $$(TLIB$(1)_T_$(2)_H_$(3),
# a directory that can be cleaned out during the middle of a run of
# the get-snapshot.py script. Therefore, every recipe needs to have
@@ -166,7 +138,10 @@ SNAPSHOT_RUSTC_POST_CLEANUP=$(HBIN0_H_$(CFG_BUILD))/rustc$(X_$(CFG_BUILD))

define TARGET_HOST_RULES

$$(TLIB$(1)_T_$(2)_H_$(3))/:
$$(TLIB$(1)_T_$(2)_H_$(3))/: | $$(SNAPSHOT_RUSTC_POST_CLEANUP)
mkdir -p $$@

$$(TBIN$(1)_T_$(2)_H_$(3))/: | $$(SNAPSHOT_RUSTC_POST_CLEANUP)
mkdir -p $$@

$$(TLIB$(1)_T_$(2)_H_$(3))/%: $$(RT_OUTPUT_DIR_$(2))/% \
@@ -197,8 +172,33 @@ $(foreach host,$(CFG_HOST), \
$(foreach tool,$(TOOLS), \
$(eval $(call TARGET_TOOL,$(stage),$(target),$(host),$(tool)))))))

# FIXME(stage0) - remove everything here after a snapshot
#
# The stage0 compiler requires the rsend.o, rsbegin.o, crt2.o, and dllcrt2.o
# startup objects on the pc-windows-gnu targets, but that's no longer the case.
# Hack in support to the makefiles to ensure that these objects all exist.
#
# Note that the rs*.o files can just be blank object files.
define STARTUP_OBJS_COMPAT
ifeq ($$(findstring pc-windows-gnu,$(2)),pc-windows-gnu)
DUMMY_DEPS_$(2)_H_$(3) := \
$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.core \
$$(HSREQ$(1)_T_$(2)_H_$(3))/stamp.core
$$(TLIB$(1)_T_$(2)_H_$(3))/rsend.o $$(TLIB$(1)_T_$(2)_H_$(3))/rsbegin.o: \
$$(DUMMY_DEPS_$(2)_H_$(3) \
| $$(TLIB$(1)_T_$(2)_H_$(3))/ $$(SNAPSHOT_RUSTC_POST_CLEANUP)
$$(CC_$(2)) $$(CFG_GCCISH_CFLAGS_$(2)) -c -x c - -o $$@ < /dev/null
$$(TLIB$(1)_T_$(2)_H_$(3))/dllcrt2.o $$(TLIB$(1)_T_$(2)_H_$(3))/crt2.o: \
$$(DUMMY_DEPS_$(2)_H_$(3) \
| $$(TLIB$(1)_T_$(2)_H_$(3))/ $$(SNAPSHOT_RUSTC_POST_CLEANUP)
cp $$(shell $$(CC_$(2)) -print-file-name=$$(@F)) $$@
$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.std: \
$$(TLIB$(1)_T_$(2)_H_$(3))/rsend.o \
$$(TLIB$(1)_T_$(2)_H_$(3))/rsbegin.o \
$$(TLIB$(1)_T_$(2)_H_$(3))/dllcrt2.o \
$$(TLIB$(1)_T_$(2)_H_$(3))/crt2.o
endif
endef
$(foreach host,$(CFG_HOST), \
$(foreach target,$(CFG_TARGET), \
$(foreach stage,$(STAGES), \
$(foreach obj,rsbegin rsend, \
$(eval $(call TARGET_RUSTRT_STARTUP_OBJ,$(stage),$(target),$(host),$(obj)))))))
$(eval $(call STARTUP_OBJS_COMPAT,0,$(target),$(host)))))
3 changes: 0 additions & 3 deletions src/doc/book/custom-allocators.md
Original file line number Diff line number Diff line change
@@ -138,9 +138,6 @@ pub extern fn __rust_usable_size(size: usize, _align: usize) -> usize {
# fn main() {}
# #[lang = "panic_fmt"] fn panic_fmt() {}
# #[lang = "eh_personality"] fn eh_personality() {}
# #[lang = "eh_unwind_resume"] extern fn eh_unwind_resume() {}
# #[no_mangle] pub extern fn rust_eh_register_frames () {}
# #[no_mangle] pub extern fn rust_eh_unregister_frames () {}
```

After we compile this crate, it can be used as follows:
3 changes: 0 additions & 3 deletions src/doc/book/lang-items.md
Original file line number Diff line number Diff line change
@@ -59,9 +59,6 @@ fn main(argc: isize, argv: *const *const u8) -> isize {

#[lang = "eh_personality"] extern fn eh_personality() {}
#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }
# #[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {}
# #[no_mangle] pub extern fn rust_eh_register_frames () {}
# #[no_mangle] pub extern fn rust_eh_unregister_frames () {}
```

Note the use of `abort`: the `exchange_malloc` lang item is assumed to
6 changes: 0 additions & 6 deletions src/doc/book/no-stdlib.md
Original file line number Diff line number Diff line change
@@ -39,9 +39,6 @@ fn start(_argc: isize, _argv: *const *const u8) -> isize {
// provided by libstd.
#[lang = "eh_personality"] extern fn eh_personality() {}
#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }
# #[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {}
# #[no_mangle] pub extern fn rust_eh_register_frames () {}
# #[no_mangle] pub extern fn rust_eh_unregister_frames () {}
# // fn main() {} tricked you, rustdoc!
```

@@ -66,9 +63,6 @@ pub extern fn main(argc: i32, argv: *const *const u8) -> i32 {

#[lang = "eh_personality"] extern fn eh_personality() {}
#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }
# #[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {}
# #[no_mangle] pub extern fn rust_eh_register_frames () {}
# #[no_mangle] pub extern fn rust_eh_unregister_frames () {}
# // fn main() {} tricked you, rustdoc!
```

1 change: 0 additions & 1 deletion src/librustc/middle/lang_items.rs
Original file line number Diff line number Diff line change
@@ -340,7 +340,6 @@ lets_do_this! {

EhPersonalityLangItem, "eh_personality", eh_personality;
EhPersonalityCatchLangItem, "eh_personality_catch", eh_personality_catch;
EhUnwindResumeLangItem, "eh_unwind_resume", eh_unwind_resume;
MSVCTryFilterLangItem, "msvc_try_filter", msvc_try_filter;

OwnedBoxLangItem, "owned_box", owned_box;
5 changes: 0 additions & 5 deletions src/librustc/middle/weak_lang_items.rs
Original file line number Diff line number Diff line change
@@ -43,10 +43,6 @@ pub fn check_crate(krate: &hir::Crate,
if items.eh_personality().is_none() {
items.missing.push(lang_items::EhPersonalityLangItem);
}
if sess.target.target.options.custom_unwind_resume &
items.eh_unwind_resume().is_none() {
items.missing.push(lang_items::EhUnwindResumeLangItem);
}

{
let mut cx = Context { sess: sess, items: items };
@@ -123,5 +119,4 @@ impl<'a, 'v> Visitor<'v> for Context<'a> {
weak_lang_items! {
panic_fmt, PanicFmtLangItem, rust_begin_unwind;
eh_personality, EhPersonalityLangItem, rust_eh_personality;
eh_unwind_resume, EhUnwindResumeLangItem, rust_eh_unwind_resume;
}
7 changes: 0 additions & 7 deletions src/librustc_back/target/mod.rs
Original file line number Diff line number Diff line change
@@ -191,11 +191,6 @@ pub struct TargetOptions {
pub archive_format: String,
/// Is asm!() allowed? Defaults to true.
pub allow_asm: bool,
/// Whether the target uses a custom unwind resumption routine.
/// By default LLVM lowers `resume` instructions into calls to `_Unwind_Resume`
/// defined in libgcc. If this option is enabled, the target must provide
/// `eh_unwind_resume` lang item.
pub custom_unwind_resume: bool,

/// Default crate for allocation symbols to link against
pub lib_allocation_crate: String,
@@ -250,7 +245,6 @@ impl Default for TargetOptions {
post_link_objects: Vec::new(),
late_link_args: Vec::new(),
archive_format: String::new(),
custom_unwind_resume: false,
lib_allocation_crate: "alloc_system".to_string(),
exe_allocation_crate: "alloc_system".to_string(),
allow_asm: true,
@@ -365,7 +359,6 @@ impl Target {
key!(post_link_args, list);
key!(archive_format);
key!(allow_asm, bool);
key!(custom_unwind_resume, bool);

base
}
25 changes: 1 addition & 24 deletions src/librustc_back/target/windows_base.rs
Original file line number Diff line number Diff line change
@@ -23,7 +23,7 @@ pub fn opts() -> TargetOptions {
exe_suffix: ".exe".to_string(),
staticlib_prefix: "".to_string(),
staticlib_suffix: ".lib".to_string(),
no_default_libraries: true,
no_default_libraries: false,
is_like_windows: true,
archive_format: "gnu".to_string(),
pre_link_args: vec!(
@@ -60,30 +60,7 @@ pub fn opts() -> TargetOptions {

// Always enable DEP (NX bit) when it is available
"-Wl,--nxcompat".to_string(),

// Do not use the standard system startup files or libraries when linking
"-nostdlib".to_string(),
),
pre_link_objects_exe: vec!(
"crt2.o".to_string(), // mingw C runtime initialization for executables
"rsbegin.o".to_string(), // Rust compiler runtime initialization, see rsbegin.rs
),
pre_link_objects_dll: vec!(
"dllcrt2.o".to_string(), // mingw C runtime initialization for dlls
"rsbegin.o".to_string(),
),
late_link_args: vec!(
"-lmingwex".to_string(),
"-lmingw32".to_string(),
"-lgcc".to_string(), // alas, mingw* libraries above depend on libgcc
"-lmsvcrt".to_string(),
"-luser32".to_string(),
"-lkernel32".to_string(),
),
post_link_objects: vec!(
"rsend.o".to_string()
),
custom_unwind_resume: true,

.. Default::default()
}
14 changes: 14 additions & 0 deletions src/librustc_llvm/lib.rs
Original file line number Diff line number Diff line change
@@ -2490,3 +2490,17 @@ impl Drop for OperandBundleDef {
mod llvmdeps {
include! { env!("CFG_LLVM_LINKAGE_FILE") }
}

// Currenty when compiling LLVM for i686-pc-windows-gnu it will think that it's
// got "ehtable support", and these two symbols here will be referenced from
// RTDyldMemoryManager. This class is, however, only really used from jits, so
// we don't really need it to work. For now just define two dummy symbols, but
// ideally we'd upstream some patch or configure LLVM in such a way that it
// doesn't even need these symbols defined.
#[cfg(all(windows, target_env = "gnu", target_arch = "x86"))]
pub mod __dummy_llvm_required_symbols {
#[no_mangle]
pub extern fn __register_frame(_ptr: *mut u8) {}
#[no_mangle]
pub extern fn __deregister_frame(_ptr: *mut u8) {}
}
23 changes: 5 additions & 18 deletions src/librustc_trans/trans/base.rs
Original file line number Diff line number Diff line change
@@ -980,11 +980,9 @@ pub fn invoke<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,

/// Returns whether this session's target will use SEH-based unwinding.
///
/// This is only true for MSVC targets, and even then the 64-bit MSVC target
/// currently uses SEH-ish unwinding with DWARF info tables to the side (same as
/// 64-bit MinGW) instead of "full SEH".
/// This is currentlyt true for all Windows targets.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo

pub fn wants_msvc_seh(sess: &Session) -> bool {
sess.target.target.options.is_like_msvc
sess.target.target.options.is_like_windows
}

pub fn avoid_invoke(bcx: Block) -> bool {
@@ -1220,19 +1218,6 @@ pub fn call_lifetime_end(cx: Block, ptr: ValueRef) {
})
}

// Generates code for resumption of unwind at the end of a landing pad.
pub fn trans_unwind_resume(bcx: Block, lpval: ValueRef) {
if !bcx.sess().target.target.options.custom_unwind_resume {
Resume(bcx, lpval);
} else {
let exc_ptr = ExtractValue(bcx, lpval, 0);
let llunwresume = bcx.fcx.eh_unwind_resume();
Call(bcx, llunwresume, &[exc_ptr], None, DebugLoc::None);
Unreachable(bcx);
}
}


pub fn call_memcpy(cx: Block, dst: ValueRef, src: ValueRef, n_bytes: ValueRef, align: u32) {
let _icx = push_ctxt("call_memcpy");
let ccx = cx.ccx();
@@ -1981,7 +1966,9 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
record_translation_item_as_generated(ccx, fn_ast_id, param_substs);

let _icx = push_ctxt("trans_closure");
attributes::emit_uwtable(llfndecl, true);
if !wants_msvc_seh(ccx.sess()) {
attributes::emit_uwtable(llfndecl, true);
}

debug!("trans_closure(..., param_substs={:?})", param_substs);

2 changes: 1 addition & 1 deletion src/librustc_trans/trans/cleanup.rs
Original file line number Diff line number Diff line change
@@ -747,7 +747,7 @@ impl<'blk, 'tcx> CleanupHelperMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx
.unwrap();
let lp = build::Load(bcx, addr);
base::call_lifetime_end(bcx, addr);
base::trans_unwind_resume(bcx, lp);
build::Resume(bcx, lp);
}
UnwindKind::CleanupPad(_) => {
let pad = build::CleanupPad(bcx, None, &[]);
29 changes: 0 additions & 29 deletions src/librustc_trans/trans/common.rs
Original file line number Diff line number Diff line change
@@ -534,35 +534,6 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> {
}
}
}

// Returns a ValueRef of the "eh_unwind_resume" lang item if one is defined,
// otherwise declares it as an external funtion.
pub fn eh_unwind_resume(&self) -> ValueRef {
use trans::attributes;
assert!(self.ccx.sess().target.target.options.custom_unwind_resume);
match self.ccx.tcx().lang_items.eh_unwind_resume() {
Some(def_id) => {
callee::trans_fn_ref(self.ccx, def_id, ExprId(0),
self.param_substs).val
}
None => {
let mut unwresume = self.ccx.eh_unwind_resume().borrow_mut();
match *unwresume {
Some(llfn) => llfn,
None => {
let fty = Type::func(&[Type::i8p(self.ccx)], &Type::void(self.ccx));
let llfn = declare::declare_fn(self.ccx,
"rust_eh_unwind_resume",
llvm::CCallConv,
fty, ty::FnDiverging);
attributes::unwind(llfn, true);
*unwresume = Some(llfn);
llfn
}
}
}
}
}
}

// Basic block context. We create a block context for each basic block
6 changes: 0 additions & 6 deletions src/librustc_trans/trans/context.rs
Original file line number Diff line number Diff line change
@@ -153,7 +153,6 @@ pub struct LocalCrateContext<'tcx> {
dbg_cx: Option<debuginfo::CrateDebugContext<'tcx>>,

eh_personality: RefCell<Option<ValueRef>>,
eh_unwind_resume: RefCell<Option<ValueRef>>,
rust_try_fn: RefCell<Option<ValueRef>>,

intrinsics: RefCell<FnvHashMap<&'static str, ValueRef>>,
@@ -493,7 +492,6 @@ impl<'tcx> LocalCrateContext<'tcx> {
closure_vals: RefCell::new(FnvHashMap()),
dbg_cx: dbg_cx,
eh_personality: RefCell::new(None),
eh_unwind_resume: RefCell::new(None),
rust_try_fn: RefCell::new(None),
intrinsics: RefCell::new(FnvHashMap()),
n_llvm_insns: Cell::new(0),
@@ -758,10 +756,6 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
&self.local.eh_personality
}

pub fn eh_unwind_resume<'a>(&'a self) -> &'a RefCell<Option<ValueRef>> {
&self.local.eh_unwind_resume
}

pub fn rust_try_fn<'a>(&'a self) -> &'a RefCell<Option<ValueRef>> {
&self.local.rust_try_fn
}
2 changes: 1 addition & 1 deletion src/librustc_trans/trans/mir/block.rs
Original file line number Diff line number Diff line change
@@ -87,7 +87,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
let ps = self.get_personality_slot(bcx);
let lp = build::Load(bcx, ps);
base::call_lifetime_end(bcx, ps);
base::trans_unwind_resume(bcx, lp);
build::Resume(bcx, lp);
}

mir::Terminator::Return => {
5 changes: 0 additions & 5 deletions src/libstd/rt.rs
Original file line number Diff line number Diff line change
@@ -27,11 +27,6 @@
// Reexport some of our utilities which are expected by other crates.
pub use sys_common::unwind::{begin_unwind, begin_unwind_fmt};

// Rust runtime's startup objects depend on these symbols, so they must be public.
// Since sys_common isn't public, we have to re-export them here.
#[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))]
pub use sys_common::unwind::imp::eh_frame_registry::*;

#[cfg(not(test))]
#[lang = "start"]
fn lang_start(main: *const u8, argc: isize, argv: *const *const u8) -> isize {
159 changes: 0 additions & 159 deletions src/libstd/sys/common/dwarf/eh.rs

This file was deleted.

107 changes: 0 additions & 107 deletions src/libstd/sys/common/dwarf/mod.rs

This file was deleted.

15 changes: 0 additions & 15 deletions src/libstd/sys/common/gnu/mod.rs

This file was deleted.

6 changes: 0 additions & 6 deletions src/libstd/sys/common/mod.rs
Original file line number Diff line number Diff line change
@@ -30,9 +30,7 @@ pub mod args;
pub mod at_exit_imp;
pub mod backtrace;
pub mod condvar;
pub mod dwarf;
pub mod io;
pub mod libunwind;
pub mod mutex;
pub mod net;
pub mod poison;
@@ -45,10 +43,6 @@ pub mod unwind;
pub mod util;
pub mod wtf8;

#[cfg(any(all(unix, not(any(target_os = "macos", target_os = "ios", target_os = "emscripten"))),
all(windows, target_env = "gnu")))]
pub mod gnu;

// common error constructors

/// A trait for viewing representations from std types
Original file line number Diff line number Diff line change
@@ -8,95 +8,23 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Implementation of Rust stack unwinding
//! Common unwinding support to all platforms.
//!
//! For background on exception handling and stack unwinding please see
//! "Exception Handling in LLVM" (llvm.org/docs/ExceptionHandling.html) and
//! documents linked from it.
//! These are also good reads:
//! http://mentorembedded.github.io/cxx-abi/abi-eh.html
//! http://monoinfinito.wordpress.com/series/exception-handling-in-c/
//! http://www.airs.com/blog/index.php?s=exception+frames
//! This module does not contain the lowest-level implementation of unwinding
//! itself, but rather contains some of the Rust APIs used as entry points to
//! unwinding itself. For example this is the location of the lang item
//! `panic_fmt` which is the entry point of all panics from libcore.
//!
//! ## A brief summary
//!
//! Exception handling happens in two phases: a search phase and a cleanup phase.
//!
//! In both phases the unwinder walks stack frames from top to bottom using
//! information from the stack frame unwind sections of the current process's
//! modules ("module" here refers to an OS module, i.e. an executable or a
//! dynamic library).
//!
//! For each stack frame, it invokes the associated "personality routine", whose
//! address is also stored in the unwind info section.
//!
//! In the search phase, the job of a personality routine is to examine exception
//! object being thrown, and to decide whether it should be caught at that stack
//! frame. Once the handler frame has been identified, cleanup phase begins.
//!
//! In the cleanup phase, the unwinder invokes each personality routine again.
//! This time it decides which (if any) cleanup code needs to be run for
//! the current stack frame. If so, the control is transferred to a special branch
//! in the function body, the "landing pad", which invokes destructors, frees memory,
//! etc. At the end of the landing pad, control is transferred back to the unwinder
//! and unwinding resumes.
//!
//! Once stack has been unwound down to the handler frame level, unwinding stops
//! and the last personality routine transfers control to the catch block.
//!
//! ## `eh_personality` and `eh_unwind_resume`
//!
//! These language items are used by the compiler when generating unwind info.
//! The first one is the personality routine described above. The second one
//! allows compilation target to customize the process of resuming unwind at the
//! end of the landing pads. `eh_unwind_resume` is used only if `custom_unwind_resume`
//! flag in the target options is set.
//!
//! ## Frame unwind info registration
//!
//! Each module's image contains a frame unwind info section (usually ".eh_frame").
//! When a module is loaded/unloaded into the process, the unwinder must be informed
//! about the location of this section in memory. The methods of achieving that vary
//! by the platform.
//! On some (e.g. Linux), the unwinder can discover unwind info sections on its own
//! (by dynamically enumerating currently loaded modules via the dl_iterate_phdr() API
//! and finding their ".eh_frame" sections);
//! Others, like Windows, require modules to actively register their unwind info
//! sections via unwinder API (see `rust_eh_register_frames`/`rust_eh_unregister_frames`).
#![allow(dead_code)]
#![allow(unused_imports)]
//! For details on how each platform implements unwinding, see the
//! platform-specific `sys::unwind` module.
use prelude::v1::*;

use any::Any;
use boxed;
use cmp;
use panicking::{self,PANIC_COUNT};
use fmt;
use intrinsics;
use mem;
use sync::atomic::{self, Ordering};
use sys_common::mutex::Mutex;

// The actual unwinding implementation is cfg'd here, and we've got two current
// implementations. One goes through SEH on Windows and the other goes through
// libgcc via the libunwind-like API.

// *-pc-windows-msvc
#[cfg(target_env = "msvc")]
#[path = "seh.rs"] #[doc(hidden)]
pub mod imp;

// x86_64-pc-windows-gnu
#[cfg(all(windows, target_arch = "x86_64", target_env = "gnu"))]
#[path = "seh64_gnu.rs"] #[doc(hidden)]
pub mod imp;

// i686-pc-windows-gnu and all others
#[cfg(any(unix, all(windows, target_arch = "x86", target_env = "gnu")))]
#[path = "gcc.rs"] #[doc(hidden)]
pub mod imp;
use sys::unwind;

/// Invoke a closure, capturing the cause of panic if one occurs.
///
@@ -140,18 +68,19 @@ unsafe fn inner_try(f: fn(*mut u8), data: *mut u8)
// the point-of-throw back to this location.
//
// A pointer to this data is passed to the `try` intrinsic itself,
// allowing this function, the `try` intrinsic, imp::payload(), and
// imp::cleanup() to all work in concert to transmit this information.
// allowing this function, the `try` intrinsic, unwind::payload(), and
// unwind::cleanup() to all work in concert to transmit this
// information.
//
// More information about what this pointer actually is can be found in
// each implementation as well as browsing the compiler source itself.
let mut payload = imp::payload();
let mut payload = unwind::payload();
let r = intrinsics::try(f, data, &mut payload as *mut _ as *mut _);
s.set(prev);
if r == 0 {
Ok(())
} else {
Err(imp::cleanup(payload))
Err(unwind::cleanup(payload))
}
})
}
@@ -167,7 +96,7 @@ unsafe fn inner_try(f: fn(*mut u8), data: *mut u8)
if ep.is_null() {
Ok(())
} else {
Err(imp::cleanup(ep))
Err(unwind::cleanup(ep))
}
})
}
@@ -183,7 +112,7 @@ pub fn panicking() -> bool {
#[allow(private_no_mangle_fns)]
pub fn rust_panic(cause: Box<Any + Send + 'static>) -> ! {
unsafe {
imp::panic(cause)
unwind::panic(cause)
}
}

146 changes: 0 additions & 146 deletions src/libstd/sys/common/unwind/seh64_gnu.rs

This file was deleted.

11 changes: 0 additions & 11 deletions src/libstd/sys/unix/backtrace/printing/gnu.rs

This file was deleted.

File renamed without changes.
2 changes: 1 addition & 1 deletion src/libstd/sys/unix/backtrace/printing/mod.rs
Original file line number Diff line number Diff line change
@@ -17,5 +17,5 @@ mod imp;

#[cfg(not(any(target_os = "macos", target_os = "ios",
target_os = "emscripten")))]
#[path = "gnu.rs"]
#[path = "libbacktrace.rs"]
mod imp;
Original file line number Diff line number Diff line change
@@ -120,9 +120,7 @@ pub type _Unwind_Exception_Cleanup_Fn =
link(name = "gcc_pic"))]
#[cfg_attr(target_os = "bitrig",
link(name = "c++abi"))]
#[cfg_attr(all(target_os = "windows", target_env="gnu"),
link(name = "gcc_eh"))]
extern "C" {
extern {
// iOS on armv7 uses SjLj exceptions and requires to link
// against corresponding routine (..._SjLj_...)
#[cfg(not(all(target_os = "ios", target_arch = "arm")))]
4 changes: 3 additions & 1 deletion src/libstd/sys/unix/mod.rs
Original file line number Diff line number Diff line change
@@ -36,6 +36,7 @@ pub mod condvar;
pub mod ext;
pub mod fd;
pub mod fs;
pub mod libunwind;
pub mod mutex;
pub mod net;
pub mod os;
@@ -44,10 +45,11 @@ pub mod pipe;
pub mod process;
pub mod rwlock;
pub mod stack_overflow;
pub mod stdio;
pub mod thread;
pub mod thread_local;
pub mod time;
pub mod stdio;
pub mod unwind;

#[cfg(not(test))]
pub fn init() {
154 changes: 91 additions & 63 deletions src/libstd/sys/common/unwind/gcc.rs → src/libstd/sys/unix/unwind.rs
Original file line number Diff line number Diff line change
@@ -8,21 +8,105 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! # Implementation of Rust stack unwinding
//!
//! Also might be known as itanium exceptions, libunwind-based unwinding,
//! libgcc unwinding, etc. Unwinding on Unix currently always happens through
//! the libunwind support library, although we don't always link to libunwind
//! directly as it's often bundled directly into libgcc (or libgcc_s).
//!
//! For background on exception handling and stack unwinding please see
//! "Exception Handling in LLVM" (llvm.org/docs/ExceptionHandling.html) and
//! documents linked from it.
//!
//! These are also good reads:
//!
//! * http://mentorembedded.github.io/cxx-abi/abi-eh.html
//! * http://monoinfinito.wordpress.com/series/exception-handling-in-c/
//! * http://www.airs.com/blog/index.php?s=exception+frames
//!
//! The basic premise here is that we're going to literally throw an exception,
//! only with library support rather than language support. This interacts with
//! LLVM by using the `invoke` instruction all over the place instead of a
//! typical `call` instruction. As a reminder, when LLVM translates an `invoke`
//! instruction it requires that the surrounding function is attached with a
//! **personality** function. The major purpose of this module is to define
//! these personality functions.
//!
//! First, though, let's take a look at how unwinding works:
//!
//! ## A brief summary
//!
//! Exception handling happens in two phases: a search phase and a cleanup
//! phase.
//!
//! In both phases the unwinder walks stack frames from top to bottom using
//! information from the stack frame unwind sections of the current process's
//! modules ("module" here refers to an OS module, i.e. an executable or a
//! dynamic library).
//!
//! For each stack frame, it invokes the associated "personality routine", whose
//! address is also stored in the unwind info section.
//!
//! In the search phase, the job of a personality routine is to examine
//! exception object being thrown, and to decide whether it should be caught at
//! that stack frame. Once the handler frame has been identified, cleanup phase
//! begins.
//!
//! In the cleanup phase, the unwinder invokes each personality routine again.
//! This time it decides which (if any) cleanup code needs to be run for
//! the current stack frame. If so, the control is transferred to a special
//! branch in the function body, the "landing pad", which invokes destructors,
//! frees memory, etc. At the end of the landing pad, control is transferred
//! back to the unwinder and unwinding resumes.
//!
//! Once stack has been unwound down to the handler frame level, unwinding stops
//! and the last personality routine transfers control to the catch block.
//!
//! ## `eh_personality` and `eh_personality_catch`
//!
//! The main personality function, `eh_personality`, is used by almost all Rust
//! functions that are translated. This personality indicates that no exceptions
//! should be caught, but cleanups should always be run. The second personality
//! function, `eh_personality_catch`, is distinct in that it indicates that
//! exceptions should be caught (no cleanups are run). The compiler will
//! annotate all generated functions with these two personalities, and then
//! we're just left to implement them over here!
//!
//! We could implement our personality routine in pure Rust, however exception
//! info decoding is tedious. More importantly, personality routines have to
//! handle various platform quirks, which are not fun to maintain. For this
//! reason, we attempt to reuse personality routine of the C language. This
//! comes under a number of names and ABIs, including `__gcc_personality_v0` and
//! `__gcc_personality_sj0`.
//!
//! Since C does not support exception catching, this personality function
//! simply always returns `_URC_CONTINUE_UNWIND` in search phase, and always
//! returns `_URC_INSTALL_CONTEXT` (i.e. "invoke cleanup code") in cleanup
//! phase.
//!
//! To implement the `eh_personality_catch` function, however, we detect when
//! the search phase is occurring and return `_URC_HANDLER_FOUND` to indicate
//! that we want to catch the exception.
//!
//! See also: `rustc_trans::trans::intrinsic::trans_gnu_try`
#![allow(private_no_mangle_fns)]

use prelude::v1::*;

use any::Any;
use sys_common::libunwind as uw;
use sys::libunwind as uw;

#[repr(C)]
struct Exception {
uwe: uw::_Unwind_Exception,
_uwe: uw::_Unwind_Exception,
cause: Option<Box<Any + Send + 'static>>,
}

pub unsafe fn panic(data: Box<Any + Send + 'static>) -> ! {
let exception: Box<_> = box Exception {
uwe: uw::_Unwind_Exception {
_uwe: uw::_Unwind_Exception {
exception_class: rust_exception_class(),
exception_cleanup: exception_cleanup,
private: [0; uw::unwinder_private_data_size],
@@ -60,30 +144,9 @@ fn rust_exception_class() -> uw::_Unwind_Exception_Class {
0x4d4f5a_00_52555354
}

// We could implement our personality routine in pure Rust, however exception
// info decoding is tedious. More importantly, personality routines have to
// handle various platform quirks, which are not fun to maintain. For this
// reason, we attempt to reuse personality routine of the C language:
// __gcc_personality_v0.
//
// Since C does not support exception catching, __gcc_personality_v0 simply
// always returns _URC_CONTINUE_UNWIND in search phase, and always returns
// _URC_INSTALL_CONTEXT (i.e. "invoke cleanup code") in cleanup phase.
//
// This is pretty close to Rust's exception handling approach, except that Rust
// does have a single "catch-all" handler at the bottom of each thread's stack.
// So we have two versions of the personality routine:
// - rust_eh_personality, used by all cleanup landing pads, which never catches,
// so the behavior of __gcc_personality_v0 is perfectly adequate there, and
// - rust_eh_personality_catch, used only by rust_try(), which always catches.
//
// See also: rustc_trans::trans::intrinsic::trans_gnu_try

#[cfg(all(not(target_arch = "arm"),
not(all(windows, target_arch = "x86_64")),
not(test)))]
#[cfg(all(not(target_arch = "arm"), not(test)))]
pub mod eabi {
use sys_common::libunwind as uw;
use sys::libunwind as uw;
use libc::c_int;

extern {
@@ -139,7 +202,7 @@ pub mod eabi {

#[cfg(all(target_os = "ios", target_arch = "arm", not(test)))]
pub mod eabi {
use sys_common::libunwind as uw;
use sys::libunwind as uw;
use libc::c_int;

extern {
@@ -194,7 +257,7 @@ pub mod eabi {
// but otherwise works the same.
#[cfg(all(target_arch = "arm", not(target_os = "ios"), not(test)))]
pub mod eabi {
use sys_common::libunwind as uw;
use sys::libunwind as uw;
use libc::c_int;

extern {
@@ -236,38 +299,3 @@ pub mod eabi {
}
}
}

// See docs in the `unwind` module.
#[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu", not(test)))]
#[lang = "eh_unwind_resume"]
#[unwind]
unsafe extern fn rust_eh_unwind_resume(panic_ctx: *mut u8) -> ! {
uw::_Unwind_Resume(panic_ctx as *mut uw::_Unwind_Exception);
}

#[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))]
pub mod eh_frame_registry {
// The implementation of stack unwinding is (for now) deferred to libgcc_eh, however Rust
// crates use these Rust-specific entry points to avoid potential clashes with GCC runtime.
// See also: rtbegin.rs, `unwind` module.

#[link(name = "gcc_eh")]
extern {
fn __register_frame_info(eh_frame_begin: *const u8, object: *mut u8);
fn __deregister_frame_info(eh_frame_begin: *const u8, object: *mut u8);
}
#[cfg(not(test))]
#[no_mangle]
#[unstable(feature = "libstd_sys_internals", issue = "0")]
pub unsafe extern fn rust_eh_register_frames(eh_frame_begin: *const u8,
object: *mut u8) {
__register_frame_info(eh_frame_begin, object);
}
#[cfg(not(test))]
#[no_mangle]
#[unstable(feature = "libstd_sys_internals", issue = "0")]
pub unsafe extern fn rust_eh_unregister_frames(eh_frame_begin: *const u8,
object: *mut u8) {
__deregister_frame_info(eh_frame_begin, object);
}
}
72 changes: 54 additions & 18 deletions src/libstd/sys/windows/backtrace.rs
Original file line number Diff line number Diff line change
@@ -27,29 +27,25 @@
use io::prelude::*;

use dynamic_lib::DynamicLibrary;
use ffi::CStr;
use io;
use libc::c_void;
use libc::{c_ulong, c_int, c_char, c_void};
use mem;
use path::Path;
use ptr;
use sync::StaticMutex;
use sys::c;

macro_rules! sym{ ($lib:expr, $e:expr, $t:ident) => (unsafe {
let lib = $lib;
match lib.symbol($e) {
Ok(f) => $crate::mem::transmute::<*mut u8, $t>(f),
Err(..) => return Ok(())
}
}) }

#[cfg(target_env = "msvc")]
#[path = "printing/msvc.rs"]
mod printing;

#[cfg(target_env = "gnu")]
#[path = "printing/gnu.rs"]
mod printing;
use sys_common::backtrace::{output, output_fileline};

macro_rules! sym {
($lib:expr, $e:expr, $t:ident) => (unsafe {
let lib = $lib;
match lib.symbol($e) {
Ok(f) => $crate::mem::transmute::<*mut u8, $t>(f),
Err(..) => return Ok(())
}
})
}

type SymFromAddrFn =
extern "system" fn(c::HANDLE, u64, *mut u64,
@@ -151,9 +147,49 @@ pub fn write(w: &mut Write) -> io::Result<()> {
i += 1;

if i >= 0 {
try!(printing::print(w, i, addr-1, &dbghelp, process));
try!(print(w, i, addr-1, &dbghelp, process));
}
}

Ok(())
}

fn print(w: &mut Write, i: isize, addr: u64, dbghelp: &DynamicLibrary,
process: c::HANDLE) -> io::Result<()> {
let SymFromAddr = sym!(dbghelp, "SymFromAddr", SymFromAddrFn);
let SymGetLineFromAddr64 = sym!(dbghelp, "SymGetLineFromAddr64", SymGetLineFromAddr64Fn);

let mut info: c::SYMBOL_INFO = unsafe { mem::zeroed() };
info.MaxNameLen = c::MAX_SYM_NAME as c_ulong;
// the struct size in C. the value is different to
// `size_of::<SYMBOL_INFO>() - MAX_SYM_NAME + 1` (== 81)
// due to struct alignment.
info.SizeOfStruct = 88;

let mut displacement = 0u64;
let ret = SymFromAddr(process, addr, &mut displacement, &mut info);

let name = if ret == c::TRUE {
let ptr = info.Name.as_ptr() as *const c_char;
Some(unsafe { CStr::from_ptr(ptr).to_bytes() })
} else {
None
};

try!(output(w, i, addr as usize as *mut c_void, name));

// Now find out the filename and line number
let mut line: c::IMAGEHLP_LINE64 = unsafe { mem::zeroed() };
line.SizeOfStruct = ::mem::size_of::<c::IMAGEHLP_LINE64>() as u32;

let mut displacement = 0u32;
let ret = SymGetLineFromAddr64(process, addr, &mut displacement, &mut line);
if ret == c::TRUE {
output_fileline(w,
unsafe { CStr::from_ptr(line.Filename).to_bytes() },
line.LineNumber as c_int,
false)
} else {
Ok(())
}
}
3 changes: 2 additions & 1 deletion src/libstd/sys/windows/mod.rs
Original file line number Diff line number Diff line change
@@ -35,10 +35,11 @@ pub mod pipe;
pub mod process;
pub mod rwlock;
pub mod stack_overflow;
pub mod stdio;
pub mod thread;
pub mod thread_local;
pub mod time;
pub mod stdio;
pub mod unwind;

#[cfg(not(test))]
pub fn init() {
25 changes: 0 additions & 25 deletions src/libstd/sys/windows/printing/gnu.rs

This file was deleted.

61 changes: 0 additions & 61 deletions src/libstd/sys/windows/printing/msvc.rs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -56,13 +56,6 @@
//! [win64]: http://msdn.microsoft.com/en-us/library/1eyas8tf.aspx
//! [llvm]: http://llvm.org/docs/ExceptionHandling.html#background-on-windows-exceptions
use sys::c;

// A code which indicates panics that originate from Rust. Note that some of the
// upper bits are used by the system so we just set them to 0 and ignore them.
// 0x 0 R S T
const RUST_PANIC: c::DWORD = 0x00525354;

pub use self::imp::*;

#[cfg(stage0)]
@@ -100,9 +93,14 @@ mod imp {
use any::Any;
use mem;
use raw;
use super::RUST_PANIC;
use sys::c;

// A code which indicates panics that originate from Rust. Note that some of
// the upper bits are used by the system so we just set them to 0 and ignore
// them.
// 0x 0 R S T
const RUST_PANIC: c::DWORD = 0x00525354;

pub unsafe fn panic(data: Box<Any + Send + 'static>) -> ! {
// As mentioned above, the call stack here is preserved while the filter
// functions are running, so it's ok to pass stack-local arrays into
78 changes: 0 additions & 78 deletions src/rtstartup/rsbegin.rs

This file was deleted.

24 changes: 0 additions & 24 deletions src/rtstartup/rsend.rs

This file was deleted.

3 changes: 0 additions & 3 deletions src/test/auxiliary/lang-item-public.rs
Original file line number Diff line number Diff line change
@@ -18,9 +18,6 @@ extern crate libc;
#[lang = "eh_personality"]
extern fn eh_personality() {}

#[lang = "eh_unwind_resume"]
extern fn eh_unwind_resume() {}

#[lang = "panic_fmt"]
extern fn rust_begin_unwind(msg: core::fmt::Arguments, file: &'static str,
line: u32) -> ! {
1 change: 0 additions & 1 deletion src/test/compile-fail/no_owned_box_lang_item.rs
Original file line number Diff line number Diff line change
@@ -20,5 +20,4 @@ fn main() {
}

#[lang = "eh_personality"] extern fn eh_personality() {}
#[lang = "eh_unwind_resume"] extern fn eh_unwind_resume() {}
#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }
2 changes: 1 addition & 1 deletion src/test/run-fail/mir_trans_calls_converging_drops.rs
Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@

#![feature(rustc_attrs)]

// ignore-msvc: FIXME(#30941)
// ignore-windows: FIXME(#30941)
// error-pattern:converging_fn called
// error-pattern:0 dropped
// error-pattern:exit
2 changes: 1 addition & 1 deletion src/test/run-fail/mir_trans_calls_converging_drops_2.rs
Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@

#![feature(rustc_attrs)]

// ignore-msvc: FIXME(#30941)
// ignore-windows: FIXME(#30941)
// error-pattern:complex called
// error-pattern:dropped
// error-pattern:exit
2 changes: 1 addition & 1 deletion src/test/run-fail/mir_trans_calls_diverging_drops.rs
Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@

#![feature(rustc_attrs)]

// ignore-msvc: FIXME(#30941)
// ignore-windows: FIXME(#30941)
// error-pattern:diverging_fn called
// error-pattern:0 dropped

3 changes: 0 additions & 3 deletions src/test/run-make/no-duplicate-libs/bar.rs
Original file line number Diff line number Diff line change
@@ -18,7 +18,4 @@ extern crate libc;
pub extern fn bar() {}

#[lang = "eh_personality"] fn eh_personality() {}
#[lang = "eh_unwind_resume"] fn eh_unwind_resume() {}
#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }
#[no_mangle] pub extern fn rust_eh_register_frames () {}
#[no_mangle] pub extern fn rust_eh_unregister_frames () {}
3 changes: 0 additions & 3 deletions src/test/run-make/no-duplicate-libs/foo.rs
Original file line number Diff line number Diff line change
@@ -18,7 +18,4 @@ extern crate libc;
pub extern fn foo() {}

#[lang = "eh_personality"] fn eh_personality() {}
#[lang = "eh_unwind_resume"] fn eh_unwind_resume() {}
#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }
#[no_mangle] pub extern fn rust_eh_register_frames () {}
#[no_mangle] pub extern fn rust_eh_unregister_frames () {}
2 changes: 1 addition & 1 deletion src/test/run-pass/backtrace.rs
Original file line number Diff line number Diff line change
@@ -89,7 +89,7 @@ fn runtest(me: &str) {
}

fn main() {
if cfg!(windows) && cfg!(target_arch = "x86") && cfg!(target_env = "gnu") {
if cfg!(windows) && cfg!(target_env = "gnu") {
return
}

3 changes: 0 additions & 3 deletions src/test/run-pass/smallest-hello-world.rs
Original file line number Diff line number Diff line change
@@ -21,10 +21,7 @@ extern { fn puts(s: *const u8); }
extern "rust-intrinsic" { fn transmute<T, U>(t: T) -> U; }

#[lang = "eh_personality"] extern fn eh_personality() {}
#[lang = "eh_unwind_resume"] extern fn eh_unwind_resume() {}
#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }
#[no_mangle] pub extern fn rust_eh_register_frames () {}
#[no_mangle] pub extern fn rust_eh_unregister_frames () {}

#[start]
fn main(_: isize, _: *const *const u8) -> isize {