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:
commit
5b838c586c
src
doc/book
grammar
librustc
librustc_metadata
librustc_mir/hair/cx
librustc_trans/trans/mir
libstd
snapshots.txttest
@ -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)].
|
||||
|
@ -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); }
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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 }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
22
src/test/run-fail/panic-set-handler.rs
Normal file
22
src/test/run-fail/panic-set-handler.rs
Normal 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");
|
||||
}
|
23
src/test/run-fail/panic-set-unset-handler.rs
Normal file
23
src/test/run-fail/panic-set-unset-handler.rs
Normal 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");
|
||||
}
|
19
src/test/run-fail/panic-take-handler-nop.rs
Normal file
19
src/test/run-fail/panic-take-handler-nop.rs
Normal 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");
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
33
src/test/run-pass/panic-handler-chain.rs
Normal file
33
src/test/run-pass/panic-handler-chain.rs
Normal 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));
|
||||
}
|
57
src/test/run-pass/panic-handler-flail-wildly.rs
Normal file
57
src/test/run-pass/panic-handler-flail-wildly.rs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
27
src/test/run-pass/panic-handler-set-twice.rs
Normal file
27
src/test/run-pass/panic-handler-set-twice.rs
Normal 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));
|
||||
}
|
@ -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>>>();
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user