Implement core::intrinsics::caller_location.
Returns a `&core::panic::Location` corresponding to where it was called, also making `Location` a lang item.
This commit is contained in:
parent
fcf516d827
commit
743964ad3f
@ -696,6 +696,10 @@ extern "rust-intrinsic" {
|
||||
/// This will statically either panic, or do nothing.
|
||||
pub fn panic_if_uninhabited<T>();
|
||||
|
||||
/// Gets a reference to a static `Location` indicating where it was called.
|
||||
#[cfg(not(bootstrap))]
|
||||
pub fn caller_location() -> &'static crate::panic::Location<'static>;
|
||||
|
||||
/// Creates a value initialized to zero.
|
||||
///
|
||||
/// `init` is unsafe because it returns a zeroed-out datum,
|
||||
|
@ -162,6 +162,7 @@ impl fmt::Display for PanicInfo<'_> {
|
||||
///
|
||||
/// panic!("Normal panic");
|
||||
/// ```
|
||||
#[cfg_attr(not(bootstrap), lang = "panic_location")]
|
||||
#[derive(Debug)]
|
||||
#[stable(feature = "panic_hooks", since = "1.10.0")]
|
||||
pub struct Location<'a> {
|
||||
|
@ -366,6 +366,7 @@ language_item_table! {
|
||||
PanicFnLangItem, "panic", panic_fn, Target::Fn;
|
||||
PanicBoundsCheckFnLangItem, "panic_bounds_check", panic_bounds_check_fn, Target::Fn;
|
||||
PanicInfoLangItem, "panic_info", panic_info, Target::Struct;
|
||||
PanicLocationLangItem, "panic_location", panic_location, Target::Struct;
|
||||
PanicImplLangItem, "panic_impl", panic_impl, Target::Fn;
|
||||
// Libstd panic entry point. Necessary for const eval to be able to catch it
|
||||
BeginPanicFnLangItem, "begin_panic", begin_panic_fn, Target::Fn;
|
||||
|
@ -2,6 +2,7 @@ use crate::llvm::{AtomicRmwBinOp, AtomicOrdering, SynchronizationScope};
|
||||
use crate::llvm::{self, False, BasicBlock};
|
||||
use crate::common::Funclet;
|
||||
use crate::context::CodegenCx;
|
||||
use crate::syntax_pos::Pos;
|
||||
use crate::type_::Type;
|
||||
use crate::type_of::LayoutLlvmExt;
|
||||
use crate::value::Value;
|
||||
@ -1068,6 +1069,20 @@ impl StaticBuilderMethods for Builder<'a, 'll, 'tcx> {
|
||||
self.cx().get_static(def_id)
|
||||
}
|
||||
|
||||
fn static_panic_location(&mut self, loc: &syntax::source_map::Loc) -> Self::Value {
|
||||
let filename = Symbol::intern(&loc.file.name.to_string());
|
||||
let filename = self.const_str(filename);
|
||||
let line = self.const_u32(loc.line as u32);
|
||||
let col = self.const_u32(loc.col.to_usize() as u32 + 1);
|
||||
let struct_ = self.const_struct(&[filename.0, filename.1, line, col], false);
|
||||
|
||||
let align = self.tcx.data_layout.aggregate_align.abi
|
||||
.max(self.tcx.data_layout.i32_align.abi)
|
||||
.max(self.tcx.data_layout.pointer_align.abi);
|
||||
// FIXME(eddyb) move this into miri, it can be correct if e.g. field order changes
|
||||
self.static_addr_of(struct_, align, Some("panic_loc"))
|
||||
}
|
||||
|
||||
fn static_panic_msg(
|
||||
&mut self,
|
||||
msg: Option<Symbol>,
|
||||
|
@ -237,6 +237,13 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
||||
unsafe { llvm::LLVMConstReal(t, val) }
|
||||
}
|
||||
|
||||
fn const_str(&self, s: Symbol) -> (&'ll Value, &'ll Value) {
|
||||
let len = s.as_str().len();
|
||||
let cs = consts::ptrcast(self.const_cstr(s, false),
|
||||
self.type_ptr_to(self.layout_of(self.tcx.mk_str()).llvm_type(self)));
|
||||
(cs, self.const_usize(len as u64))
|
||||
}
|
||||
|
||||
fn const_struct(
|
||||
&self,
|
||||
elts: &[&'ll Value],
|
||||
|
@ -613,6 +613,22 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
ReturnDest::Nothing
|
||||
};
|
||||
|
||||
if intrinsic == Some("caller_location") {
|
||||
if let Some((_, target)) = destination.as_ref() {
|
||||
let loc = bx.sess().source_map().lookup_char_pos(span.lo());
|
||||
let location = bx.static_panic_location(&loc);
|
||||
|
||||
if let ReturnDest::IndirectOperand(tmp, _) = ret_dest {
|
||||
Immediate(location).store(&mut bx, tmp);
|
||||
}
|
||||
self.store_return(&mut bx, ret_dest, &fn_ty.ret, location);
|
||||
|
||||
helper.maybe_sideeffect(self.mir, &mut bx, &[*target]);
|
||||
helper.funclet_br(self, &mut bx, *target);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if intrinsic.is_some() && intrinsic != Some("drop_in_place") {
|
||||
let dest = match ret_dest {
|
||||
_ if fn_ty.ret.is_indirect() => llargs[0],
|
||||
|
@ -3,6 +3,7 @@ use crate::mir::place::PlaceRef;
|
||||
use rustc::mir::interpret::Allocation;
|
||||
use rustc::mir::interpret::Scalar;
|
||||
use rustc::ty::layout;
|
||||
use syntax_pos::Symbol;
|
||||
|
||||
pub trait ConstMethods<'tcx>: BackendTypes {
|
||||
// Constant constructors
|
||||
@ -19,6 +20,7 @@ pub trait ConstMethods<'tcx>: BackendTypes {
|
||||
fn const_u8(&self, i: u8) -> Self::Value;
|
||||
fn const_real(&self, t: Self::Type, val: f64) -> Self::Value;
|
||||
|
||||
fn const_str(&self, s: Symbol) -> (Self::Value, Self::Value);
|
||||
fn const_struct(&self, elts: &[Self::Value], packed: bool) -> Self::Value;
|
||||
|
||||
fn const_to_opt_uint(&self, v: Self::Value) -> Option<u64>;
|
||||
|
@ -1,4 +1,5 @@
|
||||
use super::BackendTypes;
|
||||
use syntax::source_map::Loc;
|
||||
use syntax_pos::symbol::Symbol;
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::ty::layout::Align;
|
||||
@ -10,6 +11,7 @@ pub trait StaticMethods: BackendTypes {
|
||||
|
||||
pub trait StaticBuilderMethods: BackendTypes {
|
||||
fn get_static(&mut self, def_id: DefId) -> Self::Value;
|
||||
fn static_panic_location(&mut self, loc: &Loc) -> Self::Value;
|
||||
fn static_panic_msg(
|
||||
&mut self,
|
||||
msg: Option<Symbol>,
|
||||
|
@ -9,6 +9,7 @@ use std::convert::TryInto;
|
||||
|
||||
use rustc::hir::def::DefKind;
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::middle::lang_items::PanicLocationLangItem;
|
||||
use rustc::mir::interpret::{ConstEvalErr, ErrorHandled, ScalarMaybeUndef};
|
||||
use rustc::mir;
|
||||
use rustc::ty::{self, Ty, TyCtxt, subst::Subst};
|
||||
@ -505,6 +506,28 @@ pub fn const_field<'tcx>(
|
||||
op_to_const(&ecx, field)
|
||||
}
|
||||
|
||||
pub fn const_caller_location<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
(file, line, col): (Symbol, u32, u32),
|
||||
) -> &'tcx ty::Const<'tcx> {
|
||||
trace!("const_caller_location: {}:{}:{}", file, line, col);
|
||||
let mut ecx = mk_eval_cx(tcx, DUMMY_SP, ty::ParamEnv::reveal_all());
|
||||
|
||||
let loc_ty = tcx.mk_imm_ref(
|
||||
tcx.lifetimes.re_static,
|
||||
tcx.type_of(tcx.require_lang_item(PanicLocationLangItem, None))
|
||||
.subst(tcx, tcx.mk_substs([tcx.lifetimes.re_static.into()].iter())),
|
||||
);
|
||||
let loc_place = ecx.alloc_caller_location(file, line, col).unwrap();
|
||||
intern_const_alloc_recursive(&mut ecx, None, loc_place).unwrap();
|
||||
let loc_const = ty::Const {
|
||||
ty: loc_ty,
|
||||
val: ConstValue::Scalar(loc_place.ptr.into()),
|
||||
};
|
||||
|
||||
tcx.mk_const(loc_const)
|
||||
}
|
||||
|
||||
// this function uses `unwrap` copiously, because an already validated constant must have valid
|
||||
// fields and can thus never fail outside of compiler bugs
|
||||
pub fn const_variant_index<'tcx>(
|
||||
|
@ -1,6 +1,8 @@
|
||||
//! Type-checking for the rust-intrinsic and platform-intrinsic
|
||||
//! intrinsics that the compiler exposes.
|
||||
|
||||
use rustc::hir::{self, Mutability};
|
||||
use rustc::middle::lang_items::PanicLocationLangItem;
|
||||
use rustc::traits::{ObligationCause, ObligationCauseCode};
|
||||
use rustc::ty::{self, TyCtxt, Ty};
|
||||
use rustc::ty::subst::Subst;
|
||||
@ -9,8 +11,6 @@ use crate::require_same_types;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use syntax::symbol::Symbol;
|
||||
|
||||
use rustc::hir;
|
||||
|
||||
use std::iter;
|
||||
|
||||
fn equate_intrinsic_type<'tcx>(
|
||||
@ -65,7 +65,7 @@ fn equate_intrinsic_type<'tcx>(
|
||||
/// Returns `true` if the given intrinsic is unsafe to call or not.
|
||||
pub fn intrinsic_operation_unsafety(intrinsic: &str) -> hir::Unsafety {
|
||||
match intrinsic {
|
||||
"size_of" | "min_align_of" | "needs_drop" |
|
||||
"size_of" | "min_align_of" | "needs_drop" | "caller_location" |
|
||||
"add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" |
|
||||
"wrapping_add" | "wrapping_sub" | "wrapping_mul" |
|
||||
"saturating_add" | "saturating_sub" |
|
||||
@ -143,6 +143,18 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem) {
|
||||
], tcx.types.usize)
|
||||
}
|
||||
"rustc_peek" => (1, vec![param(0)], param(0)),
|
||||
"caller_location" => (
|
||||
0,
|
||||
vec![],
|
||||
tcx.mk_ref(
|
||||
tcx.lifetimes.re_static,
|
||||
ty::TypeAndMut {
|
||||
mutbl: Mutability::MutImmutable,
|
||||
ty: tcx.type_of(tcx.require_lang_item(PanicLocationLangItem, None))
|
||||
.subst(tcx, tcx.mk_substs([tcx.lifetimes.re_static.into()].iter())),
|
||||
},
|
||||
),
|
||||
),
|
||||
"panic_if_uninhabited" => (1, Vec::new(), tcx.mk_unit()),
|
||||
"init" => (1, Vec::new(), param(0)),
|
||||
"uninit" => (1, Vec::new(), param(0)),
|
||||
|
@ -0,0 +1,9 @@
|
||||
// run-pass
|
||||
|
||||
#![feature(core_intrinsics)]
|
||||
fn main() {
|
||||
let loc = core::intrinsics::caller_location();
|
||||
assert_eq!(loc.file(), file!());
|
||||
assert_eq!(loc.line(), 5);
|
||||
assert_eq!(loc.column(), 15);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user