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:
Mazdak Farrokhzad 2019-10-28 04:53:06 +01:00 committed by GitHub
commit 4728d66206
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 331 additions and 145 deletions

View File

@ -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,

View File

@ -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

View File

@ -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 }
}

View File

@ -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) }
}

View File

@ -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;

View File

@ -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 {

View File

@ -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
}
}

View File

@ -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> {

View File

@ -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],

View File

@ -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

View File

@ -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>;

View File

@ -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;
}

View File

@ -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>(

View File

@ -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),

View File

@ -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()?;

View 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)
}
}

View File

@ -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>,

View File

@ -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)?;

View File

@ -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)

View File

@ -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>,

View File

@ -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)),

View File

@ -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

View 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);
}

View File

@ -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();

View File

@ -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);
}