1 use std
::convert
::TryFrom
;
3 use rustc_apfloat
::ieee
::{Double, Single}
;
4 use rustc_apfloat
::{Float, FloatConvert}
;
5 use rustc_middle
::mir
::interpret
::{InterpResult, PointerArithmetic, Scalar}
;
6 use rustc_middle
::mir
::CastKind
;
7 use rustc_middle
::ty
::adjustment
::PointerCast
;
8 use rustc_middle
::ty
::layout
::{IntegerExt, TyAndLayout}
;
9 use rustc_middle
::ty
::{self, FloatTy, Ty, TypeAndMut}
;
10 use rustc_span
::symbol
::sym
;
11 use rustc_target
::abi
::{Integer, LayoutOf, Variants}
;
14 util
::ensure_monomorphic_enough
, FnVal
, ImmTy
, Immediate
, InterpCx
, Machine
, OpTy
, PlaceTy
,
17 impl<'mir
, 'tcx
: 'mir
, M
: Machine
<'mir
, 'tcx
>> InterpCx
<'mir
, 'tcx
, M
> {
20 src
: &OpTy
<'tcx
, M
::PointerTag
>,
23 dest
: &PlaceTy
<'tcx
, M
::PointerTag
>,
24 ) -> InterpResult
<'tcx
> {
25 use rustc_middle
::mir
::CastKind
::*;
26 // FIXME: In which cases should we trigger UB when the source is uninit?
28 Pointer(PointerCast
::Unsize
) => {
29 let cast_ty
= self.layout_of(cast_ty
)?
;
30 self.unsize_into(src
, cast_ty
, dest
)?
;
34 let src
= self.read_immediate(src
)?
;
35 let res
= self.misc_cast(&src
, cast_ty
)?
;
36 self.write_immediate(res
, dest
)?
;
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
)?
;
45 Pointer(PointerCast
::ReifyFnPointer
) => {
46 // The src operand does not matter, just its type
47 match *src
.layout
.ty
.kind() {
48 ty
::FnDef(def_id
, substs
) => {
49 // All reifications must be monomorphic, bail out otherwise.
50 ensure_monomorphic_enough(*self.tcx
, src
.layout
.ty
)?
;
52 if self.tcx
.has_attr(def_id
, sym
::rustc_args_required_const
) {
55 "reifying a fn ptr that requires const arguments"
59 let instance
= ty
::Instance
::resolve_for_fn_ptr(
65 .ok_or_else(|| err_inval
!(TooGeneric
))?
;
67 let fn_ptr
= self.memory
.create_fn_alloc(FnVal
::Instance(instance
));
68 self.write_scalar(fn_ptr
, dest
)?
;
70 _
=> span_bug
!(self.cur_span(), "reify fn pointer on {:?}", src
.layout
.ty
),
74 Pointer(PointerCast
::UnsafeFnPointer
) => {
75 let src
= self.read_immediate(src
)?
;
76 match cast_ty
.kind() {
79 self.write_immediate(*src
, dest
)?
;
81 _
=> span_bug
!(self.cur_span(), "fn to unsafe fn cast on {:?}", cast_ty
),
85 Pointer(PointerCast
::ClosureFnPointer(_
)) => {
86 // The src operand does not matter, just its type
87 match *src
.layout
.ty
.kind() {
88 ty
::Closure(def_id
, substs
) => {
89 // All reifications must be monomorphic, bail out otherwise.
90 ensure_monomorphic_enough(*self.tcx
, src
.layout
.ty
)?
;
92 let instance
= ty
::Instance
::resolve_closure(
96 ty
::ClosureKind
::FnOnce
,
98 let fn_ptr
= self.memory
.create_fn_alloc(FnVal
::Instance(instance
));
99 self.write_scalar(fn_ptr
, dest
)?
;
101 _
=> span_bug
!(self.cur_span(), "closure fn pointer on {:?}", src
.layout
.ty
),
110 src
: &ImmTy
<'tcx
, M
::PointerTag
>,
112 ) -> InterpResult
<'tcx
, Immediate
<M
::PointerTag
>> {
113 use rustc_middle
::ty
::TyKind
::*;
114 trace
!("Casting {:?}: {:?} to {:?}", *src
, src
.layout
.ty
, cast_ty
);
116 match src
.layout
.ty
.kind() {
118 Float(FloatTy
::F32
) => {
119 return Ok(self.cast_from_float(src
.to_scalar()?
.to_f32()?
, cast_ty
).into());
121 Float(FloatTy
::F64
) => {
122 return Ok(self.cast_from_float(src
.to_scalar()?
.to_f64()?
, cast_ty
).into());
124 // The rest is integer/pointer-"like", including fn ptr casts and casts from enums that
125 // are represented as integers.
127 src
.layout
.ty
.is_bool()
128 || src
.layout
.ty
.is_char()
129 || src
.layout
.ty
.is_enum()
130 || src
.layout
.ty
.is_integral()
131 || src
.layout
.ty
.is_any_ptr(),
132 "Unexpected cast from type {:?}",
137 // # First handle non-scalar source values.
139 // Handle cast from a ZST enum (0 or 1 variants).
140 match src
.layout
.variants
{
141 Variants
::Single { index }
=> {
142 if src
.layout
.abi
.is_uninhabited() {
143 // This is dead code, because an uninhabited enum is UB to
145 throw_ub
!(Unreachable
);
147 if let Some(discr
) = src
.layout
.ty
.discriminant_for_variant(*self.tcx
, index
) {
148 assert
!(src
.layout
.is_zst());
149 let discr_layout
= self.layout_of(discr
.ty
)?
;
150 return Ok(self.cast_from_scalar(discr
.val
, discr_layout
, cast_ty
).into());
153 Variants
::Multiple { .. }
=> {}
156 // Handle casting any ptr to raw ptr (might be a fat ptr).
157 if src
.layout
.ty
.is_any_ptr() && cast_ty
.is_unsafe_ptr() {
158 let dest_layout
= self.layout_of(cast_ty
)?
;
159 if dest_layout
.size
== src
.layout
.size
{
160 // Thin or fat pointer that just hast the ptr kind of target type changed.
163 // Casting the metadata away from a fat ptr.
164 assert_eq
!(src
.layout
.size
, 2 * self.memory
.pointer_size());
165 assert_eq
!(dest_layout
.size
, self.memory
.pointer_size());
166 assert
!(src
.layout
.ty
.is_unsafe_ptr());
168 Immediate
::ScalarPair(data
, _
) => Ok(data
.into()),
169 Immediate
::Scalar(..) => span_bug
!(
171 "{:?} input to a fat-to-thin cast ({:?} -> {:?})",
180 // # The remaining source values are scalar.
182 // For all remaining casts, we either
183 // (a) cast a raw ptr to usize, or
184 // (b) cast from an integer-like (including bool, char, enums).
185 // In both cases we want the bits.
186 let bits
= self.force_bits(src
.to_scalar()?
, src
.layout
.size
)?
;
187 Ok(self.cast_from_scalar(bits
, src
.layout
, cast_ty
).into())
190 pub(super) fn cast_from_scalar(
192 v
: u128
, // raw bits (there is no ScalarTy so we separate data+layout)
193 src_layout
: TyAndLayout
<'tcx
>,
195 ) -> Scalar
<M
::PointerTag
> {
196 // Let's make sure v is sign-extended *if* it has a signed type.
197 let signed
= src_layout
.abi
.is_signed(); // Also asserts that abi is `Scalar`.
198 let v
= if signed { self.sign_extend(v, src_layout) }
else { v }
;
199 trace
!("cast_from_scalar: {}, {} -> {}", v
, src_layout
.ty
, cast_ty
);
200 use rustc_middle
::ty
::TyKind
::*;
201 match *cast_ty
.kind() {
202 Int(_
) | Uint(_
) | RawPtr(_
) => {
203 let size
= match *cast_ty
.kind() {
204 Int(t
) => Integer
::from_int_ty(self, t
).size(),
205 Uint(t
) => Integer
::from_uint_ty(self, t
).size(),
206 RawPtr(_
) => self.pointer_size(),
209 let v
= size
.truncate(v
);
210 Scalar
::from_uint(v
, size
)
213 Float(FloatTy
::F32
) if signed
=> Scalar
::from_f32(Single
::from_i128(v
as i128
).value
),
214 Float(FloatTy
::F64
) if signed
=> Scalar
::from_f64(Double
::from_i128(v
as i128
).value
),
215 Float(FloatTy
::F32
) => Scalar
::from_f32(Single
::from_u128(v
).value
),
216 Float(FloatTy
::F64
) => Scalar
::from_f64(Double
::from_u128(v
).value
),
219 // `u8` to `char` cast
220 Scalar
::from_u32(u8::try_from(v
).unwrap().into())
223 // Casts to bool are not permitted by rustc, no need to handle them here.
224 _
=> span_bug
!(self.cur_span(), "invalid int to {:?} cast", cast_ty
),
228 fn cast_from_float
<F
>(&self, f
: F
, dest_ty
: Ty
<'tcx
>) -> Scalar
<M
::PointerTag
>
230 F
: Float
+ Into
<Scalar
<M
::PointerTag
>> + FloatConvert
<Single
> + FloatConvert
<Double
>,
232 use rustc_middle
::ty
::TyKind
::*;
233 match *dest_ty
.kind() {
236 let size
= Integer
::from_uint_ty(self, t
).size();
237 // `to_u128` is a saturating cast, which is what we need
238 // (https://doc.rust-lang.org/nightly/nightly-rustc/rustc_apfloat/trait.Float.html#method.to_i128_r).
239 let v
= f
.to_u128(size
.bits_usize()).value
;
240 // This should already fit the bit width
241 Scalar
::from_uint(v
, size
)
245 let size
= Integer
::from_int_ty(self, t
).size();
246 // `to_i128` is a saturating cast, which is what we need
247 // (https://doc.rust-lang.org/nightly/nightly-rustc/rustc_apfloat/trait.Float.html#method.to_i128_r).
248 let v
= f
.to_i128(size
.bits_usize()).value
;
249 Scalar
::from_int(v
, size
)
252 Float(FloatTy
::F32
) => Scalar
::from_f32(f
.convert(&mut false).value
),
254 Float(FloatTy
::F64
) => Scalar
::from_f64(f
.convert(&mut false).value
),
256 _
=> span_bug
!(self.cur_span(), "invalid float to {:?} cast", dest_ty
),
262 src
: &OpTy
<'tcx
, M
::PointerTag
>,
263 dest
: &PlaceTy
<'tcx
, M
::PointerTag
>,
267 ) -> InterpResult
<'tcx
> {
268 // A<Struct> -> A<Trait> conversion
269 let (src_pointee_ty
, dest_pointee_ty
) =
270 self.tcx
.struct_lockstep_tails_erasing_lifetimes(source_ty
, cast_ty
, self.param_env
);
272 match (&src_pointee_ty
.kind(), &dest_pointee_ty
.kind()) {
273 (&ty
::Array(_
, length
), &ty
::Slice(_
)) => {
274 let ptr
= self.read_immediate(src
)?
.to_scalar()?
;
275 // u64 cast is from usize to u64, which is always good
277 Immediate
::new_slice(ptr
, length
.eval_usize(*self.tcx
, self.param_env
), self);
278 self.write_immediate(val
, dest
)
280 (&ty
::Dynamic(..), &ty
::Dynamic(..)) => {
281 // For now, upcasts are limited to changes in marker
282 // traits, and hence never actually require an actual
283 // change to the vtable.
284 let val
= self.read_immediate(src
)?
;
285 self.write_immediate(*val
, dest
)
287 (_
, &ty
::Dynamic(ref data
, _
)) => {
288 // Initial cast from sized to dyn trait
289 let vtable
= self.get_vtable(src_pointee_ty
, data
.principal())?
;
290 let ptr
= self.read_immediate(src
)?
.to_scalar()?
;
291 let val
= Immediate
::new_dyn_trait(ptr
, vtable
);
292 self.write_immediate(val
, dest
)
296 span_bug
!(self.cur_span(), "invalid unsizing {:?} -> {:?}", src
.layout
.ty
, cast_ty
)
303 src
: &OpTy
<'tcx
, M
::PointerTag
>,
304 cast_ty
: TyAndLayout
<'tcx
>,
305 dest
: &PlaceTy
<'tcx
, M
::PointerTag
>,
306 ) -> InterpResult
<'tcx
> {
307 trace
!("Unsizing {:?} of type {} into {:?}", *src
, src
.layout
.ty
, cast_ty
.ty
);
308 match (&src
.layout
.ty
.kind(), &cast_ty
.ty
.kind()) {
309 (&ty
::Ref(_
, s
, _
), &ty
::Ref(_
, c
, _
) | &ty
::RawPtr(TypeAndMut { ty: c, .. }
))
310 | (&ty
::RawPtr(TypeAndMut { ty: s, .. }
), &ty
::RawPtr(TypeAndMut { ty: c, .. }
)) => {
311 self.unsize_into_ptr(src
, dest
, s
, c
)
313 (&ty
::Adt(def_a
, _
), &ty
::Adt(def_b
, _
)) => {
314 assert_eq
!(def_a
, def_b
);
315 if def_a
.is_box() || def_b
.is_box() {
316 if !def_a
.is_box() || !def_b
.is_box() {
319 "invalid unsizing between {:?} -> {:?}",
324 return self.unsize_into_ptr(
327 src
.layout
.ty
.boxed_ty(),
328 cast_ty
.ty
.boxed_ty(),
332 // unsizing of generic struct with pointer fields
333 // Example: `Arc<T>` -> `Arc<Trait>`
334 // here we need to increase the size of every &T thin ptr field to a fat ptr
335 for i
in 0..src
.layout
.fields
.count() {
336 let cast_ty_field
= cast_ty
.field(self, i
)?
;
337 if cast_ty_field
.is_zst() {
340 let src_field
= self.operand_field(src
, i
)?
;
341 let dst_field
= self.place_field(dest
, i
)?
;
342 if src_field
.layout
.ty
== cast_ty_field
.ty
{
343 self.copy_op(&src_field
, &dst_field
)?
;
345 self.unsize_into(&src_field
, cast_ty_field
, &dst_field
)?
;
352 "unsize_into: invalid conversion: {:?} -> {:?}",