From 2f0e07730088b7656c244030f360406758f788ea Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 6 Feb 2018 18:33:59 +0100 Subject: [PATCH] Report tcx errors with the span of the currently evaluating statement --- src/librustc_mir/interpret/const_eval.rs | 9 +-- src/librustc_mir/interpret/eval_context.rs | 62 ++++++-------------- src/librustc_mir/interpret/memory.rs | 7 ++- src/librustc_mir/interpret/place.rs | 4 +- src/librustc_mir/interpret/step.rs | 4 ++ src/librustc_mir/interpret/terminator/mod.rs | 11 ++-- src/librustc_mir/interpret/traits.rs | 5 +- src/test/ui/infinite-recursion-const-fn.rs | 4 +- 8 files changed, 41 insertions(+), 65 deletions(-) diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index b44e91d7b74..ee5874be9d7 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -24,7 +24,7 @@ pub fn mk_borrowck_eval_cx<'a, 'mir, 'tcx>( ) -> EvalResult<'tcx, EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>> { debug!("mk_borrowck_eval_cx: {:?}", instance); let param_env = tcx.param_env(instance.def_id()); - let mut ecx = EvalContext::new(tcx, param_env, CompileTimeEvaluator, (), span); + let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeEvaluator, ()); // insert a stack frame so any queries have the correct substs ecx.push_stack_frame( instance, @@ -43,7 +43,7 @@ pub fn mk_eval_cx<'a, 'tcx>( ) -> EvalResult<'tcx, EvalContext<'a, 'tcx, 'tcx, CompileTimeEvaluator>> { debug!("mk_eval_cx: {:?}, {:?}", instance, param_env); let span = tcx.def_span(instance.def_id()); - let mut ecx = EvalContext::new(tcx, param_env, CompileTimeEvaluator, (), span); + let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeEvaluator, ()); let mir = ecx.load_mir(instance.def)?; // insert a stack frame so any queries have the correct substs ecx.push_stack_frame( @@ -96,8 +96,9 @@ fn eval_body_and_ecx<'a, 'mir, 'tcx>( debug!("eval_body: {:?}, {:?}", cid, param_env); // we start out with the best span we have // and try improving it down the road when more information is available - let mut span = tcx.def_span(cid.instance.def_id()); - let mut ecx = EvalContext::new(tcx, param_env, CompileTimeEvaluator, (), mir.map(|mir| mir.span).unwrap_or(span)); + let span = tcx.def_span(cid.instance.def_id()); + let mut span = mir.map(|mir| mir.span).unwrap_or(span); + let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeEvaluator, ()); let res = (|| { let mut mir = match mir { Some(mir) => mir, diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 23ab6be1b46..f46d5631060 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -5,13 +5,13 @@ use rustc::hir::def_id::DefId; use rustc::hir::map::definitions::DefPathData; use rustc::middle::const_val::{ConstVal, ErrKind}; use rustc::mir; -use rustc::traits::Reveal; use rustc::ty::layout::{self, Size, Align, HasDataLayout, LayoutOf, TyLayout}; use rustc::ty::subst::{Subst, Substs}; use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::maps::TyCtxtAt; use rustc_data_structures::indexed_vec::Idx; use rustc::middle::const_val::FrameInfo; -use syntax::codemap::{self, DUMMY_SP, Span}; +use syntax::codemap::{self, Span}; use syntax::ast::Mutability; use rustc::mir::interpret::{ GlobalId, Value, Pointer, PrimVal, PrimValKind, @@ -27,7 +27,7 @@ pub struct EvalContext<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> { pub machine: M, /// The results of the type checker, from rustc. - pub tcx: TyCtxt<'a, 'tcx, 'tcx>, + pub tcx: TyCtxtAt<'a, 'tcx, 'tcx>, /// Bounds in scope for polymorphic evaluations. pub param_env: ty::ParamEnv<'tcx>, @@ -45,11 +45,6 @@ pub struct EvalContext<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> { /// This prevents infinite loops and huge computations from freezing up const eval. /// Remove once halting problem is solved. pub(crate) steps_remaining: usize, - - /// The span that is used if no more stack frames are available - /// - /// This happens after successful evaluation when the result is inspected - root_span: codemap::Span, } /// A stack frame. @@ -154,7 +149,7 @@ impl<'c, 'b, 'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> layout::HasTyCtxt<'tcx> for &'a EvalContext<'a, 'mir, 'tcx, M> { #[inline] fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> { - self.tcx + *self.tcx } } @@ -162,7 +157,7 @@ impl<'c, 'b, 'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> layout::HasTyCtxt<'tcx> for &'c &'b mut EvalContext<'a, 'mir, 'tcx, M> { #[inline] fn tcx<'d>(&'d self) -> TyCtxt<'d, 'tcx, 'tcx> { - self.tcx + *self.tcx } } @@ -187,11 +182,10 @@ impl<'c, 'b, 'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> LayoutOf> impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { pub fn new( - tcx: TyCtxt<'a, 'tcx, 'tcx>, + tcx: TyCtxtAt<'a, 'tcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, machine: M, memory_data: M::MemoryData, - root_span: codemap::Span, ) -> Self { EvalContext { machine, @@ -201,7 +195,6 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M stack: Vec::new(), stack_limit: tcx.sess.const_eval_stack_frame_limit.get(), steps_remaining: tcx.sess.const_eval_step_limit.get(), - root_span, } } @@ -255,7 +248,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M pub(super) fn resolve(&self, def_id: DefId, substs: &'tcx Substs<'tcx>) -> EvalResult<'tcx, ty::Instance<'tcx>> { let substs = self.tcx.trans_apply_param_substs(self.substs(), &substs); ty::Instance::resolve( - self.tcx, + *self.tcx, self.param_env, def_id, substs, @@ -263,7 +256,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M } pub(super) fn type_is_sized(&self, ty: Ty<'tcx>) -> bool { - ty.is_sized(self.tcx.at(DUMMY_SP), self.param_env) + ty.is_sized(self.tcx, self.param_env) } pub fn load_mir( @@ -290,7 +283,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M // miri doesn't care about lifetimes, and will choke on some crazy ones // let's simply get rid of them let without_lifetimes = self.tcx.erase_regions(&ty); - let substituted = without_lifetimes.subst(self.tcx, substs); + let substituted = without_lifetimes.subst(*self.tcx, substs); let substituted = self.tcx.fully_normalize_monormophic_ty(&substituted); substituted } @@ -725,7 +718,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M ty::TyClosure(def_id, substs) => { let substs = self.tcx.trans_apply_param_substs(self.substs(), &substs); let instance = ty::Instance::resolve_closure( - self.tcx, + *self.tcx, def_id, substs, ty::ClosureKind::FnOnce, @@ -748,8 +741,8 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M let place = self.eval_place(place)?; let discr_val = self.read_discriminant_value(place, ty)?; if let ty::TyAdt(adt_def, _) = ty.sty { - trace!("Read discriminant {}, valid discriminants {:?}", discr_val, adt_def.discriminants(self.tcx).collect::>()); - if adt_def.discriminants(self.tcx).all(|v| { + trace!("Read discriminant {}, valid discriminants {:?}", discr_val, adt_def.discriminants(*self.tcx).collect::>()); + if adt_def.discriminants(*self.tcx).all(|v| { discr_val != v.val }) { @@ -797,7 +790,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M pub fn eval_operand(&mut self, op: &mir::Operand<'tcx>) -> EvalResult<'tcx, ValTy<'tcx>> { use rustc::mir::Operand::*; - let ty = self.monomorphize(op.ty(self.mir(), self.tcx), self.substs()); + let ty = self.monomorphize(op.ty(self.mir(), *self.tcx), self.substs()); match *op { // FIXME: do some more logic on `move` to invalidate the old location Copy(ref place) | @@ -905,7 +898,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M } layout::Variants::Tagged { .. } => { let discr_val = dest_ty.ty_adt_def().unwrap() - .discriminant_for_variant(self.tcx, variant_index) + .discriminant_for_variant(*self.tcx, variant_index) .val; let (discr_dest, discr) = self.place_field(dest, mir::Field::new(0), layout)?; @@ -1412,7 +1405,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M } (_, &ty::TyDynamic(ref data, _)) => { let trait_ref = data.principal().unwrap().with_self_ty( - self.tcx, + *self.tcx, src_pointee_ty, ); let trait_ref = self.tcx.erase_regions(&trait_ref); @@ -1601,18 +1594,8 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M }; frames.push(FrameInfo { span, location }); } - let span = if let Some(frame) = self.stack().last() { - let bb = &frame.mir.basic_blocks()[frame.block]; - if let Some(stmt) = bb.statements.get(frame.stmt) { - stmt.source_info.span - } else { - bb.terminator().source_info.span - } - } else { - self.root_span - }; trace!("generate stacktrace: {:#?}, {:?}", frames, explicit_span); - (frames, span) + (frames, self.tcx.span) } pub fn report(&self, e: &mut EvalError, as_err: bool, explicit_span: Option) { @@ -1660,7 +1643,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M }); trace!("reporting const eval failure at {:?}", span); let mut err = if as_err { - ::rustc::middle::const_val::struct_error(self.tcx, span, "constant evaluation error") + ::rustc::middle::const_val::struct_error(*self.tcx, span, "constant evaluation error") } else { let node_id = self .stack() @@ -1722,14 +1705,3 @@ impl<'mir, 'tcx> Frame<'mir, 'tcx> { return Ok(old); } } - -// TODO(solson): Upstream these methods into rustc::ty::layout. - -pub fn resolve_drop_in_place<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - ty: Ty<'tcx>, -) -> ty::Instance<'tcx> { - let def_id = tcx.require_lang_item(::rustc::middle::lang_items::DropInPlaceFnLangItem); - let substs = tcx.intern_substs(&[ty.into()]); - ty::Instance::resolve(tcx, ty::ParamEnv::empty(Reveal::All), def_id, substs).unwrap() -} diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index da8ff11e3d0..7dceacabb29 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -2,7 +2,8 @@ use byteorder::{ReadBytesExt, WriteBytesExt, LittleEndian, BigEndian}; use std::collections::{btree_map, BTreeMap, HashMap, HashSet, VecDeque}; use std::{ptr, io}; -use rustc::ty::{Instance, TyCtxt}; +use rustc::ty::Instance; +use rustc::ty::maps::TyCtxtAt; use rustc::ty::layout::{self, Align, TargetDataLayout}; use syntax::ast::Mutability; @@ -51,11 +52,11 @@ pub struct Memory<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> { /// The current stack frame. Used to check accesses against locks. pub cur_frame: usize, - pub tcx: TyCtxt<'a, 'tcx, 'tcx>, + pub tcx: TyCtxtAt<'a, 'tcx, 'tcx>, } impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { - pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, data: M::MemoryData) -> Self { + pub fn new(tcx: TyCtxtAt<'a, 'tcx, 'tcx>, data: M::MemoryData) -> Self { Memory { data, alloc_kind: HashMap::new(), diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 4ca68068728..d27de3ef6bf 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -209,7 +209,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { extra: PlaceExtra::None, } } else { - let instance = ty::Instance::mono(self.tcx, static_.def_id); + let instance = ty::Instance::mono(*self.tcx, static_.def_id); let cid = GlobalId { instance, promoted: None @@ -445,7 +445,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { pub fn place_ty(&self, place: &mir::Place<'tcx>) -> Ty<'tcx> { self.monomorphize( - place.ty(self.mir(), self.tcx).to_ty(self.tcx), + place.ty(self.mir(), *self.tcx).to_ty(*self.tcx), self.substs(), ) } diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index 94fe3d1c67b..54fd364d3f8 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -51,6 +51,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { // Some statements (e.g. box) push new stack frames. We have to record the stack frame number // *before* executing the statement. let frame_idx = self.cur_frame(); + self.tcx.span = stmt.source_info.span; + self.memory.tcx.span = stmt.source_info.span; match stmt.kind { Assign(ref place, ref rvalue) => self.eval_rvalue_into_place(rvalue, place)?, @@ -99,6 +101,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { fn terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> EvalResult<'tcx> { trace!("{:?}", terminator.kind); + self.tcx.span = terminator.source_info.span; + self.memory.tcx.span = terminator.source_info.span; self.eval_terminator(terminator)?; if !self.stack.is_empty() { trace!("// {:?}", self.frame().block); diff --git a/src/librustc_mir/interpret/terminator/mod.rs b/src/librustc_mir/interpret/terminator/mod.rs index b1b5f77a2e6..51dee0aaff4 100644 --- a/src/librustc_mir/interpret/terminator/mod.rs +++ b/src/librustc_mir/interpret/terminator/mod.rs @@ -5,8 +5,7 @@ use syntax::codemap::Span; use syntax::abi::Abi; use rustc::mir::interpret::{EvalResult, PrimVal, Value}; -use super::{EvalContext, eval_context, - Place, Machine, ValTy}; +use super::{EvalContext, Place, Machine, ValTy}; use rustc_data_structures::indexed_vec::Idx; use interpret::memory::HasMemory; @@ -72,10 +71,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { ty::TyFnPtr(sig) => { let fn_ptr = self.value_to_primval(func)?.to_ptr()?; let instance = self.memory.get_fn(fn_ptr)?; - let instance_ty = instance.ty(self.tcx); + let instance_ty = instance.ty(*self.tcx); match instance_ty.sty { ty::TyFnDef(..) => { - let real_sig = instance_ty.fn_sig(self.tcx); + let real_sig = instance_ty.fn_sig(*self.tcx); let sig = self.tcx.erase_late_bound_regions_and_normalize(&sig); let real_sig = self.tcx.erase_late_bound_regions_and_normalize(&real_sig); if !self.check_sig_compat(sig, real_sig)? { @@ -88,7 +87,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { } ty::TyFnDef(def_id, substs) => ( self.resolve(def_id, substs)?, - func.ty.fn_sig(self.tcx), + func.ty.fn_sig(*self.tcx), ), _ => { let msg = format!("can't handle callee of type {:?}", func.ty); @@ -117,7 +116,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { let ty = self.tcx.trans_apply_param_substs(self.substs(), &ty); trace!("TerminatorKind::drop: {:?}, type {}", location, ty); - let instance = eval_context::resolve_drop_in_place(self.tcx, ty); + let instance = ::monomorphize::resolve_drop_in_place(*self.tcx, ty); self.drop_place( place, instance, diff --git a/src/librustc_mir/interpret/traits.rs b/src/librustc_mir/interpret/traits.rs index 03b215fa0b8..c67cf1c84bf 100644 --- a/src/librustc_mir/interpret/traits.rs +++ b/src/librustc_mir/interpret/traits.rs @@ -3,8 +3,7 @@ use rustc::ty::layout::{Size, Align, LayoutOf}; use syntax::ast::Mutability; use rustc::mir::interpret::{PrimVal, Value, MemoryPointer, EvalResult}; -use super::{EvalContext, eval_context, - Machine}; +use super::{EvalContext, Machine}; impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { /// Creates a dynamic vtable for the given type and vtable origin. This is used only for @@ -34,7 +33,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { None, )?; - let drop = eval_context::resolve_drop_in_place(self.tcx, ty); + let drop = ::monomorphize::resolve_drop_in_place(*self.tcx, ty); let drop = self.memory.create_fn_alloc(drop); self.memory.write_ptr_sized_unsigned(vtable, ptr_align, PrimVal::Ptr(drop))?; diff --git a/src/test/ui/infinite-recursion-const-fn.rs b/src/test/ui/infinite-recursion-const-fn.rs index 51de304405a..f98074bc554 100644 --- a/src/test/ui/infinite-recursion-const-fn.rs +++ b/src/test/ui/infinite-recursion-const-fn.rs @@ -11,8 +11,8 @@ //https://github.com/rust-lang/rust/issues/31364 #![feature(const_fn)] -const fn a() -> usize { b() } -const fn b() -> usize { a() } //~ ERROR constant evaluation error +const fn a() -> usize { b() } //~ ERROR constant evaluation error +const fn b() -> usize { a() } const ARR: [i32; a()] = [5; 6]; fn main(){}