about summary refs log tree commit diff
path: root/src/librustc_mir
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-10-28 04:53:06 +0100
committerGitHub <noreply@github.com>2019-10-28 04:53:06 +0100
commit4728d66206c82c98aa4e1fad751e8aae7489c242 (patch)
treea95e0d577f867d3fba9346478e13bcac3dc793a8 /src/librustc_mir
parentc8eefdffe9480bbd84554eab3343f71f04af8f9a (diff)
parent86e55b1882ac492d6234e5c5f97c7f151a11f5d2 (diff)
downloadrust-4728d66206c82c98aa4e1fad751e8aae7489c242.tar.gz
rust-4728d66206c82c98aa4e1fad751e8aae7489c242.zip
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.
Diffstat (limited to 'src/librustc_mir')
-rw-r--r--src/librustc_mir/const_eval.rs34
-rw-r--r--src/librustc_mir/interpret/intern.rs7
-rw-r--r--src/librustc_mir/interpret/intrinsics.rs34
-rw-r--r--src/librustc_mir/interpret/intrinsics/caller_location.rs49
-rw-r--r--src/librustc_mir/interpret/machine.rs2
-rw-r--r--src/librustc_mir/interpret/terminator.rs2
-rw-r--r--src/librustc_mir/lib.rs1
-rw-r--r--src/librustc_mir/transform/const_prop.rs1
8 files changed, 108 insertions, 22 deletions
diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs
index bb02b99dd8d..89bdf7391c3 100644
--- a/src/librustc_mir/const_eval.rs
+++ b/src/librustc_mir/const_eval.rs
@@ -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>(
diff --git a/src/librustc_mir/interpret/intern.rs b/src/librustc_mir/interpret/intern.rs
index 646d1783c8e..924529d7f55 100644
--- a/src/librustc_mir/interpret/intern.rs
+++ b/src/librustc_mir/interpret/intern.rs
@@ -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),
diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs
index 5fc23b4a69e..519f4f03222 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,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(msg.into())?;
+            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 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()?;
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..249d2f9ff53
--- /dev/null
+++ b/src/librustc_mir/interpret/intrinsics/caller_location.rs
@@ -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)
+    }
+}
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/lib.rs b/src/librustc_mir/lib.rs
index 98d5487870a..4d604cb025c 100644
--- a/src/librustc_mir/lib.rs
+++ b/src/librustc_mir/lib.rs
@@ -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)
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>,