diff options
| author | Mazdak Farrokhzad <twingoow@gmail.com> | 2019-10-28 04:53:06 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-10-28 04:53:06 +0100 |
| commit | 4728d66206c82c98aa4e1fad751e8aae7489c242 (patch) | |
| tree | a95e0d577f867d3fba9346478e13bcac3dc793a8 /src/librustc_mir | |
| parent | c8eefdffe9480bbd84554eab3343f71f04af8f9a (diff) | |
| parent | 86e55b1882ac492d6234e5c5f97c7f151a11f5d2 (diff) | |
| download | rust-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.rs | 34 | ||||
| -rw-r--r-- | src/librustc_mir/interpret/intern.rs | 7 | ||||
| -rw-r--r-- | src/librustc_mir/interpret/intrinsics.rs | 34 | ||||
| -rw-r--r-- | src/librustc_mir/interpret/intrinsics/caller_location.rs | 49 | ||||
| -rw-r--r-- | src/librustc_mir/interpret/machine.rs | 2 | ||||
| -rw-r--r-- | src/librustc_mir/interpret/terminator.rs | 2 | ||||
| -rw-r--r-- | src/librustc_mir/lib.rs | 1 | ||||
| -rw-r--r-- | src/librustc_mir/transform/const_prop.rs | 1 |
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>, |
