]> git.lizzy.rs Git - rust.git/commitdiff
rustc: Implement custom panic runtimes
authorAlex Crichton <alex@alexcrichton.com>
Fri, 8 Apr 2016 23:18:40 +0000 (16:18 -0700)
committerAlex Crichton <alex@alexcrichton.com>
Mon, 9 May 2016 15:22:36 +0000 (08:22 -0700)
This commit is an implementation of [RFC 1513] which allows applications to
alter the behavior of panics at compile time. A new compiler flag, `-C panic`,
is added and accepts the values `unwind` or `panic`, with the default being
`unwind`. This model affects how code is generated for the local crate, skipping
generation of landing pads with `-C panic=abort`.

[RFC 1513]: https://github.com/rust-lang/rfcs/blob/master/text/1513-less-unwinding.md

Panic implementations are then provided by crates tagged with
`#![panic_runtime]` and lazily required by crates with
`#![needs_panic_runtime]`. The panic strategy (`-C panic` value) of the panic
runtime must match the final product, and if the panic strategy is not `abort`
then the entire DAG must have the same panic strategy.

With the `-C panic=abort` strategy, users can expect a stable method to disable
generation of landing pads, improving optimization in niche scenarios,
decreasing compile time, and decreasing output binary size. With the `-C
panic=unwind` strategy users can expect the existing ability to isolate failure
in Rust code from the outside world.

Organizationally, this commit dismantles the `sys_common::unwind` module in
favor of some bits moving part of it to `libpanic_unwind` and the rest into the
`panicking` module in libstd. The custom panic runtime support is pretty similar
to the custom allocator support with the only major difference being how the
panic runtime is injected (takes the `-C panic` flag into account).

82 files changed:
mk/crates.mk
mk/tests.mk
src/bootstrap/rustc.rs
src/liballoc_system/lib.rs
src/libpanic_abort/Cargo.toml [new file with mode: 0644]
src/libpanic_abort/lib.rs [new file with mode: 0644]
src/libpanic_unwind/Cargo.lock [new file with mode: 0644]
src/libpanic_unwind/Cargo.toml [new file with mode: 0644]
src/libpanic_unwind/dwarf/eh.rs [new file with mode: 0644]
src/libpanic_unwind/dwarf/mod.rs [new file with mode: 0644]
src/libpanic_unwind/gcc.rs [new file with mode: 0644]
src/libpanic_unwind/lib.rs [new file with mode: 0644]
src/libpanic_unwind/seh.rs [new file with mode: 0644]
src/libpanic_unwind/seh64_gnu.rs [new file with mode: 0644]
src/libpanic_unwind/windows.rs [new file with mode: 0644]
src/librustc/middle/cstore.rs
src/librustc/middle/dependency_format.rs
src/librustc/middle/weak_lang_items.rs
src/librustc/session/config.rs
src/librustc/session/mod.rs
src/librustc_metadata/common.rs
src/librustc_metadata/creader.rs
src/librustc_metadata/csearch.rs
src/librustc_metadata/cstore.rs
src/librustc_metadata/decoder.rs
src/librustc_metadata/encoder.rs
src/librustc_trans/base.rs
src/libstd/Cargo.toml
src/libstd/build.rs
src/libstd/lib.rs
src/libstd/macros.rs
src/libstd/panic.rs
src/libstd/panicking.rs
src/libstd/rt.rs
src/libstd/sys/common/dwarf/eh.rs [deleted file]
src/libstd/sys/common/dwarf/mod.rs [deleted file]
src/libstd/sys/common/libunwind.rs [deleted file]
src/libstd/sys/common/mod.rs
src/libstd/sys/common/unwind/gcc.rs [deleted file]
src/libstd/sys/common/unwind/mod.rs [deleted file]
src/libstd/sys/common/unwind/seh.rs [deleted file]
src/libstd/sys/common/unwind/seh64_gnu.rs [deleted file]
src/libstd/sys/unix/backtrace/tracing/gcc_s.rs
src/libstd/sys/windows/c.rs
src/libstd/thread/mod.rs
src/libsyntax/ext/build.rs
src/libsyntax/feature_gate.rs
src/libtest/lib.rs
src/libunwind/Cargo.toml [new file with mode: 0644]
src/libunwind/build.rs [new file with mode: 0644]
src/libunwind/lib.rs [new file with mode: 0644]
src/libunwind/libunwind.rs [new file with mode: 0644]
src/rustc/std_shim/Cargo.lock
src/test/codegen/lto-removes-invokes.rs [new file with mode: 0644]
src/test/compile-fail/panic-runtime/abort-link-to-unwind-dylib.rs [new file with mode: 0644]
src/test/compile-fail/panic-runtime/auxiliary/needs-panic-runtime.rs [new file with mode: 0644]
src/test/compile-fail/panic-runtime/auxiliary/panic-runtime-abort.rs [new file with mode: 0644]
src/test/compile-fail/panic-runtime/auxiliary/panic-runtime-lang-items.rs [new file with mode: 0644]
src/test/compile-fail/panic-runtime/auxiliary/panic-runtime-unwind.rs [new file with mode: 0644]
src/test/compile-fail/panic-runtime/auxiliary/panic-runtime-unwind2.rs [new file with mode: 0644]
src/test/compile-fail/panic-runtime/auxiliary/runtime-depending-on-panic-runtime.rs [new file with mode: 0644]
src/test/compile-fail/panic-runtime/auxiliary/wants-panic-runtime-abort.rs [new file with mode: 0644]
src/test/compile-fail/panic-runtime/auxiliary/wants-panic-runtime-unwind.rs [new file with mode: 0644]
src/test/compile-fail/panic-runtime/bad-panic-flag1.rs [new file with mode: 0644]
src/test/compile-fail/panic-runtime/bad-panic-flag2.rs [new file with mode: 0644]
src/test/compile-fail/panic-runtime/libtest-unwinds.rs [new file with mode: 0644]
src/test/compile-fail/panic-runtime/needs-gate.rs [new file with mode: 0644]
src/test/compile-fail/panic-runtime/runtime-depend-on-needs-runtime.rs [new file with mode: 0644]
src/test/compile-fail/panic-runtime/transitive-link-a-bunch.rs [new file with mode: 0644]
src/test/compile-fail/panic-runtime/two-panic-runtimes.rs [new file with mode: 0644]
src/test/compile-fail/panic-runtime/want-abort-got-unwind.rs [new file with mode: 0644]
src/test/compile-fail/panic-runtime/want-abort-got-unwind2.rs [new file with mode: 0644]
src/test/compile-fail/panic-runtime/want-unwind-got-abort.rs [new file with mode: 0644]
src/test/compile-fail/panic-runtime/want-unwind-got-abort2.rs [new file with mode: 0644]
src/test/run-pass/panic-runtime/abort-link-to-unwinding-crates.rs [new file with mode: 0644]
src/test/run-pass/panic-runtime/abort.rs [new file with mode: 0644]
src/test/run-pass/panic-runtime/auxiliary/exit-success-if-unwind.rs [new file with mode: 0644]
src/test/run-pass/panic-runtime/link-to-abort.rs [new file with mode: 0644]
src/test/run-pass/panic-runtime/link-to-unwind.rs [new file with mode: 0644]
src/test/run-pass/panic-runtime/lto-abort.rs [new file with mode: 0644]
src/test/run-pass/panic-runtime/lto-unwind.rs [new file with mode: 0644]
src/tools/tidy/src/cargo.rs

index 48c1e4ad59d5bbe752a7cdb20da2d6ae41a061ca..1583515014a3941184ac5973e38e68f75073a079 100644 (file)
@@ -53,7 +53,8 @@ TARGET_CRATES := libc std term \
                  getopts collections test rand \
                  core alloc \
                  rustc_unicode rustc_bitflags \
-                alloc_system alloc_jemalloc
+                alloc_system alloc_jemalloc \
+                panic_abort panic_unwind unwind
 RUSTC_CRATES := rustc rustc_typeck rustc_mir rustc_borrowck rustc_resolve rustc_driver \
                 rustc_trans rustc_back rustc_llvm rustc_privacy rustc_lint \
                 rustc_data_structures rustc_platform_intrinsics \
@@ -72,10 +73,18 @@ DEPS_libc := core
 DEPS_rand := core
 DEPS_rustc_bitflags := core
 DEPS_rustc_unicode := core
+DEPS_panic_abort := libc alloc
+DEPS_panic_unwind := libc alloc unwind
+DEPS_unwind := libc
+
+# FIXME(stage0): change this to just `RUSTFLAGS_panic_abort := ...`
+RUSTFLAGS1_panic_abort := -C panic=abort
+RUSTFLAGS2_panic_abort := -C panic=abort
+RUSTFLAGS3_panic_abort := -C panic=abort
 
 DEPS_std := core libc rand alloc collections rustc_unicode \
        native:backtrace \
-       alloc_system
+       alloc_system panic_abort panic_unwind unwind
 DEPS_arena := std
 DEPS_glob := std
 DEPS_flate := std native:miniz
@@ -148,6 +157,9 @@ ONLY_RLIB_rustc_unicode := 1
 ONLY_RLIB_rustc_bitflags := 1
 ONLY_RLIB_alloc_system := 1
 ONLY_RLIB_alloc_jemalloc := 1
+ONLY_RLIB_panic_unwind := 1
+ONLY_RLIB_panic_abort := 1
+ONLY_RLIB_unwind := 1
 
 TARGET_SPECIFIC_alloc_jemalloc := 1
 
index cc712413d3b1c080313585b35c1bedaa2aca6bbb..ea610f63dbf22d30ed3c7eaa1e102f87be9bac92 100644 (file)
@@ -23,7 +23,8 @@ DEPS_collectionstest :=
 $(eval $(call RUST_CRATE,collectionstest))
 
 TEST_TARGET_CRATES = $(filter-out core rustc_unicode alloc_system libc \
-                                 alloc_jemalloc,$(TARGET_CRATES)) \
+                                 alloc_jemalloc panic_unwind \
+                                 panic_abort,$(TARGET_CRATES)) \
                        collectionstest coretest
 TEST_DOC_CRATES = $(DOC_CRATES) arena flate fmt_macros getopts graphviz \
                 log rand rbml serialize syntax term test
index 99e16035d1d4f0ba5f46d18719c565dd87cf0dcb..046bc34438c4293e7345c9fc59996c39d9d488b4 100644 (file)
@@ -48,10 +48,11 @@ fn main() {
     } else {
         env::var_os("RUSTC_REAL").unwrap()
     };
+    let stage = env::var("RUSTC_STAGE").unwrap();
 
     let mut cmd = Command::new(rustc);
     cmd.args(&args)
-       .arg("--cfg").arg(format!("stage{}", env::var("RUSTC_STAGE").unwrap()));
+       .arg("--cfg").arg(format!("stage{}", stage));
 
     if let Some(target) = target {
         // The stage0 compiler has a special sysroot distinct from what we
@@ -78,6 +79,22 @@ fn main() {
             cmd.args(&s.split(" ").filter(|s| !s.is_empty()).collect::<Vec<_>>());
         }
 
+        // If we're compiling specifically the `panic_abort` crate then we pass
+        // the `-C panic=abort` option. Note that we do not do this for any
+        // other crate intentionally as this is the only crate for now that we
+        // ship with panic=abort.
+        //
+        // This... is a bit of a hack how we detect this. Ideally this
+        // information should be encoded in the crate I guess? Would likely
+        // require an RFC amendment to RFC 1513, however.
+        let is_panic_abort = args.windows(2).any(|a| {
+            &*a[0] == "--crate-name" && &*a[1] == "panic_abort"
+        });
+        // FIXME(stage0): remove this `stage != "0"` condition
+        if is_panic_abort && stage != "0" {
+            cmd.arg("-C").arg("panic=abort");
+        }
+
         // Set various options from config.toml to configure how we're building
         // code.
         if env::var("RUSTC_DEBUGINFO") == Ok("true".to_string()) {
index ca4c9bfd9544cbde5b57c512818b1df19b140f4e..a22299c5e1a54dbe640c3364bd21f969f062209f 100644 (file)
                       form or name",
             issue = "27783")]
 #![feature(allocator)]
-#![feature(libc)]
 #![feature(staged_api)]
-
-extern crate libc;
+#![cfg_attr(unix, feature(libc))]
 
 // The minimum alignment guaranteed by the architecture. This value is used to
 // add fast paths for low alignment values. In practice, the alignment is a
@@ -72,9 +70,10 @@ pub extern "C" fn __rust_usable_size(size: usize, align: usize) -> usize {
 
 #[cfg(unix)]
 mod imp {
+    extern crate libc;
+
     use core::cmp;
     use core::ptr;
-    use libc;
     use MIN_ALIGN;
 
     pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
diff --git a/src/libpanic_abort/Cargo.toml b/src/libpanic_abort/Cargo.toml
new file mode 100644 (file)
index 0000000..a790570
--- /dev/null
@@ -0,0 +1,11 @@
+[package]
+authors = ["The Rust Project Developers"]
+name = "panic_abort"
+version = "0.0.0"
+
+[lib]
+path = "lib.rs"
+
+[dependencies]
+core = { path = "../libcore" }
+libc = { path = "../rustc/libc_shim" }
diff --git a/src/libpanic_abort/lib.rs b/src/libpanic_abort/lib.rs
new file mode 100644 (file)
index 0000000..9802f66
--- /dev/null
@@ -0,0 +1,112 @@
+// Copyright 2016 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.
+
+//! Implementation of Rust panics via process aborts
+//!
+//! When compared to the implementation via unwinding, this crate is *much*
+//! simpler! That being said, it's not quite as versatile, but here goes!
+
+#![no_std]
+#![crate_name = "panic_abort"]
+#![crate_type = "rlib"]
+#![unstable(feature = "panic_abort", issue = "32837")]
+#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
+       html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
+       html_root_url = "https://doc.rust-lang.org/nightly/",
+       issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")]
+#![cfg_attr(not(stage0), deny(warnings))]
+
+#![feature(staged_api)]
+
+#![cfg_attr(not(stage0), panic_runtime)]
+#![cfg_attr(not(stage0), feature(panic_runtime))]
+#![cfg_attr(unix, feature(libc))]
+#![cfg_attr(windows, feature(core_intrinsics))]
+
+// Rust's "try" function, but if we're aborting on panics we just call the
+// function as there's nothing else we need to do here.
+#[no_mangle]
+pub unsafe extern fn __rust_maybe_catch_panic(f: fn(*mut u8),
+                                              data: *mut u8,
+                                              _data_ptr: *mut usize,
+                                              _vtable_ptr: *mut usize) -> u32 {
+    f(data);
+    0
+}
+
+// "Leak" the payload and shim to the relevant abort on the platform in
+// question.
+//
+// For Unix we just use `abort` from libc as it'll trigger debuggers, core
+// dumps, etc, as one might expect. On Windows, however, the best option we have
+// is the `__fastfail` intrinsics, but that's unfortunately not defined in LLVM,
+// and the `RaiseFailFastException` function isn't available until Windows 7
+// which would break compat with XP. For now just use `intrinsics::abort` which
+// will kill us with an illegal instruction, which will do a good enough job for
+// now hopefully.
+#[no_mangle]
+pub unsafe extern fn __rust_start_panic(_data: usize, _vtable: usize) -> u32 {
+    return abort();
+
+    #[cfg(unix)]
+    unsafe fn abort() -> ! {
+        extern crate libc;
+        libc::abort();
+    }
+
+    #[cfg(windows)]
+    unsafe fn abort() -> ! {
+        core::intrinsics::abort();
+    }
+}
+
+// This... is a bit of an oddity. The tl;dr; is that this is required to link
+// correctly, the longer explanation is below.
+//
+// Right now the binaries of libcore/libstd that we ship are all compiled with
+// `-C panic=unwind`. This is done to ensure that the binaries are maximally
+// compatible with as many situations as possible. The compiler, however,
+// requires a "personality function" for all functions compiled with `-C
+// panic=unwind`. This personality function is hardcoded to the symbol
+// `rust_eh_personality` and is defined by the `eh_personality` lang item.
+//
+// So... why not just define that lang item here? Good question! The way that
+// panic runtimes are linked in is actually a little subtle in that they're
+// "sort of" in the compiler's crate store, but only actually linked if another
+// isn't actually linked. This ends up meaning that both this crate and the
+// panic_unwind crate can appear in the compiler's crate store, and if both
+// define the `eh_personality` lang item then that'll hit an error.
+//
+// To handle this the compiler only requires the `eh_personality` is defined if
+// the panic runtime being linked in is the unwinding runtime, and otherwise
+// it's not required to be defined (rightfully so). In this case, however, this
+// library just defines this symbol so there's at least some personality
+// somewhere.
+//
+// Essentially this symbol is just defined to get wired up to libcore/libstd
+// binaries, but it should never be called as we don't link in an unwinding
+// runtime at all.
+#[no_mangle]
+#[cfg(not(stage0))]
+pub extern fn rust_eh_personality() {}
+
+// Similar to above, this corresponds to the `eh_unwind_resume` lang item that's
+// only used on Windows currently.
+#[no_mangle]
+#[cfg(all(not(stage0), target_os = "windows", target_env = "gnu"))]
+pub extern fn rust_eh_unwind_resume() {}
+
+#[no_mangle]
+#[cfg(all(target_os = "windows", target_env = "gnu", target_arch = "x86"))]
+pub extern fn rust_eh_register_frames() {}
+
+#[no_mangle]
+#[cfg(all(target_os = "windows", target_env = "gnu", target_arch = "x86"))]
+pub extern fn rust_eh_unregister_frames() {}
diff --git a/src/libpanic_unwind/Cargo.lock b/src/libpanic_unwind/Cargo.lock
new file mode 100644 (file)
index 0000000..20d826d
--- /dev/null
@@ -0,0 +1,27 @@
+[root]
+name = "panic_unwind"
+version = "0.0.0"
+dependencies = [
+ "alloc 0.0.0",
+ "core 0.0.0",
+ "libc 0.0.0",
+]
+
+[[package]]
+name = "alloc"
+version = "0.0.0"
+dependencies = [
+ "core 0.0.0",
+]
+
+[[package]]
+name = "core"
+version = "0.0.0"
+
+[[package]]
+name = "libc"
+version = "0.0.0"
+dependencies = [
+ "core 0.0.0",
+]
+
diff --git a/src/libpanic_unwind/Cargo.toml b/src/libpanic_unwind/Cargo.toml
new file mode 100644 (file)
index 0000000..27edecd
--- /dev/null
@@ -0,0 +1,13 @@
+[package]
+authors = ["The Rust Project Developers"]
+name = "panic_unwind"
+version = "0.0.0"
+
+[lib]
+path = "lib.rs"
+
+[dependencies]
+alloc = { path = "../liballoc" }
+core = { path = "../libcore" }
+libc = { path = "../rustc/libc_shim" }
+unwind = { path = "../libunwind" }
diff --git a/src/libpanic_unwind/dwarf/eh.rs b/src/libpanic_unwind/dwarf/eh.rs
new file mode 100644 (file)
index 0000000..1c3fca9
--- /dev/null
@@ -0,0 +1,158 @@
+// 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.
+
+//! Parsing of GCC-style Language-Specific Data Area (LSDA)
+//! For details see:
+//!   http://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA/ehframechpt.html
+//!   http://mentorembedded.github.io/cxx-abi/exceptions.pdf
+//!   http://www.airs.com/blog/archives/460
+//!   http://www.airs.com/blog/archives/464
+//!
+//! A reference implementation may be found in the GCC source tree
+//! (<root>/libgcc/unwind-c.c as of this writing)
+
+#![allow(non_upper_case_globals)]
+#![allow(unused)]
+
+use dwarf::DwarfReader;
+use core::mem;
+
+pub const DW_EH_PE_omit     : u8 = 0xFF;
+pub const DW_EH_PE_absptr   : u8 = 0x00;
+
+pub const DW_EH_PE_uleb128  : u8 = 0x01;
+pub const DW_EH_PE_udata2   : u8 = 0x02;
+pub const DW_EH_PE_udata4   : u8 = 0x03;
+pub const DW_EH_PE_udata8   : u8 = 0x04;
+pub const DW_EH_PE_sleb128  : u8 = 0x09;
+pub const DW_EH_PE_sdata2   : u8 = 0x0A;
+pub const DW_EH_PE_sdata4   : u8 = 0x0B;
+pub const DW_EH_PE_sdata8   : u8 = 0x0C;
+
+pub const DW_EH_PE_pcrel    : u8 = 0x10;
+pub const DW_EH_PE_textrel  : u8 = 0x20;
+pub const DW_EH_PE_datarel  : u8 = 0x30;
+pub const DW_EH_PE_funcrel  : u8 = 0x40;
+pub const DW_EH_PE_aligned  : u8 = 0x50;
+
+pub const DW_EH_PE_indirect : u8 = 0x80;
+
+#[derive(Copy, Clone)]
+pub struct EHContext {
+    pub ip: usize,         // Current instruction pointer
+    pub func_start: usize, // Address of the current function
+    pub text_start: usize, // Address of the code section
+    pub data_start: usize, // Address of the data section
+}
+
+pub unsafe fn find_landing_pad(lsda: *const u8, context: &EHContext)
+                               -> Option<usize> {
+    if lsda.is_null() {
+        return None;
+    }
+
+    let func_start = context.func_start;
+    let mut reader = DwarfReader::new(lsda);
+
+    let start_encoding = reader.read::<u8>();
+    // base address for landing pad offsets
+    let lpad_base = if start_encoding != DW_EH_PE_omit {
+        read_encoded_pointer(&mut reader, context, start_encoding)
+    } else {
+        func_start
+    };
+
+    let ttype_encoding = reader.read::<u8>();
+    if ttype_encoding != DW_EH_PE_omit {
+        // Rust doesn't analyze exception types, so we don't care about the type table
+        reader.read_uleb128();
+    }
+
+    let call_site_encoding = reader.read::<u8>();
+    let call_site_table_length = reader.read_uleb128();
+    let action_table = reader.ptr.offset(call_site_table_length as isize);
+    // Return addresses point 1 byte past the call instruction, which could
+    // be in the next IP range.
+    let ip = context.ip-1;
+
+    while reader.ptr < action_table {
+        let cs_start = read_encoded_pointer(&mut reader, context, call_site_encoding);
+        let cs_len = read_encoded_pointer(&mut reader, context, call_site_encoding);
+        let cs_lpad = read_encoded_pointer(&mut reader, context, call_site_encoding);
+        let cs_action = reader.read_uleb128();
+        // Callsite table is sorted by cs_start, so if we've passed the ip, we
+        // may stop searching.
+        if ip < func_start + cs_start {
+            break
+        }
+        if ip < func_start + cs_start + cs_len {
+            if cs_lpad != 0 {
+                return Some(lpad_base + cs_lpad);
+            } else {
+                return None;
+            }
+        }
+    }
+    // IP range not found: gcc's C++ personality calls terminate() here,
+    // however the rest of the languages treat this the same as cs_lpad == 0.
+    // We follow this suit.
+    None
+}
+
+#[inline]
+fn round_up(unrounded: usize, align: usize) -> usize {
+    assert!(align.is_power_of_two());
+    (unrounded + align - 1) & !(align - 1)
+}
+
+unsafe fn read_encoded_pointer(reader: &mut DwarfReader,
+                               context: &EHContext,
+                               encoding: u8) -> usize {
+    assert!(encoding != DW_EH_PE_omit);
+
+    // DW_EH_PE_aligned implies it's an absolute pointer value
+    if encoding == DW_EH_PE_aligned {
+        reader.ptr = round_up(reader.ptr as usize,
+                              mem::size_of::<usize>()) as *const u8;
+        return reader.read::<usize>();
+    }
+
+    let mut result = match encoding & 0x0F {
+        DW_EH_PE_absptr => reader.read::<usize>(),
+        DW_EH_PE_uleb128 => reader.read_uleb128() as usize,
+        DW_EH_PE_udata2 => reader.read::<u16>() as usize,
+        DW_EH_PE_udata4 => reader.read::<u32>() as usize,
+        DW_EH_PE_udata8 => reader.read::<u64>() as usize,
+        DW_EH_PE_sleb128 => reader.read_sleb128() as usize,
+        DW_EH_PE_sdata2 => reader.read::<i16>() as usize,
+        DW_EH_PE_sdata4 => reader.read::<i32>() as usize,
+        DW_EH_PE_sdata8 => reader.read::<i64>() as usize,
+        _ => panic!()
+    };
+
+    result += match encoding & 0x70 {
+        DW_EH_PE_absptr => 0,
+        // relative to address of the encoded value, despite the name
+        DW_EH_PE_pcrel => reader.ptr as usize,
+        DW_EH_PE_textrel => { assert!(context.text_start != 0);
+                              context.text_start },
+        DW_EH_PE_datarel => { assert!(context.data_start != 0);
+                              context.data_start },
+        DW_EH_PE_funcrel => { assert!(context.func_start != 0);
+                              context.func_start },
+        _ => panic!()
+    };
+
+    if encoding & DW_EH_PE_indirect != 0 {
+        result = *(result as *const usize);
+    }
+
+    result
+}
diff --git a/src/libpanic_unwind/dwarf/mod.rs b/src/libpanic_unwind/dwarf/mod.rs
new file mode 100644 (file)
index 0000000..cde21f9
--- /dev/null
@@ -0,0 +1,106 @@
+// 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.
+
+//! Utilities for parsing DWARF-encoded data streams.
+//! See http://www.dwarfstd.org,
+//! DWARF-4 standard, Section 7 - "Data Representation"
+
+// This module is used only by x86_64-pc-windows-gnu for now, but we
+// are compiling it everywhere to avoid regressions.
+#![allow(unused)]
+
+pub mod eh;
+
+use core::mem;
+
+pub struct DwarfReader {
+    pub ptr : *const u8
+}
+
+#[repr(C,packed)]
+struct Unaligned<T>(T);
+
+impl DwarfReader {
+
+    pub fn new(ptr : *const u8) -> DwarfReader {
+        DwarfReader {
+            ptr : ptr
+        }
+    }
+
+    // DWARF streams are packed, so e.g. a u32 would not necessarily be aligned
+    // on a 4-byte boundary. This may cause problems on platforms with strict
+    // alignment requirements. By wrapping data in a "packed" struct, we are
+    // telling the backend to generate "misalignment-safe" code.
+    pub unsafe fn read<T:Copy>(&mut self) -> T {
+        let Unaligned(result) = *(self.ptr as *const Unaligned<T>);
+        self.ptr = self.ptr.offset(mem::size_of::<T>() as isize);
+        result
+    }
+
+    // ULEB128 and SLEB128 encodings are defined in Section 7.6 - "Variable
+    // Length Data".
+    pub unsafe fn read_uleb128(&mut self) -> u64 {
+        let mut shift : usize = 0;
+        let mut result : u64 = 0;
+        let mut byte : u8;
+        loop {
+            byte = self.read::<u8>();
+            result |= ((byte & 0x7F) as u64) << shift;
+            shift += 7;
+            if byte & 0x80 == 0 {
+                break;
+            }
+        }
+        result
+    }
+
+    pub unsafe fn read_sleb128(&mut self) -> i64 {
+        let mut shift : usize = 0;
+        let mut result : u64 = 0;
+        let mut byte : u8;
+        loop {
+            byte = self.read::<u8>();
+            result |= ((byte & 0x7F) as u64) << shift;
+            shift += 7;
+            if byte & 0x80 == 0 {
+                break;
+            }
+        }
+        // sign-extend
+        if shift < 8 * mem::size_of::<u64>() && (byte & 0x40) != 0 {
+            result |= (!0 as u64) << shift;
+        }
+        result as i64
+    }
+}
+
+#[test]
+fn dwarf_reader() {
+    let encoded: &[u8] = &[1,
+                           2, 3,
+                           4, 5, 6, 7,
+                           0xE5, 0x8E, 0x26,
+                           0x9B, 0xF1, 0x59,
+                           0xFF, 0xFF];
+
+    let mut reader = DwarfReader::new(encoded.as_ptr());
+
+    unsafe {
+        assert!(reader.read::<u8>() == u8::to_be(1u8));
+        assert!(reader.read::<u16>() == u16::to_be(0x0203));
+        assert!(reader.read::<u32>() == u32::to_be(0x04050607));
+
+        assert!(reader.read_uleb128() == 624485);
+        assert!(reader.read_sleb128() == -624485);
+
+        assert!(reader.read::<i8>() == i8::to_be(-1));
+    }
+}
diff --git a/src/libpanic_unwind/gcc.rs b/src/libpanic_unwind/gcc.rs
new file mode 100644 (file)
index 0000000..50b2e15
--- /dev/null
@@ -0,0 +1,335 @@
+// 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.
+
+//! Implementation of panics backed by libgcc/libunwind (in some form)
+//!
+//! 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
+//!
+//! ## 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.
+
+#![allow(private_no_mangle_fns)]
+
+use core::any::Any;
+use alloc::boxed::Box;
+
+use unwind as uw;
+
+#[repr(C)]
+struct Exception {
+    _uwe: uw::_Unwind_Exception,
+    cause: Option<Box<Any + Send>>,
+}
+
+pub unsafe fn panic(data: Box<Any + Send>) -> u32 {
+    let exception = Box::new(Exception {
+        _uwe: uw::_Unwind_Exception {
+            exception_class: rust_exception_class(),
+            exception_cleanup: exception_cleanup,
+            private: [0; uw::unwinder_private_data_size],
+        },
+        cause: Some(data),
+    });
+    let exception_param = Box::into_raw(exception) as *mut uw::_Unwind_Exception;
+    return uw::_Unwind_RaiseException(exception_param) as u32;
+
+    extern fn exception_cleanup(_unwind_code: uw::_Unwind_Reason_Code,
+                                exception: *mut uw::_Unwind_Exception) {
+        unsafe {
+            let _: Box<Exception> = Box::from_raw(exception as *mut Exception);
+        }
+    }
+}
+
+pub fn payload() -> *mut u8 {
+    0 as *mut u8
+}
+
+pub unsafe fn cleanup(ptr: *mut u8) -> Box<Any + Send> {
+    let my_ep = ptr as *mut Exception;
+    let cause = (*my_ep).cause.take();
+    uw::_Unwind_DeleteException(ptr as *mut _);
+    cause.unwrap()
+}
+
+// Rust's exception class identifier.  This is used by personality routines to
+// determine whether the exception was thrown by their own runtime.
+fn rust_exception_class() -> uw::_Unwind_Exception_Class {
+    // M O Z \0  R U S T -- vendor, language
+    0x4d4f5a_00_52555354
+}
+
+// We could implement our personality routine in 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"))))]
+pub mod eabi {
+    use unwind as uw;
+    use libc::c_int;
+
+    extern {
+        fn __gcc_personality_v0(version: c_int,
+                                actions: uw::_Unwind_Action,
+                                exception_class: uw::_Unwind_Exception_Class,
+                                ue_header: *mut uw::_Unwind_Exception,
+                                context: *mut uw::_Unwind_Context)
+            -> uw::_Unwind_Reason_Code;
+    }
+
+    #[lang = "eh_personality"]
+    #[no_mangle]
+    extern fn rust_eh_personality(
+        version: c_int,
+        actions: uw::_Unwind_Action,
+        exception_class: uw::_Unwind_Exception_Class,
+        ue_header: *mut uw::_Unwind_Exception,
+        context: *mut uw::_Unwind_Context
+    ) -> uw::_Unwind_Reason_Code
+    {
+        unsafe {
+            __gcc_personality_v0(version, actions, exception_class, ue_header,
+                                 context)
+        }
+    }
+
+    #[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,
+        ue_header: *mut uw::_Unwind_Exception,
+        context: *mut uw::_Unwind_Context
+    ) -> uw::_Unwind_Reason_Code
+    {
+
+        if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 { // search phase
+            uw::_URC_HANDLER_FOUND // catch!
+        }
+        else { // cleanup phase
+            unsafe {
+                __gcc_personality_v0(version, actions, exception_class, ue_header,
+                                     context)
+            }
+        }
+    }
+}
+
+// iOS on armv7 is using SjLj exceptions and therefore requires to use
+// a specialized personality routine: __gcc_personality_sj0
+
+#[cfg(all(target_os = "ios", target_arch = "arm"))]
+pub mod eabi {
+    use unwind as uw;
+    use libc::c_int;
+
+    extern {
+        fn __gcc_personality_sj0(version: c_int,
+                                actions: uw::_Unwind_Action,
+                                exception_class: uw::_Unwind_Exception_Class,
+                                ue_header: *mut uw::_Unwind_Exception,
+                                context: *mut uw::_Unwind_Context)
+            -> uw::_Unwind_Reason_Code;
+    }
+
+    #[lang = "eh_personality"]
+    #[no_mangle]
+    pub extern fn rust_eh_personality(
+        version: c_int,
+        actions: uw::_Unwind_Action,
+        exception_class: uw::_Unwind_Exception_Class,
+        ue_header: *mut uw::_Unwind_Exception,
+        context: *mut uw::_Unwind_Context
+    ) -> uw::_Unwind_Reason_Code
+    {
+        unsafe {
+            __gcc_personality_sj0(version, actions, exception_class, ue_header,
+                                  context)
+        }
+    }
+
+    #[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,
+        ue_header: *mut uw::_Unwind_Exception,
+        context: *mut uw::_Unwind_Context
+    ) -> uw::_Unwind_Reason_Code
+    {
+        if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 { // search phase
+            uw::_URC_HANDLER_FOUND // catch!
+        }
+        else { // cleanup phase
+            unsafe {
+                __gcc_personality_sj0(version, actions, exception_class, ue_header,
+                                      context)
+            }
+        }
+    }
+}
+
+
+// ARM EHABI uses a slightly different personality routine signature,
+// but otherwise works the same.
+#[cfg(all(target_arch = "arm", not(target_os = "ios")))]
+pub mod eabi {
+    use unwind as uw;
+    use libc::c_int;
+
+    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]
+    extern fn rust_eh_personality(
+        state: uw::_Unwind_State,
+        ue_header: *mut uw::_Unwind_Exception,
+        context: *mut uw::_Unwind_Context
+    ) -> uw::_Unwind_Reason_Code
+    {
+        unsafe {
+            __gcc_personality_v0(state, ue_header, context)
+        }
+    }
+
+    #[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
+    ) -> uw::_Unwind_Reason_Code
+    {
+        // Backtraces on ARM will call the personality routine with
+        // state == _US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND. In those cases
+        // we want to continue unwinding the stack, otherwise all our backtraces
+        // would end at __rust_try.
+        if (state as c_int & uw::_US_ACTION_MASK as c_int)
+                           == uw::_US_VIRTUAL_UNWIND_FRAME as c_int
+               && (state as c_int & uw::_US_FORCE_UNWIND as c_int) == 0 { // search phase
+            uw::_URC_HANDLER_FOUND // catch!
+        }
+        else { // cleanup phase
+            unsafe {
+                __gcc_personality_v0(state, ue_header, context)
+            }
+        }
+    }
+}
+
+// See docs in the `unwind` module.
+#[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))]
+#[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);
+}
+
+// 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.
+//
+// This module defines two symbols which are referenced and called from
+// rsbegin.rs to reigster our information with the GCC runtime. 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 any GCC runtime.
+#[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))]
+pub mod eh_frame_registry {
+    #[link(name = "gcc_eh")]
+    #[cfg(not(cargobuild))]
+    extern {}
+
+    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);
+    }
+
+    #[no_mangle]
+    pub unsafe extern fn rust_eh_register_frames(eh_frame_begin: *const u8,
+                                                 object: *mut u8) {
+        __register_frame_info(eh_frame_begin, object);
+    }
+
+    #[no_mangle]
+    pub  unsafe extern fn rust_eh_unregister_frames(eh_frame_begin: *const u8,
+                                                   object: *mut u8) {
+        __deregister_frame_info(eh_frame_begin, object);
+    }
+}
diff --git a/src/libpanic_unwind/lib.rs b/src/libpanic_unwind/lib.rs
new file mode 100644 (file)
index 0000000..17cbd2e
--- /dev/null
@@ -0,0 +1,109 @@
+// Copyright 2016 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.
+
+//! Implementation of panics via stack unwinding
+//!
+//! This crate is an implementation of panics in Rust using "most native" stack
+//! unwinding mechanism of the platform this is being compiled for. This
+//! essentially gets categorized into three buckets currently:
+//!
+//! 1. MSVC targets use SEH in the `seh.rs` file.
+//! 2. The 64-bit MinGW target half-uses SEH and half-use gcc-like information
+//!    in the `seh64_gnu.rs` module.
+//! 3. All other targets use libunwind/libgcc in the `gcc/mod.rs` module.
+//!
+//! More documentation about each implementation can be found in the respective
+//! module.
+
+#![no_std]
+#![crate_name = "panic_unwind"]
+#![crate_type = "rlib"]
+#![unstable(feature = "panic_unwind", issue = "32837")]
+#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
+       html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
+       html_root_url = "https://doc.rust-lang.org/nightly/",
+       issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")]
+#![cfg_attr(not(stage0), deny(warnings))]
+
+#![feature(alloc)]
+#![feature(core_intrinsics)]
+#![feature(lang_items)]
+#![feature(libc)]
+#![feature(panic_unwind)]
+#![feature(raw)]
+#![feature(staged_api)]
+#![feature(unwind_attributes)]
+#![cfg_attr(target_env = "msvc", feature(raw))]
+
+#![cfg_attr(not(stage0), panic_runtime)]
+#![cfg_attr(not(stage0), feature(panic_runtime))]
+
+extern crate alloc;
+extern crate libc;
+extern crate unwind;
+
+use core::intrinsics;
+use core::mem;
+use core::raw;
+
+// Rust runtime's startup objects depend on these symbols, so make them public.
+#[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))]
+pub use imp::eh_frame_registry::*;
+
+// *-pc-windows-msvc
+#[cfg(target_env = "msvc")]
+#[path = "seh.rs"]
+mod imp;
+
+// x86_64-pc-windows-gnu
+#[cfg(all(windows, target_arch = "x86_64", target_env = "gnu"))]
+#[path = "seh64_gnu.rs"]
+mod imp;
+
+// i686-pc-windows-gnu and all others
+#[cfg(any(unix, all(windows, target_arch = "x86", target_env = "gnu")))]
+#[path = "gcc.rs"]
+mod imp;
+
+mod dwarf;
+mod windows;
+
+// Entry point for catching an exception, implemented using the `try` intrinsic
+// in the compiler.
+//
+// The interaction between the `payload` function and the compiler is pretty
+// hairy and tightly coupled, for more information see the compiler's
+// implementation of this.
+#[no_mangle]
+pub unsafe extern fn __rust_maybe_catch_panic(f: fn(*mut u8),
+                                              data: *mut u8,
+                                              data_ptr: *mut usize,
+                                              vtable_ptr: *mut usize)
+                                              -> u32 {
+    let mut payload = imp::payload();
+    if intrinsics::try(f, data, &mut payload as *mut _ as *mut _) == 0 {
+        0
+    } else {
+        let obj = mem::transmute::<_, raw::TraitObject>(imp::cleanup(payload));
+        *data_ptr = obj.data as usize;
+        *vtable_ptr = obj.vtable as usize;
+        1
+    }
+}
+
+// Entry point for raising an exception, just delegates to the platform-specific
+// implementation.
+#[no_mangle]
+pub unsafe extern fn __rust_start_panic(data: usize, vtable: usize) -> u32 {
+    imp::panic(mem::transmute(raw::TraitObject {
+        data: data as *mut (),
+        vtable: vtable as *mut (),
+    }))
+}
diff --git a/src/libpanic_unwind/seh.rs b/src/libpanic_unwind/seh.rs
new file mode 100644 (file)
index 0000000..c451eec
--- /dev/null
@@ -0,0 +1,147 @@
+// 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.
+
+//! Windows SEH
+//!
+//! On Windows (currently only on MSVC), the default exception handling
+//! mechanism is Structured Exception Handling (SEH). This is quite different
+//! than Dwarf-based exception handling (e.g. what other unix platforms use) in
+//! terms of compiler internals, so LLVM is required to have a good deal of
+//! extra support for SEH.
+//!
+//! In a nutshell, what happens here is:
+//!
+//! 1. The `panic` function calls the standard Windows function `RaiseException`
+//!    with a Rust-specific code, triggering the unwinding process.
+//! 2. All landing pads generated by the compiler use the personality function
+//!    `__C_specific_handler` on 64-bit and `__except_handler3` on 32-bit,
+//!    functions in the CRT, and the unwinding code in Windows will use this
+//!    personality function to execute all cleanup code on the stack.
+//! 3. All compiler-generated calls to `invoke` have a landing pad set as a
+//!    `cleanuppad` LLVM instruction, which indicates the start of the cleanup
+//!    routine. The personality (in step 2, defined in the CRT) is responsible
+//!    for running the cleanup routines.
+//! 4. Eventually the "catch" code in the `try` intrinsic (generated by the
+//!    compiler) is executed, which will ensure that the exception being caught
+//!    is indeed a Rust exception, indicating that control should come back to
+//!    Rust. This is done via a `catchswitch` plus a `catchpad` instruction in
+//!    LLVM IR terms, finally returning normal control to the program with a
+//!    `catchret` instruction. The `try` intrinsic uses a filter function to
+//!    detect what kind of exception is being thrown, and this detection is
+//!    implemented as the msvc_try_filter language item below.
+//!
+//! Some specific differences from the gcc-based exception handling are:
+//!
+//! * Rust has no custom personality function, it is instead *always*
+//!   __C_specific_handler or __except_handler3, so the filtering is done in a
+//!   C++-like manner instead of in the personality function itself. Note that
+//!   the precise codegen for this was lifted from an LLVM test case for SEH
+//!   (this is the `__rust_try_filter` function below).
+//! * We've got some data to transmit across the unwinding boundary,
+//!   specifically a `Box<Any + Send>`. Like with Dwarf exceptions
+//!   these two pointers are stored as a payload in the exception itself. On
+//!   MSVC, however, there's no need for an extra allocation because the call
+//!   stack is preserved while filter functions are being executed. This means
+//!   that the pointers are passed directly to `RaiseException` which are then
+//!   recovered in the filter function to be written to the stack frame of the
+//!   `try` intrinsic.
+//!
+//! [win64]: http://msdn.microsoft.com/en-us/library/1eyas8tf.aspx
+//! [llvm]: http://llvm.org/docs/ExceptionHandling.html#background-on-windows-exceptions
+
+use alloc::boxed::Box;
+use core::any::Any;
+use core::intrinsics;
+use core::mem;
+use core::raw;
+
+use windows as 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>) -> u32 {
+    // 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
+    // `RaiseException`.
+    //
+    // The two pointers of the `data` trait object are written to the stack,
+    // passed to `RaiseException`, and they're later extracted by the filter
+    // function below in the "custom exception information" section of the
+    // `EXCEPTION_RECORD` type.
+    let ptrs = mem::transmute::<_, raw::TraitObject>(data);
+    let ptrs = [ptrs.data, ptrs.vtable];
+    c::RaiseException(RUST_PANIC, 0, 2, ptrs.as_ptr() as *mut _);
+    u32::max_value()
+}
+
+pub fn payload() -> [usize; 2] {
+    [0; 2]
+}
+
+pub unsafe fn cleanup(payload: [usize; 2]) -> Box<Any + Send> {
+    mem::transmute(raw::TraitObject {
+        data: payload[0] as *mut _,
+        vtable: payload[1] as *mut _,
+    })
+}
+
+// This is quite a special function, and it's not literally passed in as the
+// filter function for the `catchpad` of the `try` intrinsic. The compiler
+// actually generates its own filter function wrapper which will delegate to
+// this for the actual execution logic for whether the exception should be
+// caught. The reasons for this are:
+//
+// * Each architecture has a slightly different ABI for the filter function
+//   here. For example on x86 there are no arguments but on x86_64 there are
+//   two.
+// * This function needs access to the stack frame of the `try` intrinsic
+//   which is using this filter as a catch pad. This is because the payload
+//   of this exception, `Box<Any>`, needs to be transmitted to that
+//   location.
+//
+// Both of these differences end up using a ton of weird llvm-specific
+// intrinsics, so it's actually pretty difficult to express the entire
+// filter function in Rust itself. As a compromise, the compiler takes care
+// of all the weird LLVM-specific and platform-specific stuff, getting to
+// the point where this function makes the actual decision about what to
+// catch given two parameters.
+//
+// The first parameter is `*mut EXCEPTION_POINTERS` which is some contextual
+// information about the exception being filtered, and the second pointer is
+// `*mut *mut [usize; 2]` (the payload here). This value points directly
+// into the stack frame of the `try` intrinsic itself, and we use it to copy
+// information from the exception onto the stack.
+#[lang = "msvc_try_filter"]
+#[cfg(not(test))]
+unsafe extern fn __rust_try_filter(eh_ptrs: *mut u8,
+                                   payload: *mut u8) -> i32 {
+    let eh_ptrs = eh_ptrs as *mut c::EXCEPTION_POINTERS;
+    let payload = payload as *mut *mut [usize; 2];
+    let record = &*(*eh_ptrs).ExceptionRecord;
+    if record.ExceptionCode != RUST_PANIC {
+        return 0
+    }
+    (**payload)[0] = record.ExceptionInformation[0] as usize;
+    (**payload)[1] = record.ExceptionInformation[1] as usize;
+    return 1
+}
+
+// This is required by the compiler to exist (e.g. it's a lang item), but
+// it's never actually called by the compiler because __C_specific_handler
+// or _except_handler3 is the personality function that is always used.
+// Hence this is just an aborting stub.
+#[lang = "eh_personality"]
+#[cfg(not(test))]
+fn rust_eh_personality() {
+    unsafe { intrinsics::abort() }
+}
diff --git a/src/libpanic_unwind/seh64_gnu.rs b/src/libpanic_unwind/seh64_gnu.rs
new file mode 100644 (file)
index 0000000..adb38d8
--- /dev/null
@@ -0,0 +1,142 @@
+// 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.
+
+//! Unwinding implementation of top of native Win64 SEH,
+//! however the unwind handler data (aka LSDA) uses GCC-compatible encoding.
+
+#![allow(bad_style)]
+#![allow(private_no_mangle_fns)]
+
+use alloc::boxed::Box;
+
+use core::any::Any;
+use core::intrinsics;
+use dwarf::eh;
+use windows as c;
+
+// Define our exception codes:
+// according to http://msdn.microsoft.com/en-us/library/het71c37(v=VS.80).aspx,
+//    [31:30] = 3 (error), 2 (warning), 1 (info), 0 (success)
+//    [29]    = 1 (user-defined)
+//    [28]    = 0 (reserved)
+// we define bits:
+//    [24:27] = type
+//    [0:23]  = magic
+const ETYPE: c::DWORD = 0b1110_u32 << 28;
+const MAGIC: c::DWORD = 0x525354; // "RST"
+
+const RUST_PANIC: c::DWORD  = ETYPE | (1 << 24) | MAGIC;
+
+#[repr(C)]
+struct PanicData {
+    data: Box<Any + Send>
+}
+
+pub unsafe fn panic(data: Box<Any + Send>) -> u32 {
+    let panic_ctx = Box::new(PanicData { data: data });
+    let params = [Box::into_raw(panic_ctx) as c::ULONG_PTR];
+    c::RaiseException(RUST_PANIC,
+                      c::EXCEPTION_NONCONTINUABLE,
+                      params.len() as c::DWORD,
+                      &params as *const c::ULONG_PTR);
+    u32::max_value()
+}
+
+pub fn payload() -> *mut u8 {
+    0 as *mut u8
+}
+
+pub unsafe fn cleanup(ptr: *mut u8) -> Box<Any + Send> {
+    let panic_ctx = Box::from_raw(ptr as *mut PanicData);
+    return panic_ctx.data;
+}
+
+// SEH doesn't support resuming unwinds after calling a landing pad like
+// libunwind does. For this reason, MSVC compiler outlines landing pads into
+// separate functions that can be called directly from the personality function
+// but are nevertheless able to find and modify stack frame of the "parent"
+// function.
+//
+// Since this cannot be done with libdwarf-style landing pads,
+// rust_eh_personality instead catches RUST_PANICs, runs the landing pad, then
+// reraises the exception.
+//
+// Note that it makes certain assumptions about the exception:
+//
+// 1. That RUST_PANIC is non-continuable, so no lower stack frame may choose to
+//    resume execution.
+// 2. That the first parameter of the exception is a pointer to an extra data
+//    area (PanicData).
+// Since these assumptions do not generally hold true for foreign exceptions
+// (system faults, C++ exceptions, etc), we make no attempt to invoke our
+// landing pads (and, thus, destructors!) for anything other than RUST_PANICs.
+// This is considered acceptable, because the behavior of throwing exceptions
+// through a C ABI boundary is undefined.
+
+#[lang = "eh_personality_catch"]
+#[cfg(not(test))]
+unsafe extern fn rust_eh_personality_catch(
+    exceptionRecord: *mut c::EXCEPTION_RECORD,
+    establisherFrame: c::LPVOID,
+    contextRecord: *mut c::CONTEXT,
+    dispatcherContext: *mut c::DISPATCHER_CONTEXT
+) -> c::EXCEPTION_DISPOSITION
+{
+    rust_eh_personality(exceptionRecord, establisherFrame,
+                        contextRecord, dispatcherContext)
+}
+
+#[lang = "eh_personality"]
+#[cfg(not(test))]
+unsafe extern fn rust_eh_personality(
+    exceptionRecord: *mut c::EXCEPTION_RECORD,
+    establisherFrame: c::LPVOID,
+    contextRecord: *mut c::CONTEXT,
+    dispatcherContext: *mut c::DISPATCHER_CONTEXT
+) -> c::EXCEPTION_DISPOSITION
+{
+    let er = &*exceptionRecord;
+    let dc = &*dispatcherContext;
+
+    if er.ExceptionFlags & c::EXCEPTION_UNWIND == 0 { // we are in the dispatch phase
+        if er.ExceptionCode == RUST_PANIC {
+            if let Some(lpad) = find_landing_pad(dc) {
+                c::RtlUnwindEx(establisherFrame,
+                               lpad as c::LPVOID,
+                               exceptionRecord,
+                               er.ExceptionInformation[0] as c::LPVOID, // pointer to PanicData
+                               contextRecord,
+                               dc.HistoryTable);
+            }
+        }
+    }
+    c::ExceptionContinueSearch
+}
+
+#[lang = "eh_unwind_resume"]
+#[unwind]
+unsafe extern fn rust_eh_unwind_resume(panic_ctx: c::LPVOID) -> ! {
+    let params = [panic_ctx as c::ULONG_PTR];
+    c::RaiseException(RUST_PANIC,
+                      c::EXCEPTION_NONCONTINUABLE,
+                      params.len() as c::DWORD,
+                      &params as *const c::ULONG_PTR);
+    intrinsics::abort();
+}
+
+unsafe fn find_landing_pad(dc: &c::DISPATCHER_CONTEXT) -> Option<usize> {
+    let eh_ctx = eh::EHContext {
+        ip: dc.ControlPc as usize,
+        func_start: dc.ImageBase as usize + (*dc.FunctionEntry).BeginAddress as usize,
+        text_start: dc.ImageBase as usize,
+        data_start: 0
+    };
+    eh::find_landing_pad(dc.HandlerData, &eh_ctx)
+}
diff --git a/src/libpanic_unwind/windows.rs b/src/libpanic_unwind/windows.rs
new file mode 100644 (file)
index 0000000..a0ccbc0
--- /dev/null
@@ -0,0 +1,96 @@
+// Copyright 2014 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.
+
+#![allow(bad_style)]
+#![allow(dead_code)]
+#![cfg(windows)]
+
+use libc::{c_void, c_ulong, c_long, c_ulonglong};
+
+pub use self::EXCEPTION_DISPOSITION::*;
+pub type DWORD = c_ulong;
+pub type LONG = c_long;
+pub type ULONG_PTR = c_ulonglong;
+pub type LPVOID = *mut c_void;
+
+pub const EXCEPTION_MAXIMUM_PARAMETERS: usize = 15;
+pub const EXCEPTION_NONCONTINUABLE: DWORD = 0x1;   // Noncontinuable exception
+pub const EXCEPTION_UNWINDING: DWORD = 0x2;        // Unwind is in progress
+pub const EXCEPTION_EXIT_UNWIND: DWORD = 0x4;      // Exit unwind is in progress
+pub const EXCEPTION_TARGET_UNWIND: DWORD = 0x20;   // Target unwind in progress
+pub const EXCEPTION_COLLIDED_UNWIND: DWORD = 0x40; // Collided exception handler call
+pub const EXCEPTION_UNWIND: DWORD = EXCEPTION_UNWINDING |
+                                    EXCEPTION_EXIT_UNWIND |
+                                    EXCEPTION_TARGET_UNWIND |
+                                    EXCEPTION_COLLIDED_UNWIND;
+
+#[repr(C)]
+pub struct EXCEPTION_RECORD {
+    pub ExceptionCode: DWORD,
+    pub ExceptionFlags: DWORD,
+    pub ExceptionRecord: *mut EXCEPTION_RECORD,
+    pub ExceptionAddress: LPVOID,
+    pub NumberParameters: DWORD,
+    pub ExceptionInformation: [LPVOID; EXCEPTION_MAXIMUM_PARAMETERS]
+}
+
+#[repr(C)]
+pub struct EXCEPTION_POINTERS {
+    pub ExceptionRecord: *mut EXCEPTION_RECORD,
+    pub ContextRecord: *mut CONTEXT,
+}
+
+pub enum UNWIND_HISTORY_TABLE {}
+
+#[repr(C)]
+pub struct RUNTIME_FUNCTION {
+    pub BeginAddress: DWORD,
+    pub EndAddress: DWORD,
+    pub UnwindData: DWORD,
+}
+
+pub enum CONTEXT {}
+
+#[repr(C)]
+pub struct DISPATCHER_CONTEXT {
+    pub ControlPc: LPVOID,
+    pub ImageBase: LPVOID,
+    pub FunctionEntry: *const RUNTIME_FUNCTION,
+    pub EstablisherFrame: LPVOID,
+    pub TargetIp: LPVOID,
+    pub ContextRecord: *const CONTEXT,
+    pub LanguageHandler: LPVOID,
+    pub HandlerData: *const u8,
+    pub HistoryTable: *const UNWIND_HISTORY_TABLE,
+}
+
+#[repr(C)]
+#[allow(dead_code)] // we only use some variants
+pub enum EXCEPTION_DISPOSITION {
+    ExceptionContinueExecution,
+    ExceptionContinueSearch,
+    ExceptionNestedException,
+    ExceptionCollidedUnwind
+}
+
+extern "system" {
+    #[unwind]
+    pub fn RaiseException(dwExceptionCode: DWORD,
+                          dwExceptionFlags: DWORD,
+                          nNumberOfArguments: DWORD,
+                          lpArguments: *const ULONG_PTR);
+    #[unwind]
+    pub fn RtlUnwindEx(TargetFrame: LPVOID,
+                       TargetIp: LPVOID,
+                       ExceptionRecord: *const EXCEPTION_RECORD,
+                       ReturnValue: LPVOID,
+                       OriginalContext: *const CONTEXT,
+                       HistoryTable: *const UNWIND_HISTORY_TABLE);
+}
index c1a8f747de14d9823888a309505c960f8fab6ce0..035505655967c384c9d4f4ccc42e1f0368f55e7a 100644 (file)
@@ -31,6 +31,7 @@
 use mir::repr::Mir;
 use mir::mir_map::MirMap;
 use session::Session;
+use session::config::PanicStrategy;
 use session::search_paths::PathKind;
 use util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap};
 use std::any::Any;
@@ -222,6 +223,8 @@ fn dylib_dependency_formats(&self, cnum: ast::CrateNum)
     fn is_staged_api(&self, cnum: ast::CrateNum) -> bool;
     fn is_explicitly_linked(&self, cnum: ast::CrateNum) -> bool;
     fn is_allocator(&self, cnum: ast::CrateNum) -> bool;
+    fn is_panic_runtime(&self, cnum: ast::CrateNum) -> bool;
+    fn panic_strategy(&self, cnum: ast::CrateNum) -> PanicStrategy;
     fn extern_crate(&self, cnum: ast::CrateNum) -> Option<ExternCrate>;
     fn crate_attrs(&self, cnum: ast::CrateNum) -> Vec<ast::Attribute>;
     /// The name of the crate as it is referred to in source code of the current
@@ -408,6 +411,10 @@ fn missing_lang_items(&self, cnum: ast::CrateNum) -> Vec<lang_items::LangItem>
     fn is_staged_api(&self, cnum: ast::CrateNum) -> bool { bug!("is_staged_api") }
     fn is_explicitly_linked(&self, cnum: ast::CrateNum) -> bool { bug!("is_explicitly_linked") }
     fn is_allocator(&self, cnum: ast::CrateNum) -> bool { bug!("is_allocator") }
+    fn is_panic_runtime(&self, cnum: ast::CrateNum) -> bool { bug!("is_panic_runtime") }
+    fn panic_strategy(&self, cnum: ast::CrateNum) -> PanicStrategy {
+        bug!("panic_strategy")
+    }
     fn extern_crate(&self, cnum: ast::CrateNum) -> Option<ExternCrate> { bug!("extern_crate") }
     fn crate_attrs(&self, cnum: ast::CrateNum) -> Vec<ast::Attribute>
         { bug!("crate_attrs") }
index c2498b7b5eed3114de255a966ed3899e0310e714..fe22cfdb43f73ce7643b209557f8b8231d2cbc87 100644 (file)
@@ -64,7 +64,7 @@
 use syntax::ast;
 
 use session;
-use session::config;
+use session::config::{self, PanicStrategy};
 use middle::cstore::LinkagePreference::{self, RequireStatic, RequireDynamic};
 use util::nodemap::FnvHashMap;
 
@@ -193,10 +193,15 @@ fn calculate_type(sess: &session::Session,
     }
 
     // We've gotten this far because we're emitting some form of a final
-    // artifact which means that we're going to need an allocator of some form.
-    // No allocator may have been required or linked so far, so activate one
-    // here if one isn't set.
-    activate_allocator(sess, &mut ret);
+    // artifact which means that we may need to inject dependencies of some
+    // form.
+    //
+    // Things like allocators and panic runtimes may not have been activated
+    // quite yet, so do so here.
+    activate_injected_dep(sess.injected_allocator.get(), &mut ret,
+                          &|cnum| sess.cstore.is_allocator(cnum));
+    activate_injected_dep(sess.injected_panic_runtime.get(), &mut ret,
+                          &|cnum| sess.cstore.is_panic_runtime(cnum));
 
     // When dylib B links to dylib A, then when using B we must also link to A.
     // It could be the case, however, that the rlib for A is present (hence we
@@ -270,40 +275,42 @@ fn attempt_static(sess: &session::Session) -> Option<DependencyList> {
         }
     }).collect::<Vec<_>>();
 
-    // Our allocator may not have been activated as it's not flagged with
-    // explicitly_linked, so flag it here if necessary.
-    activate_allocator(sess, &mut ret);
+    // Our allocator/panic runtime may not have been linked above if it wasn't
+    // explicitly linked, which is the case for any injected dependency. Handle
+    // that here and activate them.
+    activate_injected_dep(sess.injected_allocator.get(), &mut ret,
+                          &|cnum| sess.cstore.is_allocator(cnum));
+    activate_injected_dep(sess.injected_panic_runtime.get(), &mut ret,
+                          &|cnum| sess.cstore.is_panic_runtime(cnum));
 
     Some(ret)
 }
 
 // Given a list of how to link upstream dependencies so far, ensure that an
-// allocator is activated. This will not do anything if one was transitively
-// included already (e.g. via a dylib or explicitly so).
+// injected dependency is activated. This will not do anything if one was
+// transitively included already (e.g. via a dylib or explicitly so).
 //
-// If an allocator was not found then we're guaranteed the metadata::creader
-// module has injected an allocator dependency (not listed as a required
-// dependency) in the session's `injected_allocator` field. If this field is not
-// set then this compilation doesn't actually need an allocator and we can also
-// skip this step entirely.
-fn activate_allocator(sess: &session::Session, list: &mut DependencyList) {
-    let mut allocator_found = false;
+// If an injected dependency was not found then we're guaranteed the
+// metadata::creader module has injected that dependency (not listed as
+// a required dependency) in one of the session's field. If this field is not
+// set then this compilation doesn't actually need the dependency and we can
+// also skip this step entirely.
+fn activate_injected_dep(injected: Option<ast::CrateNum>,
+                         list: &mut DependencyList,
+                         replaces_injected: &Fn(ast::CrateNum) -> bool) {
     for (i, slot) in list.iter().enumerate() {
         let cnum = (i + 1) as ast::CrateNum;
-        if !sess.cstore.is_allocator(cnum) {
+        if !replaces_injected(cnum) {
             continue
         }
-        if let Linkage::NotLinked = *slot {
-            continue
+        if *slot != Linkage::NotLinked {
+            return
         }
-        allocator_found = true;
     }
-    if !allocator_found {
-        if let Some(injected_allocator) = sess.injected_allocator.get() {
-            let idx = injected_allocator as usize - 1;
-            assert_eq!(list[idx], Linkage::NotLinked);
-            list[idx] = Linkage::Static;
-        }
+    if let Some(injected) = injected {
+        let idx = injected as usize - 1;
+        assert_eq!(list[idx], Linkage::NotLinked);
+        list[idx] = Linkage::Static;
     }
 }
 
@@ -314,21 +321,75 @@ fn verify_ok(sess: &session::Session, list: &[Linkage]) {
         return
     }
     let mut allocator = None;
+    let mut panic_runtime = None;
     for (i, linkage) in list.iter().enumerate() {
-        let cnum = (i + 1) as ast::CrateNum;
-        if !sess.cstore.is_allocator(cnum) {
-            continue
-        }
         if let Linkage::NotLinked = *linkage {
             continue
         }
-        if let Some(prev_alloc) = allocator {
-            let prev_name = sess.cstore.crate_name(prev_alloc);
-            let cur_name = sess.cstore.crate_name(cnum);
-            sess.err(&format!("cannot link together two \
-                               allocators: {} and {}",
-                              prev_name, cur_name));
+        let cnum = (i + 1) as ast::CrateNum;
+        if sess.cstore.is_allocator(cnum) {
+            if let Some(prev) = allocator {
+                let prev_name = sess.cstore.crate_name(prev);
+                let cur_name = sess.cstore.crate_name(cnum);
+                sess.err(&format!("cannot link together two \
+                                   allocators: {} and {}",
+                                  prev_name, cur_name));
+            }
+            allocator = Some(cnum);
+        }
+
+        if sess.cstore.is_panic_runtime(cnum) {
+            if let Some((prev, _)) = panic_runtime {
+                let prev_name = sess.cstore.crate_name(prev);
+                let cur_name = sess.cstore.crate_name(cnum);
+                sess.err(&format!("cannot link together two \
+                                   panic runtimes: {} and {}",
+                                  prev_name, cur_name));
+            }
+            panic_runtime = Some((cnum, sess.cstore.panic_strategy(cnum)));
+        }
+    }
+
+    // If we found a panic runtime, then we know by this point that it's the
+    // only one, but we perform validation here that all the panic strategy
+    // compilation modes for the whole DAG are valid.
+    if let Some((cnum, found_strategy)) = panic_runtime {
+        let desired_strategy = sess.opts.cg.panic.clone();
+
+        // First up, validate that our selected panic runtime is indeed exactly
+        // our same strategy.
+        if found_strategy != desired_strategy {
+            sess.err(&format!("the linked panic runtime `{}` is \
+                               not compiled with this crate's \
+                               panic strategy `{}`",
+                              sess.cstore.crate_name(cnum),
+                              desired_strategy.desc()));
+        }
+
+        // Next up, verify that all other crates are compatible with this panic
+        // strategy. If the dep isn't linked, we ignore it, and if our strategy
+        // is abort then it's compatible with everything. Otherwise all crates'
+        // panic strategy must match our own.
+        for (i, linkage) in list.iter().enumerate() {
+            if let Linkage::NotLinked = *linkage {
+                continue
+            }
+            if desired_strategy == PanicStrategy::Abort {
+                continue
+            }
+            let cnum = (i + 1) as ast::CrateNum;
+            let found_strategy = sess.cstore.panic_strategy(cnum);
+            if desired_strategy == found_strategy {
+                continue
+            }
+
+            sess.err(&format!("the crate `{}` is compiled with the \
+                               panic strategy `{}` which is \
+                               incompatible with this crate's \
+                               strategy of `{}`",
+                              sess.cstore.crate_name(cnum),
+                              found_strategy.desc(),
+                              desired_strategy.desc()));
         }
-        allocator = Some(cnum);
     }
 }
index 5fe6076e5380e16b1af7e969fe74e6aaad60ec34..b7dfc86720458c7590f914a613aadec7a2c52ccc 100644 (file)
@@ -10,7 +10,7 @@
 
 //! Validity checking for weak lang items
 
-use session::config;
+use session::config::{self, PanicStrategy};
 use session::Session;
 use middle::lang_items;
 
@@ -75,7 +75,9 @@ fn verify(sess: &Session, items: &lang_items::LanguageItems) {
             config::CrateTypeRlib => false,
         }
     });
-    if !needs_check { return }
+    if !needs_check {
+        return
+    }
 
     let mut missing = HashSet::new();
     for cnum in sess.cstore.crates() {
@@ -84,8 +86,19 @@ fn verify(sess: &Session, items: &lang_items::LanguageItems) {
         }
     }
 
+    // If we're not compiling with unwinding, we won't actually need these
+    // symbols. Other panic runtimes ensure that the relevant symbols are
+    // available to link things together, but they're never exercised.
+    let mut whitelisted = HashSet::new();
+    if sess.opts.cg.panic != PanicStrategy::Unwind {
+        whitelisted.insert(lang_items::EhPersonalityLangItem);
+        whitelisted.insert(lang_items::EhUnwindResumeLangItem);
+    }
+
     $(
-        if missing.contains(&lang_items::$item) && items.$name().is_none() {
+        if missing.contains(&lang_items::$item) &&
+           !whitelisted.contains(&lang_items::$item) &&
+           items.$name().is_none() {
             sess.err(&format!("language item required, but not found: `{}`",
                               stringify!($name)));
 
index 1a2c1b9a09528850d7e15ef3ac6a0039e545501f..82e5ce07b13d331374da122874edf37992890669 100644 (file)
@@ -317,6 +317,21 @@ pub fn is_empty(&self) -> bool {
     }
 }
 
+#[derive(Clone, PartialEq)]
+pub enum PanicStrategy {
+    Unwind,
+    Abort,
+}
+
+impl PanicStrategy {
+    pub fn desc(&self) -> &str {
+        match *self {
+            PanicStrategy::Unwind => "unwind",
+            PanicStrategy::Abort => "abort",
+        }
+    }
+}
+
 /// Declare a macro that will define all CodegenOptions/DebuggingOptions fields and parsers all
 /// at once. The goal of this macro is to define an interface that can be
 /// programmatically used by the option parser in order to initialize the struct
@@ -402,11 +417,13 @@ mod $mod_desc {
             Some("a space-separated list of passes, or `all`");
         pub const parse_opt_uint: Option<&'static str> =
             Some("a number");
+        pub const parse_panic_strategy: Option<&'static str> =
+            Some("either `panic` or `abort`");
     }
 
     #[allow(dead_code)]
     mod $mod_set {
-        use super::{$struct_name, Passes, SomePasses, AllPasses};
+        use super::{$struct_name, Passes, SomePasses, AllPasses, PanicStrategy};
 
         $(
             pub fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool {
@@ -510,6 +527,15 @@ fn parse_passes(slot: &mut Passes, v: Option<&str>) -> bool {
                 }
             }
         }
+
+        fn parse_panic_strategy(slot: &mut PanicStrategy, v: Option<&str>) -> bool {
+            match v {
+                Some("unwind") => *slot = PanicStrategy::Unwind,
+                Some("abort") => *slot = PanicStrategy::Abort,
+                _ => return false
+            }
+            true
+        }
     }
 ) }
 
@@ -575,6 +601,8 @@ fn parse_passes(slot: &mut Passes, v: Option<&str>) -> bool {
         "explicitly enable the cfg(debug_assertions) directive"),
     inline_threshold: Option<usize> = (None, parse_opt_uint,
         "set the inlining threshold for"),
+    panic: PanicStrategy = (PanicStrategy::Unwind, parse_panic_strategy,
+        "panic strategy to compile crate with"),
 }
 
 
index edb1c4530c240a979a8dd682d95a5ed7792de732..1bea01c4849e756b036d9bd6acff3512c75a4c83 100644 (file)
@@ -12,6 +12,7 @@
 use middle::cstore::CrateStore;
 use middle::dependency_format;
 use session::search_paths::PathKind;
+use session::config::PanicStrategy;
 use ty::tls;
 use util::nodemap::{NodeMap, FnvHashMap};
 use mir::transform as mir_pass;
@@ -82,9 +83,11 @@ pub struct Session {
     /// operations such as auto-dereference and monomorphization.
     pub recursion_limit: Cell<usize>,
 
-    /// The metadata::creader module may inject an allocator dependency if it
-    /// didn't already find one, and this tracks what was injected.
+    /// The metadata::creader module may inject an allocator/panic_runtime
+    /// dependency if it didn't already find one, and this tracks what was
+    /// injected.
     pub injected_allocator: Cell<Option<ast::CrateNum>>,
+    pub injected_panic_runtime: Cell<Option<ast::CrateNum>>,
 
     /// Names of all bang-style macros and syntax extensions
     /// available in this crate
@@ -295,7 +298,8 @@ pub fn lto(&self) -> bool {
         self.opts.cg.lto
     }
     pub fn no_landing_pads(&self) -> bool {
-        self.opts.debugging_opts.no_landing_pads
+        self.opts.debugging_opts.no_landing_pads ||
+            self.opts.cg.panic == PanicStrategy::Abort
     }
     pub fn unstable_options(&self) -> bool {
         self.opts.debugging_opts.unstable_options
@@ -502,6 +506,7 @@ pub fn build_session_(sopts: config::Options,
         recursion_limit: Cell::new(64),
         next_node_id: Cell::new(1),
         injected_allocator: Cell::new(None),
+        injected_panic_runtime: Cell::new(None),
         available_macros: RefCell::new(HashSet::new()),
         imported_macro_spans: RefCell::new(HashMap::new()),
     };
index ea4e25754202c7ff23466d0a135306355bd70830..2b972af07ff91f64120c79bd46ba9e620eed9a67 100644 (file)
@@ -250,3 +250,5 @@ pub fn rustc_version() -> String {
         option_env!("CFG_VERSION").unwrap_or("unknown version")
     )
 }
+
+pub const tag_panic_strategy: usize = 0x114;
index de0de219db2f13f45dec8b1c82a1cfeb56754368..190e8552d199a4caa68cecc2aa48b653185e968e 100644 (file)
@@ -20,6 +20,7 @@
 use rustc::hir::svh::Svh;
 use rustc::dep_graph::{DepGraph, DepNode};
 use rustc::session::{config, Session};
+use rustc::session::config::PanicStrategy;
 use rustc::session::search_paths::PathKind;
 use rustc::middle::cstore::{CrateStore, validate_crate_name, ExternCrate};
 use rustc::util::nodemap::FnvHashMap;
@@ -630,6 +631,85 @@ fn register_statically_included_foreign_items(&mut self) {
         }
     }
 
+    fn inject_panic_runtime(&mut self, krate: &ast::Crate) {
+        // If we're only compiling an rlib, then there's no need to select a
+        // panic runtime, so we just skip this section entirely.
+        let any_non_rlib = self.sess.crate_types.borrow().iter().any(|ct| {
+            *ct != config::CrateTypeRlib
+        });
+        if !any_non_rlib {
+            info!("panic runtime injection skipped, only generating rlib");
+            return
+        }
+
+        // If we need a panic runtime, we try to find an existing one here. At
+        // the same time we perform some general validation of the DAG we've got
+        // going such as ensuring everything has a compatible panic strategy.
+        //
+        // The logic for finding the panic runtime here is pretty much the same
+        // as the allocator case with the only addition that the panic strategy
+        // compilation mode also comes into play.
+        let desired_strategy = self.sess.opts.cg.panic.clone();
+        let mut runtime_found = false;
+        let mut needs_panic_runtime = attr::contains_name(&krate.attrs,
+                                                          "needs_panic_runtime");
+        self.cstore.iter_crate_data(|cnum, data| {
+            needs_panic_runtime = needs_panic_runtime || data.needs_panic_runtime();
+            if data.is_panic_runtime() {
+                // Inject a dependency from all #![needs_panic_runtime] to this
+                // #![panic_runtime] crate.
+                self.inject_dependency_if(cnum, "a panic runtime",
+                                          &|data| data.needs_panic_runtime());
+                runtime_found = runtime_found || data.explicitly_linked.get();
+            }
+        });
+
+        // If an explicitly linked and matching panic runtime was found, or if
+        // we just don't need one at all, then we're done here and there's
+        // nothing else to do.
+        if !needs_panic_runtime || runtime_found {
+            return
+        }
+
+        // By this point we know that we (a) need a panic runtime and (b) no
+        // panic runtime was explicitly linked. Here we just load an appropriate
+        // default runtime for our panic strategy and then inject the
+        // dependencies.
+        //
+        // We may resolve to an already loaded crate (as the crate may not have
+        // been explicitly linked prior to this) and we may re-inject
+        // dependencies again, but both of those situations are fine.
+        //
+        // Also note that we have yet to perform validation of the crate graph
+        // in terms of everyone has a compatible panic runtime format, that's
+        // performed later as part of the `dependency_format` module.
+        let name = match desired_strategy {
+            PanicStrategy::Unwind => "panic_unwind",
+            PanicStrategy::Abort => "panic_abort",
+        };
+        info!("panic runtime not found -- loading {}", name);
+
+        let (cnum, data, _) = self.resolve_crate(&None, name, name, None,
+                                                 codemap::DUMMY_SP,
+                                                 PathKind::Crate, false);
+
+        // Sanity check the loaded crate to ensure it is indeed a panic runtime
+        // and the panic strategy is indeed what we thought it was.
+        if !data.is_panic_runtime() {
+            self.sess.err(&format!("the crate `{}` is not a panic runtime",
+                                   name));
+        }
+        if data.panic_strategy() != desired_strategy {
+            self.sess.err(&format!("the crate `{}` does not have the panic \
+                                    strategy `{}`",
+                                   name, desired_strategy.desc()));
+        }
+
+        self.sess.injected_panic_runtime.set(Some(cnum));
+        self.inject_dependency_if(cnum, "a panic runtime",
+                                  &|data| data.needs_panic_runtime());
+    }
+
     fn inject_allocator_crate(&mut self) {
         // Make sure that we actually need an allocator, if none of our
         // dependencies need one then we definitely don't!
@@ -641,8 +721,9 @@ fn inject_allocator_crate(&mut self) {
         self.cstore.iter_crate_data(|cnum, data| {
             needs_allocator = needs_allocator || data.needs_allocator();
             if data.is_allocator() {
-                debug!("{} required by rlib and is an allocator", data.name());
-                self.inject_allocator_dependency(cnum);
+                info!("{} required by rlib and is an allocator", data.name());
+                self.inject_dependency_if(cnum, "an allocator",
+                                          &|data| data.needs_allocator());
                 found_required_allocator = found_required_allocator ||
                     data.explicitly_linked.get();
             }
@@ -692,58 +773,68 @@ fn inject_allocator_crate(&mut self) {
                                                  codemap::DUMMY_SP,
                                                  PathKind::Crate, false);
 
-        // To ensure that the `-Z allocation-crate=foo` option isn't abused, and
-        // to ensure that the allocator is indeed an allocator, we verify that
-        // the crate loaded here is indeed tagged #![allocator].
+        // Sanity check the crate we loaded to ensure that it is indeed an
+        // allocator.
         if !data.is_allocator() {
             self.sess.err(&format!("the allocator crate `{}` is not tagged \
                                     with #![allocator]", data.name()));
         }
 
         self.sess.injected_allocator.set(Some(cnum));
-        self.inject_allocator_dependency(cnum);
+        self.inject_dependency_if(cnum, "an allocator",
+                                  &|data| data.needs_allocator());
     }
 
-    fn inject_allocator_dependency(&self, allocator: ast::CrateNum) {
+    fn inject_dependency_if(&self,
+                            krate: ast::CrateNum,
+                            what: &str,
+                            needs_dep: &Fn(&cstore::crate_metadata) -> bool) {
+        // don't perform this validation if the session has errors, as one of
+        // those errors may indicate a circular dependency which could cause
+        // this to stack overflow.
+        if self.sess.has_errors() {
+            return
+        }
+
         // Before we inject any dependencies, make sure we don't inject a
-        // circular dependency by validating that this allocator crate doesn't
-        // transitively depend on any `#![needs_allocator]` crates.
-        validate(self, allocator, allocator);
-
-        // All crates tagged with `needs_allocator` do not explicitly depend on
-        // the allocator selected for this compile, but in order for this
-        // compilation to be successfully linked we need to inject a dependency
-        // (to order the crates on the command line correctly).
-        //
-        // Here we inject a dependency from all crates with #![needs_allocator]
-        // to the crate tagged with #![allocator] for this compilation unit.
+        // circular dependency by validating that this crate doesn't
+        // transitively depend on any crates satisfying `needs_dep`.
+        validate(self, krate, krate, what, needs_dep);
+
+        // All crates satisfying `needs_dep` do not explicitly depend on the
+        // crate provided for this compile, but in order for this compilation to
+        // be successfully linked we need to inject a dependency (to order the
+        // crates on the command line correctly).
         self.cstore.iter_crate_data(|cnum, data| {
-            if !data.needs_allocator() {
+            if !needs_dep(data) {
                 return
             }
 
-            info!("injecting a dep from {} to {}", cnum, allocator);
+            info!("injecting a dep from {} to {}", cnum, krate);
             let mut cnum_map = data.cnum_map.borrow_mut();
             let remote_cnum = cnum_map.len() + 1;
-            let prev = cnum_map.insert(remote_cnum as ast::CrateNum, allocator);
+            let prev = cnum_map.insert(remote_cnum as ast::CrateNum, krate);
             assert!(prev.is_none());
         });
 
-        fn validate(me: &CrateReader, krate: ast::CrateNum,
-                    allocator: ast::CrateNum) {
+        fn validate(me: &CrateReader,
+                    krate: ast::CrateNum,
+                    root: ast::CrateNum,
+                    what: &str,
+                    needs_dep: &Fn(&cstore::crate_metadata) -> bool) {
             let data = me.cstore.get_crate_data(krate);
-            if data.needs_allocator() {
+            if needs_dep(&data) {
                 let krate_name = data.name();
-                let data = me.cstore.get_crate_data(allocator);
-                let alloc_name = data.name();
-                me.sess.err(&format!("the allocator crate `{}` cannot depend \
-                                      on a crate that needs an allocator, but \
-                                      it depends on `{}`", alloc_name,
+                let data = me.cstore.get_crate_data(root);
+                let root_name = data.name();
+                me.sess.err(&format!("the crate `{}` cannot depend \
+                                      on a crate that needs {}, but \
+                                      it depends on `{}`", root_name, what,
                                       krate_name));
             }
 
             for (_, &dep) in data.cnum_map.borrow().iter() {
-                validate(me, dep, allocator);
+                validate(me, dep, root, what, needs_dep);
             }
         }
     }
@@ -774,6 +865,7 @@ pub fn read_crates(&mut self, dep_graph: &DepGraph) {
         self.process_crate(self.krate);
         visit::walk_crate(self, self.krate);
         self.creader.inject_allocator_crate();
+        self.creader.inject_panic_runtime(self.krate);
 
         if log_enabled!(log::INFO) {
             dump_crates(&self.cstore);
index 6a79d5df80ae23f7528a78b8d44fae6bc16c5b6b..e4a0731be559a6fe4f2bf026838f021669854ad4 100644 (file)
@@ -24,6 +24,7 @@
 use rustc::mir::repr::Mir;
 use rustc::mir::mir_map::MirMap;
 use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap};
+use rustc::session::config::PanicStrategy;
 
 use std::cell::RefCell;
 use std::rc::Rc;
@@ -306,6 +307,15 @@ fn is_allocator(&self, cnum: ast::CrateNum) -> bool
         self.get_crate_data(cnum).is_allocator()
     }
 
+    fn is_panic_runtime(&self, cnum: ast::CrateNum) -> bool
+    {
+        self.get_crate_data(cnum).is_panic_runtime()
+    }
+
+    fn panic_strategy(&self, cnum: ast::CrateNum) -> PanicStrategy {
+        self.get_crate_data(cnum).panic_strategy()
+    }
+
     fn crate_attrs(&self, cnum: ast::CrateNum) -> Vec<ast::Attribute>
     {
         decoder::get_crate_attributes(self.get_crate_data(cnum).data())
index d5a9adafe7dcad71406089649d1fa7ce61da5bb6..04b6e1c42b98a010331699f8ef8654958ab8581b 100644 (file)
@@ -23,6 +23,7 @@
 use rustc::hir::def_id::DefId;
 use rustc::hir::svh::Svh;
 use rustc::middle::cstore::{ExternCrate};
+use rustc::session::config::PanicStrategy;
 use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap};
 
 use std::cell::{RefCell, Ref, Cell};
@@ -281,6 +282,20 @@ pub fn needs_allocator(&self) -> bool {
         let attrs = decoder::get_crate_attributes(self.data());
         attr::contains_name(&attrs, "needs_allocator")
     }
+
+    pub fn is_panic_runtime(&self) -> bool {
+        let attrs = decoder::get_crate_attributes(self.data());
+        attr::contains_name(&attrs, "panic_runtime")
+    }
+
+    pub fn needs_panic_runtime(&self) -> bool {
+        let attrs = decoder::get_crate_attributes(self.data());
+        attr::contains_name(&attrs, "needs_panic_runtime")
+    }
+
+    pub fn panic_strategy(&self) -> PanicStrategy {
+        decoder::get_panic_strategy(self.data())
+    }
 }
 
 impl MetadataBlob {
index dd5a643edc1eb6a77fa7058a5ec7be4e772df179..72fbbf8051533911f0fa474f3957bf04f46f8121 100644 (file)
@@ -27,6 +27,7 @@
 use rustc::hir::map as hir_map;
 use rustc::util::nodemap::FnvHashMap;
 use rustc::hir;
+use rustc::session::config::PanicStrategy;
 
 use middle::cstore::{LOCAL_CRATE, FoundAst, InlinedItem, LinkagePreference};
 use middle::cstore::{DefLike, DlDef, DlField, DlImpl, tls};
@@ -1760,3 +1761,13 @@ pub fn def_path(cdata: Cmd, id: DefIndex) -> hir_map::DefPath {
     debug!("def_path(id={:?})", id);
     hir_map::DefPath::make(cdata.cnum, id, |parent| def_key(cdata, parent))
 }
+
+pub fn get_panic_strategy(data: &[u8]) -> PanicStrategy {
+    let crate_doc = rbml::Doc::new(data);
+    let strat_doc = reader::get_doc(crate_doc, tag_panic_strategy);
+    match reader::doc_as_u8(strat_doc) {
+        b'U' => PanicStrategy::Unwind,
+        b'A' => PanicStrategy::Abort,
+        b => panic!("unknown panic strategy in metadata: {}", b),
+    }
+}
index 7558e0774b3625c08ae2287ca4ec4ce5e2b5126c..4a0c3bbf18702f29e89d6bd5bd68482623f76d69 100644 (file)
@@ -33,7 +33,7 @@
 
 use rustc::hir::svh::Svh;
 use rustc::mir::mir_map::MirMap;
-use rustc::session::config;
+use rustc::session::config::{self, PanicStrategy};
 use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet};
 
 use rustc_serialize::Encodable;
@@ -1828,6 +1828,17 @@ fn encode_dylib_dependency_formats(rbml_w: &mut Encoder, ecx: &EncodeContext) {
     }
 }
 
+fn encode_panic_strategy(rbml_w: &mut Encoder, ecx: &EncodeContext) {
+    match ecx.tcx.sess.opts.cg.panic {
+        PanicStrategy::Unwind => {
+            rbml_w.wr_tagged_u8(tag_panic_strategy, b'U');
+        }
+        PanicStrategy::Abort => {
+            rbml_w.wr_tagged_u8(tag_panic_strategy, b'A');
+        }
+    }
+}
+
 // NB: Increment this as you change the metadata encoding version.
 #[allow(non_upper_case_globals)]
 pub const metadata_encoding_version : &'static [u8] = &[b'r', b'u', b's', b't', 0, 0, 0, 2 ];
@@ -1915,6 +1926,7 @@ struct Stats {
     encode_hash(rbml_w, &ecx.link_meta.crate_hash);
     encode_crate_disambiguator(rbml_w, &ecx.tcx.sess.crate_disambiguator.get().as_str());
     encode_dylib_dependency_formats(rbml_w, &ecx);
+    encode_panic_strategy(rbml_w, &ecx);
 
     let mut i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
     encode_attributes(rbml_w, &krate.attrs);
index dd453bf996916e2afe6324fd9d7b94e3049003a4..cbb4be5b30022b7cc9557c43d9a7b707fe4af450 100644 (file)
@@ -1829,7 +1829,9 @@ pub fn trans_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     }
 
     let _icx = push_ctxt("trans_closure");
-    attributes::emit_uwtable(llfndecl, true);
+    if !ccx.sess().no_landing_pads() {
+        attributes::emit_uwtable(llfndecl, true);
+    }
 
     debug!("trans_closure(..., {})", instance);
 
index 29bd28b6160cbc90db869ceba46007a11971765e..6d33fb311cff05d16cd87abb30b3630725cfafbb 100644 (file)
@@ -14,11 +14,14 @@ test = false
 alloc = { path = "../liballoc" }
 alloc_jemalloc = { path = "../liballoc_jemalloc", optional = true }
 alloc_system = { path = "../liballoc_system" }
+panic_unwind = { path = "../libpanic_unwind" }
+panic_abort = { path = "../libpanic_abort" }
 collections = { path = "../libcollections" }
 core = { path = "../libcore" }
 libc = { path = "../rustc/libc_shim" }
 rand = { path = "../librand" }
 rustc_unicode = { path = "../librustc_unicode" }
+unwind = { path = "../libunwind" }
 
 [build-dependencies]
 build_helper = { path = "../build_helper" }
index c32bca82bd5a0da00020956eb8f9478ddc3e0cc8..e879d440643f90d8e982d69749518f3cfb35c13c 100644 (file)
@@ -28,9 +28,7 @@ fn main() {
     }
 
     if target.contains("linux") {
-        if target.contains("musl") && (target.contains("x86_64") || target.contains("i686")) {
-            println!("cargo:rustc-link-lib=static=unwind");
-        } else if target.contains("android") {
+        if target.contains("android") {
             println!("cargo:rustc-link-lib=dl");
             println!("cargo:rustc-link-lib=log");
             println!("cargo:rustc-link-lib=gcc");
@@ -38,27 +36,13 @@ fn main() {
             println!("cargo:rustc-link-lib=dl");
             println!("cargo:rustc-link-lib=rt");
             println!("cargo:rustc-link-lib=pthread");
-            println!("cargo:rustc-link-lib=gcc_s");
         }
     } else if target.contains("freebsd") {
         println!("cargo:rustc-link-lib=execinfo");
         println!("cargo:rustc-link-lib=pthread");
-        println!("cargo:rustc-link-lib=gcc_s");
     } else if target.contains("dragonfly") || target.contains("bitrig") ||
               target.contains("netbsd") || target.contains("openbsd") {
         println!("cargo:rustc-link-lib=pthread");
-
-        if target.contains("rumprun") {
-            println!("cargo:rustc-link-lib=unwind");
-        } else if target.contains("netbsd") {
-            println!("cargo:rustc-link-lib=gcc_s");
-        } else if target.contains("openbsd") {
-            println!("cargo:rustc-link-lib=gcc");
-        } else if target.contains("bitrig") {
-            println!("cargo:rustc-link-lib=c++abi");
-        } else if target.contains("dragonfly") {
-            println!("cargo:rustc-link-lib=gcc_pic");
-        }
     } else if target.contains("apple-darwin") {
         println!("cargo:rustc-link-lib=System");
     } else if target.contains("apple-ios") {
@@ -67,9 +51,6 @@ fn main() {
         println!("cargo:rustc-link-lib=framework=Security");
         println!("cargo:rustc-link-lib=framework=Foundation");
     } else if target.contains("windows") {
-        if target.contains("windows-gnu") {
-            println!("cargo:rustc-link-lib=gcc_eh");
-        }
         println!("cargo:rustc-link-lib=advapi32");
         println!("cargo:rustc-link-lib=ws2_32");
         println!("cargo:rustc-link-lib=userenv");
index d4b40b844fce5e28d15bafcf66b1a75b3bb217d4..8f41bdf39e97a0c054f1b1645489781e908c95c8 100644 (file)
 #![feature(on_unimplemented)]
 #![feature(oom)]
 #![feature(optin_builtin_traits)]
+#![feature(panic_unwind)]
 #![feature(placement_in_syntax)]
 #![feature(rand)]
 #![feature(raw)]
 #![allow(unused_features)] // std may use features in a platform-specific way
 #![cfg_attr(not(stage0), deny(warnings))]
 
+// FIXME(stage0): after a snapshot, move needs_panic_runtime up above and remove
+//                this `extern crate` declaration and feature(panic_unwind)
+#![cfg_attr(not(stage0), needs_panic_runtime)]
+#![cfg_attr(not(stage0), feature(needs_panic_runtime))]
+#[cfg(stage0)]
+extern crate panic_unwind as __please_just_link_me_dont_reference_me;
+
 #[cfg(test)] extern crate test;
 
 // We want to reexport a few macros from core but libcore has already been
 extern crate rustc_unicode;
 extern crate libc;
 
+// We always need an unwinder currently for backtraces
+extern crate unwind;
+
 #[cfg(stage0)]
 extern crate alloc_system;
 
index 39adda1066a1194a0695bfefeba931cf0813ad09..d69789cedaf2c0e39454c999c28715c8d31b784c 100644 (file)
@@ -17,9 +17,9 @@
 /// The entry point for panic of Rust threads.
 ///
 /// This macro is used to inject panic into a Rust thread, causing the thread to
-/// unwind and panic entirely. Each thread's panic can be reaped as the
-/// `Box<Any>` type, and the single-argument form of the `panic!` macro will be
-/// the value which is transmitted.
+/// panic entirely. Each thread's panic can be reaped as the `Box<Any>` type,
+/// and the single-argument form of the `panic!` macro will be the value which
+/// is transmitted.
 ///
 /// The multi-argument form of this macro panics with a string and has the
 /// `format!` syntax for building a string.
@@ -41,14 +41,14 @@ macro_rules! panic {
         panic!("explicit panic")
     });
     ($msg:expr) => ({
-        $crate::rt::begin_unwind($msg, {
+        $crate::rt::begin_panic($msg, {
             // static requires less code at runtime, more constant data
             static _FILE_LINE: (&'static str, u32) = (file!(), line!());
             &_FILE_LINE
         })
     });
     ($fmt:expr, $($arg:tt)+) => ({
-        $crate::rt::begin_unwind_fmt(format_args!($fmt, $($arg)+), {
+        $crate::rt::begin_panic_fmt(&format_args!($fmt, $($arg)+), {
             // The leading _'s are to avoid dead code warnings if this is
             // used inside a dead function. Just `#[allow(dead_code)]` is
             // insufficient, since the user may have
index bbd89af01a73aa2bb07ff2b571f3c4a52329f154..9a195d93afde4e4df9312419945e782b532b3e98 100644 (file)
 use boxed::Box;
 use cell::UnsafeCell;
 use ops::{Deref, DerefMut};
+use panicking;
 use ptr::{Unique, Shared};
 use rc::Rc;
 use sync::{Arc, Mutex, RwLock};
-use sys_common::unwind;
 use thread::Result;
 
 #[unstable(feature = "panic_handler", issue = "30449")]
@@ -383,12 +383,9 @@ extern "rust-call" fn call_once(self, _args: ()) -> R {
 /// ```
 #[stable(feature = "catch_unwind", since = "1.9.0")]
 pub fn catch_unwind<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> {
-    let mut result = None;
     unsafe {
-        let result = &mut result;
-        unwind::try(move || *result = Some(f()))?
+        panicking::try(f)
     }
-    Ok(result.unwrap())
 }
 
 /// Deprecated, renamed to `catch_unwind`
@@ -425,7 +422,7 @@ pub fn recover<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> {
 /// ```
 #[stable(feature = "resume_unwind", since = "1.9.0")]
 pub fn resume_unwind(payload: Box<Any + Send>) -> ! {
-    unwind::rust_panic(payload)
+    panicking::rust_panic(payload)
 }
 
 /// Deprecated, use resume_unwind instead
index fd6a15b0f69a3f8bebf751eae3cfeeb643e7fbed..fd74651bf77bb3dc1e33fcb3e7f1f66068db2b89 100644 (file)
@@ -8,13 +8,25 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+//! Implementation of various bits and pieces of the `panic!` macro and
+//! associated runtime pieces.
+//!
+//! Specifically, this module contains the implementation of:
+//!
+//! * Panic hooks
+//! * Executing a panic up to doing the actual implementation
+//! * Shims around "try"
+
 use prelude::v1::*;
 use io::prelude::*;
 
 use any::Any;
 use cell::Cell;
 use cell::RefCell;
+use fmt;
 use intrinsics;
+use mem;
+use raw;
 use sync::StaticRwLock;
 use sync::atomic::{AtomicBool, Ordering};
 use sys::stdio::Stderr;
 use sys_common::util;
 use thread;
 
-thread_local! { pub static PANIC_COUNT: Cell<usize> = Cell::new(0) }
-
 thread_local! {
     pub static LOCAL_STDERR: RefCell<Option<Box<Write + Send>>> = {
         RefCell::new(None)
     }
 }
 
+thread_local! { pub static PANIC_COUNT: Cell<usize> = Cell::new(0) }
+
+// Binary interface to the panic runtime that the standard library depends on.
+//
+// The standard library is tagged with `#![needs_panic_runtime]` (introduced in
+// RFC 1513) to indicate that it requires some other crate tagged with
+// `#![panic_runtime]` to exist somewhere. Each panic runtime is intended to
+// implement these symbols (with the same signatures) so we can get matched up
+// to them.
+//
+// One day this may look a little less ad-hoc with the compiler helping out to
+// hook up these functions, but it is not this day!
+extern {
+    fn __rust_maybe_catch_panic(f: fn(*mut u8),
+                                data: *mut u8,
+                                data_ptr: *mut usize,
+                                vtable_ptr: *mut usize) -> u32;
+    #[unwind]
+    fn __rust_start_panic(data: usize, vtable: usize) -> u32;
+}
+
 #[derive(Copy, Clone)]
 enum Hook {
     Default,
@@ -57,7 +88,7 @@ enum Hook {
 /// # Panics
 ///
 /// Panics if called from a panicking thread.
-#[unstable(feature = "panic_handler", reason = "awaiting feedback", issue = "30449")]
+#[unstable(feature = "panic_handler", issue = "30449")]
 pub fn set_hook(hook: Box<Fn(&PanicInfo) + 'static + Sync + Send>) {
     if thread::panicking() {
         panic!("cannot modify the panic hook from a panicking thread");
@@ -82,7 +113,7 @@ pub fn set_hook(hook: Box<Fn(&PanicInfo) + 'static + Sync + Send>) {
 /// # Panics
 ///
 /// Panics if called from a panicking thread.
-#[unstable(feature = "panic_handler", reason = "awaiting feedback", issue = "30449")]
+#[unstable(feature = "panic_handler", issue = "30449")]
 pub fn take_hook() -> Box<Fn(&PanicInfo) + 'static + Sync + Send> {
     if thread::panicking() {
         panic!("cannot modify the panic hook from a panicking thread");
@@ -102,7 +133,7 @@ pub fn take_hook() -> Box<Fn(&PanicInfo) + 'static + Sync + Send> {
 }
 
 /// A struct providing information about a panic.
-#[unstable(feature = "panic_handler", reason = "awaiting feedback", issue = "30449")]
+#[unstable(feature = "panic_handler", issue = "30449")]
 pub struct PanicInfo<'a> {
     payload: &'a (Any + Send),
     location: Location<'a>,
@@ -112,7 +143,7 @@ impl<'a> PanicInfo<'a> {
     /// Returns the payload associated with the panic.
     ///
     /// This will commonly, but not always, be a `&'static str` or `String`.
-    #[unstable(feature = "panic_handler", reason = "awaiting feedback", issue = "30449")]
+    #[unstable(feature = "panic_handler", issue = "30449")]
     pub fn payload(&self) -> &(Any + Send) {
         self.payload
     }
@@ -122,14 +153,14 @@ pub fn payload(&self) -> &(Any + Send) {
     ///
     /// This method will currently always return `Some`, but this may change
     /// in future versions.
-    #[unstable(feature = "panic_handler", reason = "awaiting feedback", issue = "30449")]
+    #[unstable(feature = "panic_handler", issue = "30449")]
     pub fn location(&self) -> Option<&Location> {
         Some(&self.location)
     }
 }
 
 /// A struct containing information about the location of a panic.
-#[unstable(feature = "panic_handler", reason = "awaiting feedback", issue = "30449")]
+#[unstable(feature = "panic_handler", issue = "30449")]
 pub struct Location<'a> {
     file: &'a str,
     line: u32,
@@ -137,20 +168,20 @@ pub struct Location<'a> {
 
 impl<'a> Location<'a> {
     /// Returns the name of the source file from which the panic originated.
-    #[unstable(feature = "panic_handler", reason = "awaiting feedback", issue = "30449")]
+    #[unstable(feature = "panic_handler", issue = "30449")]
     pub fn file(&self) -> &str {
         self.file
     }
 
     /// Returns the line number from which the panic originated.
-    #[unstable(feature = "panic_handler", reason = "awaiting feedback", issue = "30449")]
+    #[unstable(feature = "panic_handler", issue = "30449")]
     pub fn line(&self) -> u32 {
         self.line
     }
 }
 
 fn default_hook(info: &PanicInfo) {
-    let panics = PANIC_COUNT.with(|s| s.get());
+    let panics = PANIC_COUNT.with(|c| c.get());
 
     // If this is a double panic, make sure that we print a backtrace
     // for this panic. Otherwise only print it if logging is enabled.
@@ -195,33 +226,143 @@ fn default_hook(info: &PanicInfo) {
     }
 }
 
-pub fn on_panic(obj: &(Any+Send), file: &'static str, line: u32) {
-    let panics = PANIC_COUNT.with(|s| {
-        let count = s.get() + 1;
-        s.set(count);
-        count
+/// Invoke a closure, capturing the cause of an unwinding panic if one occurs.
+pub unsafe fn try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<Any + Send>> {
+    let mut slot = None;
+    let mut f = Some(f);
+    let ret = PANIC_COUNT.with(|s| {
+        let prev = s.get();
+        s.set(0);
+
+        let mut to_run = || {
+            slot = Some(f.take().unwrap()());
+        };
+        let fnptr = get_call(&mut to_run);
+        let dataptr = &mut to_run as *mut _ as *mut u8;
+        let mut any_data = 0;
+        let mut any_vtable = 0;
+        let fnptr = mem::transmute::<fn(&mut _), fn(*mut u8)>(fnptr);
+        let r = __rust_maybe_catch_panic(fnptr,
+                                         dataptr,
+                                         &mut any_data,
+                                         &mut any_vtable);
+        s.set(prev);
+
+        if r == 0 {
+            Ok(())
+        } else {
+            Err(mem::transmute(raw::TraitObject {
+                data: any_data as *mut _,
+                vtable: any_vtable as *mut _,
+            }))
+        }
+    });
+
+    return ret.map(|()| {
+        slot.take().unwrap()
     });
 
-    // If this is the third nested call, on_panic triggered the last panic,
-    // otherwise the double-panic check would have aborted the process.
-    // Even if it is likely that on_panic was unable to log the backtrace,
-    // abort immediately to avoid infinite recursion, so that attaching a
-    // debugger provides a useable stacktrace.
-    if panics >= 3 {
+    fn get_call<F: FnMut()>(_: &mut F) -> fn(&mut F) {
+        call
+    }
+
+    fn call<F: FnMut()>(f: &mut F) {
+        f()
+    }
+}
+
+/// Determines whether the current thread is unwinding because of panic.
+pub fn panicking() -> bool {
+    PANIC_COUNT.with(|c| c.get() != 0)
+}
+
+/// Entry point of panic from the libcore crate.
+#[cfg(not(test))]
+#[lang = "panic_fmt"]
+#[unwind]
+pub extern fn rust_begin_panic(msg: fmt::Arguments,
+                               file: &'static str,
+                               line: u32) -> ! {
+    begin_panic_fmt(&msg, &(file, line))
+}
+
+/// The entry point for panicking with a formatted message.
+///
+/// This is designed to reduce the amount of code required at the call
+/// site as much as possible (so that `panic!()` has as low an impact
+/// on (e.g.) the inlining of other functions as possible), by moving
+/// the actual formatting into this shared place.
+#[unstable(feature = "libstd_sys_internals",
+           reason = "used by the panic! macro",
+           issue = "0")]
+#[inline(never)] #[cold]
+pub fn begin_panic_fmt(msg: &fmt::Arguments,
+                       file_line: &(&'static str, u32)) -> ! {
+    use fmt::Write;
+
+    // We do two allocations here, unfortunately. But (a) they're
+    // required with the current scheme, and (b) we don't handle
+    // panic + OOM properly anyway (see comment in begin_panic
+    // below).
+
+    let mut s = String::new();
+    let _ = s.write_fmt(*msg);
+    begin_panic(s, file_line)
+}
+
+/// This is the entry point of panicking for panic!() and assert!().
+#[unstable(feature = "libstd_sys_internals",
+           reason = "used by the panic! macro",
+           issue = "0")]
+#[inline(never)] #[cold] // avoid code bloat at the call sites as much as possible
+pub fn begin_panic<M: Any + Send>(msg: M, file_line: &(&'static str, u32)) -> ! {
+    // Note that this should be the only allocation performed in this code path.
+    // Currently this means that panic!() on OOM will invoke this code path,
+    // but then again we're not really ready for panic on OOM anyway. If
+    // we do start doing this, then we should propagate this allocation to
+    // be performed in the parent of this thread instead of the thread that's
+    // panicking.
+
+    rust_panic_with_hook(Box::new(msg), file_line)
+}
+
+/// Executes the primary logic for a panic, including checking for recursive
+/// panics and panic hooks.
+///
+/// This is the entry point or panics from libcore, formatted panics, and
+/// `Box<Any>` panics. Here we'll verify that we're not panicking recursively,
+/// run panic hooks, and then delegate to the actual implementation of panics.
+#[inline(never)]
+#[cold]
+fn rust_panic_with_hook(msg: Box<Any + Send>,
+                        file_line: &(&'static str, u32)) -> ! {
+    let (file, line) = *file_line;
+
+    let panics = PANIC_COUNT.with(|c| {
+        let prev = c.get();
+        c.set(prev + 1);
+        prev
+    });
+
+    // If this is the third nested call (e.g. panics == 2, this is 0-indexed),
+    // the panic hook probably triggered the last panic, otherwise the
+    // double-panic check would have aborted the process. In this case abort the
+    // process real quickly as we don't want to try calling it again as it'll
+    // probably just panic again.
+    if panics > 1 {
         util::dumb_print(format_args!("thread panicked while processing \
                                        panic. aborting.\n"));
         unsafe { intrinsics::abort() }
     }
 
-    let info = PanicInfo {
-        payload: obj,
-        location: Location {
-            file: file,
-            line: line,
-        },
-    };
-
     unsafe {
+        let info = PanicInfo {
+            payload: &*msg,
+            location: Location {
+                file: file,
+                line: line,
+            },
+        };
         let _lock = HOOK_LOCK.read();
         match HOOK {
             Hook::Default => default_hook(&info),
@@ -229,7 +370,7 @@ pub fn on_panic(obj: &(Any+Send), file: &'static str, line: u32) {
         }
     }
 
-    if panics >= 2 {
+    if panics > 0 {
         // If a thread panics while it's already unwinding then we
         // have limited options. Currently our preference is to
         // just abort. In the future we may consider resuming
@@ -238,4 +379,17 @@ pub fn on_panic(obj: &(Any+Send), file: &'static str, line: u32) {
                                        aborting.\n"));
         unsafe { intrinsics::abort() }
     }
+
+    rust_panic(msg)
+}
+
+/// A private no-mangle function on which to slap yer breakpoints.
+#[no_mangle]
+#[allow(private_no_mangle_fns)] // yes we get it, but we like breakpoints
+pub fn rust_panic(msg: Box<Any + Send>) -> ! {
+    let code = unsafe {
+        let obj = mem::transmute::<_, raw::TraitObject>(msg);
+        __rust_start_panic(obj.data as usize, obj.vtable as usize)
+    };
+    rtabort!("failed to initiate panic, error {}", code)
 }
index 83091c72c0d6bea2a2c4a0a990679effac0fd93e..6eee4ee9bbe5f66edc86d89c8fe451984025356e 100644 (file)
 
 
 // Reexport some of our utilities which are expected by other crates.
-pub use sys_common::unwind::{begin_unwind, begin_unwind_fmt};
+pub use panicking::{begin_panic, begin_panic_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(stage0)]
+pub use panicking::begin_panic as begin_unwind;
 
 #[cfg(not(test))]
 #[lang = "start"]
diff --git a/src/libstd/sys/common/dwarf/eh.rs b/src/libstd/sys/common/dwarf/eh.rs
deleted file mode 100644 (file)
index 319be24..0000000
+++ /dev/null
@@ -1,159 +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.
-
-//! Parsing of GCC-style Language-Specific Data Area (LSDA)
-//! For details see:
-//!   http://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA/ehframechpt.html
-//!   http://mentorembedded.github.io/cxx-abi/exceptions.pdf
-//!   http://www.airs.com/blog/archives/460
-//!   http://www.airs.com/blog/archives/464
-//!
-//! A reference implementation may be found in the GCC source tree
-//! (<root>/libgcc/unwind-c.c as of this writing)
-
-#![allow(non_upper_case_globals)]
-#![allow(unused)]
-
-use prelude::v1::*;
-use sys_common::dwarf::DwarfReader;
-use core::mem;
-
-pub const DW_EH_PE_omit     : u8 = 0xFF;
-pub const DW_EH_PE_absptr   : u8 = 0x00;
-
-pub const DW_EH_PE_uleb128  : u8 = 0x01;
-pub const DW_EH_PE_udata2   : u8 = 0x02;
-pub const DW_EH_PE_udata4   : u8 = 0x03;
-pub const DW_EH_PE_udata8   : u8 = 0x04;
-pub const DW_EH_PE_sleb128  : u8 = 0x09;
-pub const DW_EH_PE_sdata2   : u8 = 0x0A;
-pub const DW_EH_PE_sdata4   : u8 = 0x0B;
-pub const DW_EH_PE_sdata8   : u8 = 0x0C;
-
-pub const DW_EH_PE_pcrel    : u8 = 0x10;
-pub const DW_EH_PE_textrel  : u8 = 0x20;
-pub const DW_EH_PE_datarel  : u8 = 0x30;
-pub const DW_EH_PE_funcrel  : u8 = 0x40;
-pub const DW_EH_PE_aligned  : u8 = 0x50;
-
-pub const DW_EH_PE_indirect : u8 = 0x80;
-
-#[derive(Copy, Clone)]
-pub struct EHContext {
-    pub ip: usize,         // Current instruction pointer
-    pub func_start: usize, // Address of the current function
-    pub text_start: usize, // Address of the code section
-    pub data_start: usize, // Address of the data section
-}
-
-pub unsafe fn find_landing_pad(lsda: *const u8, context: &EHContext)
-                               -> Option<usize> {
-    if lsda.is_null() {
-        return None;
-    }
-
-    let func_start = context.func_start;
-    let mut reader = DwarfReader::new(lsda);
-
-    let start_encoding = reader.read::<u8>();
-    // base address for landing pad offsets
-    let lpad_base = if start_encoding != DW_EH_PE_omit {
-        read_encoded_pointer(&mut reader, context, start_encoding)
-    } else {
-        func_start
-    };
-
-    let ttype_encoding = reader.read::<u8>();
-    if ttype_encoding != DW_EH_PE_omit {
-        // Rust doesn't analyze exception types, so we don't care about the type table
-        reader.read_uleb128();
-    }
-
-    let call_site_encoding = reader.read::<u8>();
-    let call_site_table_length = reader.read_uleb128();
-    let action_table = reader.ptr.offset(call_site_table_length as isize);
-    // Return addresses point 1 byte past the call instruction, which could
-    // be in the next IP range.
-    let ip = context.ip-1;
-
-    while reader.ptr < action_table {
-        let cs_start = read_encoded_pointer(&mut reader, context, call_site_encoding);
-        let cs_len = read_encoded_pointer(&mut reader, context, call_site_encoding);
-        let cs_lpad = read_encoded_pointer(&mut reader, context, call_site_encoding);
-        let cs_action = reader.read_uleb128();
-        // Callsite table is sorted by cs_start, so if we've passed the ip, we
-        // may stop searching.
-        if ip < func_start + cs_start {
-            break
-        }
-        if ip < func_start + cs_start + cs_len {
-            if cs_lpad != 0 {
-                return Some(lpad_base + cs_lpad);
-            } else {
-                return None;
-            }
-        }
-    }
-    // IP range not found: gcc's C++ personality calls terminate() here,
-    // however the rest of the languages treat this the same as cs_lpad == 0.
-    // We follow this suit.
-    None
-}
-
-#[inline]
-fn round_up(unrounded: usize, align: usize) -> usize {
-    assert!(align.is_power_of_two());
-    (unrounded + align - 1) & !(align - 1)
-}
-
-unsafe fn read_encoded_pointer(reader: &mut DwarfReader,
-                               context: &EHContext,
-                               encoding: u8) -> usize {
-    assert!(encoding != DW_EH_PE_omit);
-
-    // DW_EH_PE_aligned implies it's an absolute pointer value
-    if encoding == DW_EH_PE_aligned {
-        reader.ptr = round_up(reader.ptr as usize,
-                              mem::size_of::<usize>()) as *const u8;
-        return reader.read::<usize>();
-    }
-
-    let mut result = match encoding & 0x0F {
-        DW_EH_PE_absptr => reader.read::<usize>(),
-        DW_EH_PE_uleb128 => reader.read_uleb128() as usize,
-        DW_EH_PE_udata2 => reader.read::<u16>() as usize,
-        DW_EH_PE_udata4 => reader.read::<u32>() as usize,
-        DW_EH_PE_udata8 => reader.read::<u64>() as usize,
-        DW_EH_PE_sleb128 => reader.read_sleb128() as usize,
-        DW_EH_PE_sdata2 => reader.read::<i16>() as usize,
-        DW_EH_PE_sdata4 => reader.read::<i32>() as usize,
-        DW_EH_PE_sdata8 => reader.read::<i64>() as usize,
-        _ => panic!()
-    };
-
-    result += match encoding & 0x70 {
-        DW_EH_PE_absptr => 0,
-        // relative to address of the encoded value, despite the name
-        DW_EH_PE_pcrel => reader.ptr as usize,
-        DW_EH_PE_textrel => { assert!(context.text_start != 0);
-                              context.text_start },
-        DW_EH_PE_datarel => { assert!(context.data_start != 0);
-                              context.data_start },
-        DW_EH_PE_funcrel => { assert!(context.func_start != 0);
-                              context.func_start },
-        _ => panic!()
-    };
-
-    if encoding & DW_EH_PE_indirect != 0 {
-        result = *(result as *const usize);
-    }
-
-    result
-}
diff --git a/src/libstd/sys/common/dwarf/mod.rs b/src/libstd/sys/common/dwarf/mod.rs
deleted file mode 100644 (file)
index 822826b..0000000
+++ /dev/null
@@ -1,107 +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.
-
-//! Utilities for parsing DWARF-encoded data streams.
-//! See http://www.dwarfstd.org,
-//! DWARF-4 standard, Section 7 - "Data Representation"
-
-// This module is used only by x86_64-pc-windows-gnu for now, but we
-// are compiling it everywhere to avoid regressions.
-#![allow(unused)]
-
-pub mod eh;
-
-use prelude::v1::*;
-use core::mem;
-
-pub struct DwarfReader {
-    pub ptr : *const u8
-}
-
-#[repr(C,packed)]
-struct Unaligned<T>(T);
-
-impl DwarfReader {
-
-    pub fn new(ptr : *const u8) -> DwarfReader {
-        DwarfReader {
-            ptr : ptr
-        }
-    }
-
-    // DWARF streams are packed, so e.g. a u32 would not necessarily be aligned
-    // on a 4-byte boundary. This may cause problems on platforms with strict
-    // alignment requirements. By wrapping data in a "packed" struct, we are
-    // telling the backend to generate "misalignment-safe" code.
-    pub unsafe fn read<T:Copy>(&mut self) -> T {
-        let Unaligned(result) = *(self.ptr as *const Unaligned<T>);
-        self.ptr = self.ptr.offset(mem::size_of::<T>() as isize);
-        result
-    }
-
-    // ULEB128 and SLEB128 encodings are defined in Section 7.6 - "Variable
-    // Length Data".
-    pub unsafe fn read_uleb128(&mut self) -> u64 {
-        let mut shift : usize = 0;
-        let mut result : u64 = 0;
-        let mut byte : u8;
-        loop {
-            byte = self.read::<u8>();
-            result |= ((byte & 0x7F) as u64) << shift;
-            shift += 7;
-            if byte & 0x80 == 0 {
-                break;
-            }
-        }
-        result
-    }
-
-    pub unsafe fn read_sleb128(&mut self) -> i64 {
-        let mut shift : usize = 0;
-        let mut result : u64 = 0;
-        let mut byte : u8;
-        loop {
-            byte = self.read::<u8>();
-            result |= ((byte & 0x7F) as u64) << shift;
-            shift += 7;
-            if byte & 0x80 == 0 {
-                break;
-            }
-        }
-        // sign-extend
-        if shift < 8 * mem::size_of::<u64>() && (byte & 0x40) != 0 {
-            result |= (!0 as u64) << shift;
-        }
-        result as i64
-    }
-}
-
-#[test]
-fn dwarf_reader() {
-    let encoded: &[u8] = &[1,
-                           2, 3,
-                           4, 5, 6, 7,
-                           0xE5, 0x8E, 0x26,
-                           0x9B, 0xF1, 0x59,
-                           0xFF, 0xFF];
-
-    let mut reader = DwarfReader::new(encoded.as_ptr());
-
-    unsafe {
-        assert!(reader.read::<u8>() == u8::to_be(1u8));
-        assert!(reader.read::<u16>() == u16::to_be(0x0203));
-        assert!(reader.read::<u32>() == u32::to_be(0x04050607));
-
-        assert!(reader.read_uleb128() == 624485);
-        assert!(reader.read_sleb128() == -624485);
-
-        assert!(reader.read::<i8>() == i8::to_be(-1));
-    }
-}
diff --git a/src/libstd/sys/common/libunwind.rs b/src/libstd/sys/common/libunwind.rs
deleted file mode 100644 (file)
index c1e9782..0000000
+++ /dev/null
@@ -1,158 +0,0 @@
-// Copyright 2014-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.
-
-//! Unwind library interface
-
-#![allow(non_upper_case_globals)]
-#![allow(non_camel_case_types)]
-#![allow(non_snake_case)]
-#![allow(dead_code)] // these are just bindings
-
-#[cfg(any(not(target_arch = "arm"), target_os = "ios"))]
-pub use self::_Unwind_Action::*;
-#[cfg(target_arch = "arm")]
-pub use self::_Unwind_State::*;
-pub use self::_Unwind_Reason_Code::*;
-
-use libc;
-
-#[cfg(any(not(target_arch = "arm"), target_os = "ios"))]
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub enum _Unwind_Action {
-    _UA_SEARCH_PHASE = 1,
-    _UA_CLEANUP_PHASE = 2,
-    _UA_HANDLER_FRAME = 4,
-    _UA_FORCE_UNWIND = 8,
-    _UA_END_OF_STACK = 16,
-}
-
-#[cfg(target_arch = "arm")]
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub enum _Unwind_State {
-    _US_VIRTUAL_UNWIND_FRAME = 0,
-    _US_UNWIND_FRAME_STARTING = 1,
-    _US_UNWIND_FRAME_RESUME = 2,
-    _US_ACTION_MASK = 3,
-    _US_FORCE_UNWIND = 8,
-    _US_END_OF_STACK = 16
-}
-
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub enum _Unwind_Reason_Code {
-    _URC_NO_REASON = 0,
-    _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
-    _URC_FATAL_PHASE2_ERROR = 2,
-    _URC_FATAL_PHASE1_ERROR = 3,
-    _URC_NORMAL_STOP = 4,
-    _URC_END_OF_STACK = 5,
-    _URC_HANDLER_FOUND = 6,
-    _URC_INSTALL_CONTEXT = 7,
-    _URC_CONTINUE_UNWIND = 8,
-    _URC_FAILURE = 9, // used only by ARM EABI
-}
-
-pub type _Unwind_Exception_Class = u64;
-
-pub type _Unwind_Word = libc::uintptr_t;
-
-#[cfg(target_arch = "x86")]
-pub const unwinder_private_data_size: usize = 5;
-
-#[cfg(target_arch = "x86_64")]
-pub const unwinder_private_data_size: usize = 6;
-
-#[cfg(all(target_arch = "arm", not(target_os = "ios")))]
-pub const unwinder_private_data_size: usize = 20;
-
-#[cfg(all(target_arch = "arm", target_os = "ios"))]
-pub const unwinder_private_data_size: usize = 5;
-
-#[cfg(target_arch = "aarch64")]
-pub const unwinder_private_data_size: usize = 2;
-
-#[cfg(target_arch = "mips")]
-pub const unwinder_private_data_size: usize = 2;
-
-#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
-pub const unwinder_private_data_size: usize = 2;
-
-#[cfg(target_arch = "asmjs")]
-// FIXME: Copied from arm. Need to confirm.
-pub const unwinder_private_data_size: usize = 20;
-
-#[repr(C)]
-pub struct _Unwind_Exception {
-    pub exception_class: _Unwind_Exception_Class,
-    pub exception_cleanup: _Unwind_Exception_Cleanup_Fn,
-    pub private: [_Unwind_Word; unwinder_private_data_size],
-}
-
-pub enum _Unwind_Context {}
-
-pub type _Unwind_Exception_Cleanup_Fn =
-        extern "C" fn(unwind_code: _Unwind_Reason_Code,
-                      exception: *mut _Unwind_Exception);
-
-#[cfg_attr(any(all(target_os = "linux", not(target_env = "musl")),
-               target_os = "freebsd",
-               target_os = "solaris",
-               all(target_os = "linux",
-                   target_env = "musl",
-                   not(target_arch = "x86"),
-                   not(target_arch = "x86_64"))),
-           link(name = "gcc_s"))]
-#[cfg_attr(all(target_os = "linux",
-               target_env = "musl",
-               any(target_arch = "x86", target_arch = "x86_64"),
-               not(test)),
-           link(name = "unwind", kind = "static"))]
-#[cfg_attr(any(target_os = "android", target_os = "openbsd"),
-           link(name = "gcc"))]
-#[cfg_attr(all(target_os = "netbsd", not(target_vendor = "rumprun")),
-           link(name = "gcc"))]
-#[cfg_attr(all(target_os = "netbsd", target_vendor = "rumprun"),
-           link(name = "unwind"))]
-#[cfg_attr(target_os = "dragonfly",
-           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" {
-    // iOS on armv7 uses SjLj exceptions and requires to link
-    // against corresponding routine (..._SjLj_...)
-    #[cfg(not(all(target_os = "ios", target_arch = "arm")))]
-    #[unwind]
-    pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception)
-                                  -> _Unwind_Reason_Code;
-
-    #[cfg(all(target_os = "ios", target_arch = "arm"))]
-    #[unwind]
-    fn _Unwind_SjLj_RaiseException(e: *mut _Unwind_Exception)
-                                   -> _Unwind_Reason_Code;
-
-    pub fn _Unwind_DeleteException(exception: *mut _Unwind_Exception);
-
-    #[unwind]
-    pub fn _Unwind_Resume(exception: *mut _Unwind_Exception) -> !;
-}
-
-// ... and now we just providing access to SjLj counterspart
-// through a standard name to hide those details from others
-// (see also comment above regarding _Unwind_RaiseException)
-#[cfg(all(target_os = "ios", target_arch = "arm"))]
-#[inline(always)]
-pub unsafe fn _Unwind_RaiseException(exc: *mut _Unwind_Exception)
-                                     -> _Unwind_Reason_Code {
-    _Unwind_SjLj_RaiseException(exc)
-}
index 56628a4c7545e8f26af27b71562d9a322d180d33..c9279883ae59d8e2bb32c2a0d32bfee6c73b9800 100644 (file)
@@ -30,9 +30,7 @@ macro_rules! rtassert {
 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;
@@ -41,7 +39,6 @@ macro_rules! rtassert {
 pub mod thread;
 pub mod thread_info;
 pub mod thread_local;
-pub mod unwind;
 pub mod util;
 pub mod wtf8;
 
diff --git a/src/libstd/sys/common/unwind/gcc.rs b/src/libstd/sys/common/unwind/gcc.rs
deleted file mode 100644 (file)
index da7a340..0000000
+++ /dev/null
@@ -1,280 +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.
-
-#![allow(private_no_mangle_fns)]
-
-use prelude::v1::*;
-
-use any::Any;
-use sys_common::libunwind as uw;
-
-struct 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 {
-            exception_class: rust_exception_class(),
-            exception_cleanup: exception_cleanup,
-            private: [0; uw::unwinder_private_data_size],
-        },
-        cause: Some(data),
-    };
-    let exception_param = Box::into_raw(exception) as *mut uw::_Unwind_Exception;
-    let error = uw::_Unwind_RaiseException(exception_param);
-    rtabort!("Could not unwind stack, error = {}", error as isize);
-
-    extern fn exception_cleanup(_unwind_code: uw::_Unwind_Reason_Code,
-                                exception: *mut uw::_Unwind_Exception) {
-        unsafe {
-            let _: Box<Exception> = Box::from_raw(exception as *mut Exception);
-        }
-    }
-}
-
-pub fn payload() -> *mut u8 {
-    0 as *mut u8
-}
-
-pub unsafe fn cleanup(ptr: *mut u8) -> Box<Any + Send + 'static> {
-    let my_ep = ptr as *mut Exception;
-    let cause = (*my_ep).cause.take();
-    uw::_Unwind_DeleteException(ptr as *mut _);
-    cause.unwrap()
-}
-
-// Rust's exception class identifier.  This is used by personality routines to
-// determine whether the exception was thrown by their own runtime.
-fn rust_exception_class() -> uw::_Unwind_Exception_Class {
-    // M O Z \0  R U S T -- vendor, language
-    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)))]
-pub mod eabi {
-    use sys_common::libunwind as uw;
-    use libc::c_int;
-
-    extern {
-        fn __gcc_personality_v0(version: c_int,
-                                actions: uw::_Unwind_Action,
-                                exception_class: uw::_Unwind_Exception_Class,
-                                ue_header: *mut uw::_Unwind_Exception,
-                                context: *mut uw::_Unwind_Context)
-            -> uw::_Unwind_Reason_Code;
-    }
-
-    #[lang = "eh_personality"]
-    #[no_mangle]
-    extern fn rust_eh_personality(
-        version: c_int,
-        actions: uw::_Unwind_Action,
-        exception_class: uw::_Unwind_Exception_Class,
-        ue_header: *mut uw::_Unwind_Exception,
-        context: *mut uw::_Unwind_Context
-    ) -> uw::_Unwind_Reason_Code
-    {
-        unsafe {
-            __gcc_personality_v0(version, actions, exception_class, ue_header,
-                                 context)
-        }
-    }
-
-    #[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,
-        ue_header: *mut uw::_Unwind_Exception,
-        context: *mut uw::_Unwind_Context
-    ) -> uw::_Unwind_Reason_Code
-    {
-
-        if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 { // search phase
-            uw::_URC_HANDLER_FOUND // catch!
-        }
-        else { // cleanup phase
-            unsafe {
-                __gcc_personality_v0(version, actions, exception_class, ue_header,
-                                     context)
-            }
-        }
-    }
-}
-
-// iOS on armv7 is using SjLj exceptions and therefore requires to use
-// a specialized personality routine: __gcc_personality_sj0
-
-#[cfg(all(target_os = "ios", target_arch = "arm", not(test)))]
-pub mod eabi {
-    use sys_common::libunwind as uw;
-    use libc::c_int;
-
-    extern {
-        fn __gcc_personality_sj0(version: c_int,
-                                actions: uw::_Unwind_Action,
-                                exception_class: uw::_Unwind_Exception_Class,
-                                ue_header: *mut uw::_Unwind_Exception,
-                                context: *mut uw::_Unwind_Context)
-            -> uw::_Unwind_Reason_Code;
-    }
-
-    #[lang = "eh_personality"]
-    #[no_mangle]
-    pub extern fn rust_eh_personality(
-        version: c_int,
-        actions: uw::_Unwind_Action,
-        exception_class: uw::_Unwind_Exception_Class,
-        ue_header: *mut uw::_Unwind_Exception,
-        context: *mut uw::_Unwind_Context
-    ) -> uw::_Unwind_Reason_Code
-    {
-        unsafe {
-            __gcc_personality_sj0(version, actions, exception_class, ue_header,
-                                  context)
-        }
-    }
-
-    #[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,
-        ue_header: *mut uw::_Unwind_Exception,
-        context: *mut uw::_Unwind_Context
-    ) -> uw::_Unwind_Reason_Code
-    {
-        if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 { // search phase
-            uw::_URC_HANDLER_FOUND // catch!
-        }
-        else { // cleanup phase
-            unsafe {
-                __gcc_personality_sj0(version, actions, exception_class, ue_header,
-                                      context)
-            }
-        }
-    }
-}
-
-
-// ARM EHABI uses a slightly different personality routine signature,
-// 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 libc::c_int;
-
-    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]
-    extern fn rust_eh_personality(
-        state: uw::_Unwind_State,
-        ue_header: *mut uw::_Unwind_Exception,
-        context: *mut uw::_Unwind_Context
-    ) -> uw::_Unwind_Reason_Code
-    {
-        unsafe {
-            __gcc_personality_v0(state, ue_header, context)
-        }
-    }
-
-    #[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
-    ) -> uw::_Unwind_Reason_Code
-    {
-        // Backtraces on ARM will call the personality routine with
-        // state == _US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND. In those cases
-        // we want to continue unwinding the stack, otherwise all our backtraces
-        // would end at __rust_try.
-        if (state as c_int & uw::_US_ACTION_MASK as c_int)
-                           == uw::_US_VIRTUAL_UNWIND_FRAME as c_int
-               && (state as c_int & uw::_US_FORCE_UNWIND as c_int) == 0 { // search phase
-            uw::_URC_HANDLER_FOUND // catch!
-        }
-        else { // cleanup phase
-            unsafe {
-                __gcc_personality_v0(state, ue_header, context)
-            }
-        }
-    }
-}
-
-// 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")]
-    #[cfg(not(cargobuild))]
-    extern {}
-
-    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);
-    }
-}
diff --git a/src/libstd/sys/common/unwind/mod.rs b/src/libstd/sys/common/unwind/mod.rs
deleted file mode 100644 (file)
index 527c2e6..0000000
+++ /dev/null
@@ -1,241 +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.
-
-//! Implementation of Rust stack unwinding
-//!
-//! 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
-//!
-//! ## 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)]
-
-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;
-
-/// Invoke a closure, capturing the cause of panic if one occurs.
-///
-/// This function will return `Ok(())` if the closure did not panic, and will
-/// return `Err(cause)` if the closure panics. The `cause` returned is the
-/// object with which panic was originally invoked.
-///
-/// This function also is unsafe for a variety of reasons:
-///
-/// * This is not safe to call in a nested fashion. The unwinding
-///   interface for Rust is designed to have at most one try/catch block per
-///   thread, not multiple. No runtime checking is currently performed to uphold
-///   this invariant, so this function is not safe. A nested try/catch block
-///   may result in corruption of the outer try/catch block's state, especially
-///   if this is used within a thread itself.
-///
-/// * It is not sound to trigger unwinding while already unwinding. Rust threads
-///   have runtime checks in place to ensure this invariant, but it is not
-///   guaranteed that a rust thread is in place when invoking this function.
-///   Unwinding twice can lead to resource leaks where some destructors are not
-///   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 u8);
-
-    fn try_fn<F: FnOnce()>(opt_closure: *mut u8) {
-        let opt_closure = opt_closure as *mut Option<F>;
-        unsafe { (*opt_closure).take().unwrap()(); }
-    }
-}
-
-unsafe fn inner_try(f: fn(*mut u8), data: *mut u8)
-                    -> Result<(), Box<Any + Send>> {
-    PANIC_COUNT.with(|s| {
-        let prev = s.get();
-        s.set(0);
-
-        // The "payload" here is a platform-specific region of memory which is
-        // used to transmit information about the exception being thrown from
-        // 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.
-        //
-        // 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 r = intrinsics::try(f, data, &mut payload as *mut _ as *mut _);
-        s.set(prev);
-        if r == 0 {
-            Ok(())
-        } else {
-            Err(imp::cleanup(payload))
-        }
-    })
-}
-
-/// Determines whether the current thread is unwinding because of panic.
-pub fn panicking() -> bool {
-    PANIC_COUNT.with(|s| s.get() != 0)
-}
-
-// An uninlined, unmangled function upon which to slap yer breakpoints
-#[inline(never)]
-#[no_mangle]
-#[allow(private_no_mangle_fns)]
-pub fn rust_panic(cause: Box<Any + Send + 'static>) -> ! {
-    unsafe {
-        imp::panic(cause)
-    }
-}
-
-#[cfg(not(test))]
-/// Entry point of panic from the libcore crate.
-#[lang = "panic_fmt"]
-#[unwind]
-pub extern fn rust_begin_unwind(msg: fmt::Arguments,
-                                file: &'static str, line: u32) -> ! {
-    begin_unwind_fmt(msg, &(file, line))
-}
-
-/// The entry point for unwinding with a formatted message.
-///
-/// This is designed to reduce the amount of code required at the call
-/// site as much as possible (so that `panic!()` has as low an impact
-/// on (e.g.) the inlining of other functions as possible), by moving
-/// the actual formatting into this shared place.
-#[unstable(feature = "libstd_sys_internals",
-           reason = "used by the panic! macro",
-           issue = "0")]
-#[inline(never)] #[cold]
-pub fn begin_unwind_fmt(msg: fmt::Arguments, file_line: &(&'static str, u32)) -> ! {
-    use fmt::Write;
-
-    // We do two allocations here, unfortunately. But (a) they're
-    // required with the current scheme, and (b) we don't handle
-    // panic + OOM properly anyway (see comment in begin_unwind
-    // below).
-
-    let mut s = String::new();
-    let _ = s.write_fmt(msg);
-    begin_unwind_inner(Box::new(s), file_line)
-}
-
-/// This is the entry point of unwinding for panic!() and assert!().
-#[unstable(feature = "libstd_sys_internals",
-           reason = "used by the panic! macro",
-           issue = "0")]
-#[inline(never)] #[cold] // avoid code bloat at the call sites as much as possible
-pub fn begin_unwind<M: Any + Send>(msg: M, file_line: &(&'static str, u32)) -> ! {
-    // Note that this should be the only allocation performed in this code path.
-    // Currently this means that panic!() on OOM will invoke this code path,
-    // but then again we're not really ready for panic on OOM anyway. If
-    // we do start doing this, then we should propagate this allocation to
-    // be performed in the parent of this thread instead of the thread that's
-    // panicking.
-
-    // see below for why we do the `Any` coercion here.
-    begin_unwind_inner(Box::new(msg), file_line)
-}
-
-/// The core of the unwinding.
-///
-/// This is non-generic to avoid instantiation bloat in other crates
-/// (which makes compilation of small crates noticeably slower). (Note:
-/// we need the `Any` object anyway, we're not just creating it to
-/// avoid being generic.)
-///
-/// Doing this split took the LLVM IR line counts of `fn main() { panic!()
-/// }` from ~1900/3700 (-O/no opts) to 180/590.
-#[inline(never)] #[cold] // this is the slow path, please never inline this
-fn begin_unwind_inner(msg: Box<Any + Send>,
-                      file_line: &(&'static str, u32)) -> ! {
-    let (file, line) = *file_line;
-
-    // First, invoke the default panic handler.
-    panicking::on_panic(&*msg, file, line);
-
-    // Finally, perform the unwinding.
-    rust_panic(msg);
-}
diff --git a/src/libstd/sys/common/unwind/seh.rs b/src/libstd/sys/common/unwind/seh.rs
deleted file mode 100644 (file)
index 94da42f..0000000
+++ /dev/null
@@ -1,153 +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.
-
-//! Windows SEH
-//!
-//! On Windows (currently only on MSVC), the default exception handling
-//! mechanism is Structured Exception Handling (SEH). This is quite different
-//! than Dwarf-based exception handling (e.g. what other unix platforms use) in
-//! terms of compiler internals, so LLVM is required to have a good deal of
-//! extra support for SEH.
-//!
-//! In a nutshell, what happens here is:
-//!
-//! 1. The `panic` function calls the standard Windows function `RaiseException`
-//!    with a Rust-specific code, triggering the unwinding process.
-//! 2. All landing pads generated by the compiler use the personality function
-//!    `__C_specific_handler` on 64-bit and `__except_handler3` on 32-bit,
-//!    functions in the CRT, and the unwinding code in Windows will use this
-//!    personality function to execute all cleanup code on the stack.
-//! 3. All compiler-generated calls to `invoke` have a landing pad set as a
-//!    `cleanuppad` LLVM instruction, which indicates the start of the cleanup
-//!    routine. The personality (in step 2, defined in the CRT) is responsible
-//!    for running the cleanup routines.
-//! 4. Eventually the "catch" code in the `try` intrinsic (generated by the
-//!    compiler) is executed, which will ensure that the exception being caught
-//!    is indeed a Rust exception, indicating that control should come back to
-//!    Rust. This is done via a `catchswitch` plus a `catchpad` instruction in
-//!    LLVM IR terms, finally returning normal control to the program with a
-//!    `catchret` instruction. The `try` intrinsic uses a filter function to
-//!    detect what kind of exception is being thrown, and this detection is
-//!    implemented as the msvc_try_filter language item below.
-//!
-//! Some specific differences from the gcc-based exception handling are:
-//!
-//! * Rust has no custom personality function, it is instead *always*
-//!   __C_specific_handler or __except_handler3, so the filtering is done in a
-//!   C++-like manner instead of in the personality function itself. Note that
-//!   the precise codegen for this was lifted from an LLVM test case for SEH
-//!   (this is the `__rust_try_filter` function below).
-//! * We've got some data to transmit across the unwinding boundary,
-//!   specifically a `Box<Any + Send + 'static>`. Like with Dwarf exceptions
-//!   these two pointers are stored as a payload in the exception itself. On
-//!   MSVC, however, there's no need for an extra allocation because the call
-//!   stack is preserved while filter functions are being executed. This means
-//!   that the pointers are passed directly to `RaiseException` which are then
-//!   recovered in the filter function to be written to the stack frame of the
-//!   `try` intrinsic.
-//!
-//! [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::*;
-
-mod imp {
-    use prelude::v1::*;
-
-    use any::Any;
-    use mem;
-    use raw;
-    use super::RUST_PANIC;
-    use sys::c;
-
-    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
-        // `RaiseException`.
-        //
-        // The two pointers of the `data` trait object are written to the stack,
-        // passed to `RaiseException`, and they're later extracted by the filter
-        // function below in the "custom exception information" section of the
-        // `EXCEPTION_RECORD` type.
-        let ptrs = mem::transmute::<_, raw::TraitObject>(data);
-        let ptrs = [ptrs.data, ptrs.vtable];
-        c::RaiseException(RUST_PANIC, 0, 2, ptrs.as_ptr() as *mut _);
-        rtabort!("could not unwind stack");
-    }
-
-    pub fn payload() -> [usize; 2] {
-        [0; 2]
-    }
-
-    pub unsafe fn cleanup(payload: [usize; 2]) -> Box<Any + Send + 'static> {
-        mem::transmute(raw::TraitObject {
-            data: payload[0] as *mut _,
-            vtable: payload[1] as *mut _,
-        })
-    }
-
-    // This is quite a special function, and it's not literally passed in as the
-    // filter function for the `catchpad` of the `try` intrinsic. The compiler
-    // actually generates its own filter function wrapper which will delegate to
-    // this for the actual execution logic for whether the exception should be
-    // caught. The reasons for this are:
-    //
-    // * Each architecture has a slightly different ABI for the filter function
-    //   here. For example on x86 there are no arguments but on x86_64 there are
-    //   two.
-    // * This function needs access to the stack frame of the `try` intrinsic
-    //   which is using this filter as a catch pad. This is because the payload
-    //   of this exception, `Box<Any>`, needs to be transmitted to that
-    //   location.
-    //
-    // Both of these differences end up using a ton of weird llvm-specific
-    // intrinsics, so it's actually pretty difficult to express the entire
-    // filter function in Rust itself. As a compromise, the compiler takes care
-    // of all the weird LLVM-specific and platform-specific stuff, getting to
-    // the point where this function makes the actual decision about what to
-    // catch given two parameters.
-    //
-    // The first parameter is `*mut EXCEPTION_POINTERS` which is some contextual
-    // information about the exception being filtered, and the second pointer is
-    // `*mut *mut [usize; 2]` (the payload here). This value points directly
-    // into the stack frame of the `try` intrinsic itself, and we use it to copy
-    // information from the exception onto the stack.
-    #[lang = "msvc_try_filter"]
-    #[cfg(not(test))]
-    unsafe extern fn __rust_try_filter(eh_ptrs: *mut u8,
-                                       payload: *mut u8) -> i32 {
-        let eh_ptrs = eh_ptrs as *mut c::EXCEPTION_POINTERS;
-        let payload = payload as *mut *mut [usize; 2];
-        let record = &*(*eh_ptrs).ExceptionRecord;
-        if record.ExceptionCode != RUST_PANIC {
-            return 0
-        }
-        (**payload)[0] = record.ExceptionInformation[0] as usize;
-        (**payload)[1] = record.ExceptionInformation[1] as usize;
-        return 1
-    }
-}
-
-// This is required by the compiler to exist (e.g. it's a lang item), but
-// it's never actually called by the compiler because __C_specific_handler
-// or _except_handler3 is the personality function that is always used.
-// Hence this is just an aborting stub.
-#[lang = "eh_personality"]
-#[cfg(not(test))]
-fn rust_eh_personality() {
-    unsafe { ::intrinsics::abort() }
-}
diff --git a/src/libstd/sys/common/unwind/seh64_gnu.rs b/src/libstd/sys/common/unwind/seh64_gnu.rs
deleted file mode 100644 (file)
index 57281d6..0000000
+++ /dev/null
@@ -1,145 +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.
-
-//! Unwinding implementation of top of native Win64 SEH,
-//! however the unwind handler data (aka LSDA) uses GCC-compatible encoding.
-
-#![allow(bad_style)]
-#![allow(private_no_mangle_fns)]
-
-use prelude::v1::*;
-
-use any::Any;
-use sys_common::dwarf::eh;
-use core::mem;
-use core::ptr;
-use sys::c;
-
-// Define our exception codes:
-// according to http://msdn.microsoft.com/en-us/library/het71c37(v=VS.80).aspx,
-//    [31:30] = 3 (error), 2 (warning), 1 (info), 0 (success)
-//    [29]    = 1 (user-defined)
-//    [28]    = 0 (reserved)
-// we define bits:
-//    [24:27] = type
-//    [0:23]  = magic
-const ETYPE: c::DWORD = 0b1110_u32 << 28;
-const MAGIC: c::DWORD = 0x525354; // "RST"
-
-const RUST_PANIC: c::DWORD  = ETYPE | (1 << 24) | MAGIC;
-
-#[repr(C)]
-struct PanicData {
-    data: Box<Any + Send + 'static>
-}
-
-pub unsafe fn panic(data: Box<Any + Send + 'static>) -> ! {
-    let panic_ctx = Box::new(PanicData { data: data });
-    let params = [Box::into_raw(panic_ctx) as c::ULONG_PTR];
-    c::RaiseException(RUST_PANIC,
-                      c::EXCEPTION_NONCONTINUABLE,
-                      params.len() as c::DWORD,
-                      &params as *const c::ULONG_PTR);
-    rtabort!("could not unwind stack");
-}
-
-pub fn payload() -> *mut u8 {
-    0 as *mut u8
-}
-
-pub unsafe fn cleanup(ptr: *mut u8) -> Box<Any + Send + 'static> {
-    let panic_ctx = Box::from_raw(ptr as *mut PanicData);
-    return panic_ctx.data;
-}
-
-// SEH doesn't support resuming unwinds after calling a landing pad like
-// libunwind does. For this reason, MSVC compiler outlines landing pads into
-// separate functions that can be called directly from the personality function
-// but are nevertheless able to find and modify stack frame of the "parent"
-// function.
-//
-// Since this cannot be done with libdwarf-style landing pads,
-// rust_eh_personality instead catches RUST_PANICs, runs the landing pad, then
-// reraises the exception.
-//
-// Note that it makes certain assumptions about the exception:
-//
-// 1. That RUST_PANIC is non-continuable, so no lower stack frame may choose to
-//    resume execution.
-// 2. That the first parameter of the exception is a pointer to an extra data
-//    area (PanicData).
-// Since these assumptions do not generally hold true for foreign exceptions
-// (system faults, C++ exceptions, etc), we make no attempt to invoke our
-// landing pads (and, thus, destructors!) for anything other than RUST_PANICs.
-// This is considered acceptable, because the behavior of throwing exceptions
-// through a C ABI boundary is undefined.
-
-#[lang = "eh_personality_catch"]
-#[cfg(not(test))]
-unsafe extern fn rust_eh_personality_catch(
-    exceptionRecord: *mut c::EXCEPTION_RECORD,
-    establisherFrame: c::LPVOID,
-    contextRecord: *mut c::CONTEXT,
-    dispatcherContext: *mut c::DISPATCHER_CONTEXT
-) -> c::EXCEPTION_DISPOSITION
-{
-    rust_eh_personality(exceptionRecord, establisherFrame,
-                        contextRecord, dispatcherContext)
-}
-
-#[lang = "eh_personality"]
-#[cfg(not(test))]
-unsafe extern fn rust_eh_personality(
-    exceptionRecord: *mut c::EXCEPTION_RECORD,
-    establisherFrame: c::LPVOID,
-    contextRecord: *mut c::CONTEXT,
-    dispatcherContext: *mut c::DISPATCHER_CONTEXT
-) -> c::EXCEPTION_DISPOSITION
-{
-    let er = &*exceptionRecord;
-    let dc = &*dispatcherContext;
-
-    if er.ExceptionFlags & c::EXCEPTION_UNWIND == 0 { // we are in the dispatch phase
-        if er.ExceptionCode == RUST_PANIC {
-            if let Some(lpad) = find_landing_pad(dc) {
-                c::RtlUnwindEx(establisherFrame,
-                               lpad as c::LPVOID,
-                               exceptionRecord,
-                               er.ExceptionInformation[0] as c::LPVOID, // pointer to PanicData
-                               contextRecord,
-                               dc.HistoryTable);
-                rtabort!("could not unwind");
-            }
-        }
-    }
-    c::ExceptionContinueSearch
-}
-
-#[cfg(not(test))]
-#[lang = "eh_unwind_resume"]
-#[unwind]
-unsafe extern fn rust_eh_unwind_resume(panic_ctx: c::LPVOID) -> ! {
-    let params = [panic_ctx as c::ULONG_PTR];
-    c::RaiseException(RUST_PANIC,
-                      c::EXCEPTION_NONCONTINUABLE,
-                      params.len() as c::DWORD,
-                      &params as *const c::ULONG_PTR);
-    rtabort!("could not resume unwind");
-}
-
-unsafe fn find_landing_pad(dc: &c::DISPATCHER_CONTEXT) -> Option<usize> {
-    let eh_ctx = eh::EHContext {
-        ip: dc.ControlPc as usize,
-        func_start: dc.ImageBase as usize + (*dc.FunctionEntry).BeginAddress as usize,
-        text_start: dc.ImageBase as usize,
-        data_start: 0
-    };
-    eh::find_landing_pad(dc.HandlerData, &eh_ctx)
-}
index 8d88091716676ee49c538d4a0a1f336df94ec8a2..5f7ad6918cdd26830366c5605a6c0cb4a6b5c7a8 100644 (file)
@@ -15,6 +15,7 @@
 use sync::StaticMutex;
 
 use super::super::printing::print;
+use unwind as uw;
 
 #[inline(never)] // if we know this is a function call, we can skip it when
                  // tracing
@@ -102,126 +103,3 @@ struct Context<'a> {
         uw::_URC_NO_REASON
     }
 }
-
-/// Unwind library interface used for backtraces
-///
-/// Note that dead code is allowed as here are just bindings
-/// iOS doesn't use all of them it but adding more
-/// platform-specific configs pollutes the code too much
-#[allow(non_camel_case_types)]
-#[allow(non_snake_case)]
-mod uw {
-    pub use self::_Unwind_Reason_Code::*;
-
-    use libc;
-
-    #[repr(C)]
-    pub enum _Unwind_Reason_Code {
-        _URC_NO_REASON = 0,
-        _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
-        _URC_FATAL_PHASE2_ERROR = 2,
-        _URC_FATAL_PHASE1_ERROR = 3,
-        _URC_NORMAL_STOP = 4,
-        _URC_END_OF_STACK = 5,
-        _URC_HANDLER_FOUND = 6,
-        _URC_INSTALL_CONTEXT = 7,
-        _URC_CONTINUE_UNWIND = 8,
-        _URC_FAILURE = 9, // used only by ARM EABI
-    }
-
-    pub enum _Unwind_Context {}
-
-    pub type _Unwind_Trace_Fn =
-            extern fn(ctx: *mut _Unwind_Context,
-                      arg: *mut libc::c_void) -> _Unwind_Reason_Code;
-
-    extern {
-        // No native _Unwind_Backtrace on iOS
-        #[cfg(not(all(target_os = "ios", target_arch = "arm")))]
-        pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn,
-                                 trace_argument: *mut libc::c_void)
-                    -> _Unwind_Reason_Code;
-
-        // available since GCC 4.2.0, should be fine for our purpose
-        #[cfg(all(not(all(target_os = "android", target_arch = "arm")),
-                  not(all(target_os = "linux", target_arch = "arm"))))]
-        pub fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context,
-                                 ip_before_insn: *mut libc::c_int)
-                    -> libc::uintptr_t;
-
-        #[cfg(all(not(target_os = "android"),
-                  not(all(target_os = "linux", target_arch = "arm"))))]
-        pub fn _Unwind_FindEnclosingFunction(pc: *mut libc::c_void)
-            -> *mut libc::c_void;
-    }
-
-    // On android, the function _Unwind_GetIP is a macro, and this is the
-    // expansion of the macro. This is all copy/pasted directly from the
-    // header file with the definition of _Unwind_GetIP.
-    #[cfg(any(all(target_os = "android", target_arch = "arm"),
-              all(target_os = "linux", target_arch = "arm")))]
-    pub unsafe fn _Unwind_GetIP(ctx: *mut _Unwind_Context) -> libc::uintptr_t {
-        #[repr(C)]
-        enum _Unwind_VRS_Result {
-            _UVRSR_OK = 0,
-            _UVRSR_NOT_IMPLEMENTED = 1,
-            _UVRSR_FAILED = 2,
-        }
-        #[repr(C)]
-        enum _Unwind_VRS_RegClass {
-            _UVRSC_CORE = 0,
-            _UVRSC_VFP = 1,
-            _UVRSC_FPA = 2,
-            _UVRSC_WMMXD = 3,
-            _UVRSC_WMMXC = 4,
-        }
-        #[repr(C)]
-        enum _Unwind_VRS_DataRepresentation {
-            _UVRSD_UINT32 = 0,
-            _UVRSD_VFPX = 1,
-            _UVRSD_FPAX = 2,
-            _UVRSD_UINT64 = 3,
-            _UVRSD_FLOAT = 4,
-            _UVRSD_DOUBLE = 5,
-        }
-
-        type _Unwind_Word = libc::c_uint;
-        extern {
-            fn _Unwind_VRS_Get(ctx: *mut _Unwind_Context,
-                               klass: _Unwind_VRS_RegClass,
-                               word: _Unwind_Word,
-                               repr: _Unwind_VRS_DataRepresentation,
-                               data: *mut libc::c_void)
-                -> _Unwind_VRS_Result;
-        }
-
-        let mut val: _Unwind_Word = 0;
-        let ptr = &mut val as *mut _Unwind_Word;
-        let _ = _Unwind_VRS_Get(ctx, _Unwind_VRS_RegClass::_UVRSC_CORE, 15,
-                                _Unwind_VRS_DataRepresentation::_UVRSD_UINT32,
-                                ptr as *mut libc::c_void);
-        (val & !1) as libc::uintptr_t
-    }
-
-    // This function doesn't exist on Android or ARM/Linux, so make it same
-    // to _Unwind_GetIP
-    #[cfg(any(all(target_os = "android", target_arch = "arm"),
-              all(target_os = "linux", target_arch = "arm")))]
-    pub unsafe fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context,
-                                    ip_before_insn: *mut libc::c_int)
-        -> libc::uintptr_t
-    {
-        *ip_before_insn = 0;
-        _Unwind_GetIP(ctx)
-    }
-
-    // This function also doesn't exist on Android or ARM/Linux, so make it
-    // a no-op
-    #[cfg(any(target_os = "android",
-              all(target_os = "linux", target_arch = "arm")))]
-    pub unsafe fn _Unwind_FindEnclosingFunction(pc: *mut libc::c_void)
-        -> *mut libc::c_void
-    {
-        pc
-    }
-}
index ab24b9e6fd601560e37f5f78e96523ed87442f89..2acf6485eb3dad6bf9252a609020ede0945706fb 100644 (file)
@@ -277,21 +277,6 @@ pub struct ipv6_mreq {
 pub const EXCEPTION_CONTINUE_SEARCH: LONG = 0;
 pub const EXCEPTION_STACK_OVERFLOW: DWORD = 0xc00000fd;
 pub const EXCEPTION_MAXIMUM_PARAMETERS: usize = 15;
-#[cfg(all(target_arch = "x86_64", target_env = "gnu"))]
-pub const EXCEPTION_NONCONTINUABLE: DWORD = 0x1;   // Noncontinuable exception
-#[cfg(all(target_arch = "x86_64", target_env = "gnu"))]
-pub const EXCEPTION_UNWINDING: DWORD = 0x2;        // Unwind is in progress
-#[cfg(all(target_arch = "x86_64", target_env = "gnu"))]
-pub const EXCEPTION_EXIT_UNWIND: DWORD = 0x4;      // Exit unwind is in progress
-#[cfg(all(target_arch = "x86_64", target_env = "gnu"))]
-pub const EXCEPTION_TARGET_UNWIND: DWORD = 0x20;   // Target unwind in progress
-#[cfg(all(target_arch = "x86_64", target_env = "gnu"))]
-pub const EXCEPTION_COLLIDED_UNWIND: DWORD = 0x40; // Collided exception handler call
-#[cfg(all(target_arch = "x86_64", target_env = "gnu"))]
-pub const EXCEPTION_UNWIND: DWORD = EXCEPTION_UNWINDING |
-                                    EXCEPTION_EXIT_UNWIND |
-                                    EXCEPTION_TARGET_UNWIND |
-                                    EXCEPTION_COLLIDED_UNWIND;
 
 pub const PIPE_ACCESS_INBOUND: DWORD = 0x00000001;
 pub const FILE_FLAG_FIRST_PIPE_INSTANCE: DWORD = 0x00080000;
@@ -813,31 +798,6 @@ pub struct in6_addr {
     pub s6_addr: [u8; 16],
 }
 
-#[cfg(all(target_arch = "x86_64", target_env = "gnu"))]
-pub enum UNWIND_HISTORY_TABLE {}
-
-#[repr(C)]
-#[cfg(all(target_arch = "x86_64", target_env = "gnu"))]
-pub struct RUNTIME_FUNCTION {
-    pub BeginAddress: DWORD,
-    pub EndAddress: DWORD,
-    pub UnwindData: DWORD,
-}
-
-#[repr(C)]
-#[cfg(all(target_arch = "x86_64", target_env = "gnu"))]
-pub struct DISPATCHER_CONTEXT {
-    pub ControlPc: LPVOID,
-    pub ImageBase: LPVOID,
-    pub FunctionEntry: *const RUNTIME_FUNCTION,
-    pub EstablisherFrame: LPVOID,
-    pub TargetIp: LPVOID,
-    pub ContextRecord: *const CONTEXT,
-    pub LanguageHandler: LPVOID,
-    pub HandlerData: *const u8,
-    pub HistoryTable: *const UNWIND_HISTORY_TABLE,
-}
-
 #[repr(C)]
 #[derive(Copy, Clone)]
 #[allow(dead_code)] // we only use some variants
@@ -1113,19 +1073,6 @@ pub fn CryptGenRandom(hProv: HCRYPTPROV,
                           pbBuffer: *mut BYTE) -> BOOL;
     pub fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> BOOL;
 
-    #[unwind]
-    #[cfg(any(target_arch = "x86_64", target_env = "msvc"))]
-    pub fn RaiseException(dwExceptionCode: DWORD,
-                          dwExceptionFlags: DWORD,
-                          nNumberOfArguments: DWORD,
-                          lpArguments: *const ULONG_PTR);
-    #[cfg(all(target_arch = "x86_64", target_env = "gnu"))]
-    pub fn RtlUnwindEx(TargetFrame: LPVOID,
-                       TargetIp: LPVOID,
-                       ExceptionRecord: *const EXCEPTION_RECORD,
-                       ReturnValue: LPVOID,
-                       OriginalContext: *const CONTEXT,
-                       HistoryTable: *const UNWIND_HISTORY_TABLE);
     pub fn GetSystemTimeAsFileTime(lpSystemTimeAsFileTime: LPFILETIME);
 
     pub fn CreateEventW(lpEventAttributes: LPSECURITY_ATTRIBUTES,
index 2f0dec759b3d57f175473da5425e759bb6eff7c5..99e6ba8c770b92b3bc68a499de4cb92fdf971418 100644 (file)
 
 use any::Any;
 use cell::UnsafeCell;
+use ffi::{CStr, CString};
 use fmt;
 use io;
+use panic;
+use panicking;
 use str;
-use ffi::{CStr, CString};
 use sync::{Mutex, Condvar, Arc};
 use sys::thread as imp;
 use sys_common::thread_info;
-use sys_common::unwind;
 use sys_common::util;
 use sys_common::{AsInner, IntoInner};
 use time::Duration;
@@ -273,14 +274,8 @@ pub fn spawn<F, T>(self, f: F) -> io::Result<JoinHandle<T>> where
             }
             unsafe {
                 thread_info::set(imp::guard::current(), their_thread);
-                let mut output = None;
-                let try_result = {
-                    let ptr = &mut output;
-                    unwind::try(move || *ptr = Some(f()))
-                };
-                *their_packet.get() = Some(try_result.map(|()| {
-                    output.unwrap()
-                }));
+                let try_result = panic::catch_unwind(panic::AssertUnwindSafe(f));
+                *their_packet.get() = Some(try_result);
             }
         };
 
@@ -337,7 +332,7 @@ pub fn yield_now() {
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn panicking() -> bool {
-    unwind::panicking()
+    panicking::panicking()
 }
 
 /// Puts the current thread to sleep for the specified amount of time.
index 67bce440d4d48213bbdd282bbd3f431c4aa5c720..7958162986cfc558f2fbd7ddf0daaf829d7ec6b0 100644 (file)
@@ -755,7 +755,7 @@ fn expr_fail(&self, span: Span, msg: InternedString) -> P<ast::Expr> {
         let expr_file_line_ptr = self.expr_addr_of(span, expr_file_line_tuple);
         self.expr_call_global(
             span,
-            self.std_path(&["rt", "begin_unwind"]),
+            self.std_path(&["rt", "begin_panic"]),
             vec!(
                 self.expr_str(span, msg),
                 expr_file_line_ptr))
index 7f01821b00433aa4c507497a5ae1011cdb2b5a12..dbe4d9bb6f7c7a31b8a02a964ccdafa9c586f001 100644 (file)
@@ -141,6 +141,8 @@ pub fn new() -> Features {
     (active, simd_ffi, "1.0.0", Some(27731)),
     (active, start, "1.0.0", Some(29633)),
     (active, structural_match, "1.8.0", Some(31434)),
+    (active, panic_runtime, "1.10.0", Some(32837)),
+    (active, needs_panic_runtime, "1.10.0", Some(32837)),
 
     // OIBIT specific features
     (active, optin_builtin_traits, "1.0.0", Some(13231)),
@@ -435,6 +437,15 @@ fn f(features: &Features) -> bool {
                                        attribute is an experimental \
                                        feature",
                                       cfg_fn!(needs_allocator))),
+    ("panic_runtime", Whitelisted, Gated("panic_runtime",
+                                         "the `#[panic_runtime]` attribute is \
+                                          an experimental feature",
+                                         cfg_fn!(panic_runtime))),
+    ("needs_panic_runtime", Whitelisted, Gated("needs_panic_runtime",
+                                               "the `#[needs_panic_runtime]` \
+                                                attribute is an experimental \
+                                                feature",
+                                               cfg_fn!(needs_panic_runtime))),
     ("rustc_variance", Normal, Gated("rustc_attrs",
                                      "the `#[rustc_variance]` attribute \
                                       is just used for rustc unit tests \
index c6a70edf2a8f222280ab5fcb2217513c48e7d929..88be3ade83922b399abb116253c386c8dcc58d1b 100644 (file)
 #![feature(set_stdio)]
 #![feature(staged_api)]
 #![feature(question_mark)]
+#![feature(panic_unwind)]
 
 extern crate getopts;
 extern crate term;
 extern crate libc;
+extern crate panic_unwind;
 
 pub use self::TestFn::*;
 pub use self::ColorConfig::*;
diff --git a/src/libunwind/Cargo.toml b/src/libunwind/Cargo.toml
new file mode 100644 (file)
index 0000000..dca222c
--- /dev/null
@@ -0,0 +1,13 @@
+[package]
+authors = ["The Rust Project Developers"]
+name = "unwind"
+version = "0.0.0"
+build = "build.rs"
+
+[lib]
+name = "unwind"
+path = "lib.rs"
+
+[dependencies]
+core = { path = "../libcore" }
+libc = { path = "../rustc/libc_shim" }
diff --git a/src/libunwind/build.rs b/src/libunwind/build.rs
new file mode 100644 (file)
index 0000000..ebe6fd5
--- /dev/null
@@ -0,0 +1,39 @@
+// Copyright 2016 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.
+
+use std::env;
+
+fn main() {
+    println!("cargo:rustc-cfg=cargobuild");
+
+    let target = env::var("TARGET").unwrap();
+
+    if target.contains("linux") {
+        if target.contains("musl") && (target.contains("x86_64") || target.contains("i686")) {
+            println!("cargo:rustc-link-lib=static=unwind");
+        } else if !target.contains("android") {
+            println!("cargo:rustc-link-lib=gcc_s");
+        }
+    } else if target.contains("freebsd") {
+        println!("cargo:rustc-link-lib=gcc_s");
+    } else if target.contains("rumprun") {
+        println!("cargo:rustc-link-lib=unwind");
+    } else if target.contains("netbsd") {
+        println!("cargo:rustc-link-lib=gcc_s");
+    } else if target.contains("openbsd") {
+        println!("cargo:rustc-link-lib=gcc");
+    } else if target.contains("bitrig") {
+        println!("cargo:rustc-link-lib=c++abi");
+    } else if target.contains("dragonfly") {
+        println!("cargo:rustc-link-lib=gcc_pic");
+    } else if target.contains("windows-gnu") {
+        println!("cargo:rustc-link-lib=gcc_eh");
+    }
+}
diff --git a/src/libunwind/lib.rs b/src/libunwind/lib.rs
new file mode 100644 (file)
index 0000000..3ff61fd
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright 2016 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.
+
+#![no_std]
+#![crate_name = "unwind"]
+#![crate_type = "rlib"]
+#![unstable(feature = "panic_unwind", issue = "32837")]
+#![cfg_attr(not(stage0), deny(warnings))]
+
+#![feature(cfg_target_vendor)]
+#![feature(staged_api)]
+#![feature(unwind_attributes)]
+
+#![cfg_attr(not(target_env = "msvc"), feature(libc))]
+
+#[cfg(not(target_env = "msvc"))]
+extern crate libc;
+
+#[cfg(not(target_env = "msvc"))]
+mod libunwind;
+#[cfg(not(target_env = "msvc"))]
+pub use libunwind::*;
+
diff --git a/src/libunwind/libunwind.rs b/src/libunwind/libunwind.rs
new file mode 100644 (file)
index 0000000..ce74e5d
--- /dev/null
@@ -0,0 +1,247 @@
+// Copyright 2016 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.
+
+#![allow(bad_style)]
+
+use libc;
+
+#[cfg(any(not(target_arch = "arm"), target_os = "ios"))]
+pub use self::_Unwind_Action::*;
+#[cfg(target_arch = "arm")]
+pub use self::_Unwind_State::*;
+pub use self::_Unwind_Reason_Code::*;
+
+#[cfg(any(not(target_arch = "arm"), target_os = "ios"))]
+#[repr(C)]
+#[derive(Clone, Copy)]
+pub enum _Unwind_Action {
+    _UA_SEARCH_PHASE = 1,
+    _UA_CLEANUP_PHASE = 2,
+    _UA_HANDLER_FRAME = 4,
+    _UA_FORCE_UNWIND = 8,
+    _UA_END_OF_STACK = 16,
+}
+
+#[cfg(target_arch = "arm")]
+#[repr(C)]
+#[derive(Clone, Copy)]
+pub enum _Unwind_State {
+    _US_VIRTUAL_UNWIND_FRAME = 0,
+    _US_UNWIND_FRAME_STARTING = 1,
+    _US_UNWIND_FRAME_RESUME = 2,
+    _US_ACTION_MASK = 3,
+    _US_FORCE_UNWIND = 8,
+    _US_END_OF_STACK = 16
+}
+
+#[repr(C)]
+pub enum _Unwind_Reason_Code {
+    _URC_NO_REASON = 0,
+    _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
+    _URC_FATAL_PHASE2_ERROR = 2,
+    _URC_FATAL_PHASE1_ERROR = 3,
+    _URC_NORMAL_STOP = 4,
+    _URC_END_OF_STACK = 5,
+    _URC_HANDLER_FOUND = 6,
+    _URC_INSTALL_CONTEXT = 7,
+    _URC_CONTINUE_UNWIND = 8,
+    _URC_FAILURE = 9, // used only by ARM EABI
+}
+
+pub type _Unwind_Exception_Class = u64;
+
+pub type _Unwind_Word = libc::uintptr_t;
+
+pub type _Unwind_Trace_Fn =
+        extern fn(ctx: *mut _Unwind_Context,
+                  arg: *mut libc::c_void) -> _Unwind_Reason_Code;
+
+#[cfg(target_arch = "x86")]
+pub const unwinder_private_data_size: usize = 5;
+
+#[cfg(target_arch = "x86_64")]
+pub const unwinder_private_data_size: usize = 6;
+
+#[cfg(all(target_arch = "arm", not(target_os = "ios")))]
+pub const unwinder_private_data_size: usize = 20;
+
+#[cfg(all(target_arch = "arm", target_os = "ios"))]
+pub const unwinder_private_data_size: usize = 5;
+
+#[cfg(target_arch = "aarch64")]
+pub const unwinder_private_data_size: usize = 2;
+
+#[cfg(target_arch = "mips")]
+pub const unwinder_private_data_size: usize = 2;
+
+#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
+pub const unwinder_private_data_size: usize = 2;
+
+#[cfg(target_arch = "asmjs")]
+// FIXME: Copied from arm. Need to confirm.
+pub const unwinder_private_data_size: usize = 20;
+
+#[repr(C)]
+pub struct _Unwind_Exception {
+    pub exception_class: _Unwind_Exception_Class,
+    pub exception_cleanup: _Unwind_Exception_Cleanup_Fn,
+    pub private: [_Unwind_Word; unwinder_private_data_size],
+}
+
+pub enum _Unwind_Context {}
+
+pub type _Unwind_Exception_Cleanup_Fn =
+        extern "C" fn(unwind_code: _Unwind_Reason_Code,
+                      exception: *mut _Unwind_Exception);
+
+#[cfg_attr(any(all(target_os = "linux", not(target_env = "musl")),
+               target_os = "freebsd",
+               target_os = "solaris",
+               all(target_os = "linux",
+                   target_env = "musl",
+                   not(target_arch = "x86"),
+                   not(target_arch = "x86_64"))),
+           link(name = "gcc_s"))]
+#[cfg_attr(all(target_os = "linux",
+               target_env = "musl",
+               any(target_arch = "x86", target_arch = "x86_64"),
+               not(test)),
+           link(name = "unwind", kind = "static"))]
+#[cfg_attr(any(target_os = "android", target_os = "openbsd"),
+           link(name = "gcc"))]
+#[cfg_attr(all(target_os = "netbsd", not(target_vendor = "rumprun")),
+           link(name = "gcc"))]
+#[cfg_attr(all(target_os = "netbsd", target_vendor = "rumprun"),
+           link(name = "unwind"))]
+#[cfg_attr(target_os = "dragonfly",
+           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"))]
+#[cfg(not(cargobuild))]
+extern {}
+
+extern {
+    // iOS on armv7 uses SjLj exceptions and requires to link
+    // against corresponding routine (..._SjLj_...)
+    #[cfg(not(all(target_os = "ios", target_arch = "arm")))]
+    #[unwind]
+    pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception)
+                                  -> _Unwind_Reason_Code;
+
+    #[cfg(all(target_os = "ios", target_arch = "arm"))]
+    #[unwind]
+    fn _Unwind_SjLj_RaiseException(e: *mut _Unwind_Exception)
+                                   -> _Unwind_Reason_Code;
+
+    pub fn _Unwind_DeleteException(exception: *mut _Unwind_Exception);
+
+    #[unwind]
+    pub fn _Unwind_Resume(exception: *mut _Unwind_Exception) -> !;
+
+    // No native _Unwind_Backtrace on iOS
+    #[cfg(not(all(target_os = "ios", target_arch = "arm")))]
+    pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn,
+                             trace_argument: *mut libc::c_void)
+                -> _Unwind_Reason_Code;
+
+    // available since GCC 4.2.0, should be fine for our purpose
+    #[cfg(all(not(all(target_os = "android", target_arch = "arm")),
+              not(all(target_os = "linux", target_arch = "arm"))))]
+    pub fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context,
+                             ip_before_insn: *mut libc::c_int)
+                -> libc::uintptr_t;
+
+    #[cfg(all(not(target_os = "android"),
+              not(all(target_os = "linux", target_arch = "arm"))))]
+    pub fn _Unwind_FindEnclosingFunction(pc: *mut libc::c_void)
+        -> *mut libc::c_void;
+}
+
+// ... and now we just providing access to SjLj counterspart
+// through a standard name to hide those details from others
+// (see also comment above regarding _Unwind_RaiseException)
+#[cfg(all(target_os = "ios", target_arch = "arm"))]
+#[inline]
+pub unsafe fn _Unwind_RaiseException(exc: *mut _Unwind_Exception)
+                                     -> _Unwind_Reason_Code {
+    _Unwind_SjLj_RaiseException(exc)
+}
+
+// On android, the function _Unwind_GetIP is a macro, and this is the
+// expansion of the macro. This is all copy/pasted directly from the
+// header file with the definition of _Unwind_GetIP.
+#[cfg(any(all(target_os = "android", target_arch = "arm"),
+          all(target_os = "linux", target_arch = "arm")))]
+pub unsafe fn _Unwind_GetIP(ctx: *mut _Unwind_Context) -> libc::uintptr_t {
+    #[repr(C)]
+    enum _Unwind_VRS_Result {
+        _UVRSR_OK = 0,
+        _UVRSR_NOT_IMPLEMENTED = 1,
+        _UVRSR_FAILED = 2,
+    }
+    #[repr(C)]
+    enum _Unwind_VRS_RegClass {
+        _UVRSC_CORE = 0,
+        _UVRSC_VFP = 1,
+        _UVRSC_FPA = 2,
+        _UVRSC_WMMXD = 3,
+        _UVRSC_WMMXC = 4,
+    }
+    #[repr(C)]
+    enum _Unwind_VRS_DataRepresentation {
+        _UVRSD_UINT32 = 0,
+        _UVRSD_VFPX = 1,
+        _UVRSD_FPAX = 2,
+        _UVRSD_UINT64 = 3,
+        _UVRSD_FLOAT = 4,
+        _UVRSD_DOUBLE = 5,
+    }
+
+    type _Unwind_Word = libc::c_uint;
+    extern {
+        fn _Unwind_VRS_Get(ctx: *mut _Unwind_Context,
+                           klass: _Unwind_VRS_RegClass,
+                           word: _Unwind_Word,
+                           repr: _Unwind_VRS_DataRepresentation,
+                           data: *mut libc::c_void)
+            -> _Unwind_VRS_Result;
+    }
+
+    let mut val: _Unwind_Word = 0;
+    let ptr = &mut val as *mut _Unwind_Word;
+    let _ = _Unwind_VRS_Get(ctx, _Unwind_VRS_RegClass::_UVRSC_CORE, 15,
+                            _Unwind_VRS_DataRepresentation::_UVRSD_UINT32,
+                            ptr as *mut libc::c_void);
+    (val & !1) as libc::uintptr_t
+}
+
+// This function doesn't exist on Android or ARM/Linux, so make it same
+// to _Unwind_GetIP
+#[cfg(any(all(target_os = "android", target_arch = "arm"),
+          all(target_os = "linux", target_arch = "arm")))]
+pub unsafe fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context,
+                                ip_before_insn: *mut libc::c_int)
+    -> libc::uintptr_t
+{
+    *ip_before_insn = 0;
+    _Unwind_GetIP(ctx)
+}
+
+// This function also doesn't exist on Android or ARM/Linux, so make it
+// a no-op
+#[cfg(any(target_os = "android",
+          all(target_os = "linux", target_arch = "arm")))]
+pub unsafe fn _Unwind_FindEnclosingFunction(pc: *mut libc::c_void)
+    -> *mut libc::c_void
+{
+    pc
+}
index 530c04da8a0c9503a102f740bbc16284e0ddb339..bad46966ffa6bef5eed035363137dcc75c097e14 100644 (file)
@@ -5,15 +5,6 @@ dependencies = [
  "std 0.0.0",
 ]
 
-[[package]]
-name = "advapi32-sys"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "winapi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "alloc"
 version = "0.0.0"
@@ -27,7 +18,7 @@ version = "0.0.0"
 dependencies = [
  "build_helper 0.1.0",
  "core 0.0.0",
- "gcc 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.0.0",
 ]
 
@@ -58,18 +49,32 @@ version = "0.0.0"
 
 [[package]]
 name = "gcc"
-version = "0.3.17"
+version = "0.3.26"
 source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "libc"
+version = "0.0.0"
 dependencies = [
- "advapi32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "core 0.0.0",
 ]
 
 [[package]]
-name = "libc"
+name = "panic_abort"
 version = "0.0.0"
 dependencies = [
  "core 0.0.0",
+ "libc 0.0.0",
+]
+
+[[package]]
+name = "panic_unwind"
+version = "0.0.0"
+dependencies = [
+ "alloc 0.0.0",
+ "core 0.0.0",
+ "libc 0.0.0",
+ "unwind 0.0.0",
 ]
 
 [[package]]
@@ -96,19 +101,20 @@ dependencies = [
  "build_helper 0.1.0",
  "collections 0.0.0",
  "core 0.0.0",
- "gcc 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.0.0",
+ "panic_abort 0.0.0",
+ "panic_unwind 0.0.0",
  "rand 0.0.0",
  "rustc_unicode 0.0.0",
+ "unwind 0.0.0",
 ]
 
 [[package]]
-name = "winapi"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "winapi-build"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
+name = "unwind"
+version = "0.0.0"
+dependencies = [
+ "core 0.0.0",
+ "libc 0.0.0",
+]
 
diff --git a/src/test/codegen/lto-removes-invokes.rs b/src/test/codegen/lto-removes-invokes.rs
new file mode 100644 (file)
index 0000000..b2f4348
--- /dev/null
@@ -0,0 +1,31 @@
+// Copyright 2016 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.
+
+// compile-flags: -C lto -C panic=abort -O
+// no-prefer-dynamic
+
+fn main() {
+    foo();
+}
+
+#[no_mangle]
+#[inline(never)]
+fn foo() {
+    let _a = Box::new(3);
+    bar();
+// CHECK-LABEL: foo
+// CHECK: call {{.*}} void @bar
+}
+
+#[inline(never)]
+#[no_mangle]
+fn bar() {
+    println!("hello!");
+}
diff --git a/src/test/compile-fail/panic-runtime/abort-link-to-unwind-dylib.rs b/src/test/compile-fail/panic-runtime/abort-link-to-unwind-dylib.rs
new file mode 100644 (file)
index 0000000..c3242a5
--- /dev/null
@@ -0,0 +1,24 @@
+// Copyright 2016 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.
+
+// compile-flags:-C panic=abort -C prefer-dynamic
+// ignore-musl - no dylibs here
+// error-pattern:`panic_unwind` is not compiled with this crate's panic strategy
+
+// This is a test where the local crate, compiled with `panic=abort`, links to
+// the standard library **dynamically** which is already linked against
+// `panic=unwind`. We should fail because the linked panic runtime does not
+// correspond with our `-C panic` option.
+//
+// Note that this test assumes that the dynamic version of the standard library
+// is linked to `panic_unwind`, which is currently the case.
+
+fn main() {
+}
diff --git a/src/test/compile-fail/panic-runtime/auxiliary/needs-panic-runtime.rs b/src/test/compile-fail/panic-runtime/auxiliary/needs-panic-runtime.rs
new file mode 100644 (file)
index 0000000..d6c21fe
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright 2016 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.
+
+// no-prefer-dynamic
+
+#![feature(needs_panic_runtime)]
+#![crate_type = "rlib"]
+#![needs_panic_runtime]
+#![no_std]
diff --git a/src/test/compile-fail/panic-runtime/auxiliary/panic-runtime-abort.rs b/src/test/compile-fail/panic-runtime/auxiliary/panic-runtime-abort.rs
new file mode 100644 (file)
index 0000000..3b74156
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright 2016 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.
+
+// compile-flags:-C panic=abort
+// no-prefer-dynamic
+
+#![feature(panic_runtime)]
+#![crate_type = "rlib"]
+
+#![no_std]
+#![panic_runtime]
+
+#[no_mangle]
+pub extern fn __rust_maybe_catch_panic() {}
+
+#[no_mangle]
+pub extern fn __rust_start_panic() {}
+
+#[no_mangle]
+pub extern fn rust_eh_personality() {}
diff --git a/src/test/compile-fail/panic-runtime/auxiliary/panic-runtime-lang-items.rs b/src/test/compile-fail/panic-runtime/auxiliary/panic-runtime-lang-items.rs
new file mode 100644 (file)
index 0000000..fbf70b3
--- /dev/null
@@ -0,0 +1,23 @@
+// Copyright 2016 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.
+
+// no-prefer-dynamic
+
+#![crate_type = "rlib"]
+
+#![no_std]
+#![feature(lang_items)]
+
+#[lang = "panic_fmt"]
+fn panic_fmt() {}
+#[lang = "eh_personality"]
+fn eh_personality() {}
+#[lang = "eh_unwind_resume"]
+fn eh_unwind_resume() {}
diff --git a/src/test/compile-fail/panic-runtime/auxiliary/panic-runtime-unwind.rs b/src/test/compile-fail/panic-runtime/auxiliary/panic-runtime-unwind.rs
new file mode 100644 (file)
index 0000000..4bb3683
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright 2016 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.
+
+// compile-flags:-C panic=unwind
+// no-prefer-dynamic
+
+#![feature(panic_runtime)]
+#![crate_type = "rlib"]
+
+#![no_std]
+#![panic_runtime]
+
+#[no_mangle]
+pub extern fn __rust_maybe_catch_panic() {}
+
+#[no_mangle]
+pub extern fn __rust_start_panic() {}
+
+#[no_mangle]
+pub extern fn rust_eh_personality() {}
diff --git a/src/test/compile-fail/panic-runtime/auxiliary/panic-runtime-unwind2.rs b/src/test/compile-fail/panic-runtime/auxiliary/panic-runtime-unwind2.rs
new file mode 100644 (file)
index 0000000..4bb3683
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright 2016 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.
+
+// compile-flags:-C panic=unwind
+// no-prefer-dynamic
+
+#![feature(panic_runtime)]
+#![crate_type = "rlib"]
+
+#![no_std]
+#![panic_runtime]
+
+#[no_mangle]
+pub extern fn __rust_maybe_catch_panic() {}
+
+#[no_mangle]
+pub extern fn __rust_start_panic() {}
+
+#[no_mangle]
+pub extern fn rust_eh_personality() {}
diff --git a/src/test/compile-fail/panic-runtime/auxiliary/runtime-depending-on-panic-runtime.rs b/src/test/compile-fail/panic-runtime/auxiliary/runtime-depending-on-panic-runtime.rs
new file mode 100644 (file)
index 0000000..b90dec9
--- /dev/null
@@ -0,0 +1,18 @@
+// Copyright 2016 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.
+
+// no-prefer-dynamic
+
+#![feature(panic_runtime)]
+#![crate_type = "rlib"]
+#![panic_runtime]
+#![no_std]
+
+extern crate needs_panic_runtime;
diff --git a/src/test/compile-fail/panic-runtime/auxiliary/wants-panic-runtime-abort.rs b/src/test/compile-fail/panic-runtime/auxiliary/wants-panic-runtime-abort.rs
new file mode 100644 (file)
index 0000000..e1902e4
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2016 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.
+
+// compile-flags:-C panic=abort
+// no-prefer-dynamic
+
+#![crate_type = "rlib"]
+#![no_std]
+
+extern crate panic_runtime_abort;
diff --git a/src/test/compile-fail/panic-runtime/auxiliary/wants-panic-runtime-unwind.rs b/src/test/compile-fail/panic-runtime/auxiliary/wants-panic-runtime-unwind.rs
new file mode 100644 (file)
index 0000000..2183338
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright 2016 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.
+
+// no-prefer-dynamic
+
+#![crate_type = "rlib"]
+#![no_std]
+
+extern crate panic_runtime_unwind;
diff --git a/src/test/compile-fail/panic-runtime/bad-panic-flag1.rs b/src/test/compile-fail/panic-runtime/bad-panic-flag1.rs
new file mode 100644 (file)
index 0000000..f067b6b
--- /dev/null
@@ -0,0 +1,14 @@
+// Copyright 2016 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.
+
+// compile-flags:-C panic=foo
+// error-pattern:either `panic` or `abort` was expected
+
+fn main() {}
diff --git a/src/test/compile-fail/panic-runtime/bad-panic-flag2.rs b/src/test/compile-fail/panic-runtime/bad-panic-flag2.rs
new file mode 100644 (file)
index 0000000..0ecf65f
--- /dev/null
@@ -0,0 +1,14 @@
+// Copyright 2016 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.
+
+// compile-flags:-C panic
+// error-pattern:requires either `panic` or `abort`
+
+fn main() {}
diff --git a/src/test/compile-fail/panic-runtime/libtest-unwinds.rs b/src/test/compile-fail/panic-runtime/libtest-unwinds.rs
new file mode 100644 (file)
index 0000000..5f6f4ec
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2016 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.
+
+// error-pattern:is not compiled with this crate's panic strategy `abort`
+// compile-flags:-C panic=abort
+
+#![feature(test)]
+
+extern crate test;
+
+fn main() {
+}
+
diff --git a/src/test/compile-fail/panic-runtime/needs-gate.rs b/src/test/compile-fail/panic-runtime/needs-gate.rs
new file mode 100644 (file)
index 0000000..02f3da5
--- /dev/null
@@ -0,0 +1,14 @@
+// Copyright 2016 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.
+
+#![panic_runtime] //~ ERROR: is an experimental feature
+#![needs_panic_runtime] //~ ERROR: is an experimental feature
+
+fn main() {}
diff --git a/src/test/compile-fail/panic-runtime/runtime-depend-on-needs-runtime.rs b/src/test/compile-fail/panic-runtime/runtime-depend-on-needs-runtime.rs
new file mode 100644 (file)
index 0000000..0681f99
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2016 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.
+
+// aux-build:needs-panic-runtime.rs
+// aux-build:runtime-depending-on-panic-runtime.rs
+// error-pattern:cannot depend on a crate that needs a panic runtime
+
+extern crate runtime_depending_on_panic_runtime;
diff --git a/src/test/compile-fail/panic-runtime/transitive-link-a-bunch.rs b/src/test/compile-fail/panic-runtime/transitive-link-a-bunch.rs
new file mode 100644 (file)
index 0000000..885b3e6
--- /dev/null
@@ -0,0 +1,24 @@
+// Copyright 2016 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.
+
+// aux-build:panic-runtime-unwind.rs
+// aux-build:panic-runtime-abort.rs
+// aux-build:wants-panic-runtime-unwind.rs
+// aux-build:wants-panic-runtime-abort.rs
+// aux-build:panic-runtime-lang-items.rs
+// error-pattern: is not compiled with this crate's panic strategy `unwind`
+
+#![no_std]
+
+extern crate wants_panic_runtime_unwind;
+extern crate wants_panic_runtime_abort;
+extern crate panic_runtime_lang_items;
+
+fn main() {}
diff --git a/src/test/compile-fail/panic-runtime/two-panic-runtimes.rs b/src/test/compile-fail/panic-runtime/two-panic-runtimes.rs
new file mode 100644 (file)
index 0000000..0fe0da2
--- /dev/null
@@ -0,0 +1,23 @@
+// Copyright 2016 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.
+
+// error-pattern:cannot link together two panic runtimes: panic_runtime_unwind and panic_runtime_unwind2
+// ignore-tidy-linelength
+// aux-build:panic-runtime-unwind.rs
+// aux-build:panic-runtime-unwind2.rs
+// aux-build:panic-runtime-lang-items.rs
+
+#![no_std]
+
+extern crate panic_runtime_unwind;
+extern crate panic_runtime_unwind2;
+extern crate panic_runtime_lang_items;
+
+fn main() {}
diff --git a/src/test/compile-fail/panic-runtime/want-abort-got-unwind.rs b/src/test/compile-fail/panic-runtime/want-abort-got-unwind.rs
new file mode 100644 (file)
index 0000000..b178006
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2016 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.
+
+// error-pattern:is not compiled with this crate's panic strategy `abort`
+// aux-build:panic-runtime-unwind.rs
+// compile-flags:-C panic=abort
+
+extern crate panic_runtime_unwind;
+
+fn main() {}
diff --git a/src/test/compile-fail/panic-runtime/want-abort-got-unwind2.rs b/src/test/compile-fail/panic-runtime/want-abort-got-unwind2.rs
new file mode 100644 (file)
index 0000000..de8e010
--- /dev/null
@@ -0,0 +1,18 @@
+// Copyright 2016 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.
+
+// error-pattern:is not compiled with this crate's panic strategy `abort`
+// aux-build:panic-runtime-unwind.rs
+// aux-build:wants-panic-runtime-unwind.rs
+// compile-flags:-C panic=abort
+
+extern crate wants_panic_runtime_unwind;
+
+fn main() {}
diff --git a/src/test/compile-fail/panic-runtime/want-unwind-got-abort.rs b/src/test/compile-fail/panic-runtime/want-unwind-got-abort.rs
new file mode 100644 (file)
index 0000000..88ad36f
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2016 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.
+
+// error-pattern:is incompatible with this crate's strategy of `unwind`
+// aux-build:panic-runtime-abort.rs
+// aux-build:panic-runtime-lang-items.rs
+
+#![no_std]
+
+extern crate panic_runtime_abort;
+extern crate panic_runtime_lang_items;
+
+fn main() {}
diff --git a/src/test/compile-fail/panic-runtime/want-unwind-got-abort2.rs b/src/test/compile-fail/panic-runtime/want-unwind-got-abort2.rs
new file mode 100644 (file)
index 0000000..c42a25a
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright 2016 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.
+
+// error-pattern:is incompatible with this crate's strategy of `unwind`
+// aux-build:panic-runtime-abort.rs
+// aux-build:wants-panic-runtime-abort.rs
+// aux-build:panic-runtime-lang-items.rs
+
+#![no_std]
+
+extern crate wants_panic_runtime_abort;
+extern crate panic_runtime_lang_items;
+
+fn main() {}
diff --git a/src/test/run-pass/panic-runtime/abort-link-to-unwinding-crates.rs b/src/test/run-pass/panic-runtime/abort-link-to-unwinding-crates.rs
new file mode 100644 (file)
index 0000000..71c1a61
--- /dev/null
@@ -0,0 +1,35 @@
+// Copyright 2016 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.
+
+// compile-flags:-C panic=abort
+// aux-build:exit-success-if-unwind.rs
+// no-prefer-dynamic
+
+extern crate exit_success_if_unwind;
+
+use std::process::Command;
+use std::env;
+
+fn main() {
+    let mut args = env::args_os();
+    let me = args.next().unwrap();
+
+    if let Some(s) = args.next() {
+        if &*s == "foo" {
+            exit_success_if_unwind::bar(do_panic);
+        }
+    }
+    let s = Command::new(env::args_os().next().unwrap()).arg("foo").status();
+    assert!(s.unwrap().code() != Some(0));
+}
+
+fn do_panic() {
+    panic!("try to catch me");
+}
diff --git a/src/test/run-pass/panic-runtime/abort.rs b/src/test/run-pass/panic-runtime/abort.rs
new file mode 100644 (file)
index 0000000..2fc9d6c
--- /dev/null
@@ -0,0 +1,39 @@
+// Copyright 2016 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.
+
+// compile-flags:-C panic=abort
+// no-prefer-dynamic
+
+use std::process::Command;
+use std::env;
+
+struct Bomb;
+
+impl Drop for Bomb {
+    fn drop(&mut self) {
+        std::process::exit(0);
+    }
+}
+
+fn main() {
+    let mut args = env::args_os();
+    let me = args.next().unwrap();
+
+    if let Some(s) = args.next() {
+        if &*s == "foo" {
+
+            let _bomb = Bomb;
+
+            panic!("try to catch me");
+        }
+    }
+    let s = Command::new(env::args_os().next().unwrap()).arg("foo").status();
+    assert!(s.unwrap().code() != Some(0));
+}
diff --git a/src/test/run-pass/panic-runtime/auxiliary/exit-success-if-unwind.rs b/src/test/run-pass/panic-runtime/auxiliary/exit-success-if-unwind.rs
new file mode 100644 (file)
index 0000000..9e5fc59
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright 2016 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.
+
+// no-prefer-dynamic
+
+#![crate_type = "rlib"]
+
+struct Bomb;
+
+impl Drop for Bomb {
+    fn drop(&mut self) {
+        std::process::exit(0);
+    }
+}
+
+pub fn bar(f: fn()) {
+    let _bomb = Bomb;
+    f();
+}
diff --git a/src/test/run-pass/panic-runtime/link-to-abort.rs b/src/test/run-pass/panic-runtime/link-to-abort.rs
new file mode 100644 (file)
index 0000000..71e35e4
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2016 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.
+
+// compile-flags:-C panic=abort
+// no-prefer-dynamic
+
+#![feature(panic_abort)]
+
+extern crate panic_abort;
+
+fn main() {
+}
diff --git a/src/test/run-pass/panic-runtime/link-to-unwind.rs b/src/test/run-pass/panic-runtime/link-to-unwind.rs
new file mode 100644 (file)
index 0000000..dec8f73
--- /dev/null
@@ -0,0 +1,18 @@
+// Copyright 2016 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.
+
+// no-prefer-dynamic
+
+#![feature(panic_unwind)]
+
+extern crate panic_unwind;
+
+fn main() {
+}
diff --git a/src/test/run-pass/panic-runtime/lto-abort.rs b/src/test/run-pass/panic-runtime/lto-abort.rs
new file mode 100644 (file)
index 0000000..09e33b8
--- /dev/null
@@ -0,0 +1,39 @@
+// Copyright 2016 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.
+
+// compile-flags:-C lto -C panic=abort
+// no-prefer-dynamic
+
+use std::process::Command;
+use std::env;
+
+struct Bomb;
+
+impl Drop for Bomb {
+    fn drop(&mut self) {
+        std::process::exit(0);
+    }
+}
+
+fn main() {
+    let mut args = env::args_os();
+    let me = args.next().unwrap();
+
+    if let Some(s) = args.next() {
+        if &*s == "foo" {
+
+            let _bomb = Bomb;
+
+            panic!("try to catch me");
+        }
+    }
+    let s = Command::new(env::args_os().next().unwrap()).arg("foo").status();
+    assert!(s.unwrap().code() != Some(0));
+}
diff --git a/src/test/run-pass/panic-runtime/lto-unwind.rs b/src/test/run-pass/panic-runtime/lto-unwind.rs
new file mode 100644 (file)
index 0000000..10e633b
--- /dev/null
@@ -0,0 +1,41 @@
+// Copyright 2016 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.
+
+// compile-flags:-C lto -C panic=unwind
+// no-prefer-dynamic
+
+use std::process::Command;
+use std::env;
+
+struct Bomb;
+
+impl Drop for Bomb {
+    fn drop(&mut self) {
+        println!("hurray you ran me");
+    }
+}
+
+fn main() {
+    let mut args = env::args_os();
+    let me = args.next().unwrap();
+
+    if let Some(s) = args.next() {
+        if &*s == "foo" {
+
+            let _bomb = Bomb;
+
+            panic!("try to catch me");
+        }
+    }
+    let s = Command::new(env::args_os().next().unwrap()).arg("foo").output();
+    let s = s.unwrap();
+    assert!(!s.status.success());
+    assert!(String::from_utf8_lossy(&s.stdout).contains("hurray you ran me"));
+}
index 77dcf9c1bd81fdb180b5e35b1e166a5cc096c6b5..6a9d52cb0048f17eb913378a525f80e6c966b2fb 100644 (file)
@@ -85,6 +85,9 @@ fn verify(tomlfile: &Path, libfile: &Path, bad: &mut bool) {
         if krate == "alloc_jemalloc" && toml.contains("name = \"std\"") {
             continue
         }
+        if krate == "panic_abort" && toml.contains("name = \"std\"") {
+            continue
+        }
 
         if !librs.contains(&format!("extern crate {}", krate)) {
             println!("{} doesn't have `extern crate {}`, but Cargo.toml \