]> git.proxmox.com Git - rustc.git/blame - src/librustc_mir/interpret/cast.rs
New upstream version 1.46.0+dfsg1
[rustc.git] / src / librustc_mir / interpret / cast.rs
CommitLineData
ba9703b0 1use std::convert::TryFrom;
ea8adc8c 2
dfeec247
XL
3use rustc_apfloat::ieee::{Double, Single};
4use rustc_apfloat::{Float, FloatConvert};
ba9703b0 5use rustc_ast::ast::FloatTy;
f9f354fc 6use rustc_attr as attr;
ba9703b0
XL
7use rustc_middle::mir::interpret::{InterpResult, PointerArithmetic, Scalar};
8use rustc_middle::mir::CastKind;
9use rustc_middle::ty::adjustment::PointerCast;
f9f354fc 10use rustc_middle::ty::layout::{IntegerExt, TyAndLayout};
ba9703b0
XL
11use rustc_middle::ty::{self, Ty, TypeAndMut, TypeFoldable};
12use rustc_span::symbol::sym;
f9f354fc
XL
13use rustc_target::abi::{Integer, LayoutOf, Variants};
14
15use super::{truncate, FnVal, ImmTy, Immediate, InterpCx, Machine, OpTy, PlaceTy};
b7449926 16
ba9703b0 17impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
b7449926 18 pub fn cast(
8faf50e0 19 &mut self,
0bf4aa26 20 src: OpTy<'tcx, M::PointerTag>,
f9f354fc
XL
21 cast_kind: CastKind,
22 cast_ty: Ty<'tcx>,
0bf4aa26 23 dest: PlaceTy<'tcx, M::PointerTag>,
dc9dc135 24 ) -> InterpResult<'tcx> {
ba9703b0 25 use rustc_middle::mir::CastKind::*;
f9f354fc
XL
26 // FIXME: In which cases should we trigger UB when the source is uninit?
27 match cast_kind {
48663c56 28 Pointer(PointerCast::Unsize) => {
f9f354fc
XL
29 let cast_ty = self.layout_of(cast_ty)?;
30 self.unsize_into(src, cast_ty, dest)?;
8faf50e0
XL
31 }
32
f9f354fc 33 Misc => {
a1dfa0c6 34 let src = self.read_immediate(src)?;
f9f354fc 35 let res = self.misc_cast(src, cast_ty)?;
416331ca 36 self.write_immediate(res, dest)?;
8faf50e0
XL
37 }
38
f9f354fc
XL
39 Pointer(PointerCast::MutToConstPointer | PointerCast::ArrayToPointer) => {
40 // These are NOPs, but can be wide pointers.
41 let v = self.read_immediate(src)?;
42 self.write_immediate(*v, dest)?;
43 }
44
48663c56 45 Pointer(PointerCast::ReifyFnPointer) => {
b7449926 46 // The src operand does not matter, just its type
e74abb32 47 match src.layout.ty.kind {
b7449926 48 ty::FnDef(def_id, substs) => {
e1599b0c
XL
49 // All reifications must be monomorphic, bail out otherwise.
50 if src.layout.ty.needs_subst() {
51 throw_inval!(TooGeneric);
52 }
53
48663c56 54 if self.tcx.has_attr(def_id, sym::rustc_args_required_const) {
f035d41b
XL
55 span_bug!(
56 self.cur_span(),
57 "reifying a fn ptr that requires const arguments"
58 );
8faf50e0 59 }
e74abb32
XL
60
61 let instance = ty::Instance::resolve_for_fn_ptr(
62 *self.tcx,
63 self.param_env,
64 def_id,
65 substs,
dfeec247
XL
66 )
67 .ok_or_else(|| err_inval!(TooGeneric))?;
e74abb32 68
416331ca 69 let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance));
60c5eb7d 70 self.write_scalar(fn_ptr, dest)?;
8faf50e0 71 }
f035d41b 72 _ => span_bug!(self.cur_span(), "reify fn pointer on {:?}", src.layout.ty),
8faf50e0
XL
73 }
74 }
75
48663c56 76 Pointer(PointerCast::UnsafeFnPointer) => {
a1dfa0c6 77 let src = self.read_immediate(src)?;
f9f354fc 78 match cast_ty.kind {
b7449926
XL
79 ty::FnPtr(_) => {
80 // No change to value
a1dfa0c6 81 self.write_immediate(*src, dest)?;
8faf50e0 82 }
f035d41b 83 _ => span_bug!(self.cur_span(), "fn to unsafe fn cast on {:?}", cast_ty),
8faf50e0
XL
84 }
85 }
86
48663c56 87 Pointer(PointerCast::ClosureFnPointer(_)) => {
b7449926 88 // The src operand does not matter, just its type
e74abb32 89 match src.layout.ty.kind {
b7449926 90 ty::Closure(def_id, substs) => {
e1599b0c
XL
91 // All reifications must be monomorphic, bail out otherwise.
92 if src.layout.ty.needs_subst() {
93 throw_inval!(TooGeneric);
94 }
95
8faf50e0
XL
96 let instance = ty::Instance::resolve_closure(
97 *self.tcx,
98 def_id,
99 substs,
100 ty::ClosureKind::FnOnce,
101 );
416331ca 102 let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance));
60c5eb7d 103 self.write_scalar(fn_ptr, dest)?;
8faf50e0 104 }
f035d41b 105 _ => span_bug!(self.cur_span(), "closure fn pointer on {:?}", src.layout.ty),
8faf50e0
XL
106 }
107 }
108 }
109 Ok(())
110 }
111
f9f354fc 112 fn misc_cast(
ea8adc8c 113 &self,
416331ca 114 src: ImmTy<'tcx, M::PointerTag>,
f9f354fc 115 cast_ty: Ty<'tcx>,
416331ca 116 ) -> InterpResult<'tcx, Immediate<M::PointerTag>> {
ba9703b0 117 use rustc_middle::ty::TyKind::*;
f9f354fc 118 trace!("Casting {:?}: {:?} to {:?}", *src, src.layout.ty, cast_ty);
ea8adc8c 119
e74abb32 120 match src.layout.ty.kind {
dc9dc135 121 // Floating point
dfeec247 122 Float(FloatTy::F32) => {
f9f354fc 123 return Ok(self.cast_from_float(src.to_scalar()?.to_f32()?, cast_ty).into());
dfeec247
XL
124 }
125 Float(FloatTy::F64) => {
f9f354fc 126 return Ok(self.cast_from_float(src.to_scalar()?.to_f64()?, cast_ty).into());
dfeec247 127 }
416331ca
XL
128 // The rest is integer/pointer-"like", including fn ptr casts and casts from enums that
129 // are represented as integers.
dfeec247
XL
130 _ => assert!(
131 src.layout.ty.is_bool()
132 || src.layout.ty.is_char()
133 || src.layout.ty.is_enum()
134 || src.layout.ty.is_integral()
135 || src.layout.ty.is_any_ptr(),
136 "Unexpected cast from type {:?}",
137 src.layout.ty
138 ),
416331ca
XL
139 }
140
f9f354fc
XL
141 // # First handle non-scalar source values.
142
416331ca
XL
143 // Handle cast from a univariant (ZST) enum.
144 match src.layout.variants {
ba9703b0 145 Variants::Single { index } => {
dfeec247 146 if let Some(discr) = src.layout.ty.discriminant_for_variant(*self.tcx, index) {
416331ca 147 assert!(src.layout.is_zst());
ba9703b0 148 let discr_layout = self.layout_of(discr.ty)?;
f9f354fc 149 return Ok(self.cast_from_scalar(discr.val, discr_layout, cast_ty).into());
ea8adc8c
XL
150 }
151 }
ba9703b0 152 Variants::Multiple { .. } => {}
416331ca
XL
153 }
154
416331ca 155 // Handle casting any ptr to raw ptr (might be a fat ptr).
f9f354fc
XL
156 if src.layout.ty.is_any_ptr() && cast_ty.is_unsafe_ptr() {
157 let dest_layout = self.layout_of(cast_ty)?;
158 if dest_layout.size == src.layout.size {
159 // Thin or fat pointer that just hast the ptr kind of target type changed.
160 return Ok(*src);
161 } else {
162 // Casting the metadata away from a fat ptr.
163 assert_eq!(src.layout.size, 2 * self.memory.pointer_size());
164 assert_eq!(dest_layout.size, self.memory.pointer_size());
165 assert!(src.layout.ty.is_unsafe_ptr());
166 return match *src {
167 Immediate::ScalarPair(data, _) => Ok(data.into()),
f035d41b
XL
168 Immediate::Scalar(..) => span_bug!(
169 self.cur_span(),
f9f354fc
XL
170 "{:?} input to a fat-to-thin cast ({:?} -> {:?})",
171 *src,
172 src.layout.ty,
173 cast_ty
174 ),
175 };
176 }
ea8adc8c 177 }
416331ca 178
f9f354fc
XL
179 // # The remaining source values are scalar.
180
416331ca
XL
181 // For all remaining casts, we either
182 // (a) cast a raw ptr to usize, or
183 // (b) cast from an integer-like (including bool, char, enums).
184 // In both cases we want the bits.
185 let bits = self.force_bits(src.to_scalar()?, src.layout.size)?;
f9f354fc 186 Ok(self.cast_from_scalar(bits, src.layout, cast_ty).into())
ea8adc8c
XL
187 }
188
f9f354fc 189 pub(super) fn cast_from_scalar(
ea8adc8c 190 &self,
f9f354fc 191 v: u128, // raw bits (there is no ScalarTy so we separate data+layout)
ba9703b0 192 src_layout: TyAndLayout<'tcx>,
f9f354fc
XL
193 cast_ty: Ty<'tcx>,
194 ) -> Scalar<M::PointerTag> {
dc9dc135 195 // Let's make sure v is sign-extended *if* it has a signed type.
f9f354fc 196 let signed = src_layout.abi.is_signed(); // Also asserts that abi is `Scalar`.
dfeec247 197 let v = if signed { self.sign_extend(v, src_layout) } else { v };
f9f354fc 198 trace!("cast_from_scalar: {}, {} -> {}", v, src_layout.ty, cast_ty);
ba9703b0 199 use rustc_middle::ty::TyKind::*;
f9f354fc 200 match cast_ty.kind {
dc9dc135 201 Int(_) | Uint(_) | RawPtr(_) => {
f9f354fc
XL
202 let size = match cast_ty.kind {
203 Int(t) => Integer::from_attr(self, attr::IntType::SignedInt(t)).size(),
204 Uint(t) => Integer::from_attr(self, attr::IntType::UnsignedInt(t)).size(),
205 RawPtr(_) => self.pointer_size(),
206 _ => bug!(),
207 };
208 let v = truncate(v, size);
209 Scalar::from_uint(v, size)
0531ce1d 210 }
ea8adc8c 211
f9f354fc
XL
212 Float(FloatTy::F32) if signed => Scalar::from_f32(Single::from_i128(v as i128).value),
213 Float(FloatTy::F64) if signed => Scalar::from_f64(Double::from_i128(v as i128).value),
214 Float(FloatTy::F32) => Scalar::from_f32(Single::from_u128(v).value),
215 Float(FloatTy::F64) => Scalar::from_f64(Double::from_u128(v).value),
ea8adc8c 216
b7449926
XL
217 Char => {
218 // `u8` to `char` cast
f9f354fc 219 Scalar::from_u32(u8::try_from(v).unwrap().into())
dfeec247 220 }
ea8adc8c 221
0531ce1d 222 // Casts to bool are not permitted by rustc, no need to handle them here.
f035d41b 223 _ => span_bug!(self.cur_span(), "invalid int to {:?} cast", cast_ty),
ea8adc8c
XL
224 }
225 }
226
f9f354fc 227 fn cast_from_float<F>(&self, f: F, dest_ty: Ty<'tcx>) -> Scalar<M::PointerTag>
dfeec247
XL
228 where
229 F: Float + Into<Scalar<M::PointerTag>> + FloatConvert<Single> + FloatConvert<Double>,
dc9dc135 230 {
ba9703b0 231 use rustc_middle::ty::TyKind::*;
e74abb32 232 match dest_ty.kind {
0531ce1d 233 // float -> uint
b7449926 234 Uint(t) => {
f9f354fc 235 let size = Integer::from_attr(self, attr::IntType::UnsignedInt(t)).size();
ba9703b0
XL
236 // `to_u128` is a saturating cast, which is what we need
237 // (https://doc.rust-lang.org/nightly/nightly-rustc/rustc_apfloat/trait.Float.html#method.to_i128_r).
f9f354fc 238 let v = f.to_u128(size.bits_usize()).value;
b7449926 239 // This should already fit the bit width
f9f354fc 240 Scalar::from_uint(v, size)
dfeec247 241 }
0531ce1d 242 // float -> int
b7449926 243 Int(t) => {
f9f354fc 244 let size = Integer::from_attr(self, attr::IntType::SignedInt(t)).size();
ba9703b0
XL
245 // `to_i128` is a saturating cast, which is what we need
246 // (https://doc.rust-lang.org/nightly/nightly-rustc/rustc_apfloat/trait.Float.html#method.to_i128_r).
f9f354fc
XL
247 let v = f.to_i128(size.bits_usize()).value;
248 Scalar::from_int(v, size)
dfeec247 249 }
dc9dc135 250 // float -> f32
f9f354fc 251 Float(FloatTy::F32) => Scalar::from_f32(f.convert(&mut false).value),
dc9dc135 252 // float -> f64
f9f354fc 253 Float(FloatTy::F64) => Scalar::from_f64(f.convert(&mut false).value),
dc9dc135 254 // That's it.
f035d41b 255 _ => span_bug!(self.cur_span(), "invalid float to {:?} cast", dest_ty),
ea8adc8c
XL
256 }
257 }
258
b7449926
XL
259 fn unsize_into_ptr(
260 &mut self,
0bf4aa26
XL
261 src: OpTy<'tcx, M::PointerTag>,
262 dest: PlaceTy<'tcx, M::PointerTag>,
b7449926 263 // The pointee types
e74abb32 264 source_ty: Ty<'tcx>,
f9f354fc 265 cast_ty: Ty<'tcx>,
dc9dc135 266 ) -> InterpResult<'tcx> {
b7449926 267 // A<Struct> -> A<Trait> conversion
416331ca 268 let (src_pointee_ty, dest_pointee_ty) =
f9f354fc 269 self.tcx.struct_lockstep_tails_erasing_lifetimes(source_ty, cast_ty, self.param_env);
b7449926 270
e74abb32 271 match (&src_pointee_ty.kind, &dest_pointee_ty.kind) {
b7449926 272 (&ty::Array(_, length), &ty::Slice(_)) => {
60c5eb7d 273 let ptr = self.read_immediate(src)?.to_scalar()?;
b7449926 274 // u64 cast is from usize to u64, which is always good
f035d41b
XL
275 let val =
276 Immediate::new_slice(ptr, length.eval_usize(*self.tcx, self.param_env), self);
a1dfa0c6 277 self.write_immediate(val, dest)
b7449926
XL
278 }
279 (&ty::Dynamic(..), &ty::Dynamic(..)) => {
280 // For now, upcasts are limited to changes in marker
281 // traits, and hence never actually require an actual
282 // change to the vtable.
a1dfa0c6
XL
283 let val = self.read_immediate(src)?;
284 self.write_immediate(*val, dest)
b7449926
XL
285 }
286 (_, &ty::Dynamic(ref data, _)) => {
287 // Initial cast from sized to dyn trait
0bf4aa26 288 let vtable = self.get_vtable(src_pointee_ty, data.principal())?;
60c5eb7d 289 let ptr = self.read_immediate(src)?.to_scalar()?;
a1dfa0c6
XL
290 let val = Immediate::new_dyn_trait(ptr, vtable);
291 self.write_immediate(val, dest)
b7449926
XL
292 }
293
f035d41b
XL
294 _ => {
295 span_bug!(self.cur_span(), "invalid unsizing {:?} -> {:?}", src.layout.ty, cast_ty)
296 }
b7449926
XL
297 }
298 }
299
300 fn unsize_into(
301 &mut self,
0bf4aa26 302 src: OpTy<'tcx, M::PointerTag>,
f9f354fc 303 cast_ty: TyAndLayout<'tcx>,
0bf4aa26 304 dest: PlaceTy<'tcx, M::PointerTag>,
dc9dc135 305 ) -> InterpResult<'tcx> {
f9f354fc
XL
306 trace!("Unsizing {:?} of type {} into {:?}", *src, src.layout.ty, cast_ty.ty);
307 match (&src.layout.ty.kind, &cast_ty.ty.kind) {
308 (&ty::Ref(_, s, _), &ty::Ref(_, c, _) | &ty::RawPtr(TypeAndMut { ty: c, .. }))
309 | (&ty::RawPtr(TypeAndMut { ty: s, .. }), &ty::RawPtr(TypeAndMut { ty: c, .. })) => {
310 self.unsize_into_ptr(src, dest, s, c)
b7449926
XL
311 }
312 (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
313 assert_eq!(def_a, def_b);
314 if def_a.is_box() || def_b.is_box() {
315 if !def_a.is_box() || !def_b.is_box() {
f035d41b
XL
316 span_bug!(
317 self.cur_span(),
318 "invalid unsizing between {:?} -> {:?}",
319 src.layout.ty,
320 cast_ty.ty
321 );
b7449926
XL
322 }
323 return self.unsize_into_ptr(
324 src,
325 dest,
326 src.layout.ty.boxed_ty(),
f9f354fc 327 cast_ty.ty.boxed_ty(),
b7449926
XL
328 );
329 }
330
331 // unsizing of generic struct with pointer fields
332 // Example: `Arc<T>` -> `Arc<Trait>`
333 // here we need to increase the size of every &T thin ptr field to a fat ptr
334 for i in 0..src.layout.fields.count() {
f9f354fc
XL
335 let cast_ty_field = cast_ty.field(self, i)?;
336 if cast_ty_field.is_zst() {
b7449926
XL
337 continue;
338 }
ba9703b0 339 let src_field = self.operand_field(src, i)?;
f9f354fc
XL
340 let dst_field = self.place_field(dest, i)?;
341 if src_field.layout.ty == cast_ty_field.ty {
b7449926
XL
342 self.copy_op(src_field, dst_field)?;
343 } else {
f9f354fc 344 self.unsize_into(src_field, cast_ty_field, dst_field)?;
b7449926
XL
345 }
346 }
347 Ok(())
348 }
f035d41b
XL
349 _ => span_bug!(
350 self.cur_span(),
351 "unsize_into: invalid conversion: {:?} -> {:?}",
352 src.layout,
353 dest.layout
354 ),
b7449926
XL
355 }
356 }
ea8adc8c 357}