Auto merge of #30555 - Manishearth:rollup, r=Manishearth

- Successful merges: #30485, #30490, #30513, #30518, #30528, #30545, #30551, #30552
- Failed merges:
This commit is contained in:
bors 2015-12-25 14:27:58 +00:00
commit 5b838c586c
21 changed files with 487 additions and 108 deletions

View File

@ -41,6 +41,7 @@
* `!` (`ident!(…)`, `ident!{…}`, `ident![…]`): denotes macro expansion. See [Macros].
* `!` (`!expr`): bitwise or logical complement. Overloadable (`Not`).
* `!=` (`var != expr`): nonequality comparison. Overloadable (`PartialEq`).
* `%` (`expr % expr`): arithmetic remainder. Overloadable (`Rem`).
* `%=` (`var %= expr`): arithmetic remainder & assignment.
* `&` (`expr & expr`): bitwise and. Overloadable (`BitAnd`).
@ -75,13 +76,13 @@
* `;` (`[…; len]`): part of fixed-size array syntax. See [Primitive Types (Arrays)].
* `<<` (`expr << expr`): left-shift. Overloadable (`Shl`).
* `<<=` (`var <<= expr`): left-shift & assignment.
* `<` (`expr < expr`): less-than comparison. Overloadable (`Cmp`, `PartialCmp`).
* `<=` (`var <= expr`): less-than or equal-to comparison. Overloadable (`Cmp`, `PartialCmp`).
* `<` (`expr < expr`): less-than comparison. Overloadable (`PartialOrd`).
* `<=` (`var <= expr`): less-than or equal-to comparison. Overloadable (`PartialOrd`).
* `=` (`var = expr`, `ident = type`): assignment/equivalence. See [Variable Bindings], [`type` Aliases], generic parameter defaults.
* `==` (`var == expr`): comparison. Overloadable (`Eq`, `PartialEq`).
* `==` (`var == expr`): equality comparison. Overloadable (`PartialEq`).
* `=>` (`pat => expr`): part of match arm syntax. See [Match].
* `>` (`expr > expr`): greater-than comparison. Overloadable (`Cmp`, `PartialCmp`).
* `>=` (`var >= expr`): greater-than or equal-to comparison. Overloadable (`Cmp`, `PartialCmp`).
* `>` (`expr > expr`): greater-than comparison. Overloadable (`PartialOrd`).
* `>=` (`var >= expr`): greater-than or equal-to comparison. Overloadable (`PartialOrd`).
* `>>` (`expr >> expr`): right-shift. Overloadable (`Shr`).
* `>>=` (`var >>= expr`): right-shift & assignment.
* `@` (`ident @ pat`): pattern binding. See [Patterns (Bindings)].

View File

@ -1822,8 +1822,8 @@ unpaired_token
| LIT_FLOAT { $$ = mk_atom(yytext); }
| LIT_STR { $$ = mk_atom(yytext); }
| LIT_STR_RAW { $$ = mk_atom(yytext); }
| LIT_BYTE_STR { $$ = mk_atom(yytext); }
| LIT_BYTE_STR_RAW { $$ = mk_atom(yytext); }
| LIT_BYTE_STR { $$ = mk_atom(yytext); }
| LIT_BYTE_STR_RAW { $$ = mk_atom(yytext); }
| IDENT { $$ = mk_atom(yytext); }
| UNDERSCORE { $$ = mk_atom(yytext); }
| LIFETIME { $$ = mk_atom(yytext); }

View File

@ -839,11 +839,10 @@ pub fn map_crate<'ast>(forest: &'ast mut Forest) -> Map<'ast> {
}
/// Used for items loaded from external crate that are being inlined into this
/// crate. The `path` should be the path to the item but should not include
/// the item itself.
/// crate.
pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>,
path: Vec<PathElem>,
def_path: DefPath,
parent_path: Vec<PathElem>,
parent_def_path: DefPath,
ii: InlinedItem,
fold_ops: F)
-> &'ast InlinedItem {
@ -862,7 +861,7 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>,
};
let ii_parent = map.forest.inlined_items.alloc(InlinedParent {
path: path,
path: parent_path,
ii: ii
});
@ -872,7 +871,7 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>,
map.krate(),
ii_parent,
ii_parent_id,
def_path,
parent_def_path,
mem::replace(&mut *map.map.borrow_mut(), vec![]),
mem::replace(&mut *map.definitions.borrow_mut(), Definitions::new()));
ii_parent.ii.visit(&mut collector);

View File

@ -701,9 +701,9 @@ pub struct Constant<'tcx> {
#[derive(Clone, Copy, Debug, PartialEq, RustcEncodable, RustcDecodable)]
pub enum ItemKind {
Constant,
/// This is any sort of callable (usually those that have a type of `fn(…) -> …`). This
/// includes functions, constructors, but not methods which have their own ItemKind.
Function,
Struct,
Variant,
Method,
}

View File

@ -124,20 +124,20 @@ impl<'a, 'b, 'c, 'tcx> ast_map::FoldOps for &'a DecodeContext<'b, 'c, 'tcx> {
/// ast-map.
pub fn decode_inlined_item<'tcx>(cdata: &cstore::crate_metadata,
tcx: &ty::ctxt<'tcx>,
path: Vec<ast_map::PathElem>,
def_path: ast_map::DefPath,
parent_path: Vec<ast_map::PathElem>,
parent_def_path: ast_map::DefPath,
par_doc: rbml::Doc,
orig_did: DefId)
-> Result<&'tcx InlinedItem, (Vec<ast_map::PathElem>,
ast_map::DefPath)> {
match par_doc.opt_child(c::tag_ast) {
None => Err((path, def_path)),
None => Err((parent_path, parent_def_path)),
Some(ast_doc) => {
let mut path_as_str = None;
debug!("> Decoding inlined fn: {:?}::?",
{
// Do an Option dance to use the path after it is moved below.
let s = ast_map::path_to_string(path.iter().cloned());
let s = ast_map::path_to_string(parent_path.iter().cloned());
path_as_str = Some(s);
path_as_str.as_ref().map(|x| &x[..])
});
@ -152,8 +152,11 @@ pub fn decode_inlined_item<'tcx>(cdata: &cstore::crate_metadata,
last_filemap_index: Cell::new(0)
};
let raw_ii = decode_ast(ast_doc);
let ii = ast_map::map_decoded_item(&dcx.tcx.map, path, def_path, raw_ii, dcx);
let ii = ast_map::map_decoded_item(&dcx.tcx.map,
parent_path,
parent_def_path,
raw_ii,
dcx);
let name = match *ii {
InlinedItem::Item(ref i) => i.name,
InlinedItem::Foreign(ref i) => i.name,

View File

@ -763,29 +763,54 @@ pub fn get_item_name(intr: &IdentInterner, cdata: Cmd, id: DefIndex) -> ast::Nam
pub type DecodeInlinedItem<'a> =
Box<for<'tcx> FnMut(Cmd,
&ty::ctxt<'tcx>,
Vec<hir_map::PathElem>,
hir_map::DefPath,
Vec<hir_map::PathElem>, // parent_path
hir_map::DefPath, // parent_def_path
rbml::Doc,
DefId)
-> Result<&'tcx InlinedItem, (Vec<hir_map::PathElem>,
hir_map::DefPath)> + 'a>;
pub fn maybe_get_item_ast<'tcx>(cdata: Cmd, tcx: &ty::ctxt<'tcx>, id: DefIndex,
pub fn maybe_get_item_ast<'tcx>(cdata: Cmd,
tcx: &ty::ctxt<'tcx>,
id: DefIndex,
mut decode_inlined_item: DecodeInlinedItem)
-> FoundAst<'tcx> {
debug!("Looking up item: {:?}", id);
let item_doc = cdata.lookup_item(id);
let item_did = item_def_id(item_doc, cdata);
let path = item_path(item_doc).split_last().unwrap().1.to_vec();
let def_path = def_path(cdata, id);
match decode_inlined_item(cdata, tcx, path, def_path, item_doc, item_did) {
let parent_path = {
let mut path = item_path(item_doc);
path.pop();
path
};
let parent_def_path = {
let mut def_path = def_path(cdata, id);
def_path.pop();
def_path
};
match decode_inlined_item(cdata,
tcx,
parent_path,
parent_def_path,
item_doc,
item_did) {
Ok(ii) => FoundAst::Found(ii),
Err((path, def_path)) => {
Err((mut parent_path, mut parent_def_path)) => {
match item_parent_item(cdata, item_doc) {
Some(did) => {
let parent_item = cdata.lookup_item(did.index);
match decode_inlined_item(cdata, tcx, path, def_path, parent_item, did) {
Ok(ii) => FoundAst::FoundParent(did, ii),
Some(parent_did) => {
// Remove the last element from the paths, since we are now
// trying to inline the parent.
parent_path.pop();
parent_def_path.pop();
let parent_item = cdata.lookup_item(parent_did.index);
match decode_inlined_item(cdata,
tcx,
parent_path,
parent_def_path,
parent_item,
parent_did) {
Ok(ii) => FoundAst::FoundParent(parent_did, ii),
Err(_) => FoundAst::NotFound
}
}

View File

@ -519,51 +519,51 @@ fn convert_path_expr<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, expr: &'tcx hir::Expr)
let substs = cx.tcx.mk_substs(cx.tcx.node_id_item_substs(expr.id).substs);
// Otherwise there may be def_map borrow conflicts
let def = cx.tcx.def_map.borrow()[&expr.id].full_def();
match def {
def::DefVariant(_, def_id, false) |
def::DefStruct(def_id) |
def::DefFn(def_id, _) |
def::DefMethod(def_id) => {
let kind = match def {
def::DefVariant(..) => ItemKind::Variant,
def::DefStruct(..) => ItemKind::Struct,
def::DefFn(..) => ItemKind::Function,
def::DefMethod(..) => ItemKind::Method,
_ => panic!()
};
ExprKind::Literal {
literal: Literal::Item { def_id: def_id, kind: kind, substs: substs }
let (def_id, kind) = match def {
// A variant constructor.
def::DefVariant(_, def_id, false) => (def_id, ItemKind::Function),
// A regular function.
def::DefFn(def_id, _) => (def_id, ItemKind::Function),
def::DefMethod(def_id) => (def_id, ItemKind::Method),
def::DefStruct(def_id) => {
match cx.tcx.node_id_to_type(expr.id).sty {
// A tuple-struct constructor.
ty::TyBareFn(..) => (def_id, ItemKind::Function),
// This is a special case: a unit struct which is used as a value. We return a
// completely different ExprKind here to account for this special case.
ty::TyStruct(adt_def, substs) => return ExprKind::Adt {
adt_def: adt_def,
variant_index: 0,
substs: substs,
fields: vec![],
base: None
},
ref sty => panic!("unexpected sty: {:?}", sty)
}
},
def::DefConst(def_id) |
def::DefAssociatedConst(def_id) => {
if let Some(v) = cx.try_const_eval_literal(expr) {
ExprKind::Literal { literal: v }
return ExprKind::Literal { literal: v };
} else {
ExprKind::Literal {
literal: Literal::Item {
def_id: def_id,
kind: ItemKind::Constant,
substs: substs
}
}
(def_id, ItemKind::Constant)
}
}
def::DefStatic(node_id, _) =>
ExprKind::StaticRef {
id: node_id,
},
def::DefStatic(node_id, _) => return ExprKind::StaticRef {
id: node_id,
},
def @ def::DefLocal(..) |
def @ def::DefUpvar(..) =>
convert_var(cx, expr, def),
def @ def::DefUpvar(..) => return convert_var(cx, expr, def),
def =>
cx.tcx.sess.span_bug(
expr.span,
&format!("def `{:?}` not yet implemented", def)),
};
ExprKind::Literal {
literal: Literal::Item { def_id: def_id, kind: kind, substs: substs }
}
}

View File

@ -39,9 +39,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
did: DefId)
-> OperandRef<'tcx> {
match kind {
ItemKind::Function |
ItemKind::Struct |
ItemKind::Variant => self.trans_fn_ref(bcx, ty, substs, did),
ItemKind::Function => self.trans_fn_ref(bcx, ty, substs, did),
ItemKind::Method => match bcx.tcx().impl_or_trait_item(did).container() {
ty::ImplContainer(_) => self.trans_fn_ref(bcx, ty, substs, did),
ty::TraitContainer(tdid) => self.trans_static_method(bcx, ty, did, tdid, substs)

View File

@ -19,6 +19,7 @@ use trans::common::{self, Block, Result};
use trans::debuginfo::DebugLoc;
use trans::declare;
use trans::expr;
use trans::adt;
use trans::machine;
use trans::type_::Type;
use trans::type_of;
@ -26,21 +27,22 @@ use trans::tvec;
use super::MirContext;
use super::operand::{OperandRef, OperandValue};
use super::lvalue::LvalueRef;
impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
pub fn trans_rvalue(&mut self,
bcx: Block<'bcx, 'tcx>,
lldest: ValueRef,
dest: LvalueRef<'tcx>,
rvalue: &mir::Rvalue<'tcx>)
-> Block<'bcx, 'tcx>
{
debug!("trans_rvalue(lldest={}, rvalue={:?})",
bcx.val_to_string(lldest),
debug!("trans_rvalue(dest.llval={}, rvalue={:?})",
bcx.val_to_string(dest.llval),
rvalue);
match *rvalue {
mir::Rvalue::Use(ref operand) => {
self.trans_operand_into(bcx, lldest, operand);
self.trans_operand_into(bcx, dest.llval, operand);
bcx
}
@ -49,7 +51,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
// into-coerce of a thin pointer to a fat pointer - just
// use the operand path.
let (bcx, temp) = self.trans_rvalue_operand(bcx, rvalue);
self.store_operand(bcx, lldest, temp);
self.store_operand(bcx, dest.llval, temp);
return bcx;
}
@ -72,12 +74,12 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
base::store_ty(bcx, llval, lltemp, operand.ty);
base::coerce_unsized_into(bcx,
lltemp, operand.ty,
lldest, cast_ty);
dest.llval, cast_ty);
}
OperandValue::Ref(llref) => {
base::coerce_unsized_into(bcx,
llref, operand.ty,
lldest, cast_ty);
dest.llval, cast_ty);
}
}
bcx
@ -86,20 +88,31 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
mir::Rvalue::Repeat(ref elem, ref count) => {
let elem = self.trans_operand(bcx, elem);
let size = self.trans_constant(bcx, count).immediate();
let base = expr::get_dataptr(bcx, lldest);
let base = expr::get_dataptr(bcx, dest.llval);
tvec::iter_vec_raw(bcx, base, elem.ty, size, |bcx, llslot, _| {
self.store_operand(bcx, llslot, elem);
bcx
})
}
mir::Rvalue::Aggregate(_, ref operands) => {
for (i, operand) in operands.iter().enumerate() {
// Note: perhaps this should be StructGep, but
// note that in some cases the values here will
// not be structs but arrays.
let lldest_i = build::GEPi(bcx, lldest, &[0, i]);
self.trans_operand_into(bcx, lldest_i, operand);
mir::Rvalue::Aggregate(ref kind, ref operands) => {
match *kind {
// Unit struct, which is translated very differently compared to any other
// aggregate
mir::AggregateKind::Adt(adt_def, 0, _)
if adt_def.struct_variant().kind() == ty::VariantKind::Unit => {
let repr = adt::represent_type(bcx.ccx(), dest.ty.to_ty(bcx.tcx()));
adt::trans_set_discr(bcx, &*repr, dest.llval, 0);
},
_ => {
for (i, operand) in operands.iter().enumerate() {
// Note: perhaps this should be StructGep, but
// note that in some cases the values here will
// not be structs but arrays.
let lldest_i = build::GEPi(bcx, dest.llval, &[0, i]);
self.trans_operand_into(bcx, lldest_i, operand);
}
}
}
bcx
}
@ -113,9 +126,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
let llbase1 = build::GEPi(bcx, llbase, &[from_start]);
let adj = common::C_uint(ccx, from_start + from_end);
let lllen1 = build::Sub(bcx, lllen, adj, DebugLoc::None);
let lladdrdest = expr::get_dataptr(bcx, lldest);
let lladdrdest = expr::get_dataptr(bcx, dest.llval);
build::Store(bcx, llbase1, lladdrdest);
let llmetadest = expr::get_meta(bcx, lldest);
let llmetadest = expr::get_meta(bcx, dest.llval);
build::Store(bcx, lllen1, llmetadest);
bcx
}
@ -127,7 +140,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
_ => {
assert!(rvalue_creates_operand(rvalue));
let (bcx, temp) = self.trans_rvalue_operand(bcx, rvalue);
self.store_operand(bcx, lldest, temp);
self.store_operand(bcx, dest.llval, temp);
bcx
}
}

View File

@ -31,7 +31,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
let index = index as usize;
match self.temps[index as usize] {
TempRef::Lvalue(tr_dest) => {
self.trans_rvalue(bcx, tr_dest.llval, rvalue)
self.trans_rvalue(bcx, tr_dest, rvalue)
}
TempRef::Operand(None) => {
let (bcx, operand) = self.trans_rvalue_operand(bcx, rvalue);
@ -47,7 +47,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
}
_ => {
let tr_dest = self.trans_lvalue(bcx, lvalue);
self.trans_rvalue(bcx, tr_dest.llval, rvalue)
self.trans_rvalue(bcx, tr_dest, rvalue)
}
}
}

View File

@ -21,6 +21,8 @@ use sync::{Arc, Mutex, RwLock};
use sys_common::unwind;
use thread::Result;
pub use panicking::{take_handler, set_handler, PanicInfo, Location};
/// A marker trait which represents "panic safe" types in Rust.
///
/// This trait is implemented by default for many types and behaves similarly in
@ -99,8 +101,11 @@ use thread::Result;
across a recover boundary"]
pub trait RecoverSafe {}
/// A marker trait representing types which do not contain an `UnsafeCell` by
/// value internally.
/// A marker trait representing types where a shared reference is considered
/// recover safe.
///
/// This trait is namely not implemented by `UnsafeCell`, the root of all
/// interior mutability.
///
/// This is a "helper marker trait" used to provide impl blocks for the
/// `RecoverSafe` trait, for more information see that documentation.
@ -108,7 +113,7 @@ pub trait RecoverSafe {}
#[rustc_on_unimplemented = "the type {Self} contains interior mutability \
and a reference may not be safely transferrable \
across a recover boundary"]
pub trait NoUnsafeCell {}
pub trait RefRecoverSafe {}
/// A simple wrapper around a type to assert that it is panic safe.
///
@ -157,11 +162,11 @@ pub struct AssertRecoverSafe<T>(T);
// * Our custom AssertRecoverSafe wrapper is indeed recover safe
impl RecoverSafe for .. {}
impl<'a, T: ?Sized> !RecoverSafe for &'a mut T {}
impl<'a, T: NoUnsafeCell + ?Sized> RecoverSafe for &'a T {}
impl<T: NoUnsafeCell + ?Sized> RecoverSafe for *const T {}
impl<T: NoUnsafeCell + ?Sized> RecoverSafe for *mut T {}
impl<'a, T: RefRecoverSafe + ?Sized> RecoverSafe for &'a T {}
impl<T: RefRecoverSafe + ?Sized> RecoverSafe for *const T {}
impl<T: RefRecoverSafe + ?Sized> RecoverSafe for *mut T {}
impl<T: RecoverSafe> RecoverSafe for Unique<T> {}
impl<T: NoUnsafeCell + ?Sized> RecoverSafe for Shared<T> {}
impl<T: RefRecoverSafe + ?Sized> RecoverSafe for Shared<T> {}
impl<T: ?Sized> RecoverSafe for Mutex<T> {}
impl<T: ?Sized> RecoverSafe for RwLock<T> {}
impl<T> RecoverSafe for AssertRecoverSafe<T> {}
@ -169,15 +174,16 @@ impl<T> RecoverSafe for AssertRecoverSafe<T> {}
// not covered via the Shared impl above b/c the inner contents use
// Cell/AtomicUsize, but the usage here is recover safe so we can lift the
// impl up one level to Arc/Rc itself
impl<T: NoUnsafeCell + ?Sized> RecoverSafe for Rc<T> {}
impl<T: NoUnsafeCell + ?Sized> RecoverSafe for Arc<T> {}
impl<T: RefRecoverSafe + ?Sized> RecoverSafe for Rc<T> {}
impl<T: RefRecoverSafe + ?Sized> RecoverSafe for Arc<T> {}
// Pretty simple implementations for the `NoUnsafeCell` marker trait, basically
// just saying that this is a marker trait and `UnsafeCell` is the only thing
// which doesn't implement it (which then transitively applies to everything
// else.
impl NoUnsafeCell for .. {}
impl<T: ?Sized> !NoUnsafeCell for UnsafeCell<T> {}
// Pretty simple implementations for the `RefRecoverSafe` marker trait,
// basically just saying that this is a marker trait and `UnsafeCell` is the
// only thing which doesn't implement it (which then transitively applies to
// everything else.
impl RefRecoverSafe for .. {}
impl<T: ?Sized> !RefRecoverSafe for UnsafeCell<T> {}
impl<T> RefRecoverSafe for AssertRecoverSafe<T> {}
impl<T> AssertRecoverSafe<T> {
/// Creates a new `AssertRecoverSafe` wrapper around the provided type.

View File

@ -15,10 +15,12 @@ use any::Any;
use cell::Cell;
use cell::RefCell;
use intrinsics;
use sync::StaticRwLock;
use sys::stdio::Stderr;
use sys_common::backtrace;
use sys_common::thread_info;
use sys_common::util;
use thread;
thread_local! { pub static PANIC_COUNT: Cell<usize> = Cell::new(0) }
@ -28,11 +30,138 @@ thread_local! {
}
}
fn log_panic(obj: &(Any+Send), file: &'static str, line: u32,
log_backtrace: bool) {
let msg = match obj.downcast_ref::<&'static str>() {
#[derive(Copy, Clone)]
enum Handler {
Default,
Custom(*mut (Fn(&PanicInfo) + 'static + Sync + Send)),
}
static HANDLER_LOCK: StaticRwLock = StaticRwLock::new();
static mut HANDLER: Handler = Handler::Default;
/// Registers a custom panic handler, replacing any that was previously
/// registered.
///
/// The panic handler is invoked when a thread panics, but before it begins
/// unwinding the stack. The default handler prints a message to standard error
/// and generates a backtrace if requested, but this behavior can be customized
/// with the `set_handler` and `take_handler` functions.
///
/// The handler is provided with a `PanicInfo` struct which contains information
/// about the origin of the panic, including the payload passed to `panic!` and
/// the source code location from which the panic originated.
///
/// The panic handler is a global resource.
///
/// # Panics
///
/// Panics if called from a panicking thread.
#[unstable(feature = "panic_handler", reason = "awaiting feedback", issue = "30449")]
pub fn set_handler<F>(handler: F) where F: Fn(&PanicInfo) + 'static + Sync + Send {
if thread::panicking() {
panic!("cannot modify the panic handler from a panicking thread");
}
let handler = Box::new(handler);
unsafe {
let lock = HANDLER_LOCK.write();
let old_handler = HANDLER;
HANDLER = Handler::Custom(Box::into_raw(handler));
drop(lock);
if let Handler::Custom(ptr) = old_handler {
Box::from_raw(ptr);
}
}
}
/// Unregisters the current panic handler, returning it.
///
/// If no custom handler is registered, the default handler will be returned.
///
/// # Panics
///
/// Panics if called from a panicking thread.
#[unstable(feature = "panic_handler", reason = "awaiting feedback", issue = "30449")]
pub fn take_handler() -> Box<Fn(&PanicInfo) + 'static + Sync + Send> {
if thread::panicking() {
panic!("cannot modify the panic handler from a panicking thread");
}
unsafe {
let lock = HANDLER_LOCK.write();
let handler = HANDLER;
HANDLER = Handler::Default;
drop(lock);
match handler {
Handler::Default => Box::new(default_handler),
Handler::Custom(ptr) => {Box::from_raw(ptr)} // FIXME #30530
}
}
}
/// A struct providing information about a panic.
#[unstable(feature = "panic_handler", reason = "awaiting feedback", issue = "30449")]
pub struct PanicInfo<'a> {
payload: &'a (Any + Send),
location: Location<'a>,
}
impl<'a> PanicInfo<'a> {
/// Returns the payload associated with the panic.
///
/// This will commonly, but not always, be a `&'static str` or `String`.
#[unstable(feature = "panic_handler", reason = "awaiting feedback", issue = "30449")]
pub fn payload(&self) -> &(Any + Send) {
self.payload
}
/// Returns information about the location from which the panic originated,
/// if available.
///
/// This method will currently always return `Some`, but this may change
/// in future versions.
#[unstable(feature = "panic_handler", reason = "awaiting feedback", issue = "30449")]
pub fn location(&self) -> Option<&Location> {
Some(&self.location)
}
}
/// A struct containing information about the location of a panic.
#[unstable(feature = "panic_handler", reason = "awaiting feedback", issue = "30449")]
pub struct Location<'a> {
file: &'a str,
line: u32,
}
impl<'a> Location<'a> {
/// Returns the name of the source file from which the panic originated.
#[unstable(feature = "panic_handler", reason = "awaiting feedback", issue = "30449")]
pub fn file(&self) -> &str {
self.file
}
/// Returns the line number from which the panic originated.
#[unstable(feature = "panic_handler", reason = "awaiting feedback", issue = "30449")]
pub fn line(&self) -> u32 {
self.line
}
}
fn default_handler(info: &PanicInfo) {
let panics = PANIC_COUNT.with(|s| s.get());
// If this is a double panic, make sure that we print a backtrace
// for this panic. Otherwise only print it if logging is enabled.
let log_backtrace = panics >= 2 || backtrace::log_enabled();
let file = info.location.file;
let line = info.location.line;
let msg = match info.payload.downcast_ref::<&'static str>() {
Some(s) => *s,
None => match obj.downcast_ref::<String>() {
None => match info.payload.downcast_ref::<String>() {
Some(s) => &s[..],
None => "Box<Any>",
}
@ -81,10 +210,21 @@ pub fn on_panic(obj: &(Any+Send), file: &'static str, line: u32) {
unsafe { intrinsics::abort() }
}
// If this is a double panic, make sure that we print a backtrace
// for this panic. Otherwise only print it if logging is enabled.
let log_backtrace = panics >= 2 || backtrace::log_enabled();
log_panic(obj, file, line, log_backtrace);
let info = PanicInfo {
payload: obj,
location: Location {
file: file,
line: line,
},
};
unsafe {
let _lock = HANDLER_LOCK.read();
match HANDLER {
Handler::Default => default_handler(&info),
Handler::Custom(ptr) => (*ptr)(&info),
}
}
if panics >= 2 {
// If a thread panics while it's already unwinding then we

View File

@ -3,6 +3,7 @@ S 2015-12-18 3391630
linux-x86_64 97e2a5eb8904962df8596e95d6e5d9b574d73bf4
macos-i386 ca52d2d3ba6497ed007705ee3401cf7efc136ca1
macos-x86_64 3c44ffa18f89567c2b81f8d695e711c86d81ffc7
openbsd-x86_64 6c8aab2c8a169274942f9a15e460069a3ff64be9
winnt-i386 f9056ebd3db9611d31c2dc6dc5f96c7208d5d227
winnt-x86_64 a85a40e535d828016181d3aa40afe34c3e36ab8c

View File

@ -0,0 +1,22 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// error-pattern:greetings from the panic handler
#![feature(std_panic, panic_handler)]
use std::panic;
use std::io::{self, Write};
fn main() {
panic::set_handler(|i| {
write!(io::stderr(), "greetings from the panic handler");
});
panic!("foobar");
}

View File

@ -0,0 +1,23 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// error-pattern:thread '<main>' panicked at 'foobar'
#![feature(std_panic, panic_handler)]
use std::panic;
use std::io::{self, Write};
fn main() {
panic::set_handler(|i| {
write!(io::stderr(), "greetings from the panic handler");
});
panic::take_handler();
panic!("foobar");
}

View File

@ -0,0 +1,19 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// error-pattern:thread '<main>' panicked at 'foobar'
#![feature(std_panic, panic_handler)]
use std::panic;
fn main() {
panic::take_handler();
panic!("foobar");
}

View File

@ -14,6 +14,8 @@
extern crate mir_external_refs as ext;
struct S(u8);
#[derive(Debug, PartialEq, Eq)]
struct Unit;
impl S {
fn hey() -> u8 { 42 }
@ -175,6 +177,11 @@ fn t20() -> fn(u64, u32)->(u64, u32) {
<u32 as T<_, _>>::staticmeth
}
#[rustc_mir]
fn t21() -> Unit {
Unit
}
fn main(){
unsafe {
assert_eq!(t1()(), regular());
@ -214,5 +221,6 @@ fn main(){
assert_eq!(t18()(50u64, 5u64), F::f(50u64, 5u64));
assert_eq!(t19()(322u64, 2u32), F::f(322u64, 2u32));
assert_eq!(t20()(123u64, 38u32), <u32 as T<_, _>>::staticmeth(123, 38));
assert_eq!(t21(), Unit);
}
}

View File

@ -0,0 +1,33 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(panic_handler, const_fn, std_panic)]
use std::sync::atomic::{AtomicUsize, Ordering};
use std::panic;
use std::thread;
static A: AtomicUsize = AtomicUsize::new(0);
static B: AtomicUsize = AtomicUsize::new(0);
fn main() {
panic::set_handler(|_| { A.fetch_add(1, Ordering::SeqCst); });
let handler = panic::take_handler();
panic::set_handler(move |info| {
B.fetch_add(1, Ordering::SeqCst);
handler(info);
});
let _ = thread::spawn(|| {
panic!();
}).join();
assert_eq!(1, A.load(Ordering::SeqCst));
assert_eq!(1, B.load(Ordering::SeqCst));
}

View File

@ -0,0 +1,57 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(panic_handler, std_panic)]
use std::panic;
use std::thread;
fn a() {
panic::set_handler(|_| println!("hello yes this is a"));
panic::take_handler();
panic::set_handler(|_| println!("hello yes this is a part 2"));
panic::take_handler();
}
fn b() {
panic::take_handler();
panic::take_handler();
panic::take_handler();
panic::take_handler();
panic::take_handler();
panic!();
}
fn c() {
panic::set_handler(|_| ());
panic::set_handler(|_| ());
panic::set_handler(|_| ());
panic::set_handler(|_| ());
panic::set_handler(|_| ());
panic::set_handler(|_| ());
panic!();
}
fn main() {
for _ in 0..10 {
let mut handles = vec![];
for _ in 0..10 {
handles.push(thread::spawn(a));
}
for _ in 0..10 {
handles.push(thread::spawn(b));
}
for _ in 0..10 {
handles.push(thread::spawn(c));
}
for handle in handles {
let _ = handle.join();
}
}
}

View File

@ -0,0 +1,27 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(panic_handler, const_fn, std_panic)]
use std::sync::atomic::{AtomicUsize, Ordering};
use std::panic;
use std::thread;
static A: AtomicUsize = AtomicUsize::new(0);
fn main() {
panic::set_handler(|_| ());
panic::set_handler(|info| { A.fetch_add(1, Ordering::SeqCst); });
let _ = thread::spawn(|| {
panic!();
}).join();
assert_eq!(1, A.load(Ordering::SeqCst));
}

View File

@ -11,7 +11,7 @@
#![allow(dead_code)]
#![feature(recover)]
use std::panic::RecoverSafe;
use std::panic::{RecoverSafe, AssertRecoverSafe};
use std::cell::RefCell;
use std::sync::{Mutex, RwLock, Arc};
use std::rc::Rc;
@ -47,5 +47,9 @@ fn main() {
assert::<Box<T>>();
assert::<Vec<T>>();
assert::<RefCell<T>>();
assert::<AssertRecoverSafe<T>>();
assert::<&AssertRecoverSafe<T>>();
assert::<Rc<AssertRecoverSafe<T>>>();
assert::<Arc<AssertRecoverSafe<T>>>();
}
}