+ crate fn cast(
+ &mut self,
+ src: ValTy<'tcx>,
+ kind: CastKind,
+ dest_ty: Ty<'tcx>,
+ dest: Place,
+ ) -> EvalResult<'tcx> {
+ use rustc::mir::CastKind::*;
+ match kind {
+ Unsize => {
+ let src_layout = self.layout_of(src.ty)?;
+ let dst_layout = self.layout_of(dest_ty)?;
+ self.unsize_into(src.value, src_layout, dest, dst_layout)?;
+ }
+
+ Misc => {
+ if self.type_is_fat_ptr(src.ty) {
+ match (src.value, self.type_is_fat_ptr(dest_ty)) {
+ (Value::ByRef { .. }, _) |
+ // pointers to extern types
+ (Value::Scalar(_),_) |
+ // slices and trait objects to other slices/trait objects
+ (Value::ScalarPair(..), true) => {
+ let valty = ValTy {
+ value: src.value,
+ ty: dest_ty,
+ };
+ self.write_value(valty, dest)?;
+ }
+ // slices and trait objects to thin pointers (dropping the metadata)
+ (Value::ScalarPair(data, _), false) => {
+ let valty = ValTy {
+ value: Value::Scalar(data),
+ ty: dest_ty,
+ };
+ self.write_value(valty, dest)?;
+ }
+ }
+ } else {
+ let src_layout = self.layout_of(src.ty)?;
+ match src_layout.variants {
+ layout::Variants::Single { index } => {
+ if let Some(def) = src.ty.ty_adt_def() {
+ let discr_val = def
+ .discriminant_for_variant(*self.tcx, index)
+ .val;
+ let defined = self
+ .layout_of(dest_ty)
+ .unwrap()
+ .size
+ .bits() as u8;
+ return self.write_scalar(
+ dest,
+ Scalar::Bits {
+ bits: discr_val,
+ defined,
+ },
+ dest_ty);
+ }
+ }
+ layout::Variants::Tagged { .. } |
+ layout::Variants::NicheFilling { .. } => {},
+ }
+
+ let src_val = self.value_to_scalar(src)?;
+ let dest_val = self.cast_scalar(src_val, src.ty, dest_ty)?;
+ let valty = ValTy {
+ value: Value::Scalar(dest_val),
+ ty: dest_ty,
+ };
+ self.write_value(valty, dest)?;
+ }
+ }
+
+ ReifyFnPointer => {
+ match src.ty.sty {
+ ty::TyFnDef(def_id, substs) => {
+ if self.tcx.has_attr(def_id, "rustc_args_required_const") {
+ bug!("reifying a fn ptr that requires \
+ const arguments");
+ }
+ let instance: EvalResult<'tcx, _> = ty::Instance::resolve(
+ *self.tcx,
+ self.param_env,
+ def_id,
+ substs,
+ ).ok_or_else(|| EvalErrorKind::TooGeneric.into());
+ let fn_ptr = self.memory.create_fn_alloc(instance?);
+ let valty = ValTy {
+ value: Value::Scalar(fn_ptr.into()),
+ ty: dest_ty,
+ };
+ self.write_value(valty, dest)?;
+ }
+ ref other => bug!("reify fn pointer on {:?}", other),
+ }
+ }
+
+ UnsafeFnPointer => {
+ match dest_ty.sty {
+ ty::TyFnPtr(_) => {
+ let mut src = src;
+ src.ty = dest_ty;
+ self.write_value(src, dest)?;
+ }
+ ref other => bug!("fn to unsafe fn cast on {:?}", other),
+ }
+ }
+
+ ClosureFnPointer => {
+ match src.ty.sty {
+ ty::TyClosure(def_id, substs) => {
+ let substs = self.tcx.subst_and_normalize_erasing_regions(
+ self.substs(),
+ ty::ParamEnv::reveal_all(),
+ &substs,
+ );
+ let instance = ty::Instance::resolve_closure(
+ *self.tcx,
+ def_id,
+ substs,
+ ty::ClosureKind::FnOnce,
+ );
+ let fn_ptr = self.memory.create_fn_alloc(instance);
+ let valty = ValTy {
+ value: Value::Scalar(fn_ptr.into()),
+ ty: dest_ty,
+ };
+ self.write_value(valty, dest)?;
+ }
+ ref other => bug!("closure fn pointer on {:?}", other),
+ }
+ }
+ }
+ Ok(())
+ }
+