Skip to content

Commit 017877c

Browse files
committed
Implementation of const caller_location.
1 parent aec97e0 commit 017877c

File tree

7 files changed

+90
-2
lines changed

7 files changed

+90
-2
lines changed

src/librustc_mir/const_eval.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -375,11 +375,12 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
375375

376376
fn call_intrinsic(
377377
ecx: &mut InterpCx<'mir, 'tcx, Self>,
378+
span: Span,
378379
instance: ty::Instance<'tcx>,
379380
args: &[OpTy<'tcx>],
380381
dest: PlaceTy<'tcx>,
381382
) -> InterpResult<'tcx> {
382-
if ecx.emulate_intrinsic(instance, args, dest)? {
383+
if ecx.emulate_intrinsic(span, instance, args, dest)? {
383384
return Ok(());
384385
}
385386
// An intrinsic that we do not support

src/librustc_mir/interpret/intrinsics.rs

+7
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
//! and miri.
44
55
use syntax::symbol::Symbol;
6+
use syntax_pos::Span;
67
use rustc::ty;
78
use rustc::ty::layout::{LayoutOf, Primitive, Size};
89
use rustc::ty::subst::SubstsRef;
@@ -15,6 +16,7 @@ use super::{
1516
Machine, PlaceTy, OpTy, InterpCx,
1617
};
1718

19+
mod caller_location;
1820
mod type_name;
1921

2022
fn numeric_intrinsic<'tcx, Tag>(
@@ -86,6 +88,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
8688
/// Returns `true` if emulation happened.
8789
pub fn emulate_intrinsic(
8890
&mut self,
91+
span: Span,
8992
instance: ty::Instance<'tcx>,
9093
args: &[OpTy<'tcx, M::PointerTag>],
9194
dest: PlaceTy<'tcx, M::PointerTag>,
@@ -94,6 +97,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
9497

9598
let intrinsic_name = &self.tcx.item_name(instance.def_id()).as_str()[..];
9699
match intrinsic_name {
100+
"caller_location" => {
101+
self.write_caller_location(span, dest)?;
102+
}
103+
97104
"min_align_of" |
98105
"pref_align_of" |
99106
"needs_drop" |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
use rustc::middle::lang_items::PanicLocationLangItem;
2+
use rustc::mir::interpret::{Pointer, PointerArithmetic, Scalar};
3+
use rustc::ty::subst::Subst;
4+
use rustc_target::abi::{LayoutOf, Size};
5+
use syntax_pos::Span;
6+
7+
use crate::interpret::{
8+
MemoryKind,
9+
intrinsics::{InterpCx, InterpResult, Machine, PlaceTy},
10+
};
11+
12+
impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
13+
pub fn write_caller_location(
14+
&mut self,
15+
span: Span,
16+
dest: PlaceTy<'tcx, M::PointerTag>,
17+
) -> InterpResult<'tcx> {
18+
let caller = self.tcx.sess.source_map().lookup_char_pos(span.lo());
19+
let filename = caller.file.name.to_string();
20+
let line = Scalar::from_u32(caller.line as u32);
21+
let col = Scalar::from_u32(caller.col_display as u32 + 1);
22+
23+
let ptr_size = self.pointer_size();
24+
let u32_size = Size::from_bits(32);
25+
26+
let loc_ty = self.tcx.type_of(self.tcx.require_lang_item(PanicLocationLangItem, None))
27+
.subst(*self.tcx, self.tcx.mk_substs([self.tcx.lifetimes.re_static.into()].iter()));
28+
let loc_layout = self.layout_of(loc_ty)?;
29+
30+
let file_alloc = self.tcx.allocate_bytes(filename.as_bytes());
31+
let file_ptr = Pointer::new(file_alloc, Size::ZERO);
32+
let file = Scalar::Ptr(self.tag_static_base_pointer(file_ptr));
33+
let file_len = Scalar::from_uint(filename.len() as u128, ptr_size);
34+
35+
let location = self.allocate(loc_layout, MemoryKind::Stack);
36+
37+
let file_out = self.mplace_field(location, 0)?;
38+
let file_ptr_out = self.force_ptr(self.mplace_field(file_out, 0)?.ptr)?;
39+
let file_len_out = self.force_ptr(self.mplace_field(file_out, 1)?.ptr)?;
40+
let line_out = self.force_ptr(self.mplace_field(location, 1)?.ptr)?;
41+
let col_out = self.force_ptr(self.mplace_field(location, 2)?.ptr)?;
42+
43+
let layout = &self.tcx.data_layout;
44+
let alloc = self.memory.get_mut(file_ptr_out.alloc_id)?;
45+
46+
alloc.write_scalar(layout, file_ptr_out, file.into(), ptr_size)?;
47+
alloc.write_scalar(layout, file_len_out, file_len.into(), ptr_size)?;
48+
alloc.write_scalar(layout, line_out, line.into(), u32_size)?;
49+
alloc.write_scalar(layout, col_out, col.into(), u32_size)?;
50+
51+
self.write_scalar(location.ptr, dest)?;
52+
Ok(())
53+
}
54+
}

src/librustc_mir/interpret/machine.rs

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use std::hash::Hash;
88
use rustc::hir::def_id::DefId;
99
use rustc::mir;
1010
use rustc::ty::{self, Ty, TyCtxt};
11+
use syntax_pos::Span;
1112

1213
use super::{
1314
Allocation, AllocId, InterpResult, Scalar, AllocationExtra,
@@ -152,6 +153,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
152153
/// If this returns successfully, the engine will take care of jumping to the next block.
153154
fn call_intrinsic(
154155
ecx: &mut InterpCx<'mir, 'tcx, Self>,
156+
span: Span,
155157
instance: ty::Instance<'tcx>,
156158
args: &[OpTy<'tcx, Self::PointerTag>],
157159
dest: PlaceTy<'tcx, Self::PointerTag>,

src/librustc_mir/interpret/terminator.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
255255
Some(dest) => dest,
256256
None => throw_ub!(Unreachable)
257257
};
258-
M::call_intrinsic(self, instance, args, dest)?;
258+
M::call_intrinsic(self, span, instance, args, dest)?;
259259
// No stack frame gets pushed, the main loop will just act as if the
260260
// call completed.
261261
self.goto_block(ret)?;

src/librustc_mir/transform/const_prop.rs

+1
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine {
158158

159159
fn call_intrinsic(
160160
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
161+
_span: Span,
161162
_instance: ty::Instance<'tcx>,
162163
_args: &[OpTy<'tcx>],
163164
_dest: PlaceTy<'tcx>,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// run-pass
2+
3+
#![feature(const_fn, core_intrinsics)]
4+
5+
use std::{intrinsics::caller_location, panic::Location};
6+
7+
const LOCATION: &Location = caller_location();
8+
const NESTED: &Location = {
9+
const fn nested_location() -> &'static Location<'static> {
10+
caller_location()
11+
};
12+
nested_location()
13+
};
14+
15+
fn main() {
16+
assert_eq!(LOCATION.file(), file!());
17+
assert_eq!(LOCATION.line(), 7);
18+
assert_eq!(LOCATION.column(), 29);
19+
20+
assert_eq!(NESTED.file(), file!());
21+
assert_eq!(NESTED.line(), 10);
22+
assert_eq!(NESTED.column(), 9);
23+
}

0 commit comments

Comments
 (0)