Rollup merge of #65664 - anp:panic-location, r=eddyb
`std::panic::Location` is a lang_item, add `core::intrinsics::caller_location` (RFC 2091 3/N) [Tracking issue](https://github.com/rust-lang/rust/issues/47809) [RFC text](https://github.com/rust-lang/rfcs/blob/master/text/2091-inline-semantic.md) @eddyb suggested doing this intrinsic implementation ahead of actually implementing the `#[track_caller]` attribute so that there's an easily tested intermediate step between adding the shim and wiring up the attribute.
This commit is contained in:
commit
4728d66206
@ -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,
|
||||
|
@ -1,8 +1,9 @@
|
||||
/// Panics the current thread.
|
||||
///
|
||||
/// For details, see `std::macros`.
|
||||
#[cfg(bootstrap)]
|
||||
#[macro_export]
|
||||
#[allow_internal_unstable(core_panic)]
|
||||
#[allow_internal_unstable(core_panic, panic_internals)]
|
||||
#[stable(feature = "core", since = "1.6.0")]
|
||||
macro_rules! panic {
|
||||
() => (
|
||||
@ -20,6 +21,38 @@ macro_rules! panic {
|
||||
});
|
||||
}
|
||||
|
||||
/// Panics the current thread.
|
||||
///
|
||||
/// For details, see `std::macros`.
|
||||
#[cfg(not(bootstrap))]
|
||||
#[macro_export]
|
||||
#[allow_internal_unstable(core_panic, panic_internals)]
|
||||
#[stable(feature = "core", since = "1.6.0")]
|
||||
macro_rules! panic {
|
||||
() => (
|
||||
$crate::panic!("explicit panic")
|
||||
);
|
||||
($msg:expr) => ({
|
||||
const LOC: &$crate::panic::Location<'_> = &$crate::panic::Location::internal_constructor(
|
||||
$crate::file!(),
|
||||
$crate::line!(),
|
||||
$crate::column!(),
|
||||
);
|
||||
$crate::panicking::panic($msg, LOC)
|
||||
});
|
||||
($msg:expr,) => (
|
||||
$crate::panic!($msg)
|
||||
);
|
||||
($fmt:expr, $($arg:tt)+) => ({
|
||||
const LOC: &$crate::panic::Location<'_> = &$crate::panic::Location::internal_constructor(
|
||||
$crate::file!(),
|
||||
$crate::line!(),
|
||||
$crate::column!(),
|
||||
);
|
||||
$crate::panicking::panic_fmt($crate::format_args!($fmt, $($arg)+), LOC)
|
||||
});
|
||||
}
|
||||
|
||||
/// Asserts that two expressions are equal to each other (using [`PartialEq`]).
|
||||
///
|
||||
/// On panic, this macro will print the values of the expressions with their
|
||||
|
@ -35,7 +35,7 @@ use crate::fmt;
|
||||
pub struct PanicInfo<'a> {
|
||||
payload: &'a (dyn Any + Send),
|
||||
message: Option<&'a fmt::Arguments<'a>>,
|
||||
location: Location<'a>,
|
||||
location: &'a Location<'a>,
|
||||
}
|
||||
|
||||
impl<'a> PanicInfo<'a> {
|
||||
@ -45,11 +45,16 @@ impl<'a> PanicInfo<'a> {
|
||||
issue = "0")]
|
||||
#[doc(hidden)]
|
||||
#[inline]
|
||||
pub fn internal_constructor(message: Option<&'a fmt::Arguments<'a>>,
|
||||
location: Location<'a>)
|
||||
-> Self {
|
||||
pub fn internal_constructor(
|
||||
message: Option<&'a fmt::Arguments<'a>>,
|
||||
location: &'a Location<'a>,
|
||||
) -> Self {
|
||||
struct NoPayload;
|
||||
PanicInfo { payload: &NoPayload, location, message }
|
||||
PanicInfo {
|
||||
location,
|
||||
message,
|
||||
payload: &NoPayload,
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
@ -162,6 +167,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> {
|
||||
@ -176,7 +182,7 @@ impl<'a> Location<'a> {
|
||||
and related macros",
|
||||
issue = "0")]
|
||||
#[doc(hidden)]
|
||||
pub fn internal_constructor(file: &'a str, line: u32, col: u32) -> Self {
|
||||
pub const fn internal_constructor(file: &'a str, line: u32, col: u32) -> Self {
|
||||
Location { file, line, col }
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,7 @@
|
||||
use crate::fmt;
|
||||
use crate::panic::{Location, PanicInfo};
|
||||
|
||||
#[cfg(bootstrap)]
|
||||
#[cold]
|
||||
// never inline unless panic_immediate_abort to avoid code
|
||||
// bloat at the call sites as much as possible
|
||||
@ -49,6 +50,27 @@ pub fn panic(expr_file_line_col: &(&'static str, &'static str, u32, u32)) -> ! {
|
||||
panic_fmt(fmt::Arguments::new_v1(&[expr], &[]), &(file, line, col))
|
||||
}
|
||||
|
||||
#[cfg(not(bootstrap))]
|
||||
#[cold]
|
||||
// never inline unless panic_immediate_abort to avoid code
|
||||
// bloat at the call sites as much as possible
|
||||
#[cfg_attr(not(feature="panic_immediate_abort"),inline(never))]
|
||||
#[lang = "panic"]
|
||||
pub fn panic(expr: &str, location: &Location<'_>) -> ! {
|
||||
if cfg!(feature = "panic_immediate_abort") {
|
||||
unsafe { super::intrinsics::abort() }
|
||||
}
|
||||
|
||||
// Use Arguments::new_v1 instead of format_args!("{}", expr) to potentially
|
||||
// reduce size overhead. The format_args! macro uses str's Display trait to
|
||||
// write expr, which calls Formatter::pad, which must accommodate string
|
||||
// truncation and padding (even though none is used here). Using
|
||||
// Arguments::new_v1 may allow the compiler to omit Formatter::pad from the
|
||||
// output binary, saving up to a few kilobytes.
|
||||
panic_fmt(fmt::Arguments::new_v1(&[expr], &[]), location)
|
||||
}
|
||||
|
||||
#[cfg(bootstrap)]
|
||||
#[cold]
|
||||
#[cfg_attr(not(feature="panic_immediate_abort"),inline(never))]
|
||||
#[lang = "panic_bounds_check"]
|
||||
@ -62,6 +84,22 @@ fn panic_bounds_check(file_line_col: &(&'static str, u32, u32),
|
||||
len, index), file_line_col)
|
||||
}
|
||||
|
||||
#[cfg(not(bootstrap))]
|
||||
#[cold]
|
||||
#[cfg_attr(not(feature="panic_immediate_abort"),inline(never))]
|
||||
#[lang = "panic_bounds_check"]
|
||||
fn panic_bounds_check(location: &Location<'_>, index: usize, len: usize) -> ! {
|
||||
if cfg!(feature = "panic_immediate_abort") {
|
||||
unsafe { super::intrinsics::abort() }
|
||||
}
|
||||
|
||||
panic_fmt(
|
||||
format_args!("index out of bounds: the len is {} but the index is {}", len, index),
|
||||
location
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(bootstrap)]
|
||||
#[cold]
|
||||
#[cfg_attr(not(feature="panic_immediate_abort"),inline(never))]
|
||||
#[cfg_attr( feature="panic_immediate_abort" ,inline)]
|
||||
@ -77,9 +115,26 @@ pub fn panic_fmt(fmt: fmt::Arguments<'_>, file_line_col: &(&'static str, u32, u3
|
||||
}
|
||||
|
||||
let (file, line, col) = *file_line_col;
|
||||
let pi = PanicInfo::internal_constructor(
|
||||
Some(&fmt),
|
||||
Location::internal_constructor(file, line, col),
|
||||
);
|
||||
let location = Location::internal_constructor(file, line, col);
|
||||
let pi = PanicInfo::internal_constructor(Some(&fmt), &location);
|
||||
unsafe { panic_impl(&pi) }
|
||||
}
|
||||
|
||||
#[cfg(not(bootstrap))]
|
||||
#[cold]
|
||||
#[cfg_attr(not(feature="panic_immediate_abort"),inline(never))]
|
||||
#[cfg_attr( feature="panic_immediate_abort" ,inline)]
|
||||
pub fn panic_fmt(fmt: fmt::Arguments<'_>, location: &Location<'_>) -> ! {
|
||||
if cfg!(feature = "panic_immediate_abort") {
|
||||
unsafe { super::intrinsics::abort() }
|
||||
}
|
||||
|
||||
// NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call
|
||||
extern "Rust" {
|
||||
#[lang = "panic_impl"]
|
||||
fn panic_impl(pi: &PanicInfo<'_>) -> !;
|
||||
}
|
||||
|
||||
let pi = PanicInfo::internal_constructor(Some(&fmt), location);
|
||||
unsafe { panic_impl(&pi) }
|
||||
}
|
||||
|
@ -370,6 +370,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;
|
||||
|
@ -466,6 +466,12 @@ rustc_queries! {
|
||||
no_force
|
||||
desc { "extract field of const" }
|
||||
}
|
||||
|
||||
query const_caller_location(key: (syntax_pos::Symbol, u32, u32)) -> &'tcx ty::Const<'tcx> {
|
||||
eval_always
|
||||
no_force
|
||||
desc { "get a &core::panic::Location referring to a span" }
|
||||
}
|
||||
}
|
||||
|
||||
TypeChecking {
|
||||
|
@ -208,3 +208,13 @@ impl<'tcx, T> Key for Canonical<'tcx, T> {
|
||||
DUMMY_SP
|
||||
}
|
||||
}
|
||||
|
||||
impl Key for (Symbol, u32, u32) {
|
||||
fn query_crate(&self) -> CrateNum {
|
||||
LOCAL_CRATE
|
||||
}
|
||||
|
||||
fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
|
||||
DUMMY_SP
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,6 @@ use std::ffi::CStr;
|
||||
use std::ops::{Deref, Range};
|
||||
use std::ptr;
|
||||
use std::iter::TrustedLen;
|
||||
use syntax::symbol::Symbol;
|
||||
|
||||
// All Builders must have an llfn associated with them
|
||||
#[must_use]
|
||||
@ -1067,36 +1066,6 @@ impl StaticBuilderMethods for Builder<'a, 'll, 'tcx> {
|
||||
// Forward to the `get_static` method of `CodegenCx`
|
||||
self.cx().get_static(def_id)
|
||||
}
|
||||
|
||||
fn static_panic_msg(
|
||||
&mut self,
|
||||
msg: Option<Symbol>,
|
||||
filename: Symbol,
|
||||
line: Self::Value,
|
||||
col: Self::Value,
|
||||
kind: &str,
|
||||
) -> Self::Value {
|
||||
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);
|
||||
|
||||
let filename = self.const_str_slice(filename);
|
||||
|
||||
let with_msg_components;
|
||||
let without_msg_components;
|
||||
|
||||
let components = if let Some(msg) = msg {
|
||||
let msg = self.const_str_slice(msg);
|
||||
with_msg_components = [msg, filename, line, col];
|
||||
&with_msg_components as &[_]
|
||||
} else {
|
||||
without_msg_components = [filename, line, col];
|
||||
&without_msg_components as &[_]
|
||||
};
|
||||
|
||||
let struct_ = self.const_struct(&components, false);
|
||||
self.static_addr_of(struct_, align, Some(kind))
|
||||
}
|
||||
}
|
||||
|
||||
impl Builder<'a, 'll, 'tcx> {
|
||||
|
@ -3,7 +3,6 @@
|
||||
//! Code that is useful in various codegen modules.
|
||||
|
||||
use crate::llvm::{self, True, False, Bool, BasicBlock, OperandBundleDef, ConstantInt};
|
||||
use crate::abi;
|
||||
use crate::consts;
|
||||
use crate::type_::Type;
|
||||
use crate::type_of::LayoutLlvmExt;
|
||||
@ -96,16 +95,6 @@ impl BackendTypes for CodegenCx<'ll, 'tcx> {
|
||||
}
|
||||
|
||||
impl CodegenCx<'ll, 'tcx> {
|
||||
pub fn const_fat_ptr(
|
||||
&self,
|
||||
ptr: &'ll Value,
|
||||
meta: &'ll Value
|
||||
) -> &'ll Value {
|
||||
assert_eq!(abi::FAT_PTR_ADDR, 0);
|
||||
assert_eq!(abi::FAT_PTR_EXTRA, 1);
|
||||
self.const_struct(&[ptr, meta], false)
|
||||
}
|
||||
|
||||
pub fn const_array(&self, ty: &'ll Type, elts: &[&'ll Value]) -> &'ll Value {
|
||||
unsafe {
|
||||
return llvm::LLVMConstArray(ty, elts.as_ptr(), elts.len() as c_uint);
|
||||
@ -150,13 +139,6 @@ impl CodegenCx<'ll, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn const_str_slice(&self, s: Symbol) -> &'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)));
|
||||
self.const_fat_ptr(cs, self.const_usize(len as u64))
|
||||
}
|
||||
|
||||
pub fn const_get_elt(&self, v: &'ll Value, idx: u64) -> &'ll Value {
|
||||
unsafe {
|
||||
assert_eq!(idx as c_uint as u64, idx);
|
||||
@ -237,6 +219,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],
|
||||
|
@ -15,8 +15,7 @@ use crate::traits::*;
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
use syntax::symbol::Symbol;
|
||||
use syntax_pos::Pos;
|
||||
use syntax::{source_map::Span, symbol::Symbol};
|
||||
|
||||
use super::{FunctionCx, LocalRef};
|
||||
use super::place::PlaceRef;
|
||||
@ -421,38 +420,19 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
self.set_debug_loc(&mut bx, terminator.source_info);
|
||||
|
||||
// Get the location information.
|
||||
let loc = bx.sess().source_map().lookup_char_pos(span.lo());
|
||||
let filename = Symbol::intern(&loc.file.name.to_string());
|
||||
let line = bx.const_u32(loc.line as u32);
|
||||
let col = bx.const_u32(loc.col.to_usize() as u32 + 1);
|
||||
let location = self.get_caller_location(&mut bx, span).immediate();
|
||||
|
||||
// Put together the arguments to the panic entry point.
|
||||
let (lang_item, args) = match msg {
|
||||
PanicInfo::BoundsCheck { ref len, ref index } => {
|
||||
let len = self.codegen_operand(&mut bx, len).immediate();
|
||||
let index = self.codegen_operand(&mut bx, index).immediate();
|
||||
|
||||
let file_line_col = bx.static_panic_msg(
|
||||
None,
|
||||
filename,
|
||||
line,
|
||||
col,
|
||||
"panic_bounds_check_loc",
|
||||
);
|
||||
(lang_items::PanicBoundsCheckFnLangItem,
|
||||
vec![file_line_col, index, len])
|
||||
(lang_items::PanicBoundsCheckFnLangItem, vec![location, index, len])
|
||||
}
|
||||
_ => {
|
||||
let msg_str = Symbol::intern(msg.description());
|
||||
let msg_file_line_col = bx.static_panic_msg(
|
||||
Some(msg_str),
|
||||
filename,
|
||||
line,
|
||||
col,
|
||||
"panic_loc",
|
||||
);
|
||||
(lang_items::PanicFnLangItem,
|
||||
vec![msg_file_line_col])
|
||||
let msg = bx.const_str(msg_str);
|
||||
(lang_items::PanicFnLangItem, vec![msg.0, msg.1, location])
|
||||
}
|
||||
};
|
||||
|
||||
@ -553,23 +533,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
let ty = instance.unwrap().substs.type_at(0);
|
||||
let layout = bx.layout_of(ty);
|
||||
if layout.abi.is_uninhabited() {
|
||||
let loc = bx.sess().source_map().lookup_char_pos(span.lo());
|
||||
let filename = Symbol::intern(&loc.file.name.to_string());
|
||||
let line = bx.const_u32(loc.line as u32);
|
||||
let col = bx.const_u32(loc.col.to_usize() as u32 + 1);
|
||||
|
||||
let str = format!(
|
||||
"Attempted to instantiate uninhabited type {}",
|
||||
ty
|
||||
);
|
||||
let msg_str = Symbol::intern(&str);
|
||||
let msg_file_line_col = bx.static_panic_msg(
|
||||
Some(msg_str),
|
||||
filename,
|
||||
line,
|
||||
col,
|
||||
"panic_loc",
|
||||
);
|
||||
let msg_str = format!("Attempted to instantiate uninhabited type {}", ty);
|
||||
let msg = bx.const_str(Symbol::intern(&msg_str));
|
||||
let location = self.get_caller_location(&mut bx, span).immediate();
|
||||
|
||||
// Obtain the panic entry point.
|
||||
let def_id =
|
||||
@ -587,7 +553,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
&mut bx,
|
||||
fn_ty,
|
||||
llfn,
|
||||
&[msg_file_line_col],
|
||||
&[msg.0, msg.1, location],
|
||||
destination.as_ref().map(|(_, bb)| (ReturnDest::Nothing, *bb)),
|
||||
cleanup,
|
||||
);
|
||||
@ -613,6 +579,21 @@ 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 location = self.get_caller_location(&mut bx, span);
|
||||
|
||||
if let ReturnDest::IndirectOperand(tmp, _) = ret_dest {
|
||||
location.val.store(&mut bx, tmp);
|
||||
}
|
||||
self.store_return(&mut bx, ret_dest, &fn_ty.ret, location.immediate());
|
||||
|
||||
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],
|
||||
@ -1009,6 +990,20 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_caller_location(
|
||||
&mut self,
|
||||
bx: &mut Bx,
|
||||
span: Span,
|
||||
) -> OperandRef<'tcx, Bx::Value> {
|
||||
let caller = bx.tcx().sess.source_map().lookup_char_pos(span.lo());
|
||||
let const_loc = bx.tcx().const_caller_location((
|
||||
Symbol::intern(&caller.file.name.to_string()),
|
||||
caller.line as u32,
|
||||
caller.col_display as u32 + 1,
|
||||
));
|
||||
OperandRef::from_const(bx, const_loc)
|
||||
}
|
||||
|
||||
fn get_personality_slot(
|
||||
&mut self,
|
||||
bx: &mut Bx
|
||||
|
@ -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,5 +1,4 @@
|
||||
use super::BackendTypes;
|
||||
use syntax_pos::symbol::Symbol;
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::ty::layout::Align;
|
||||
|
||||
@ -10,12 +9,4 @@ pub trait StaticMethods: BackendTypes {
|
||||
|
||||
pub trait StaticBuilderMethods: BackendTypes {
|
||||
fn get_static(&mut self, def_id: DefId) -> Self::Value;
|
||||
fn static_panic_msg(
|
||||
&mut self,
|
||||
msg: Option<Symbol>,
|
||||
filename: Symbol,
|
||||
line: Self::Value,
|
||||
col: Self::Value,
|
||||
kind: &str,
|
||||
) -> Self::Value;
|
||||
}
|
||||
|
@ -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};
|
||||
@ -17,7 +18,7 @@ use rustc::traits::Reveal;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use crate::interpret::eval_nullary_intrinsic;
|
||||
|
||||
use syntax::source_map::{Span, DUMMY_SP};
|
||||
use syntax::{source_map::{Span, DUMMY_SP}, symbol::Symbol};
|
||||
|
||||
use crate::interpret::{self,
|
||||
PlaceTy, MPlaceTy, OpTy, ImmTy, Immediate, Scalar, Pointer,
|
||||
@ -158,11 +159,7 @@ fn eval_body_using_ecx<'mir, 'tcx>(
|
||||
ecx.run()?;
|
||||
|
||||
// Intern the result
|
||||
intern_const_alloc_recursive(
|
||||
ecx,
|
||||
cid.instance.def_id(),
|
||||
ret,
|
||||
)?;
|
||||
intern_const_alloc_recursive(ecx, tcx.static_mutability(cid.instance.def_id()), ret)?;
|
||||
|
||||
debug!("eval_body_using_ecx done: {:?}", *ret);
|
||||
Ok(ret)
|
||||
@ -374,11 +371,12 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
|
||||
|
||||
fn call_intrinsic(
|
||||
ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
||||
span: Span,
|
||||
instance: ty::Instance<'tcx>,
|
||||
args: &[OpTy<'tcx>],
|
||||
dest: PlaceTy<'tcx>,
|
||||
) -> InterpResult<'tcx> {
|
||||
if ecx.emulate_intrinsic(instance, args, dest)? {
|
||||
if ecx.emulate_intrinsic(span, instance, args, dest)? {
|
||||
return Ok(());
|
||||
}
|
||||
// An intrinsic that we do not support
|
||||
@ -505,6 +503,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>(
|
||||
|
@ -6,7 +6,6 @@
|
||||
use rustc::ty::{Ty, self};
|
||||
use rustc::mir::interpret::{InterpResult, ErrorHandled};
|
||||
use rustc::hir;
|
||||
use rustc::hir::def_id::DefId;
|
||||
use super::validity::RefTracking;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
|
||||
@ -270,12 +269,12 @@ for
|
||||
|
||||
pub fn intern_const_alloc_recursive(
|
||||
ecx: &mut CompileTimeEvalContext<'mir, 'tcx>,
|
||||
def_id: DefId,
|
||||
// The `mutability` of the place, ignoring the type.
|
||||
place_mut: Option<hir::Mutability>,
|
||||
ret: MPlaceTy<'tcx>,
|
||||
) -> InterpResult<'tcx> {
|
||||
let tcx = ecx.tcx;
|
||||
// this `mutability` is the mutability of the place, ignoring the type
|
||||
let (base_mutability, base_intern_mode) = match tcx.static_mutability(def_id) {
|
||||
let (base_mutability, base_intern_mode) = match place_mut {
|
||||
Some(hir::Mutability::MutImmutable) => (Mutability::Immutable, InternMode::Static),
|
||||
// `static mut` doesn't care about interior mutability, it's mutable anyway
|
||||
Some(hir::Mutability::MutMutable) => (Mutability::Mutable, InternMode::Static),
|
||||
|
@ -3,6 +3,7 @@
|
||||
//! and miri.
|
||||
|
||||
use syntax::symbol::Symbol;
|
||||
use syntax_pos::Span;
|
||||
use rustc::ty;
|
||||
use rustc::ty::layout::{LayoutOf, Primitive, Size};
|
||||
use rustc::ty::subst::SubstsRef;
|
||||
@ -15,6 +16,7 @@ use super::{
|
||||
Machine, PlaceTy, OpTy, InterpCx,
|
||||
};
|
||||
|
||||
mod caller_location;
|
||||
mod type_name;
|
||||
|
||||
fn numeric_intrinsic<'tcx, Tag>(
|
||||
@ -86,6 +88,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
/// Returns `true` if emulation happened.
|
||||
pub fn emulate_intrinsic(
|
||||
&mut self,
|
||||
span: Span,
|
||||
instance: ty::Instance<'tcx>,
|
||||
args: &[OpTy<'tcx, M::PointerTag>],
|
||||
dest: PlaceTy<'tcx, M::PointerTag>,
|
||||
@ -94,6 +97,16 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
|
||||
let intrinsic_name = &self.tcx.item_name(instance.def_id()).as_str()[..];
|
||||
match intrinsic_name {
|
||||
"caller_location" => {
|
||||
let caller = self.tcx.sess.source_map().lookup_char_pos(span.lo());
|
||||
let location = self.alloc_caller_location(
|
||||
Symbol::intern(&caller.file.name.to_string()),
|
||||
caller.line as u32,
|
||||
caller.col_display as u32 + 1,
|
||||
)?;
|
||||
self.write_scalar(location.ptr, dest)?;
|
||||
}
|
||||
|
||||
"min_align_of" |
|
||||
"pref_align_of" |
|
||||
"needs_drop" |
|
||||
@ -301,18 +314,19 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
) -> InterpResult<'tcx, bool> {
|
||||
let def_id = instance.def_id();
|
||||
if Some(def_id) == self.tcx.lang_items().panic_fn() {
|
||||
assert!(args.len() == 1);
|
||||
// &(&'static str, &'static str, u32, u32)
|
||||
let place = self.deref_operand(args[0])?;
|
||||
let (msg, file, line, col) = (
|
||||
self.mplace_field(place, 0)?,
|
||||
self.mplace_field(place, 1)?,
|
||||
self.mplace_field(place, 2)?,
|
||||
self.mplace_field(place, 3)?,
|
||||
// &'static str, &core::panic::Location { &'static str, u32, u32 }
|
||||
assert!(args.len() == 2);
|
||||
|
||||
let msg_place = self.deref_operand(args[0])?;
|
||||
let msg = Symbol::intern(self.read_str(msg_place)?);
|
||||
|
||||
let location = self.deref_operand(args[1])?;
|
||||
let (file, line, col) = (
|
||||
self.mplace_field(location, 0)?,
|
||||
self.mplace_field(location, 1)?,
|
||||
self.mplace_field(location, 2)?,
|
||||
);
|
||||
|
||||
let msg_place = self.deref_operand(msg.into())?;
|
||||
let msg = Symbol::intern(self.read_str(msg_place)?);
|
||||
let file_place = self.deref_operand(file.into())?;
|
||||
let file = Symbol::intern(self.read_str(file_place)?);
|
||||
let line = self.read_scalar(line.into())?.to_u32()?;
|
||||
|
49
src/librustc_mir/interpret/intrinsics/caller_location.rs
Normal file
49
src/librustc_mir/interpret/intrinsics/caller_location.rs
Normal file
@ -0,0 +1,49 @@
|
||||
use rustc::middle::lang_items::PanicLocationLangItem;
|
||||
use rustc::mir::interpret::{Pointer, PointerArithmetic, Scalar};
|
||||
use rustc::ty::subst::Subst;
|
||||
use rustc_target::abi::{LayoutOf, Size};
|
||||
use syntax_pos::Symbol;
|
||||
|
||||
use crate::interpret::{MemoryKind, MPlaceTy, intrinsics::{InterpCx, InterpResult, Machine}};
|
||||
|
||||
impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
pub fn alloc_caller_location(
|
||||
&mut self,
|
||||
filename: Symbol,
|
||||
line: u32,
|
||||
col: u32,
|
||||
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
|
||||
let line = Scalar::from_u32(line);
|
||||
let col = Scalar::from_u32(col);
|
||||
|
||||
let ptr_size = self.pointer_size();
|
||||
let u32_size = Size::from_bits(32);
|
||||
|
||||
let loc_ty = self.tcx.type_of(self.tcx.require_lang_item(PanicLocationLangItem, None))
|
||||
.subst(*self.tcx, self.tcx.mk_substs([self.tcx.lifetimes.re_static.into()].iter()));
|
||||
let loc_layout = self.layout_of(loc_ty)?;
|
||||
|
||||
let file_alloc = self.tcx.allocate_bytes(filename.as_str().as_bytes());
|
||||
let file_ptr = Pointer::new(file_alloc, Size::ZERO);
|
||||
let file = Scalar::Ptr(self.tag_static_base_pointer(file_ptr));
|
||||
let file_len = Scalar::from_uint(filename.as_str().len() as u128, ptr_size);
|
||||
|
||||
let location = self.allocate(loc_layout, MemoryKind::Stack);
|
||||
|
||||
let file_out = self.mplace_field(location, 0)?;
|
||||
let file_ptr_out = self.force_ptr(self.mplace_field(file_out, 0)?.ptr)?;
|
||||
let file_len_out = self.force_ptr(self.mplace_field(file_out, 1)?.ptr)?;
|
||||
let line_out = self.force_ptr(self.mplace_field(location, 1)?.ptr)?;
|
||||
let col_out = self.force_ptr(self.mplace_field(location, 2)?.ptr)?;
|
||||
|
||||
let layout = &self.tcx.data_layout;
|
||||
let alloc = self.memory.get_mut(file_ptr_out.alloc_id)?;
|
||||
|
||||
alloc.write_scalar(layout, file_ptr_out, file.into(), ptr_size)?;
|
||||
alloc.write_scalar(layout, file_len_out, file_len.into(), ptr_size)?;
|
||||
alloc.write_scalar(layout, line_out, line.into(), u32_size)?;
|
||||
alloc.write_scalar(layout, col_out, col.into(), u32_size)?;
|
||||
|
||||
Ok(location)
|
||||
}
|
||||
}
|
@ -8,6 +8,7 @@ use std::hash::Hash;
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::mir;
|
||||
use rustc::ty::{self, Ty, TyCtxt};
|
||||
use syntax_pos::Span;
|
||||
|
||||
use super::{
|
||||
Allocation, AllocId, InterpResult, Scalar, AllocationExtra,
|
||||
@ -152,6 +153,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
|
||||
/// If this returns successfully, the engine will take care of jumping to the next block.
|
||||
fn call_intrinsic(
|
||||
ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
||||
span: Span,
|
||||
instance: ty::Instance<'tcx>,
|
||||
args: &[OpTy<'tcx, Self::PointerTag>],
|
||||
dest: PlaceTy<'tcx, Self::PointerTag>,
|
||||
|
@ -255,7 +255,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
Some(dest) => dest,
|
||||
None => throw_ub!(Unreachable)
|
||||
};
|
||||
M::call_intrinsic(self, instance, args, dest)?;
|
||||
M::call_intrinsic(self, span, instance, args, dest)?;
|
||||
// No stack frame gets pushed, the main loop will just act as if the
|
||||
// call completed.
|
||||
self.goto_block(ret)?;
|
||||
|
@ -58,6 +58,7 @@ pub fn provide(providers: &mut Providers<'_>) {
|
||||
providers.const_eval = const_eval::const_eval_provider;
|
||||
providers.const_eval_raw = const_eval::const_eval_raw_provider;
|
||||
providers.check_match = hair::pattern::check_match;
|
||||
providers.const_caller_location = const_eval::const_caller_location;
|
||||
providers.const_field = |tcx, param_env_and_value| {
|
||||
let (param_env, (value, field)) = param_env_and_value.into_parts();
|
||||
const_eval::const_field(tcx, param_env, None, field, value)
|
||||
|
@ -158,6 +158,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine {
|
||||
|
||||
fn call_intrinsic(
|
||||
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
||||
_span: Span,
|
||||
_instance: ty::Instance<'tcx>,
|
||||
_args: &[OpTy<'tcx>],
|
||||
_dest: PlaceTy<'tcx>,
|
||||
|
@ -1,6 +1,7 @@
|
||||
//! Type-checking for the rust-intrinsic and platform-intrinsic
|
||||
//! intrinsics that the compiler exposes.
|
||||
|
||||
use rustc::middle::lang_items::PanicLocationLangItem;
|
||||
use rustc::traits::{ObligationCause, ObligationCauseCode};
|
||||
use rustc::ty::{self, TyCtxt, Ty};
|
||||
use rustc::ty::subst::Subst;
|
||||
@ -65,7 +66,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 +144,15 @@ 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_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())),
|
||||
),
|
||||
),
|
||||
"panic_if_uninhabited" => (1, Vec::new(), tcx.mk_unit()),
|
||||
"init" => (1, Vec::new(), param(0)),
|
||||
"uninit" => (1, Vec::new(), param(0)),
|
||||
|
@ -323,10 +323,8 @@ pub fn begin_panic_fmt(msg: &fmt::Arguments<'_>,
|
||||
}
|
||||
|
||||
let (file, line, col) = *file_line_col;
|
||||
let info = PanicInfo::internal_constructor(
|
||||
Some(msg),
|
||||
Location::internal_constructor(file, line, col),
|
||||
);
|
||||
let location = Location::internal_constructor(file, line, col);
|
||||
let info = PanicInfo::internal_constructor(Some(msg), &location);
|
||||
continue_panic_fmt(&info)
|
||||
}
|
||||
|
||||
@ -453,10 +451,8 @@ fn rust_panic_with_hook(payload: &mut dyn BoxMeUp,
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let mut info = PanicInfo::internal_constructor(
|
||||
message,
|
||||
Location::internal_constructor(file, line, col),
|
||||
);
|
||||
let location = Location::internal_constructor(file, line, col);
|
||||
let mut info = PanicInfo::internal_constructor(message, &location);
|
||||
HOOK_LOCK.read();
|
||||
match HOOK {
|
||||
// Some platforms know that printing to stderr won't ever actually
|
||||
|
23
src/test/ui/consts/const-eval/const_caller_location.rs
Normal file
23
src/test/ui/consts/const-eval/const_caller_location.rs
Normal file
@ -0,0 +1,23 @@
|
||||
// run-pass
|
||||
|
||||
#![feature(const_fn, core_intrinsics)]
|
||||
|
||||
use std::{intrinsics::caller_location, panic::Location};
|
||||
|
||||
const LOCATION: &Location = caller_location();
|
||||
const NESTED: &Location = {
|
||||
const fn nested_location() -> &'static Location<'static> {
|
||||
caller_location()
|
||||
};
|
||||
nested_location()
|
||||
};
|
||||
|
||||
fn main() {
|
||||
assert_eq!(LOCATION.file(), file!());
|
||||
assert_eq!(LOCATION.line(), 7);
|
||||
assert_eq!(LOCATION.column(), 29);
|
||||
|
||||
assert_eq!(NESTED.file(), file!());
|
||||
assert_eq!(NESTED.line(), 10);
|
||||
assert_eq!(NESTED.column(), 9);
|
||||
}
|
@ -22,7 +22,7 @@
|
||||
//[thin]compile-flags: -C lto=thin
|
||||
//[fat]compile-flags: -C lto=fat
|
||||
|
||||
#![feature(core_panic)]
|
||||
#![feature(core_panic, panic_internals)]
|
||||
|
||||
// (For some reason, reproducing the LTO issue requires pulling in std
|
||||
// explicitly this way.)
|
||||
@ -51,7 +51,8 @@ fn main() {
|
||||
|
||||
let _guard = Droppable;
|
||||
let s = "issue-64655-allow-unwind-when-calling-panic-directly.rs";
|
||||
core::panicking::panic(&("???", s, 17, 4));
|
||||
let location = core::panic::Location::internal_constructor(s, 17, 4);
|
||||
core::panicking::panic("???", &location);
|
||||
});
|
||||
|
||||
let wait = handle.join();
|
||||
|
@ -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