rustc: Implement custom panic runtimes
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).
This commit is contained in:
parent
32683ce193
commit
0ec321f7b5
76 changed files with 2000 additions and 745 deletions
16
mk/crates.mk
16
mk/crates.mk
|
@ -53,7 +53,8 @@ TARGET_CRATES := libc std term \
|
||||||
getopts collections test rand \
|
getopts collections test rand \
|
||||||
core alloc \
|
core alloc \
|
||||||
rustc_unicode rustc_bitflags \
|
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_CRATES := rustc rustc_typeck rustc_mir rustc_borrowck rustc_resolve rustc_driver \
|
||||||
rustc_trans rustc_back rustc_llvm rustc_privacy rustc_lint \
|
rustc_trans rustc_back rustc_llvm rustc_privacy rustc_lint \
|
||||||
rustc_data_structures rustc_platform_intrinsics \
|
rustc_data_structures rustc_platform_intrinsics \
|
||||||
|
@ -72,10 +73,18 @@ DEPS_libc := core
|
||||||
DEPS_rand := core
|
DEPS_rand := core
|
||||||
DEPS_rustc_bitflags := core
|
DEPS_rustc_bitflags := core
|
||||||
DEPS_rustc_unicode := 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 \
|
DEPS_std := core libc rand alloc collections rustc_unicode \
|
||||||
native:backtrace \
|
native:backtrace \
|
||||||
alloc_system
|
alloc_system panic_abort panic_unwind unwind
|
||||||
DEPS_arena := std
|
DEPS_arena := std
|
||||||
DEPS_glob := std
|
DEPS_glob := std
|
||||||
DEPS_flate := std native:miniz
|
DEPS_flate := std native:miniz
|
||||||
|
@ -148,6 +157,9 @@ ONLY_RLIB_rustc_unicode := 1
|
||||||
ONLY_RLIB_rustc_bitflags := 1
|
ONLY_RLIB_rustc_bitflags := 1
|
||||||
ONLY_RLIB_alloc_system := 1
|
ONLY_RLIB_alloc_system := 1
|
||||||
ONLY_RLIB_alloc_jemalloc := 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
|
TARGET_SPECIFIC_alloc_jemalloc := 1
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,8 @@ DEPS_collectionstest :=
|
||||||
$(eval $(call RUST_CRATE,collectionstest))
|
$(eval $(call RUST_CRATE,collectionstest))
|
||||||
|
|
||||||
TEST_TARGET_CRATES = $(filter-out core rustc_unicode alloc_system libc \
|
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
|
collectionstest coretest
|
||||||
TEST_DOC_CRATES = $(DOC_CRATES) arena flate fmt_macros getopts graphviz \
|
TEST_DOC_CRATES = $(DOC_CRATES) arena flate fmt_macros getopts graphviz \
|
||||||
log rand rbml serialize syntax term test
|
log rand rbml serialize syntax term test
|
||||||
|
|
|
@ -48,10 +48,11 @@ fn main() {
|
||||||
} else {
|
} else {
|
||||||
env::var_os("RUSTC_REAL").unwrap()
|
env::var_os("RUSTC_REAL").unwrap()
|
||||||
};
|
};
|
||||||
|
let stage = env::var("RUSTC_STAGE").unwrap();
|
||||||
|
|
||||||
let mut cmd = Command::new(rustc);
|
let mut cmd = Command::new(rustc);
|
||||||
cmd.args(&args)
|
cmd.args(&args)
|
||||||
.arg("--cfg").arg(format!("stage{}", env::var("RUSTC_STAGE").unwrap()));
|
.arg("--cfg").arg(format!("stage{}", stage));
|
||||||
|
|
||||||
if let Some(target) = target {
|
if let Some(target) = target {
|
||||||
// The stage0 compiler has a special sysroot distinct from what we
|
// 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<_>>());
|
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
|
// Set various options from config.toml to configure how we're building
|
||||||
// code.
|
// code.
|
||||||
if env::var("RUSTC_DEBUGINFO") == Ok("true".to_string()) {
|
if env::var("RUSTC_DEBUGINFO") == Ok("true".to_string()) {
|
||||||
|
|
|
@ -18,10 +18,8 @@
|
||||||
form or name",
|
form or name",
|
||||||
issue = "27783")]
|
issue = "27783")]
|
||||||
#![feature(allocator)]
|
#![feature(allocator)]
|
||||||
#![feature(libc)]
|
|
||||||
#![feature(staged_api)]
|
#![feature(staged_api)]
|
||||||
|
#![cfg_attr(unix, feature(libc))]
|
||||||
extern crate libc;
|
|
||||||
|
|
||||||
// The minimum alignment guaranteed by the architecture. This value is used to
|
// 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
|
// 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)]
|
#[cfg(unix)]
|
||||||
mod imp {
|
mod imp {
|
||||||
|
extern crate libc;
|
||||||
|
|
||||||
use core::cmp;
|
use core::cmp;
|
||||||
use core::ptr;
|
use core::ptr;
|
||||||
use libc;
|
|
||||||
use MIN_ALIGN;
|
use MIN_ALIGN;
|
||||||
|
|
||||||
pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
|
pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
|
||||||
|
|
11
src/libpanic_abort/Cargo.toml
Normal file
11
src/libpanic_abort/Cargo.toml
Normal file
|
@ -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" }
|
112
src/libpanic_abort/lib.rs
Normal file
112
src/libpanic_abort/lib.rs
Normal file
|
@ -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() {}
|
27
src/libpanic_unwind/Cargo.lock
generated
Normal file
27
src/libpanic_unwind/Cargo.lock
generated
Normal file
|
@ -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",
|
||||||
|
]
|
||||||
|
|
13
src/libpanic_unwind/Cargo.toml
Normal file
13
src/libpanic_unwind/Cargo.toml
Normal file
|
@ -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" }
|
|
@ -21,8 +21,7 @@
|
||||||
#![allow(non_upper_case_globals)]
|
#![allow(non_upper_case_globals)]
|
||||||
#![allow(unused)]
|
#![allow(unused)]
|
||||||
|
|
||||||
use prelude::v1::*;
|
use dwarf::DwarfReader;
|
||||||
use sys_common::dwarf::DwarfReader;
|
|
||||||
use core::mem;
|
use core::mem;
|
||||||
|
|
||||||
pub const DW_EH_PE_omit : u8 = 0xFF;
|
pub const DW_EH_PE_omit : u8 = 0xFF;
|
|
@ -18,7 +18,6 @@
|
||||||
|
|
||||||
pub mod eh;
|
pub mod eh;
|
||||||
|
|
||||||
use prelude::v1::*;
|
|
||||||
use core::mem;
|
use core::mem;
|
||||||
|
|
||||||
pub struct DwarfReader {
|
pub struct DwarfReader {
|
|
@ -8,30 +8,76 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// 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)]
|
#![allow(private_no_mangle_fns)]
|
||||||
|
|
||||||
use prelude::v1::*;
|
use core::any::Any;
|
||||||
|
use alloc::boxed::Box;
|
||||||
|
|
||||||
use any::Any;
|
use unwind as uw;
|
||||||
use sys_common::libunwind as uw;
|
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
struct Exception {
|
struct Exception {
|
||||||
uwe: uw::_Unwind_Exception,
|
_uwe: uw::_Unwind_Exception,
|
||||||
cause: Option<Box<Any + Send + 'static>>,
|
cause: Option<Box<Any + Send>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn panic(data: Box<Any + Send + 'static>) -> ! {
|
pub unsafe fn panic(data: Box<Any + Send>) -> u32 {
|
||||||
let exception: Box<_> = box Exception {
|
let exception = Box::new(Exception {
|
||||||
uwe: uw::_Unwind_Exception {
|
_uwe: uw::_Unwind_Exception {
|
||||||
exception_class: rust_exception_class(),
|
exception_class: rust_exception_class(),
|
||||||
exception_cleanup: exception_cleanup,
|
exception_cleanup: exception_cleanup,
|
||||||
private: [0; uw::unwinder_private_data_size],
|
private: [0; uw::unwinder_private_data_size],
|
||||||
},
|
},
|
||||||
cause: Some(data),
|
cause: Some(data),
|
||||||
};
|
});
|
||||||
let exception_param = Box::into_raw(exception) as *mut uw::_Unwind_Exception;
|
let exception_param = Box::into_raw(exception) as *mut uw::_Unwind_Exception;
|
||||||
let error = uw::_Unwind_RaiseException(exception_param);
|
return uw::_Unwind_RaiseException(exception_param) as u32;
|
||||||
rtabort!("Could not unwind stack, error = {}", error as isize);
|
|
||||||
|
|
||||||
extern fn exception_cleanup(_unwind_code: uw::_Unwind_Reason_Code,
|
extern fn exception_cleanup(_unwind_code: uw::_Unwind_Reason_Code,
|
||||||
exception: *mut uw::_Unwind_Exception) {
|
exception: *mut uw::_Unwind_Exception) {
|
||||||
|
@ -45,7 +91,7 @@ pub fn payload() -> *mut u8 {
|
||||||
0 as *mut u8
|
0 as *mut u8
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn cleanup(ptr: *mut u8) -> Box<Any + Send + 'static> {
|
pub unsafe fn cleanup(ptr: *mut u8) -> Box<Any + Send> {
|
||||||
let my_ep = ptr as *mut Exception;
|
let my_ep = ptr as *mut Exception;
|
||||||
let cause = (*my_ep).cause.take();
|
let cause = (*my_ep).cause.take();
|
||||||
uw::_Unwind_DeleteException(ptr as *mut _);
|
uw::_Unwind_DeleteException(ptr as *mut _);
|
||||||
|
@ -59,7 +105,7 @@ fn rust_exception_class() -> uw::_Unwind_Exception_Class {
|
||||||
0x4d4f5a_00_52555354
|
0x4d4f5a_00_52555354
|
||||||
}
|
}
|
||||||
|
|
||||||
// We could implement our personality routine in pure Rust, however exception
|
// We could implement our personality routine in Rust, however exception
|
||||||
// info decoding is tedious. More importantly, personality routines have to
|
// info decoding is tedious. More importantly, personality routines have to
|
||||||
// handle various platform quirks, which are not fun to maintain. For this
|
// handle various platform quirks, which are not fun to maintain. For this
|
||||||
// reason, we attempt to reuse personality routine of the C language:
|
// reason, we attempt to reuse personality routine of the C language:
|
||||||
|
@ -79,10 +125,9 @@ fn rust_exception_class() -> uw::_Unwind_Exception_Class {
|
||||||
// See also: rustc_trans::trans::intrinsic::trans_gnu_try
|
// See also: rustc_trans::trans::intrinsic::trans_gnu_try
|
||||||
|
|
||||||
#[cfg(all(not(target_arch = "arm"),
|
#[cfg(all(not(target_arch = "arm"),
|
||||||
not(all(windows, target_arch = "x86_64")),
|
not(all(windows, target_arch = "x86_64"))))]
|
||||||
not(test)))]
|
|
||||||
pub mod eabi {
|
pub mod eabi {
|
||||||
use sys_common::libunwind as uw;
|
use unwind as uw;
|
||||||
use libc::c_int;
|
use libc::c_int;
|
||||||
|
|
||||||
extern {
|
extern {
|
||||||
|
@ -136,9 +181,9 @@ pub mod eabi {
|
||||||
// iOS on armv7 is using SjLj exceptions and therefore requires to use
|
// iOS on armv7 is using SjLj exceptions and therefore requires to use
|
||||||
// a specialized personality routine: __gcc_personality_sj0
|
// a specialized personality routine: __gcc_personality_sj0
|
||||||
|
|
||||||
#[cfg(all(target_os = "ios", target_arch = "arm", not(test)))]
|
#[cfg(all(target_os = "ios", target_arch = "arm"))]
|
||||||
pub mod eabi {
|
pub mod eabi {
|
||||||
use sys_common::libunwind as uw;
|
use unwind as uw;
|
||||||
use libc::c_int;
|
use libc::c_int;
|
||||||
|
|
||||||
extern {
|
extern {
|
||||||
|
@ -191,9 +236,9 @@ pub mod eabi {
|
||||||
|
|
||||||
// ARM EHABI uses a slightly different personality routine signature,
|
// ARM EHABI uses a slightly different personality routine signature,
|
||||||
// but otherwise works the same.
|
// but otherwise works the same.
|
||||||
#[cfg(all(target_arch = "arm", not(target_os = "ios"), not(test)))]
|
#[cfg(all(target_arch = "arm", not(target_os = "ios")))]
|
||||||
pub mod eabi {
|
pub mod eabi {
|
||||||
use sys_common::libunwind as uw;
|
use unwind as uw;
|
||||||
use libc::c_int;
|
use libc::c_int;
|
||||||
|
|
||||||
extern {
|
extern {
|
||||||
|
@ -242,19 +287,31 @@ pub mod eabi {
|
||||||
}
|
}
|
||||||
|
|
||||||
// See docs in the `unwind` module.
|
// See docs in the `unwind` module.
|
||||||
#[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu", not(test)))]
|
#[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))]
|
||||||
#[lang = "eh_unwind_resume"]
|
#[lang = "eh_unwind_resume"]
|
||||||
#[unwind]
|
#[unwind]
|
||||||
unsafe extern fn rust_eh_unwind_resume(panic_ctx: *mut u8) -> ! {
|
unsafe extern fn rust_eh_unwind_resume(panic_ctx: *mut u8) -> ! {
|
||||||
uw::_Unwind_Resume(panic_ctx as *mut uw::_Unwind_Exception);
|
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"))]
|
#[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))]
|
||||||
pub mod eh_frame_registry {
|
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")]
|
#[link(name = "gcc_eh")]
|
||||||
#[cfg(not(cargobuild))]
|
#[cfg(not(cargobuild))]
|
||||||
extern {}
|
extern {}
|
||||||
|
@ -263,16 +320,14 @@ pub mod eh_frame_registry {
|
||||||
fn __register_frame_info(eh_frame_begin: *const u8, object: *mut u8);
|
fn __register_frame_info(eh_frame_begin: *const u8, object: *mut u8);
|
||||||
fn __deregister_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]
|
#[no_mangle]
|
||||||
#[unstable(feature = "libstd_sys_internals", issue = "0")]
|
|
||||||
pub unsafe extern fn rust_eh_register_frames(eh_frame_begin: *const u8,
|
pub unsafe extern fn rust_eh_register_frames(eh_frame_begin: *const u8,
|
||||||
object: *mut u8) {
|
object: *mut u8) {
|
||||||
__register_frame_info(eh_frame_begin, object);
|
__register_frame_info(eh_frame_begin, object);
|
||||||
}
|
}
|
||||||
#[cfg(not(test))]
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
#[unstable(feature = "libstd_sys_internals", issue = "0")]
|
|
||||||
pub unsafe extern fn rust_eh_unregister_frames(eh_frame_begin: *const u8,
|
pub unsafe extern fn rust_eh_unregister_frames(eh_frame_begin: *const u8,
|
||||||
object: *mut u8) {
|
object: *mut u8) {
|
||||||
__deregister_frame_info(eh_frame_begin, object);
|
__deregister_frame_info(eh_frame_begin, object);
|
109
src/libpanic_unwind/lib.rs
Normal file
109
src/libpanic_unwind/lib.rs
Normal file
|
@ -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 (),
|
||||||
|
}))
|
||||||
|
}
|
|
@ -45,7 +45,7 @@
|
||||||
//! the precise codegen for this was lifted from an LLVM test case for SEH
|
//! the precise codegen for this was lifted from an LLVM test case for SEH
|
||||||
//! (this is the `__rust_try_filter` function below).
|
//! (this is the `__rust_try_filter` function below).
|
||||||
//! * We've got some data to transmit across the unwinding boundary,
|
//! * We've got some data to transmit across the unwinding boundary,
|
||||||
//! specifically a `Box<Any + Send + 'static>`. Like with Dwarf exceptions
|
//! specifically a `Box<Any + Send>`. Like with Dwarf exceptions
|
||||||
//! these two pointers are stored as a payload in the exception itself. On
|
//! 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
|
//! MSVC, however, there's no need for an extra allocation because the call
|
||||||
//! stack is preserved while filter functions are being executed. This means
|
//! stack is preserved while filter functions are being executed. This means
|
||||||
|
@ -56,25 +56,20 @@
|
||||||
//! [win64]: http://msdn.microsoft.com/en-us/library/1eyas8tf.aspx
|
//! [win64]: http://msdn.microsoft.com/en-us/library/1eyas8tf.aspx
|
||||||
//! [llvm]: http://llvm.org/docs/ExceptionHandling.html#background-on-windows-exceptions
|
//! [llvm]: http://llvm.org/docs/ExceptionHandling.html#background-on-windows-exceptions
|
||||||
|
|
||||||
use sys::c;
|
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
|
// 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.
|
// upper bits are used by the system so we just set them to 0 and ignore them.
|
||||||
// 0x 0 R S T
|
// 0x 0 R S T
|
||||||
const RUST_PANIC: c::DWORD = 0x00525354;
|
const RUST_PANIC: c::DWORD = 0x00525354;
|
||||||
|
|
||||||
pub use self::imp::*;
|
pub unsafe fn panic(data: Box<Any + Send>) -> u32 {
|
||||||
|
|
||||||
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
|
// 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
|
// functions are running, so it's ok to pass stack-local arrays into
|
||||||
// `RaiseException`.
|
// `RaiseException`.
|
||||||
|
@ -86,14 +81,14 @@ mod imp {
|
||||||
let ptrs = mem::transmute::<_, raw::TraitObject>(data);
|
let ptrs = mem::transmute::<_, raw::TraitObject>(data);
|
||||||
let ptrs = [ptrs.data, ptrs.vtable];
|
let ptrs = [ptrs.data, ptrs.vtable];
|
||||||
c::RaiseException(RUST_PANIC, 0, 2, ptrs.as_ptr() as *mut _);
|
c::RaiseException(RUST_PANIC, 0, 2, ptrs.as_ptr() as *mut _);
|
||||||
rtabort!("could not unwind stack");
|
u32::max_value()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn payload() -> [usize; 2] {
|
pub fn payload() -> [usize; 2] {
|
||||||
[0; 2]
|
[0; 2]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn cleanup(payload: [usize; 2]) -> Box<Any + Send + 'static> {
|
pub unsafe fn cleanup(payload: [usize; 2]) -> Box<Any + Send> {
|
||||||
mem::transmute(raw::TraitObject {
|
mem::transmute(raw::TraitObject {
|
||||||
data: payload[0] as *mut _,
|
data: payload[0] as *mut _,
|
||||||
vtable: payload[1] as *mut _,
|
vtable: payload[1] as *mut _,
|
||||||
|
@ -140,7 +135,6 @@ mod imp {
|
||||||
(**payload)[1] = record.ExceptionInformation[1] as usize;
|
(**payload)[1] = record.ExceptionInformation[1] as usize;
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// This is required by the compiler to exist (e.g. it's a lang item), but
|
// 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
|
// it's never actually called by the compiler because __C_specific_handler
|
||||||
|
@ -149,5 +143,5 @@ mod imp {
|
||||||
#[lang = "eh_personality"]
|
#[lang = "eh_personality"]
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
fn rust_eh_personality() {
|
fn rust_eh_personality() {
|
||||||
unsafe { ::intrinsics::abort() }
|
unsafe { intrinsics::abort() }
|
||||||
}
|
}
|
|
@ -14,13 +14,12 @@
|
||||||
#![allow(bad_style)]
|
#![allow(bad_style)]
|
||||||
#![allow(private_no_mangle_fns)]
|
#![allow(private_no_mangle_fns)]
|
||||||
|
|
||||||
use prelude::v1::*;
|
use alloc::boxed::Box;
|
||||||
|
|
||||||
use any::Any;
|
use core::any::Any;
|
||||||
use sys_common::dwarf::eh;
|
use core::intrinsics;
|
||||||
use core::mem;
|
use dwarf::eh;
|
||||||
use core::ptr;
|
use windows as c;
|
||||||
use sys::c;
|
|
||||||
|
|
||||||
// Define our exception codes:
|
// Define our exception codes:
|
||||||
// according to http://msdn.microsoft.com/en-us/library/het71c37(v=VS.80).aspx,
|
// according to http://msdn.microsoft.com/en-us/library/het71c37(v=VS.80).aspx,
|
||||||
|
@ -37,24 +36,24 @@ const RUST_PANIC: c::DWORD = ETYPE | (1 << 24) | MAGIC;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
struct PanicData {
|
struct PanicData {
|
||||||
data: Box<Any + Send + 'static>
|
data: Box<Any + Send>
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn panic(data: Box<Any + Send + 'static>) -> ! {
|
pub unsafe fn panic(data: Box<Any + Send>) -> u32 {
|
||||||
let panic_ctx = Box::new(PanicData { data: data });
|
let panic_ctx = Box::new(PanicData { data: data });
|
||||||
let params = [Box::into_raw(panic_ctx) as c::ULONG_PTR];
|
let params = [Box::into_raw(panic_ctx) as c::ULONG_PTR];
|
||||||
c::RaiseException(RUST_PANIC,
|
c::RaiseException(RUST_PANIC,
|
||||||
c::EXCEPTION_NONCONTINUABLE,
|
c::EXCEPTION_NONCONTINUABLE,
|
||||||
params.len() as c::DWORD,
|
params.len() as c::DWORD,
|
||||||
¶ms as *const c::ULONG_PTR);
|
¶ms as *const c::ULONG_PTR);
|
||||||
rtabort!("could not unwind stack");
|
u32::max_value()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn payload() -> *mut u8 {
|
pub fn payload() -> *mut u8 {
|
||||||
0 as *mut u8
|
0 as *mut u8
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn cleanup(ptr: *mut u8) -> Box<Any + Send + 'static> {
|
pub unsafe fn cleanup(ptr: *mut u8) -> Box<Any + Send> {
|
||||||
let panic_ctx = Box::from_raw(ptr as *mut PanicData);
|
let panic_ctx = Box::from_raw(ptr as *mut PanicData);
|
||||||
return panic_ctx.data;
|
return panic_ctx.data;
|
||||||
}
|
}
|
||||||
|
@ -115,14 +114,12 @@ unsafe extern fn rust_eh_personality(
|
||||||
er.ExceptionInformation[0] as c::LPVOID, // pointer to PanicData
|
er.ExceptionInformation[0] as c::LPVOID, // pointer to PanicData
|
||||||
contextRecord,
|
contextRecord,
|
||||||
dc.HistoryTable);
|
dc.HistoryTable);
|
||||||
rtabort!("could not unwind");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
c::ExceptionContinueSearch
|
c::ExceptionContinueSearch
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(test))]
|
|
||||||
#[lang = "eh_unwind_resume"]
|
#[lang = "eh_unwind_resume"]
|
||||||
#[unwind]
|
#[unwind]
|
||||||
unsafe extern fn rust_eh_unwind_resume(panic_ctx: c::LPVOID) -> ! {
|
unsafe extern fn rust_eh_unwind_resume(panic_ctx: c::LPVOID) -> ! {
|
||||||
|
@ -131,7 +128,7 @@ unsafe extern fn rust_eh_unwind_resume(panic_ctx: c::LPVOID) -> ! {
|
||||||
c::EXCEPTION_NONCONTINUABLE,
|
c::EXCEPTION_NONCONTINUABLE,
|
||||||
params.len() as c::DWORD,
|
params.len() as c::DWORD,
|
||||||
¶ms as *const c::ULONG_PTR);
|
¶ms as *const c::ULONG_PTR);
|
||||||
rtabort!("could not resume unwind");
|
intrinsics::abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn find_landing_pad(dc: &c::DISPATCHER_CONTEXT) -> Option<usize> {
|
unsafe fn find_landing_pad(dc: &c::DISPATCHER_CONTEXT) -> Option<usize> {
|
96
src/libpanic_unwind/windows.rs
Normal file
96
src/libpanic_unwind/windows.rs
Normal file
|
@ -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);
|
||||||
|
}
|
|
@ -31,6 +31,7 @@ use hir::def_id::{DefId, DefIndex};
|
||||||
use mir::repr::Mir;
|
use mir::repr::Mir;
|
||||||
use mir::mir_map::MirMap;
|
use mir::mir_map::MirMap;
|
||||||
use session::Session;
|
use session::Session;
|
||||||
|
use session::config::PanicStrategy;
|
||||||
use session::search_paths::PathKind;
|
use session::search_paths::PathKind;
|
||||||
use util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap};
|
use util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap};
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
|
@ -222,6 +223,8 @@ pub trait CrateStore<'tcx> : Any {
|
||||||
fn is_staged_api(&self, cnum: ast::CrateNum) -> bool;
|
fn is_staged_api(&self, cnum: ast::CrateNum) -> bool;
|
||||||
fn is_explicitly_linked(&self, cnum: ast::CrateNum) -> bool;
|
fn is_explicitly_linked(&self, cnum: ast::CrateNum) -> bool;
|
||||||
fn is_allocator(&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 extern_crate(&self, cnum: ast::CrateNum) -> Option<ExternCrate>;
|
||||||
fn crate_attrs(&self, cnum: ast::CrateNum) -> Vec<ast::Attribute>;
|
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
|
/// The name of the crate as it is referred to in source code of the current
|
||||||
|
@ -408,6 +411,10 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
|
||||||
fn is_staged_api(&self, cnum: ast::CrateNum) -> bool { bug!("is_staged_api") }
|
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_explicitly_linked(&self, cnum: ast::CrateNum) -> bool { bug!("is_explicitly_linked") }
|
||||||
fn is_allocator(&self, cnum: ast::CrateNum) -> bool { bug!("is_allocator") }
|
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 extern_crate(&self, cnum: ast::CrateNum) -> Option<ExternCrate> { bug!("extern_crate") }
|
||||||
fn crate_attrs(&self, cnum: ast::CrateNum) -> Vec<ast::Attribute>
|
fn crate_attrs(&self, cnum: ast::CrateNum) -> Vec<ast::Attribute>
|
||||||
{ bug!("crate_attrs") }
|
{ bug!("crate_attrs") }
|
||||||
|
|
|
@ -64,7 +64,7 @@
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
|
|
||||||
use session;
|
use session;
|
||||||
use session::config;
|
use session::config::{self, PanicStrategy};
|
||||||
use middle::cstore::LinkagePreference::{self, RequireStatic, RequireDynamic};
|
use middle::cstore::LinkagePreference::{self, RequireStatic, RequireDynamic};
|
||||||
use util::nodemap::FnvHashMap;
|
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
|
// 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.
|
// artifact which means that we may need to inject dependencies of some
|
||||||
// No allocator may have been required or linked so far, so activate one
|
// form.
|
||||||
// here if one isn't set.
|
//
|
||||||
activate_allocator(sess, &mut ret);
|
// 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.
|
// 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
|
// It could be the case, however, that the rlib for A is present (hence we
|
||||||
|
@ -270,42 +275,44 @@ fn attempt_static(sess: &session::Session) -> Option<DependencyList> {
|
||||||
}
|
}
|
||||||
}).collect::<Vec<_>>();
|
}).collect::<Vec<_>>();
|
||||||
|
|
||||||
// Our allocator may not have been activated as it's not flagged with
|
// Our allocator/panic runtime may not have been linked above if it wasn't
|
||||||
// explicitly_linked, so flag it here if necessary.
|
// explicitly linked, which is the case for any injected dependency. Handle
|
||||||
activate_allocator(sess, &mut ret);
|
// 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)
|
Some(ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Given a list of how to link upstream dependencies so far, ensure that an
|
// 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
|
// injected dependency is activated. This will not do anything if one was
|
||||||
// included already (e.g. via a dylib or explicitly so).
|
// transitively included already (e.g. via a dylib or explicitly so).
|
||||||
//
|
//
|
||||||
// If an allocator was not found then we're guaranteed the metadata::creader
|
// If an injected dependency was not found then we're guaranteed the
|
||||||
// module has injected an allocator dependency (not listed as a required
|
// metadata::creader module has injected that dependency (not listed as
|
||||||
// dependency) in the session's `injected_allocator` field. If this field is not
|
// a required dependency) in one of the session's field. If this field is not
|
||||||
// set then this compilation doesn't actually need an allocator and we can also
|
// set then this compilation doesn't actually need the dependency and we can
|
||||||
// skip this step entirely.
|
// also skip this step entirely.
|
||||||
fn activate_allocator(sess: &session::Session, list: &mut DependencyList) {
|
fn activate_injected_dep(injected: Option<ast::CrateNum>,
|
||||||
let mut allocator_found = false;
|
list: &mut DependencyList,
|
||||||
|
replaces_injected: &Fn(ast::CrateNum) -> bool) {
|
||||||
for (i, slot) in list.iter().enumerate() {
|
for (i, slot) in list.iter().enumerate() {
|
||||||
let cnum = (i + 1) as ast::CrateNum;
|
let cnum = (i + 1) as ast::CrateNum;
|
||||||
if !sess.cstore.is_allocator(cnum) {
|
if !replaces_injected(cnum) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if let Linkage::NotLinked = *slot {
|
if *slot != Linkage::NotLinked {
|
||||||
continue
|
return
|
||||||
}
|
}
|
||||||
allocator_found = true;
|
|
||||||
}
|
}
|
||||||
if !allocator_found {
|
if let Some(injected) = injected {
|
||||||
if let Some(injected_allocator) = sess.injected_allocator.get() {
|
let idx = injected as usize - 1;
|
||||||
let idx = injected_allocator as usize - 1;
|
|
||||||
assert_eq!(list[idx], Linkage::NotLinked);
|
assert_eq!(list[idx], Linkage::NotLinked);
|
||||||
list[idx] = Linkage::Static;
|
list[idx] = Linkage::Static;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// After the linkage for a crate has been determined we need to verify that
|
// After the linkage for a crate has been determined we need to verify that
|
||||||
// there's only going to be one allocator in the output.
|
// there's only going to be one allocator in the output.
|
||||||
|
@ -314,16 +321,15 @@ fn verify_ok(sess: &session::Session, list: &[Linkage]) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let mut allocator = None;
|
let mut allocator = None;
|
||||||
|
let mut panic_runtime = None;
|
||||||
for (i, linkage) in list.iter().enumerate() {
|
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 {
|
if let Linkage::NotLinked = *linkage {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if let Some(prev_alloc) = allocator {
|
let cnum = (i + 1) as ast::CrateNum;
|
||||||
let prev_name = sess.cstore.crate_name(prev_alloc);
|
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);
|
let cur_name = sess.cstore.crate_name(cnum);
|
||||||
sess.err(&format!("cannot link together two \
|
sess.err(&format!("cannot link together two \
|
||||||
allocators: {} and {}",
|
allocators: {} and {}",
|
||||||
|
@ -331,4 +337,59 @@ fn verify_ok(sess: &session::Session, list: &[Linkage]) {
|
||||||
}
|
}
|
||||||
allocator = Some(cnum);
|
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()));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
//! Validity checking for weak lang items
|
//! Validity checking for weak lang items
|
||||||
|
|
||||||
use session::config;
|
use session::config::{self, PanicStrategy};
|
||||||
use session::Session;
|
use session::Session;
|
||||||
use middle::lang_items;
|
use middle::lang_items;
|
||||||
|
|
||||||
|
@ -75,7 +75,9 @@ fn verify(sess: &Session, items: &lang_items::LanguageItems) {
|
||||||
config::CrateTypeRlib => false,
|
config::CrateTypeRlib => false,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if !needs_check { return }
|
if !needs_check {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
let mut missing = HashSet::new();
|
let mut missing = HashSet::new();
|
||||||
for cnum in sess.cstore.crates() {
|
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: `{}`",
|
sess.err(&format!("language item required, but not found: `{}`",
|
||||||
stringify!($name)));
|
stringify!($name)));
|
||||||
|
|
||||||
|
|
|
@ -317,6 +317,21 @@ impl Passes {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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
|
/// 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
|
/// 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
|
/// programmatically used by the option parser in order to initialize the struct
|
||||||
|
@ -402,11 +417,13 @@ macro_rules! options {
|
||||||
Some("a space-separated list of passes, or `all`");
|
Some("a space-separated list of passes, or `all`");
|
||||||
pub const parse_opt_uint: Option<&'static str> =
|
pub const parse_opt_uint: Option<&'static str> =
|
||||||
Some("a number");
|
Some("a number");
|
||||||
|
pub const parse_panic_strategy: Option<&'static str> =
|
||||||
|
Some("either `panic` or `abort`");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
mod $mod_set {
|
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 {
|
pub fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool {
|
||||||
|
@ -510,6 +527,15 @@ macro_rules! options {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options,
|
||||||
"explicitly enable the cfg(debug_assertions) directive"),
|
"explicitly enable the cfg(debug_assertions) directive"),
|
||||||
inline_threshold: Option<usize> = (None, parse_opt_uint,
|
inline_threshold: Option<usize> = (None, parse_opt_uint,
|
||||||
"set the inlining threshold for"),
|
"set the inlining threshold for"),
|
||||||
|
panic: PanicStrategy = (PanicStrategy::Unwind, parse_panic_strategy,
|
||||||
|
"panic strategy to compile crate with"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ use lint;
|
||||||
use middle::cstore::CrateStore;
|
use middle::cstore::CrateStore;
|
||||||
use middle::dependency_format;
|
use middle::dependency_format;
|
||||||
use session::search_paths::PathKind;
|
use session::search_paths::PathKind;
|
||||||
|
use session::config::PanicStrategy;
|
||||||
use ty::tls;
|
use ty::tls;
|
||||||
use util::nodemap::{NodeMap, FnvHashMap};
|
use util::nodemap::{NodeMap, FnvHashMap};
|
||||||
use mir::transform as mir_pass;
|
use mir::transform as mir_pass;
|
||||||
|
@ -82,9 +83,11 @@ pub struct Session {
|
||||||
/// operations such as auto-dereference and monomorphization.
|
/// operations such as auto-dereference and monomorphization.
|
||||||
pub recursion_limit: Cell<usize>,
|
pub recursion_limit: Cell<usize>,
|
||||||
|
|
||||||
/// The metadata::creader module may inject an allocator dependency if it
|
/// The metadata::creader module may inject an allocator/panic_runtime
|
||||||
/// didn't already find one, and this tracks what was injected.
|
/// dependency if it didn't already find one, and this tracks what was
|
||||||
|
/// injected.
|
||||||
pub injected_allocator: Cell<Option<ast::CrateNum>>,
|
pub injected_allocator: Cell<Option<ast::CrateNum>>,
|
||||||
|
pub injected_panic_runtime: Cell<Option<ast::CrateNum>>,
|
||||||
|
|
||||||
/// Names of all bang-style macros and syntax extensions
|
/// Names of all bang-style macros and syntax extensions
|
||||||
/// available in this crate
|
/// available in this crate
|
||||||
|
@ -295,7 +298,8 @@ impl Session {
|
||||||
self.opts.cg.lto
|
self.opts.cg.lto
|
||||||
}
|
}
|
||||||
pub fn no_landing_pads(&self) -> bool {
|
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 {
|
pub fn unstable_options(&self) -> bool {
|
||||||
self.opts.debugging_opts.unstable_options
|
self.opts.debugging_opts.unstable_options
|
||||||
|
@ -502,6 +506,7 @@ pub fn build_session_(sopts: config::Options,
|
||||||
recursion_limit: Cell::new(64),
|
recursion_limit: Cell::new(64),
|
||||||
next_node_id: Cell::new(1),
|
next_node_id: Cell::new(1),
|
||||||
injected_allocator: Cell::new(None),
|
injected_allocator: Cell::new(None),
|
||||||
|
injected_panic_runtime: Cell::new(None),
|
||||||
available_macros: RefCell::new(HashSet::new()),
|
available_macros: RefCell::new(HashSet::new()),
|
||||||
imported_macro_spans: RefCell::new(HashMap::new()),
|
imported_macro_spans: RefCell::new(HashMap::new()),
|
||||||
};
|
};
|
||||||
|
|
|
@ -250,3 +250,5 @@ pub fn rustc_version() -> String {
|
||||||
option_env!("CFG_VERSION").unwrap_or("unknown version")
|
option_env!("CFG_VERSION").unwrap_or("unknown version")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const tag_panic_strategy: usize = 0x114;
|
||||||
|
|
|
@ -20,6 +20,7 @@ use loader::{self, CratePaths};
|
||||||
use rustc::hir::svh::Svh;
|
use rustc::hir::svh::Svh;
|
||||||
use rustc::dep_graph::{DepGraph, DepNode};
|
use rustc::dep_graph::{DepGraph, DepNode};
|
||||||
use rustc::session::{config, Session};
|
use rustc::session::{config, Session};
|
||||||
|
use rustc::session::config::PanicStrategy;
|
||||||
use rustc::session::search_paths::PathKind;
|
use rustc::session::search_paths::PathKind;
|
||||||
use rustc::middle::cstore::{CrateStore, validate_crate_name, ExternCrate};
|
use rustc::middle::cstore::{CrateStore, validate_crate_name, ExternCrate};
|
||||||
use rustc::util::nodemap::FnvHashMap;
|
use rustc::util::nodemap::FnvHashMap;
|
||||||
|
@ -630,6 +631,85 @@ impl<'a> CrateReader<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
fn inject_allocator_crate(&mut self) {
|
||||||
// Make sure that we actually need an allocator, if none of our
|
// Make sure that we actually need an allocator, if none of our
|
||||||
// dependencies need one then we definitely don't!
|
// dependencies need one then we definitely don't!
|
||||||
|
@ -641,8 +721,9 @@ impl<'a> CrateReader<'a> {
|
||||||
self.cstore.iter_crate_data(|cnum, data| {
|
self.cstore.iter_crate_data(|cnum, data| {
|
||||||
needs_allocator = needs_allocator || data.needs_allocator();
|
needs_allocator = needs_allocator || data.needs_allocator();
|
||||||
if data.is_allocator() {
|
if data.is_allocator() {
|
||||||
debug!("{} required by rlib and is an allocator", data.name());
|
info!("{} required by rlib and is an allocator", data.name());
|
||||||
self.inject_allocator_dependency(cnum);
|
self.inject_dependency_if(cnum, "an allocator",
|
||||||
|
&|data| data.needs_allocator());
|
||||||
found_required_allocator = found_required_allocator ||
|
found_required_allocator = found_required_allocator ||
|
||||||
data.explicitly_linked.get();
|
data.explicitly_linked.get();
|
||||||
}
|
}
|
||||||
|
@ -692,58 +773,68 @@ impl<'a> CrateReader<'a> {
|
||||||
codemap::DUMMY_SP,
|
codemap::DUMMY_SP,
|
||||||
PathKind::Crate, false);
|
PathKind::Crate, false);
|
||||||
|
|
||||||
// To ensure that the `-Z allocation-crate=foo` option isn't abused, and
|
// Sanity check the crate we loaded to ensure that it is indeed an
|
||||||
// to ensure that the allocator is indeed an allocator, we verify that
|
// allocator.
|
||||||
// the crate loaded here is indeed tagged #![allocator].
|
|
||||||
if !data.is_allocator() {
|
if !data.is_allocator() {
|
||||||
self.sess.err(&format!("the allocator crate `{}` is not tagged \
|
self.sess.err(&format!("the allocator crate `{}` is not tagged \
|
||||||
with #![allocator]", data.name()));
|
with #![allocator]", data.name()));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.sess.injected_allocator.set(Some(cnum));
|
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,
|
||||||
// Before we inject any dependencies, make sure we don't inject a
|
krate: ast::CrateNum,
|
||||||
// circular dependency by validating that this allocator crate doesn't
|
what: &str,
|
||||||
// transitively depend on any `#![needs_allocator]` crates.
|
needs_dep: &Fn(&cstore::crate_metadata) -> bool) {
|
||||||
validate(self, allocator, allocator);
|
// don't perform this validation if the session has errors, as one of
|
||||||
|
// those errors may indicate a circular dependency which could cause
|
||||||
// All crates tagged with `needs_allocator` do not explicitly depend on
|
// this to stack overflow.
|
||||||
// the allocator selected for this compile, but in order for this
|
if self.sess.has_errors() {
|
||||||
// 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.
|
|
||||||
self.cstore.iter_crate_data(|cnum, data| {
|
|
||||||
if !data.needs_allocator() {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
info!("injecting a dep from {} to {}", cnum, allocator);
|
// Before we inject any dependencies, make sure we don't inject a
|
||||||
|
// 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 !needs_dep(data) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
info!("injecting a dep from {} to {}", cnum, krate);
|
||||||
let mut cnum_map = data.cnum_map.borrow_mut();
|
let mut cnum_map = data.cnum_map.borrow_mut();
|
||||||
let remote_cnum = cnum_map.len() + 1;
|
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());
|
assert!(prev.is_none());
|
||||||
});
|
});
|
||||||
|
|
||||||
fn validate(me: &CrateReader, krate: ast::CrateNum,
|
fn validate(me: &CrateReader,
|
||||||
allocator: ast::CrateNum) {
|
krate: ast::CrateNum,
|
||||||
|
root: ast::CrateNum,
|
||||||
|
what: &str,
|
||||||
|
needs_dep: &Fn(&cstore::crate_metadata) -> bool) {
|
||||||
let data = me.cstore.get_crate_data(krate);
|
let data = me.cstore.get_crate_data(krate);
|
||||||
if data.needs_allocator() {
|
if needs_dep(&data) {
|
||||||
let krate_name = data.name();
|
let krate_name = data.name();
|
||||||
let data = me.cstore.get_crate_data(allocator);
|
let data = me.cstore.get_crate_data(root);
|
||||||
let alloc_name = data.name();
|
let root_name = data.name();
|
||||||
me.sess.err(&format!("the allocator crate `{}` cannot depend \
|
me.sess.err(&format!("the crate `{}` cannot depend \
|
||||||
on a crate that needs an allocator, but \
|
on a crate that needs {}, but \
|
||||||
it depends on `{}`", alloc_name,
|
it depends on `{}`", root_name, what,
|
||||||
krate_name));
|
krate_name));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (_, &dep) in data.cnum_map.borrow().iter() {
|
for (_, &dep) in data.cnum_map.borrow().iter() {
|
||||||
validate(me, dep, allocator);
|
validate(me, dep, root, what, needs_dep);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -774,6 +865,7 @@ impl<'a> LocalCrateReader<'a> {
|
||||||
self.process_crate(self.krate);
|
self.process_crate(self.krate);
|
||||||
visit::walk_crate(self, self.krate);
|
visit::walk_crate(self, self.krate);
|
||||||
self.creader.inject_allocator_crate();
|
self.creader.inject_allocator_crate();
|
||||||
|
self.creader.inject_panic_runtime(self.krate);
|
||||||
|
|
||||||
if log_enabled!(log::INFO) {
|
if log_enabled!(log::INFO) {
|
||||||
dump_crates(&self.cstore);
|
dump_crates(&self.cstore);
|
||||||
|
|
|
@ -24,6 +24,7 @@ use rustc::hir::map as hir_map;
|
||||||
use rustc::mir::repr::Mir;
|
use rustc::mir::repr::Mir;
|
||||||
use rustc::mir::mir_map::MirMap;
|
use rustc::mir::mir_map::MirMap;
|
||||||
use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap};
|
use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap};
|
||||||
|
use rustc::session::config::PanicStrategy;
|
||||||
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
@ -306,6 +307,15 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
|
||||||
self.get_crate_data(cnum).is_allocator()
|
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>
|
fn crate_attrs(&self, cnum: ast::CrateNum) -> Vec<ast::Attribute>
|
||||||
{
|
{
|
||||||
decoder::get_crate_attributes(self.get_crate_data(cnum).data())
|
decoder::get_crate_attributes(self.get_crate_data(cnum).data())
|
||||||
|
|
|
@ -23,6 +23,7 @@ use loader;
|
||||||
use rustc::hir::def_id::DefId;
|
use rustc::hir::def_id::DefId;
|
||||||
use rustc::hir::svh::Svh;
|
use rustc::hir::svh::Svh;
|
||||||
use rustc::middle::cstore::{ExternCrate};
|
use rustc::middle::cstore::{ExternCrate};
|
||||||
|
use rustc::session::config::PanicStrategy;
|
||||||
use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap};
|
use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap};
|
||||||
|
|
||||||
use std::cell::{RefCell, Ref, Cell};
|
use std::cell::{RefCell, Ref, Cell};
|
||||||
|
@ -281,6 +282,20 @@ impl crate_metadata {
|
||||||
let attrs = decoder::get_crate_attributes(self.data());
|
let attrs = decoder::get_crate_attributes(self.data());
|
||||||
attr::contains_name(&attrs, "needs_allocator")
|
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 {
|
impl MetadataBlob {
|
||||||
|
|
|
@ -27,6 +27,7 @@ use rustc::hir::svh::Svh;
|
||||||
use rustc::hir::map as hir_map;
|
use rustc::hir::map as hir_map;
|
||||||
use rustc::util::nodemap::FnvHashMap;
|
use rustc::util::nodemap::FnvHashMap;
|
||||||
use rustc::hir;
|
use rustc::hir;
|
||||||
|
use rustc::session::config::PanicStrategy;
|
||||||
|
|
||||||
use middle::cstore::{LOCAL_CRATE, FoundAst, InlinedItem, LinkagePreference};
|
use middle::cstore::{LOCAL_CRATE, FoundAst, InlinedItem, LinkagePreference};
|
||||||
use middle::cstore::{DefLike, DlDef, DlField, DlImpl, tls};
|
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);
|
debug!("def_path(id={:?})", id);
|
||||||
hir_map::DefPath::make(cdata.cnum, id, |parent| def_key(cdata, parent))
|
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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ use rustc::ty::util::IntTypeExt;
|
||||||
|
|
||||||
use rustc::hir::svh::Svh;
|
use rustc::hir::svh::Svh;
|
||||||
use rustc::mir::mir_map::MirMap;
|
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::util::nodemap::{FnvHashMap, NodeMap, NodeSet};
|
||||||
|
|
||||||
use rustc_serialize::Encodable;
|
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.
|
// NB: Increment this as you change the metadata encoding version.
|
||||||
#[allow(non_upper_case_globals)]
|
#[allow(non_upper_case_globals)]
|
||||||
pub const metadata_encoding_version : &'static [u8] = &[b'r', b'u', b's', b't', 0, 0, 0, 2 ];
|
pub const metadata_encoding_version : &'static [u8] = &[b'r', b'u', b's', b't', 0, 0, 0, 2 ];
|
||||||
|
@ -1915,6 +1926,7 @@ fn encode_metadata_inner(rbml_w: &mut Encoder,
|
||||||
encode_hash(rbml_w, &ecx.link_meta.crate_hash);
|
encode_hash(rbml_w, &ecx.link_meta.crate_hash);
|
||||||
encode_crate_disambiguator(rbml_w, &ecx.tcx.sess.crate_disambiguator.get().as_str());
|
encode_crate_disambiguator(rbml_w, &ecx.tcx.sess.crate_disambiguator.get().as_str());
|
||||||
encode_dylib_dependency_formats(rbml_w, &ecx);
|
encode_dylib_dependency_formats(rbml_w, &ecx);
|
||||||
|
encode_panic_strategy(rbml_w, &ecx);
|
||||||
|
|
||||||
let mut i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
|
let mut i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
|
||||||
encode_attributes(rbml_w, &krate.attrs);
|
encode_attributes(rbml_w, &krate.attrs);
|
||||||
|
|
|
@ -1829,7 +1829,9 @@ pub fn trans_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
let _icx = push_ctxt("trans_closure");
|
let _icx = push_ctxt("trans_closure");
|
||||||
|
if !ccx.sess().no_landing_pads() {
|
||||||
attributes::emit_uwtable(llfndecl, true);
|
attributes::emit_uwtable(llfndecl, true);
|
||||||
|
}
|
||||||
|
|
||||||
debug!("trans_closure(..., {})", instance);
|
debug!("trans_closure(..., {})", instance);
|
||||||
|
|
||||||
|
|
|
@ -14,11 +14,14 @@ test = false
|
||||||
alloc = { path = "../liballoc" }
|
alloc = { path = "../liballoc" }
|
||||||
alloc_jemalloc = { path = "../liballoc_jemalloc", optional = true }
|
alloc_jemalloc = { path = "../liballoc_jemalloc", optional = true }
|
||||||
alloc_system = { path = "../liballoc_system" }
|
alloc_system = { path = "../liballoc_system" }
|
||||||
|
panic_unwind = { path = "../libpanic_unwind" }
|
||||||
|
panic_abort = { path = "../libpanic_abort" }
|
||||||
collections = { path = "../libcollections" }
|
collections = { path = "../libcollections" }
|
||||||
core = { path = "../libcore" }
|
core = { path = "../libcore" }
|
||||||
libc = { path = "../rustc/libc_shim" }
|
libc = { path = "../rustc/libc_shim" }
|
||||||
rand = { path = "../librand" }
|
rand = { path = "../librand" }
|
||||||
rustc_unicode = { path = "../librustc_unicode" }
|
rustc_unicode = { path = "../librustc_unicode" }
|
||||||
|
unwind = { path = "../libunwind" }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
build_helper = { path = "../build_helper" }
|
build_helper = { path = "../build_helper" }
|
||||||
|
|
|
@ -28,9 +28,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if target.contains("linux") {
|
if target.contains("linux") {
|
||||||
if target.contains("musl") && (target.contains("x86_64") || target.contains("i686")) {
|
if target.contains("android") {
|
||||||
println!("cargo:rustc-link-lib=static=unwind");
|
|
||||||
} else if target.contains("android") {
|
|
||||||
println!("cargo:rustc-link-lib=dl");
|
println!("cargo:rustc-link-lib=dl");
|
||||||
println!("cargo:rustc-link-lib=log");
|
println!("cargo:rustc-link-lib=log");
|
||||||
println!("cargo:rustc-link-lib=gcc");
|
println!("cargo:rustc-link-lib=gcc");
|
||||||
|
@ -38,27 +36,13 @@ fn main() {
|
||||||
println!("cargo:rustc-link-lib=dl");
|
println!("cargo:rustc-link-lib=dl");
|
||||||
println!("cargo:rustc-link-lib=rt");
|
println!("cargo:rustc-link-lib=rt");
|
||||||
println!("cargo:rustc-link-lib=pthread");
|
println!("cargo:rustc-link-lib=pthread");
|
||||||
println!("cargo:rustc-link-lib=gcc_s");
|
|
||||||
}
|
}
|
||||||
} else if target.contains("freebsd") {
|
} else if target.contains("freebsd") {
|
||||||
println!("cargo:rustc-link-lib=execinfo");
|
println!("cargo:rustc-link-lib=execinfo");
|
||||||
println!("cargo:rustc-link-lib=pthread");
|
println!("cargo:rustc-link-lib=pthread");
|
||||||
println!("cargo:rustc-link-lib=gcc_s");
|
|
||||||
} else if target.contains("dragonfly") || target.contains("bitrig") ||
|
} else if target.contains("dragonfly") || target.contains("bitrig") ||
|
||||||
target.contains("netbsd") || target.contains("openbsd") {
|
target.contains("netbsd") || target.contains("openbsd") {
|
||||||
println!("cargo:rustc-link-lib=pthread");
|
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") {
|
} else if target.contains("apple-darwin") {
|
||||||
println!("cargo:rustc-link-lib=System");
|
println!("cargo:rustc-link-lib=System");
|
||||||
} else if target.contains("apple-ios") {
|
} 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=Security");
|
||||||
println!("cargo:rustc-link-lib=framework=Foundation");
|
println!("cargo:rustc-link-lib=framework=Foundation");
|
||||||
} else if target.contains("windows") {
|
} 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=advapi32");
|
||||||
println!("cargo:rustc-link-lib=ws2_32");
|
println!("cargo:rustc-link-lib=ws2_32");
|
||||||
println!("cargo:rustc-link-lib=userenv");
|
println!("cargo:rustc-link-lib=userenv");
|
||||||
|
|
|
@ -245,6 +245,7 @@
|
||||||
#![feature(on_unimplemented)]
|
#![feature(on_unimplemented)]
|
||||||
#![feature(oom)]
|
#![feature(oom)]
|
||||||
#![feature(optin_builtin_traits)]
|
#![feature(optin_builtin_traits)]
|
||||||
|
#![feature(panic_unwind)]
|
||||||
#![feature(placement_in_syntax)]
|
#![feature(placement_in_syntax)]
|
||||||
#![feature(rand)]
|
#![feature(rand)]
|
||||||
#![feature(raw)]
|
#![feature(raw)]
|
||||||
|
@ -283,6 +284,13 @@
|
||||||
#![allow(unused_features)] // std may use features in a platform-specific way
|
#![allow(unused_features)] // std may use features in a platform-specific way
|
||||||
#![cfg_attr(not(stage0), deny(warnings))]
|
#![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;
|
#[cfg(test)] extern crate test;
|
||||||
|
|
||||||
// We want to reexport a few macros from core but libcore has already been
|
// We want to reexport a few macros from core but libcore has already been
|
||||||
|
@ -301,6 +309,9 @@ extern crate alloc;
|
||||||
extern crate rustc_unicode;
|
extern crate rustc_unicode;
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
|
|
||||||
|
// We always need an unwinder currently for backtraces
|
||||||
|
extern crate unwind;
|
||||||
|
|
||||||
#[cfg(stage0)]
|
#[cfg(stage0)]
|
||||||
extern crate alloc_system;
|
extern crate alloc_system;
|
||||||
|
|
||||||
|
|
|
@ -17,9 +17,9 @@
|
||||||
/// The entry point for panic of Rust threads.
|
/// The entry point for panic of Rust threads.
|
||||||
///
|
///
|
||||||
/// This macro is used to inject panic into a Rust thread, causing the thread to
|
/// 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
|
/// panic entirely. Each thread's panic can be reaped as the `Box<Any>` type,
|
||||||
/// `Box<Any>` type, and the single-argument form of the `panic!` macro will be
|
/// and the single-argument form of the `panic!` macro will be the value which
|
||||||
/// the value which is transmitted.
|
/// is transmitted.
|
||||||
///
|
///
|
||||||
/// The multi-argument form of this macro panics with a string and has the
|
/// The multi-argument form of this macro panics with a string and has the
|
||||||
/// `format!` syntax for building a string.
|
/// `format!` syntax for building a string.
|
||||||
|
@ -41,14 +41,14 @@ macro_rules! panic {
|
||||||
panic!("explicit panic")
|
panic!("explicit panic")
|
||||||
});
|
});
|
||||||
($msg:expr) => ({
|
($msg:expr) => ({
|
||||||
$crate::rt::begin_unwind($msg, {
|
$crate::rt::begin_panic($msg, {
|
||||||
// static requires less code at runtime, more constant data
|
// static requires less code at runtime, more constant data
|
||||||
static _FILE_LINE: (&'static str, u32) = (file!(), line!());
|
static _FILE_LINE: (&'static str, u32) = (file!(), line!());
|
||||||
&_FILE_LINE
|
&_FILE_LINE
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
($fmt:expr, $($arg:tt)+) => ({
|
($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
|
// The leading _'s are to avoid dead code warnings if this is
|
||||||
// used inside a dead function. Just `#[allow(dead_code)]` is
|
// used inside a dead function. Just `#[allow(dead_code)]` is
|
||||||
// insufficient, since the user may have
|
// insufficient, since the user may have
|
||||||
|
|
|
@ -16,10 +16,10 @@ use any::Any;
|
||||||
use boxed::Box;
|
use boxed::Box;
|
||||||
use cell::UnsafeCell;
|
use cell::UnsafeCell;
|
||||||
use ops::{Deref, DerefMut};
|
use ops::{Deref, DerefMut};
|
||||||
|
use panicking;
|
||||||
use ptr::{Unique, Shared};
|
use ptr::{Unique, Shared};
|
||||||
use rc::Rc;
|
use rc::Rc;
|
||||||
use sync::{Arc, Mutex, RwLock};
|
use sync::{Arc, Mutex, RwLock};
|
||||||
use sys_common::unwind;
|
|
||||||
use thread::Result;
|
use thread::Result;
|
||||||
|
|
||||||
#[unstable(feature = "panic_handler", issue = "30449")]
|
#[unstable(feature = "panic_handler", issue = "30449")]
|
||||||
|
@ -383,12 +383,9 @@ impl<R, F: FnOnce() -> R> FnOnce<()> for AssertRecoverSafe<F> {
|
||||||
/// ```
|
/// ```
|
||||||
#[stable(feature = "catch_unwind", since = "1.9.0")]
|
#[stable(feature = "catch_unwind", since = "1.9.0")]
|
||||||
pub fn catch_unwind<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> {
|
pub fn catch_unwind<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> {
|
||||||
let mut result = None;
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let result = &mut result;
|
panicking::try(f)
|
||||||
unwind::try(move || *result = Some(f()))?
|
|
||||||
}
|
}
|
||||||
Ok(result.unwrap())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deprecated, renamed to `catch_unwind`
|
/// 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")]
|
#[stable(feature = "resume_unwind", since = "1.9.0")]
|
||||||
pub fn resume_unwind(payload: Box<Any + Send>) -> ! {
|
pub fn resume_unwind(payload: Box<Any + Send>) -> ! {
|
||||||
unwind::rust_panic(payload)
|
panicking::rust_panic(payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deprecated, use resume_unwind instead
|
/// Deprecated, use resume_unwind instead
|
||||||
|
|
|
@ -8,13 +8,25 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// 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 prelude::v1::*;
|
||||||
use io::prelude::*;
|
use io::prelude::*;
|
||||||
|
|
||||||
use any::Any;
|
use any::Any;
|
||||||
use cell::Cell;
|
use cell::Cell;
|
||||||
use cell::RefCell;
|
use cell::RefCell;
|
||||||
|
use fmt;
|
||||||
use intrinsics;
|
use intrinsics;
|
||||||
|
use mem;
|
||||||
|
use raw;
|
||||||
use sync::StaticRwLock;
|
use sync::StaticRwLock;
|
||||||
use sync::atomic::{AtomicBool, Ordering};
|
use sync::atomic::{AtomicBool, Ordering};
|
||||||
use sys::stdio::Stderr;
|
use sys::stdio::Stderr;
|
||||||
|
@ -23,14 +35,33 @@ use sys_common::thread_info;
|
||||||
use sys_common::util;
|
use sys_common::util;
|
||||||
use thread;
|
use thread;
|
||||||
|
|
||||||
thread_local! { pub static PANIC_COUNT: Cell<usize> = Cell::new(0) }
|
|
||||||
|
|
||||||
thread_local! {
|
thread_local! {
|
||||||
pub static LOCAL_STDERR: RefCell<Option<Box<Write + Send>>> = {
|
pub static LOCAL_STDERR: RefCell<Option<Box<Write + Send>>> = {
|
||||||
RefCell::new(None)
|
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)]
|
#[derive(Copy, Clone)]
|
||||||
enum Hook {
|
enum Hook {
|
||||||
Default,
|
Default,
|
||||||
|
@ -57,7 +88,7 @@ static FIRST_PANIC: AtomicBool = AtomicBool::new(true);
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// Panics if called from a panicking thread.
|
/// 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>) {
|
pub fn set_hook(hook: Box<Fn(&PanicInfo) + 'static + Sync + Send>) {
|
||||||
if thread::panicking() {
|
if thread::panicking() {
|
||||||
panic!("cannot modify the panic hook from a panicking thread");
|
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
|
||||||
///
|
///
|
||||||
/// Panics if called from a panicking thread.
|
/// 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> {
|
pub fn take_hook() -> Box<Fn(&PanicInfo) + 'static + Sync + Send> {
|
||||||
if thread::panicking() {
|
if thread::panicking() {
|
||||||
panic!("cannot modify the panic hook from a panicking thread");
|
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.
|
/// 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> {
|
pub struct PanicInfo<'a> {
|
||||||
payload: &'a (Any + Send),
|
payload: &'a (Any + Send),
|
||||||
location: Location<'a>,
|
location: Location<'a>,
|
||||||
|
@ -112,7 +143,7 @@ impl<'a> PanicInfo<'a> {
|
||||||
/// Returns the payload associated with the panic.
|
/// Returns the payload associated with the panic.
|
||||||
///
|
///
|
||||||
/// This will commonly, but not always, be a `&'static str` or `String`.
|
/// 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) {
|
pub fn payload(&self) -> &(Any + Send) {
|
||||||
self.payload
|
self.payload
|
||||||
}
|
}
|
||||||
|
@ -122,14 +153,14 @@ impl<'a> PanicInfo<'a> {
|
||||||
///
|
///
|
||||||
/// This method will currently always return `Some`, but this may change
|
/// This method will currently always return `Some`, but this may change
|
||||||
/// in future versions.
|
/// in future versions.
|
||||||
#[unstable(feature = "panic_handler", reason = "awaiting feedback", issue = "30449")]
|
#[unstable(feature = "panic_handler", issue = "30449")]
|
||||||
pub fn location(&self) -> Option<&Location> {
|
pub fn location(&self) -> Option<&Location> {
|
||||||
Some(&self.location)
|
Some(&self.location)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A struct containing information about the location of a panic.
|
/// 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> {
|
pub struct Location<'a> {
|
||||||
file: &'a str,
|
file: &'a str,
|
||||||
line: u32,
|
line: u32,
|
||||||
|
@ -137,20 +168,20 @@ pub struct Location<'a> {
|
||||||
|
|
||||||
impl<'a> Location<'a> {
|
impl<'a> Location<'a> {
|
||||||
/// Returns the name of the source file from which the panic originated.
|
/// 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 {
|
pub fn file(&self) -> &str {
|
||||||
self.file
|
self.file
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the line number from which the panic originated.
|
/// 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 {
|
pub fn line(&self) -> u32 {
|
||||||
self.line
|
self.line
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_hook(info: &PanicInfo) {
|
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
|
// If this is a double panic, make sure that we print a backtrace
|
||||||
// for this panic. Otherwise only print it if logging is enabled.
|
// 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) {
|
/// Invoke a closure, capturing the cause of an unwinding panic if one occurs.
|
||||||
let panics = PANIC_COUNT.with(|s| {
|
pub unsafe fn try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<Any + Send>> {
|
||||||
let count = s.get() + 1;
|
let mut slot = None;
|
||||||
s.set(count);
|
let mut f = Some(f);
|
||||||
count
|
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 _,
|
||||||
|
}))
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// If this is the third nested call, on_panic triggered the last panic,
|
return ret.map(|()| {
|
||||||
// otherwise the double-panic check would have aborted the process.
|
slot.take().unwrap()
|
||||||
// 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.
|
fn get_call<F: FnMut()>(_: &mut F) -> fn(&mut F) {
|
||||||
if panics >= 3 {
|
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 \
|
util::dumb_print(format_args!("thread panicked while processing \
|
||||||
panic. aborting.\n"));
|
panic. aborting.\n"));
|
||||||
unsafe { intrinsics::abort() }
|
unsafe { intrinsics::abort() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
let info = PanicInfo {
|
let info = PanicInfo {
|
||||||
payload: obj,
|
payload: &*msg,
|
||||||
location: Location {
|
location: Location {
|
||||||
file: file,
|
file: file,
|
||||||
line: line,
|
line: line,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
unsafe {
|
|
||||||
let _lock = HOOK_LOCK.read();
|
let _lock = HOOK_LOCK.read();
|
||||||
match HOOK {
|
match HOOK {
|
||||||
Hook::Default => default_hook(&info),
|
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
|
// If a thread panics while it's already unwinding then we
|
||||||
// have limited options. Currently our preference is to
|
// have limited options. Currently our preference is to
|
||||||
// just abort. In the future we may consider resuming
|
// 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"));
|
aborting.\n"));
|
||||||
unsafe { intrinsics::abort() }
|
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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,12 +25,10 @@
|
||||||
|
|
||||||
|
|
||||||
// Reexport some of our utilities which are expected by other crates.
|
// 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.
|
#[cfg(stage0)]
|
||||||
// Since sys_common isn't public, we have to re-export them here.
|
pub use panicking::begin_panic as begin_unwind;
|
||||||
#[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))]
|
|
||||||
pub use sys_common::unwind::imp::eh_frame_registry::*;
|
|
||||||
|
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
#[lang = "start"]
|
#[lang = "start"]
|
||||||
|
|
|
@ -30,9 +30,7 @@ pub mod args;
|
||||||
pub mod at_exit_imp;
|
pub mod at_exit_imp;
|
||||||
pub mod backtrace;
|
pub mod backtrace;
|
||||||
pub mod condvar;
|
pub mod condvar;
|
||||||
pub mod dwarf;
|
|
||||||
pub mod io;
|
pub mod io;
|
||||||
pub mod libunwind;
|
|
||||||
pub mod mutex;
|
pub mod mutex;
|
||||||
pub mod net;
|
pub mod net;
|
||||||
pub mod poison;
|
pub mod poison;
|
||||||
|
@ -41,7 +39,6 @@ pub mod rwlock;
|
||||||
pub mod thread;
|
pub mod thread;
|
||||||
pub mod thread_info;
|
pub mod thread_info;
|
||||||
pub mod thread_local;
|
pub mod thread_local;
|
||||||
pub mod unwind;
|
|
||||||
pub mod util;
|
pub mod util;
|
||||||
pub mod wtf8;
|
pub mod wtf8;
|
||||||
|
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -15,6 +15,7 @@ use mem;
|
||||||
use sync::StaticMutex;
|
use sync::StaticMutex;
|
||||||
|
|
||||||
use super::super::printing::print;
|
use super::super::printing::print;
|
||||||
|
use unwind as uw;
|
||||||
|
|
||||||
#[inline(never)] // if we know this is a function call, we can skip it when
|
#[inline(never)] // if we know this is a function call, we can skip it when
|
||||||
// tracing
|
// tracing
|
||||||
|
@ -102,126 +103,3 @@ pub fn write(w: &mut Write) -> io::Result<()> {
|
||||||
uw::_URC_NO_REASON
|
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -277,21 +277,6 @@ pub const CRYPT_VERIFYCONTEXT: DWORD = 0xF0000000;
|
||||||
pub const EXCEPTION_CONTINUE_SEARCH: LONG = 0;
|
pub const EXCEPTION_CONTINUE_SEARCH: LONG = 0;
|
||||||
pub const EXCEPTION_STACK_OVERFLOW: DWORD = 0xc00000fd;
|
pub const EXCEPTION_STACK_OVERFLOW: DWORD = 0xc00000fd;
|
||||||
pub const EXCEPTION_MAXIMUM_PARAMETERS: usize = 15;
|
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 PIPE_ACCESS_INBOUND: DWORD = 0x00000001;
|
||||||
pub const FILE_FLAG_FIRST_PIPE_INSTANCE: DWORD = 0x00080000;
|
pub const FILE_FLAG_FIRST_PIPE_INSTANCE: DWORD = 0x00080000;
|
||||||
|
@ -813,31 +798,6 @@ pub struct in6_addr {
|
||||||
pub s6_addr: [u8; 16],
|
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)]
|
#[repr(C)]
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
#[allow(dead_code)] // we only use some variants
|
#[allow(dead_code)] // we only use some variants
|
||||||
|
@ -1113,19 +1073,6 @@ extern "system" {
|
||||||
pbBuffer: *mut BYTE) -> BOOL;
|
pbBuffer: *mut BYTE) -> BOOL;
|
||||||
pub fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> 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 GetSystemTimeAsFileTime(lpSystemTimeAsFileTime: LPFILETIME);
|
||||||
|
|
||||||
pub fn CreateEventW(lpEventAttributes: LPSECURITY_ATTRIBUTES,
|
pub fn CreateEventW(lpEventAttributes: LPSECURITY_ATTRIBUTES,
|
||||||
|
|
|
@ -163,14 +163,15 @@ use prelude::v1::*;
|
||||||
|
|
||||||
use any::Any;
|
use any::Any;
|
||||||
use cell::UnsafeCell;
|
use cell::UnsafeCell;
|
||||||
|
use ffi::{CStr, CString};
|
||||||
use fmt;
|
use fmt;
|
||||||
use io;
|
use io;
|
||||||
|
use panic;
|
||||||
|
use panicking;
|
||||||
use str;
|
use str;
|
||||||
use ffi::{CStr, CString};
|
|
||||||
use sync::{Mutex, Condvar, Arc};
|
use sync::{Mutex, Condvar, Arc};
|
||||||
use sys::thread as imp;
|
use sys::thread as imp;
|
||||||
use sys_common::thread_info;
|
use sys_common::thread_info;
|
||||||
use sys_common::unwind;
|
|
||||||
use sys_common::util;
|
use sys_common::util;
|
||||||
use sys_common::{AsInner, IntoInner};
|
use sys_common::{AsInner, IntoInner};
|
||||||
use time::Duration;
|
use time::Duration;
|
||||||
|
@ -273,14 +274,8 @@ impl Builder {
|
||||||
}
|
}
|
||||||
unsafe {
|
unsafe {
|
||||||
thread_info::set(imp::guard::current(), their_thread);
|
thread_info::set(imp::guard::current(), their_thread);
|
||||||
let mut output = None;
|
let try_result = panic::catch_unwind(panic::AssertUnwindSafe(f));
|
||||||
let try_result = {
|
*their_packet.get() = Some(try_result);
|
||||||
let ptr = &mut output;
|
|
||||||
unwind::try(move || *ptr = Some(f()))
|
|
||||||
};
|
|
||||||
*their_packet.get() = Some(try_result.map(|()| {
|
|
||||||
output.unwrap()
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -337,7 +332,7 @@ pub fn yield_now() {
|
||||||
#[inline]
|
#[inline]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub fn panicking() -> bool {
|
pub fn panicking() -> bool {
|
||||||
unwind::panicking()
|
panicking::panicking()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Puts the current thread to sleep for the specified amount of time.
|
/// Puts the current thread to sleep for the specified amount of time.
|
||||||
|
|
|
@ -755,7 +755,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
|
||||||
let expr_file_line_ptr = self.expr_addr_of(span, expr_file_line_tuple);
|
let expr_file_line_ptr = self.expr_addr_of(span, expr_file_line_tuple);
|
||||||
self.expr_call_global(
|
self.expr_call_global(
|
||||||
span,
|
span,
|
||||||
self.std_path(&["rt", "begin_unwind"]),
|
self.std_path(&["rt", "begin_panic"]),
|
||||||
vec!(
|
vec!(
|
||||||
self.expr_str(span, msg),
|
self.expr_str(span, msg),
|
||||||
expr_file_line_ptr))
|
expr_file_line_ptr))
|
||||||
|
|
|
@ -141,6 +141,8 @@ declare_features! (
|
||||||
(active, simd_ffi, "1.0.0", Some(27731)),
|
(active, simd_ffi, "1.0.0", Some(27731)),
|
||||||
(active, start, "1.0.0", Some(29633)),
|
(active, start, "1.0.0", Some(29633)),
|
||||||
(active, structural_match, "1.8.0", Some(31434)),
|
(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
|
// OIBIT specific features
|
||||||
(active, optin_builtin_traits, "1.0.0", Some(13231)),
|
(active, optin_builtin_traits, "1.0.0", Some(13231)),
|
||||||
|
@ -435,6 +437,15 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGat
|
||||||
attribute is an experimental \
|
attribute is an experimental \
|
||||||
feature",
|
feature",
|
||||||
cfg_fn!(needs_allocator))),
|
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",
|
("rustc_variance", Normal, Gated("rustc_attrs",
|
||||||
"the `#[rustc_variance]` attribute \
|
"the `#[rustc_variance]` attribute \
|
||||||
is just used for rustc unit tests \
|
is just used for rustc unit tests \
|
||||||
|
|
|
@ -41,10 +41,12 @@
|
||||||
#![feature(set_stdio)]
|
#![feature(set_stdio)]
|
||||||
#![feature(staged_api)]
|
#![feature(staged_api)]
|
||||||
#![feature(question_mark)]
|
#![feature(question_mark)]
|
||||||
|
#![feature(panic_unwind)]
|
||||||
|
|
||||||
extern crate getopts;
|
extern crate getopts;
|
||||||
extern crate term;
|
extern crate term;
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
|
extern crate panic_unwind;
|
||||||
|
|
||||||
pub use self::TestFn::*;
|
pub use self::TestFn::*;
|
||||||
pub use self::ColorConfig::*;
|
pub use self::ColorConfig::*;
|
||||||
|
|
13
src/libunwind/Cargo.toml
Normal file
13
src/libunwind/Cargo.toml
Normal file
|
@ -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" }
|
39
src/libunwind/build.rs
Normal file
39
src/libunwind/build.rs
Normal file
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
30
src/libunwind/lib.rs
Normal file
30
src/libunwind/lib.rs
Normal file
|
@ -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::*;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
|
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||||
// file at the top-level directory of this distribution and at
|
// file at the top-level directory of this distribution and at
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
//
|
//
|
||||||
|
@ -8,12 +8,9 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
//! Unwind library interface
|
#![allow(bad_style)]
|
||||||
|
|
||||||
#![allow(non_upper_case_globals)]
|
use libc;
|
||||||
#![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"))]
|
#[cfg(any(not(target_arch = "arm"), target_os = "ios"))]
|
||||||
pub use self::_Unwind_Action::*;
|
pub use self::_Unwind_Action::*;
|
||||||
|
@ -21,11 +18,9 @@ pub use self::_Unwind_Action::*;
|
||||||
pub use self::_Unwind_State::*;
|
pub use self::_Unwind_State::*;
|
||||||
pub use self::_Unwind_Reason_Code::*;
|
pub use self::_Unwind_Reason_Code::*;
|
||||||
|
|
||||||
use libc;
|
|
||||||
|
|
||||||
#[cfg(any(not(target_arch = "arm"), target_os = "ios"))]
|
#[cfg(any(not(target_arch = "arm"), target_os = "ios"))]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum _Unwind_Action {
|
pub enum _Unwind_Action {
|
||||||
_UA_SEARCH_PHASE = 1,
|
_UA_SEARCH_PHASE = 1,
|
||||||
_UA_CLEANUP_PHASE = 2,
|
_UA_CLEANUP_PHASE = 2,
|
||||||
|
@ -36,7 +31,7 @@ pub enum _Unwind_Action {
|
||||||
|
|
||||||
#[cfg(target_arch = "arm")]
|
#[cfg(target_arch = "arm")]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum _Unwind_State {
|
pub enum _Unwind_State {
|
||||||
_US_VIRTUAL_UNWIND_FRAME = 0,
|
_US_VIRTUAL_UNWIND_FRAME = 0,
|
||||||
_US_UNWIND_FRAME_STARTING = 1,
|
_US_UNWIND_FRAME_STARTING = 1,
|
||||||
|
@ -47,7 +42,6 @@ pub enum _Unwind_State {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub enum _Unwind_Reason_Code {
|
pub enum _Unwind_Reason_Code {
|
||||||
_URC_NO_REASON = 0,
|
_URC_NO_REASON = 0,
|
||||||
_URC_FOREIGN_EXCEPTION_CAUGHT = 1,
|
_URC_FOREIGN_EXCEPTION_CAUGHT = 1,
|
||||||
|
@ -65,6 +59,10 @@ pub type _Unwind_Exception_Class = u64;
|
||||||
|
|
||||||
pub type _Unwind_Word = libc::uintptr_t;
|
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")]
|
#[cfg(target_arch = "x86")]
|
||||||
pub const unwinder_private_data_size: usize = 5;
|
pub const unwinder_private_data_size: usize = 5;
|
||||||
|
|
||||||
|
@ -128,7 +126,10 @@ pub type _Unwind_Exception_Cleanup_Fn =
|
||||||
link(name = "c++abi"))]
|
link(name = "c++abi"))]
|
||||||
#[cfg_attr(all(target_os = "windows", target_env = "gnu"),
|
#[cfg_attr(all(target_os = "windows", target_env = "gnu"),
|
||||||
link(name = "gcc_eh"))]
|
link(name = "gcc_eh"))]
|
||||||
extern "C" {
|
#[cfg(not(cargobuild))]
|
||||||
|
extern {}
|
||||||
|
|
||||||
|
extern {
|
||||||
// iOS on armv7 uses SjLj exceptions and requires to link
|
// iOS on armv7 uses SjLj exceptions and requires to link
|
||||||
// against corresponding routine (..._SjLj_...)
|
// against corresponding routine (..._SjLj_...)
|
||||||
#[cfg(not(all(target_os = "ios", target_arch = "arm")))]
|
#[cfg(not(all(target_os = "ios", target_arch = "arm")))]
|
||||||
|
@ -145,14 +146,102 @@ extern "C" {
|
||||||
|
|
||||||
#[unwind]
|
#[unwind]
|
||||||
pub fn _Unwind_Resume(exception: *mut _Unwind_Exception) -> !;
|
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
|
// ... and now we just providing access to SjLj counterspart
|
||||||
// through a standard name to hide those details from others
|
// through a standard name to hide those details from others
|
||||||
// (see also comment above regarding _Unwind_RaiseException)
|
// (see also comment above regarding _Unwind_RaiseException)
|
||||||
#[cfg(all(target_os = "ios", target_arch = "arm"))]
|
#[cfg(all(target_os = "ios", target_arch = "arm"))]
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
pub unsafe fn _Unwind_RaiseException(exc: *mut _Unwind_Exception)
|
pub unsafe fn _Unwind_RaiseException(exc: *mut _Unwind_Exception)
|
||||||
-> _Unwind_Reason_Code {
|
-> _Unwind_Reason_Code {
|
||||||
_Unwind_SjLj_RaiseException(exc)
|
_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
|
||||||
|
}
|
54
src/rustc/std_shim/Cargo.lock
generated
54
src/rustc/std_shim/Cargo.lock
generated
|
@ -5,15 +5,6 @@ dependencies = [
|
||||||
"std 0.0.0",
|
"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]]
|
[[package]]
|
||||||
name = "alloc"
|
name = "alloc"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
|
@ -27,7 +18,7 @@ version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"build_helper 0.1.0",
|
"build_helper 0.1.0",
|
||||||
"core 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",
|
"libc 0.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -58,12 +49,8 @@ version = "0.0.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gcc"
|
name = "gcc"
|
||||||
version = "0.3.17"
|
version = "0.3.26"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
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)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
|
@ -72,6 +59,24 @@ dependencies = [
|
||||||
"core 0.0.0",
|
"core 0.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
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]]
|
[[package]]
|
||||||
name = "rand"
|
name = "rand"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
|
@ -96,19 +101,20 @@ dependencies = [
|
||||||
"build_helper 0.1.0",
|
"build_helper 0.1.0",
|
||||||
"collections 0.0.0",
|
"collections 0.0.0",
|
||||||
"core 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",
|
"libc 0.0.0",
|
||||||
|
"panic_abort 0.0.0",
|
||||||
|
"panic_unwind 0.0.0",
|
||||||
"rand 0.0.0",
|
"rand 0.0.0",
|
||||||
"rustc_unicode 0.0.0",
|
"rustc_unicode 0.0.0",
|
||||||
|
"unwind 0.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi"
|
name = "unwind"
|
||||||
version = "0.2.2"
|
version = "0.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
dependencies = [
|
||||||
|
"core 0.0.0",
|
||||||
[[package]]
|
"libc 0.0.0",
|
||||||
name = "winapi-build"
|
]
|
||||||
version = "0.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
|
|
||||||
|
|
31
src/test/codegen/lto-removes-invokes.rs
Normal file
31
src/test/codegen/lto-removes-invokes.rs
Normal file
|
@ -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!");
|
||||||
|
}
|
|
@ -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() {
|
||||||
|
}
|
|
@ -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]
|
|
@ -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() {}
|
|
@ -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() {}
|
|
@ -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() {}
|
|
@ -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() {}
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
14
src/test/compile-fail/panic-runtime/bad-panic-flag1.rs
Normal file
14
src/test/compile-fail/panic-runtime/bad-panic-flag1.rs
Normal file
|
@ -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() {}
|
14
src/test/compile-fail/panic-runtime/bad-panic-flag2.rs
Normal file
14
src/test/compile-fail/panic-runtime/bad-panic-flag2.rs
Normal file
|
@ -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() {}
|
20
src/test/compile-fail/panic-runtime/libtest-unwinds.rs
Normal file
20
src/test/compile-fail/panic-runtime/libtest-unwinds.rs
Normal file
|
@ -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() {
|
||||||
|
}
|
||||||
|
|
14
src/test/compile-fail/panic-runtime/needs-gate.rs
Normal file
14
src/test/compile-fail/panic-runtime/needs-gate.rs
Normal file
|
@ -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() {}
|
|
@ -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;
|
|
@ -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() {}
|
23
src/test/compile-fail/panic-runtime/two-panic-runtimes.rs
Normal file
23
src/test/compile-fail/panic-runtime/two-panic-runtimes.rs
Normal file
|
@ -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() {}
|
17
src/test/compile-fail/panic-runtime/want-abort-got-unwind.rs
Normal file
17
src/test/compile-fail/panic-runtime/want-abort-got-unwind.rs
Normal file
|
@ -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() {}
|
|
@ -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() {}
|
20
src/test/compile-fail/panic-runtime/want-unwind-got-abort.rs
Normal file
20
src/test/compile-fail/panic-runtime/want-unwind-got-abort.rs
Normal file
|
@ -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() {}
|
|
@ -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() {}
|
|
@ -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");
|
||||||
|
}
|
39
src/test/run-pass/panic-runtime/abort.rs
Normal file
39
src/test/run-pass/panic-runtime/abort.rs
Normal file
|
@ -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));
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
19
src/test/run-pass/panic-runtime/link-to-abort.rs
Normal file
19
src/test/run-pass/panic-runtime/link-to-abort.rs
Normal file
|
@ -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() {
|
||||||
|
}
|
18
src/test/run-pass/panic-runtime/link-to-unwind.rs
Normal file
18
src/test/run-pass/panic-runtime/link-to-unwind.rs
Normal file
|
@ -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() {
|
||||||
|
}
|
39
src/test/run-pass/panic-runtime/lto-abort.rs
Normal file
39
src/test/run-pass/panic-runtime/lto-abort.rs
Normal file
|
@ -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));
|
||||||
|
}
|
41
src/test/run-pass/panic-runtime/lto-unwind.rs
Normal file
41
src/test/run-pass/panic-runtime/lto-unwind.rs
Normal file
|
@ -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"));
|
||||||
|
}
|
|
@ -85,6 +85,9 @@ fn verify(tomlfile: &Path, libfile: &Path, bad: &mut bool) {
|
||||||
if krate == "alloc_jemalloc" && toml.contains("name = \"std\"") {
|
if krate == "alloc_jemalloc" && toml.contains("name = \"std\"") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if krate == "panic_abort" && toml.contains("name = \"std\"") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if !librs.contains(&format!("extern crate {}", krate)) {
|
if !librs.contains(&format!("extern crate {}", krate)) {
|
||||||
println!("{} doesn't have `extern crate {}`, but Cargo.toml \
|
println!("{} doesn't have `extern crate {}`, but Cargo.toml \
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue