1 use rustc
::ty
::{self, Ty, TypeAndMut, TypeFoldable}
;
2 use rustc
::ty
::layout
::{self, TyLayout, Size}
;
3 use rustc
::ty
::adjustment
::{PointerCast}
;
4 use syntax
::ast
::FloatTy
;
5 use syntax
::symbol
::sym
;
7 use rustc_apfloat
::ieee
::{Single, Double}
;
8 use rustc_apfloat
::{Float, FloatConvert}
;
9 use rustc
::mir
::interpret
::{
10 Scalar
, InterpResult
, PointerArithmetic
,
12 use rustc
::mir
::CastKind
;
14 use super::{InterpCx, Machine, PlaceTy, OpTy, ImmTy, Immediate, FnVal}
;
16 impl<'mir
, 'tcx
, M
: Machine
<'mir
, 'tcx
>> InterpCx
<'mir
, 'tcx
, M
> {
19 src
: OpTy
<'tcx
, M
::PointerTag
>,
21 dest
: PlaceTy
<'tcx
, M
::PointerTag
>,
22 ) -> InterpResult
<'tcx
> {
23 use rustc
::mir
::CastKind
::*;
25 Pointer(PointerCast
::Unsize
) => {
26 self.unsize_into(src
, dest
)?
;
30 | Pointer(PointerCast
::MutToConstPointer
)
31 | Pointer(PointerCast
::ArrayToPointer
) => {
32 let src
= self.read_immediate(src
)?
;
33 let res
= self.cast_immediate(src
, dest
.layout
)?
;
34 self.write_immediate(res
, dest
)?
;
37 Pointer(PointerCast
::ReifyFnPointer
) => {
38 // The src operand does not matter, just its type
39 match src
.layout
.ty
.kind
{
40 ty
::FnDef(def_id
, substs
) => {
41 // All reifications must be monomorphic, bail out otherwise.
42 if src
.layout
.ty
.needs_subst() {
43 throw_inval
!(TooGeneric
);
46 if self.tcx
.has_attr(def_id
, sym
::rustc_args_required_const
) {
47 bug
!("reifying a fn ptr that requires const arguments");
50 let instance
= ty
::Instance
::resolve_for_fn_ptr(
55 ).ok_or_else(|| err_inval
!(TooGeneric
))?
;
57 let fn_ptr
= self.memory
.create_fn_alloc(FnVal
::Instance(instance
));
58 self.write_scalar(fn_ptr
, dest
)?
;
60 _
=> bug
!("reify fn pointer on {:?}", src
.layout
.ty
),
64 Pointer(PointerCast
::UnsafeFnPointer
) => {
65 let src
= self.read_immediate(src
)?
;
66 match dest
.layout
.ty
.kind
{
69 self.write_immediate(*src
, dest
)?
;
71 _
=> bug
!("fn to unsafe fn cast on {:?}", dest
.layout
.ty
),
75 Pointer(PointerCast
::ClosureFnPointer(_
)) => {
76 // The src operand does not matter, just its type
77 match src
.layout
.ty
.kind
{
78 ty
::Closure(def_id
, substs
) => {
79 // All reifications must be monomorphic, bail out otherwise.
80 if src
.layout
.ty
.needs_subst() {
81 throw_inval
!(TooGeneric
);
84 let instance
= ty
::Instance
::resolve_closure(
88 ty
::ClosureKind
::FnOnce
,
90 let fn_ptr
= self.memory
.create_fn_alloc(FnVal
::Instance(instance
));
91 self.write_scalar(fn_ptr
, dest
)?
;
93 _
=> bug
!("closure fn pointer on {:?}", src
.layout
.ty
),
102 src
: ImmTy
<'tcx
, M
::PointerTag
>,
103 dest_layout
: TyLayout
<'tcx
>,
104 ) -> InterpResult
<'tcx
, Immediate
<M
::PointerTag
>> {
105 use rustc
::ty
::TyKind
::*;
106 trace
!("Casting {:?}: {:?} to {:?}", *src
, src
.layout
.ty
, dest_layout
.ty
);
108 match src
.layout
.ty
.kind
{
110 Float(FloatTy
::F32
) =>
111 return Ok(self.cast_from_float(src
.to_scalar()?
.to_f32()?
, dest_layout
.ty
)?
.into()),
112 Float(FloatTy
::F64
) =>
113 return Ok(self.cast_from_float(src
.to_scalar()?
.to_f64()?
, dest_layout
.ty
)?
.into()),
114 // The rest is integer/pointer-"like", including fn ptr casts and casts from enums that
115 // are represented as integers.
118 src
.layout
.ty
.is_bool() || src
.layout
.ty
.is_char() ||
119 src
.layout
.ty
.is_enum() || src
.layout
.ty
.is_integral() ||
120 src
.layout
.ty
.is_any_ptr(),
121 "Unexpected cast from type {:?}", src
.layout
.ty
125 // Handle cast from a univariant (ZST) enum.
126 match src
.layout
.variants
{
127 layout
::Variants
::Single { index }
=> {
129 src
.layout
.ty
.discriminant_for_variant(*self.tcx
, index
)
131 assert
!(src
.layout
.is_zst());
132 return Ok(Scalar
::from_uint(discr
.val
, dest_layout
.size
).into());
135 layout
::Variants
::Multiple { .. }
=> {}
,
138 // Handle casting the metadata away from a fat pointer.
139 if src
.layout
.ty
.is_unsafe_ptr() && dest_layout
.ty
.is_unsafe_ptr() &&
140 dest_layout
.size
!= src
.layout
.size
142 assert_eq
!(src
.layout
.size
, 2*self.memory
.pointer_size());
143 assert_eq
!(dest_layout
.size
, self.memory
.pointer_size());
144 assert
!(dest_layout
.ty
.is_unsafe_ptr());
146 Immediate
::ScalarPair(data
, _
) =>
147 return Ok(data
.into()),
148 Immediate
::Scalar(..) =>
150 "{:?} input to a fat-to-thin cast ({:?} -> {:?})",
151 *src
, src
.layout
.ty
, dest_layout
.ty
156 // Handle casting any ptr to raw ptr (might be a fat ptr).
157 if src
.layout
.ty
.is_any_ptr() && dest_layout
.ty
.is_unsafe_ptr()
159 // The only possible size-unequal case was handled above.
160 assert_eq
!(src
.layout
.size
, dest_layout
.size
);
164 // For all remaining casts, we either
165 // (a) cast a raw ptr to usize, or
166 // (b) cast from an integer-like (including bool, char, enums).
167 // In both cases we want the bits.
168 let bits
= self.force_bits(src
.to_scalar()?
, src
.layout
.size
)?
;
169 Ok(self.cast_from_int(bits
, src
.layout
, dest_layout
)?
.into())
175 src_layout
: TyLayout
<'tcx
>,
176 dest_layout
: TyLayout
<'tcx
>,
177 ) -> InterpResult
<'tcx
, Scalar
<M
::PointerTag
>> {
178 // Let's make sure v is sign-extended *if* it has a signed type.
179 let signed
= src_layout
.abi
.is_signed();
181 self.sign_extend(v
, src_layout
)
185 trace
!("cast_from_int: {}, {}, {}", v
, src_layout
.ty
, dest_layout
.ty
);
186 use rustc
::ty
::TyKind
::*;
187 match dest_layout
.ty
.kind
{
188 Int(_
) | Uint(_
) | RawPtr(_
) => {
189 let v
= self.truncate(v
, dest_layout
);
190 Ok(Scalar
::from_uint(v
, dest_layout
.size
))
193 Float(FloatTy
::F32
) if signed
=> Ok(Scalar
::from_f32(
194 Single
::from_i128(v
as i128
).value
196 Float(FloatTy
::F64
) if signed
=> Ok(Scalar
::from_f64(
197 Double
::from_i128(v
as i128
).value
199 Float(FloatTy
::F32
) => Ok(Scalar
::from_f32(
200 Single
::from_u128(v
).value
202 Float(FloatTy
::F64
) => Ok(Scalar
::from_f64(
203 Double
::from_u128(v
).value
207 // `u8` to `char` cast
208 debug_assert_eq
!(v
as u8 as u128
, v
);
209 Ok(Scalar
::from_uint(v
, Size
::from_bytes(4)))
212 // Casts to bool are not permitted by rustc, no need to handle them here.
213 _
=> bug
!("invalid int to {:?} cast", dest_layout
.ty
),
217 fn cast_from_float
<F
>(
221 ) -> InterpResult
<'tcx
, Scalar
<M
::PointerTag
>>
222 where F
: Float
+ Into
<Scalar
<M
::PointerTag
>> + FloatConvert
<Single
> + FloatConvert
<Double
>
224 use rustc
::ty
::TyKind
::*;
228 let width
= t
.bit_width().unwrap_or_else(|| self.pointer_size().bits() as usize);
229 let v
= f
.to_u128(width
).value
;
230 // This should already fit the bit width
231 Ok(Scalar
::from_uint(v
, Size
::from_bits(width
as u64)))
235 let width
= t
.bit_width().unwrap_or_else(|| self.pointer_size().bits() as usize);
236 let v
= f
.to_i128(width
).value
;
237 Ok(Scalar
::from_int(v
, Size
::from_bits(width
as u64)))
240 Float(FloatTy
::F32
) =>
241 Ok(Scalar
::from_f32(f
.convert(&mut false).value
)),
243 Float(FloatTy
::F64
) =>
244 Ok(Scalar
::from_f64(f
.convert(&mut false).value
)),
246 _
=> bug
!("invalid float to {:?} cast", dest_ty
),
252 src
: OpTy
<'tcx
, M
::PointerTag
>,
253 dest
: PlaceTy
<'tcx
, M
::PointerTag
>,
257 ) -> InterpResult
<'tcx
> {
258 // A<Struct> -> A<Trait> conversion
259 let (src_pointee_ty
, dest_pointee_ty
) =
260 self.tcx
.struct_lockstep_tails_erasing_lifetimes(source_ty
, dest_ty
, self.param_env
);
262 match (&src_pointee_ty
.kind
, &dest_pointee_ty
.kind
) {
263 (&ty
::Array(_
, length
), &ty
::Slice(_
)) => {
264 let ptr
= self.read_immediate(src
)?
.to_scalar()?
;
265 // u64 cast is from usize to u64, which is always good
266 let val
= Immediate
::new_slice(
268 length
.eval_usize(self.tcx
.tcx
, self.param_env
),
271 self.write_immediate(val
, dest
)
273 (&ty
::Dynamic(..), &ty
::Dynamic(..)) => {
274 // For now, upcasts are limited to changes in marker
275 // traits, and hence never actually require an actual
276 // change to the vtable.
277 let val
= self.read_immediate(src
)?
;
278 self.write_immediate(*val
, dest
)
280 (_
, &ty
::Dynamic(ref data
, _
)) => {
281 // Initial cast from sized to dyn trait
282 let vtable
= self.get_vtable(src_pointee_ty
, data
.principal())?
;
283 let ptr
= self.read_immediate(src
)?
.to_scalar()?
;
284 let val
= Immediate
::new_dyn_trait(ptr
, vtable
);
285 self.write_immediate(val
, dest
)
288 _
=> bug
!("invalid unsizing {:?} -> {:?}", src
.layout
.ty
, dest
.layout
.ty
),
294 src
: OpTy
<'tcx
, M
::PointerTag
>,
295 dest
: PlaceTy
<'tcx
, M
::PointerTag
>,
296 ) -> InterpResult
<'tcx
> {
297 trace
!("Unsizing {:?} into {:?}", src
, dest
);
298 match (&src
.layout
.ty
.kind
, &dest
.layout
.ty
.kind
) {
299 (&ty
::Ref(_
, s
, _
), &ty
::Ref(_
, d
, _
)) |
300 (&ty
::Ref(_
, s
, _
), &ty
::RawPtr(TypeAndMut { ty: d, .. }
)) |
301 (&ty
::RawPtr(TypeAndMut { ty: s, .. }
),
302 &ty
::RawPtr(TypeAndMut { ty: d, .. }
)) => {
303 self.unsize_into_ptr(src
, dest
, s
, d
)
305 (&ty
::Adt(def_a
, _
), &ty
::Adt(def_b
, _
)) => {
306 assert_eq
!(def_a
, def_b
);
307 if def_a
.is_box() || def_b
.is_box() {
308 if !def_a
.is_box() || !def_b
.is_box() {
309 bug
!("invalid unsizing between {:?} -> {:?}", src
.layout
, dest
.layout
);
311 return self.unsize_into_ptr(
314 src
.layout
.ty
.boxed_ty(),
315 dest
.layout
.ty
.boxed_ty(),
319 // unsizing of generic struct with pointer fields
320 // Example: `Arc<T>` -> `Arc<Trait>`
321 // here we need to increase the size of every &T thin ptr field to a fat ptr
322 for i
in 0..src
.layout
.fields
.count() {
323 let dst_field
= self.place_field(dest
, i
as u64)?
;
324 if dst_field
.layout
.is_zst() {
327 let src_field
= self.operand_field(src
, i
as u64)?
;
328 if src_field
.layout
.ty
== dst_field
.layout
.ty
{
329 self.copy_op(src_field
, dst_field
)?
;
331 self.unsize_into(src_field
, dst_field
)?
;
338 "unsize_into: invalid conversion: {:?} -> {:?}",