about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAdam Perry <adam.n.perry@gmail.com>2019-10-24 08:03:57 -0700
committerAdam Perry <adam.n.perry@gmail.com>2019-10-27 12:51:34 -0700
commit017877cbbe7903beb483f13678aedae1e40b6ab0 (patch)
treea95b12e405248ac18cb7ed7c504f47e43c38d561
parentaec97e050ea5247fa13612399a7a812dbce89ec9 (diff)
downloadrust-017877cbbe7903beb483f13678aedae1e40b6ab0.tar.gz
rust-017877cbbe7903beb483f13678aedae1e40b6ab0.zip
Implementation of const caller_location.
-rw-r--r--src/librustc_mir/const_eval.rs3
-rw-r--r--src/librustc_mir/interpret/intrinsics.rs7
-rw-r--r--src/librustc_mir/interpret/intrinsics/caller_location.rs54
-rw-r--r--src/librustc_mir/interpret/machine.rs2
-rw-r--r--src/librustc_mir/interpret/terminator.rs2
-rw-r--r--src/librustc_mir/transform/const_prop.rs1
-rw-r--r--src/test/ui/consts/const-eval/const_caller_location.rs23
7 files changed, 90 insertions, 2 deletions
diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs
index eeaa3c6792d..eed26c32b7a 100644
--- a/src/librustc_mir/const_eval.rs
+++ b/src/librustc_mir/const_eval.rs
@@ -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
diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs
index 20cb2926d66..12e080869c7 100644
--- a/src/librustc_mir/interpret/intrinsics.rs
+++ b/src/librustc_mir/interpret/intrinsics.rs
@@ -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" |
diff --git a/src/librustc_mir/interpret/intrinsics/caller_location.rs b/src/librustc_mir/interpret/intrinsics/caller_location.rs
new file mode 100644
index 00000000000..5addb13b61c
--- /dev/null
+++ b/src/librustc_mir/interpret/intrinsics/caller_location.rs
@@ -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(())
+    }
+}
diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs
index c30c59bbf10..870e50a3cbb 100644
--- a/src/librustc_mir/interpret/machine.rs
+++ b/src/librustc_mir/interpret/machine.rs
@@ -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>,
diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs
index 7f6baf0bb49..d90f2058aa7 100644
--- a/src/librustc_mir/interpret/terminator.rs
+++ b/src/librustc_mir/interpret/terminator.rs
@@ -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)?;
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index 13097a21561..e7095101f46 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -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>,
diff --git a/src/test/ui/consts/const-eval/const_caller_location.rs b/src/test/ui/consts/const-eval/const_caller_location.rs
new file mode 100644
index 00000000000..c63822f052b
--- /dev/null
+++ b/src/test/ui/consts/const-eval/const_caller_location.rs
@@ -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);
+}