1
Fork 0

Implementation of const caller_location.

This commit is contained in:
Adam Perry 2019-10-24 08:03:57 -07:00
parent aec97e050e
commit 017877cbbe
7 changed files with 90 additions and 2 deletions

View file

@ -375,11 +375,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

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,10 @@ 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" => {
self.write_caller_location(span, dest)?;
}
"min_align_of" |
"pref_align_of" |
"needs_drop" |

View file

@ -0,0 +1,54 @@
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::Span;
use crate::interpret::{
MemoryKind,
intrinsics::{InterpCx, InterpResult, Machine, PlaceTy},
};
impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
pub fn write_caller_location(
&mut self,
span: Span,
dest: PlaceTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx> {
let caller = self.tcx.sess.source_map().lookup_char_pos(span.lo());
let filename = caller.file.name.to_string();
let line = Scalar::from_u32(caller.line as u32);
let col = Scalar::from_u32(caller.col_display as u32 + 1);
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_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.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)?;
self.write_scalar(location.ptr, dest)?;
Ok(())
}
}

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

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

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