diff --git a/src/const_eval.rs b/src/const_eval.rs index ff80f68e2c3f..771b740b3755 100644 --- a/src/const_eval.rs +++ b/src/const_eval.rs @@ -1,22 +1,20 @@ -use rustc::hir::def_id::DefId; use rustc::traits::Reveal; -use rustc::ty::subst::Substs; -use rustc::ty::{self, TyCtxt}; +use rustc::ty::{self, TyCtxt, Ty, Instance}; use error::{EvalError, EvalResult}; use lvalue::{Global, GlobalId, Lvalue}; +use value::PrimVal; use rustc_const_math::ConstInt; use eval_context::{EvalContext, StackPopCleanup}; -pub fn eval_body_as_integer<'a, 'tcx>( +pub fn eval_body_as_primval<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, - (def_id, substs): (DefId, &'tcx Substs<'tcx>), -) -> EvalResult<'tcx, ConstInt> { + instance: Instance<'tcx>, +) -> EvalResult<'tcx, (PrimVal, Ty<'tcx>)> { let limits = ::ResourceLimits::default(); let mut ecx = EvalContext::new(tcx, limits); - let instance = ecx.resolve_associated_const(def_id, substs); let cid = GlobalId { instance, promoted: None }; - if ecx.tcx.has_attr(def_id, "linkage") { + if ecx.tcx.has_attr(instance.def_id(), "linkage") { return Err(EvalError::NotConst("extern global".to_string())); } @@ -28,7 +26,7 @@ pub fn eval_body_as_integer<'a, 'tcx>( ty::ParamEnv::empty(Reveal::All), mir.span); let cleanup = StackPopCleanup::MarkStatic(mutable); - let name = ty::tls::with(|tcx| tcx.item_path_str(def_id)); + let name = ty::tls::with(|tcx| tcx.item_path_str(instance.def_id())); trace!("pushing stack frame for global: {}", name); ecx.push_stack_frame( instance, @@ -41,11 +39,19 @@ pub fn eval_body_as_integer<'a, 'tcx>( while ecx.step()? {} } let value = ecx.globals.get(&cid).expect("global not cached").value; - let prim = ecx.value_to_primval(value, mir.return_ty)?.to_bytes()?; + Ok((ecx.value_to_primval(value, mir.return_ty)?, mir.return_ty)) +} + +pub fn eval_body_as_integer<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + instance: Instance<'tcx>, +) -> EvalResult<'tcx, ConstInt> { + let (prim, ty) = eval_body_as_primval(tcx, instance)?; + let prim = prim.to_bytes()?; use syntax::ast::{IntTy, UintTy}; use rustc::ty::TypeVariants::*; use rustc_const_math::{ConstIsize, ConstUsize}; - Ok(match mir.return_ty.sty { + Ok(match ty.sty { TyInt(IntTy::I8) => ConstInt::I8(prim as i128 as i8), TyInt(IntTy::I16) => ConstInt::I16(prim as i128 as i16), TyInt(IntTy::I32) => ConstInt::I32(prim as i128 as i32), diff --git a/src/error.rs b/src/error.rs index 801ea5c7da48..3e1155e0b874 100644 --- a/src/error.rs +++ b/src/error.rs @@ -69,6 +69,7 @@ pub enum EvalError<'tcx> { NeedsRfc(String), NotConst(String), ReadFromReturnPointer, + PathNotFound(Vec), } pub type EvalResult<'tcx, T = ()> = Result>; @@ -175,6 +176,8 @@ fn description(&self) -> &str { "this feature is not compatible with constant evaluation", ReadFromReturnPointer => "tried to read from the return pointer", + EvalError::PathNotFound(_) => + "a path could not be resolved, maybe the crate is not loaded", } } @@ -215,6 +218,8 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "\"{}\" needs an rfc before being allowed inside constants", msg), NotConst(ref msg) => write!(f, "Cannot evaluate within constants: \"{}\"", msg), + EvalError::PathNotFound(ref path) => + write!(f, "Cannot find path {:?}", path), _ => write!(f, "{}", self.description()), } } diff --git a/src/terminator/mod.rs b/src/terminator/mod.rs index dc6610a2213b..643df3608f9c 100644 --- a/src/terminator/mod.rs +++ b/src/terminator/mod.rs @@ -1,4 +1,4 @@ -use rustc::hir::def_id::DefId; +use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; use rustc::ty::{self, TypeVariants, Ty}; use rustc::ty::layout::Layout; @@ -13,6 +13,8 @@ use value::{PrimVal, Value}; use rustc_data_structures::indexed_vec::Idx; +use std::mem; + mod drop; mod intrinsic; @@ -853,12 +855,32 @@ fn call_c_abi( "sysconf" => { let name = self.value_to_primval(args[0], usize)?.to_u64()?; trace!("sysconf() called with name {}", name); - let result = match name { - 30 => PrimVal::Bytes(4096), // _SC_PAGESIZE - 70 => PrimVal::from_i128(-1), // _SC_GETPW_R_SIZE_MAX - _ => return Err(EvalError::Unimplemented(format!("Unimplemented sysconf name: {}", name))) - }; - self.write_primval(dest, result, dest_ty)?; + // cache the sysconf integers via miri's global cache + let paths = &[ + (&["libc", "_SC_PAGESIZE"], PrimVal::Bytes(4096)), + (&["libc", "_SC_GETPW_R_SIZE_MAX"], PrimVal::from_i128(-1)), + ]; + let mut result = None; + for &(path, path_value) in paths { + if let Ok(instance) = self.resolve_path(path) { + use lvalue::GlobalId; + let cid = GlobalId { instance, promoted: None }; + // compute global if not cached + let val = match self.globals.get(&cid).map(|glob| glob.value) { + Some(value) => self.value_to_primval(value, usize)?.to_u64()?, + None => ::const_eval::eval_body_as_primval(self.tcx, instance)?.0.to_u64()?, + }; + if val == name { + result = Some(path_value); + break; + } + } + } + if let Some(result) = result { + self.write_primval(dest, result, dest_ty)?; + } else { + return Err(EvalError::Unimplemented(format!("Unimplemented sysconf name: {}", name))); + } } // Hook pthread calls that go to the thread-local storage memory subsystem @@ -933,4 +955,41 @@ fn call_c_abi( self.goto_block(dest_block); Ok(()) } + + /// Get an instance for a path. + fn resolve_path(&self, path: &[&str]) -> EvalResult<'tcx, ty::Instance<'tcx>> { + let cstore = &self.tcx.sess.cstore; + + let crates = cstore.crates(); + crates.iter() + .find(|&&krate| cstore.crate_name(krate) == path[0]) + .and_then(|krate| { + let krate = DefId { + krate: *krate, + index: CRATE_DEF_INDEX, + }; + let mut items = cstore.item_children(krate, self.tcx.sess); + let mut path_it = path.iter().skip(1).peekable(); + + while let Some(segment) = path_it.next() { + for item in &mem::replace(&mut items, vec![]) { + if item.ident.name == *segment { + if path_it.peek().is_none() { + return Some(ty::Instance::mono(self.tcx, item.def.def_id())); + } + + items = cstore.item_children(item.def.def_id(), self.tcx.sess); + break; + } + } + } + None + }) + .ok_or_else(|| { + let path = path.iter() + .map(|&s| s.to_owned()) + .collect(); + EvalError::PathNotFound(path) + }) + } }