diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index e216f5c4d8a8..b141106aa60f 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -61,7 +61,7 @@ pub fn eval_body_with_mir<'a, 'mir, 'tcx>( mir: &'mir mir::Mir<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> Option<(Value, Pointer, Ty<'tcx>)> { - let (res, ecx) = eval_body_and_ecx(tcx, cid, Some(mir), param_env); + let (res, ecx, _) = eval_body_and_ecx(tcx, cid, Some(mir), param_env); match res { Ok(val) => Some(val), Err(mut err) => { @@ -76,7 +76,7 @@ pub fn eval_body<'a, 'tcx>( cid: GlobalId<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> Option<(Value, Pointer, Ty<'tcx>)> { - let (res, ecx) = eval_body_and_ecx(tcx, cid, None, param_env); + let (res, ecx, _) = eval_body_and_ecx(tcx, cid, None, param_env); match res { Ok(val) => Some(val), Err(mut err) => { @@ -91,9 +91,12 @@ fn eval_body_and_ecx<'a, 'mir, 'tcx>( cid: GlobalId<'tcx>, mir: Option<&'mir mir::Mir<'tcx>>, param_env: ty::ParamEnv<'tcx>, -) -> (EvalResult<'tcx, (Value, Pointer, Ty<'tcx>)>, EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>) { +) -> (EvalResult<'tcx, (Value, Pointer, Ty<'tcx>)>, EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>, Span) { debug!("eval_body: {:?}, {:?}", cid, param_env); let mut ecx = EvalContext::new(tcx, param_env, CompileTimeEvaluator, ()); + // 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 res = (|| { let mut mir = match mir { Some(mir) => mir, @@ -102,6 +105,7 @@ fn eval_body_and_ecx<'a, 'mir, 'tcx>( if let Some(index) = cid.promoted { mir = &mir.promoted[index]; } + span = mir.span; let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?; let alloc = tcx.interpret_interner.get_cached(cid.instance.def_id()); let alloc = match alloc { @@ -120,8 +124,7 @@ fn eval_body_and_ecx<'a, 'mir, 'tcx>( if tcx.is_static(cid.instance.def_id()).is_some() { tcx.interpret_interner.cache(cid.instance.def_id(), ptr.alloc_id); } - let span = tcx.def_span(cid.instance.def_id()); - let internally_mutable = !layout.ty.is_freeze(tcx, param_env, span); + let internally_mutable = !layout.ty.is_freeze(tcx, param_env, mir.span); let mutability = tcx.is_static(cid.instance.def_id()); let mutability = if mutability == Some(hir::Mutability::MutMutable) || internally_mutable { Mutability::Mutable @@ -152,7 +155,7 @@ fn eval_body_and_ecx<'a, 'mir, 'tcx>( }; Ok((value, ptr, layout.ty)) })(); - (res, ecx) + (res, ecx, span) } pub struct CompileTimeEvaluator; @@ -499,7 +502,7 @@ pub fn const_eval_provider<'a, 'tcx>( } }; - let (res, ecx) = eval_body_and_ecx(tcx, cid, None, key.param_env); + let (res, ecx, span) = eval_body_and_ecx(tcx, cid, None, key.param_env); res.map(|(miri_value, _, miri_ty)| { tcx.mk_const(ty::Const { val: ConstVal::Value(miri_value), @@ -509,7 +512,6 @@ pub fn const_eval_provider<'a, 'tcx>( if tcx.is_static(def_id).is_some() { ecx.report(&mut err, true, None); } - let span = ecx.frame().span; ConstEvalErr { kind: err.into(), span, diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 09c72c4bf938..d3ab494139a5 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -21,11 +21,12 @@ use rustc::ty::layout::LayoutOf; use rustc::middle::const_val::ConstVal; use rustc::ty::{TyCtxt, self, Instance}; use rustc::mir::interpret::{Value, PrimVal, GlobalId}; -use interpret::{eval_body_with_mir, eval_body, mk_borrowck_eval_cx, unary_op, ValTy}; +use interpret::{eval_body_with_mir, mk_borrowck_eval_cx, unary_op, ValTy}; use transform::{MirPass, MirSource}; use syntax::codemap::Span; use rustc::ty::subst::Substs; use rustc_data_structures::indexed_vec::IndexVec; +use rustc::ty::ParamEnv; pub struct ConstProp; @@ -56,6 +57,7 @@ struct ConstPropagator<'b, 'a, 'tcx:'a+'b> { source: MirSource, places: IndexVec>>, can_const_prop: IndexVec, + param_env: ParamEnv<'tcx>, } impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> { @@ -64,24 +66,40 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> { tcx: TyCtxt<'a, 'tcx, 'tcx>, source: MirSource, ) -> ConstPropagator<'b, 'a, 'tcx> { + let param_env = tcx.param_env(source.def_id); ConstPropagator { mir, tcx, source, + param_env, can_const_prop: CanConstProp::check(mir), places: IndexVec::from_elem(None, &mir.local_decls), } } + fn const_eval(&self, cid: GlobalId<'tcx>, span: Span) -> Option> { + let value = match self.tcx.const_eval(self.param_env.and(cid)) { + Ok(val) => val, + // FIXME: report some errors + Err(_) => return None, + }; + let val = match value.val { + ConstVal::Value(v) => v, + _ => bug!("eval produced: {:?}", value), + }; + let val = (val, value.ty, span); + trace!("evaluated {:?} to {:?}", cid, val); + Some(val) + } + fn eval_constant(&mut self, c: &Constant<'tcx>) -> Option> { match c.literal { Literal::Value { value } => match value.val { ConstVal::Value(v) => Some((v, value.ty, c.span)), ConstVal::Unevaluated(did, substs) => { - let param_env = self.tcx.param_env(self.source.def_id); let instance = Instance::resolve( self.tcx, - param_env, + self.param_env, did, substs, )?; @@ -89,10 +107,7 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> { instance, promoted: None, }; - let (value, _, ty) = eval_body(self.tcx, cid, param_env)?; - let val = (value, ty, c.span); - trace!("evaluated {:?} to {:?}", c, val); - Some(val) + self.const_eval(cid, c.span) }, }, // evaluate the promoted and replace the constant with the evaluated result @@ -108,8 +123,9 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> { instance, promoted: Some(index), }; - let param_env = self.tcx.param_env(self.source.def_id); - let (value, _, ty) = eval_body_with_mir(self.tcx, cid, self.mir, param_env)?; + // cannot use `const_eval` here, because that would require having the MIR + // for the current function available, but we're producing said MIR right now + let (value, _, ty) = eval_body_with_mir(self.tcx, cid, self.mir, self.param_env)?; let val = (value, ty, c.span); trace!("evaluated {:?} to {:?}", c, val); Some(val)