1use std::assert_matches;
2
3use rustc_abi::{FieldIdx, Integer};
4use rustc_apfloat::ieee::{Double, Half, Quad, Single};
5use rustc_apfloat::{Float, FloatConvert};
6use rustc_middle::mir::CastKind;
7use rustc_middle::mir::interpret::{InterpResult, PointerArithmetic, Scalar};
8use rustc_middle::ty::adjustment::PointerCoercion;
9use rustc_middle::ty::consts::ConstExt;
10use rustc_middle::ty::layout::{IntegerExt, TyAndLayout};
11use rustc_middle::ty::{self, FloatTy, Ty};
12use rustc_span::{bug, span_bug};
13use tracing::trace;
14
15use super::util::ensure_monomorphic_enough;
16use super::{
17 FnVal, ImmTy, Immediate, InterpCx, Machine, OpTy, PlaceTy, err_inval, interp_ok, throw_ub,
18 throw_ub_format,
19};
20use crate::enter_trace_span;
21use crate::interpret::{Projectable, Writeable};
22
23impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
24 pub fn cast(
25 &mut self,
26 src: &OpTy<'tcx, M::Provenance>,
27 cast_kind: CastKind,
28 cast_ty: Ty<'tcx>,
29 dest: &PlaceTy<'tcx, M::Provenance>,
30 ) -> InterpResult<'tcx> {
31 let cast_layout =
34 if cast_ty == dest.layout.ty { dest.layout } else { self.layout_of(cast_ty)? };
35
36 if !#[allow(non_exhaustive_omitted_patterns)] match cast_kind {
CastKind::Transmute | CastKind::Subtype | CastKind::BoxDerefTransmute |
CastKind::PointerCoercion(PointerCoercion::Unsize, _) => true,
_ => false,
}matches!(
39 cast_kind,
40 CastKind::Transmute
41 | CastKind::Subtype
42 | CastKind::BoxDerefTransmute
43 | CastKind::PointerCoercion(PointerCoercion::Unsize, _)
44 ) && M::enforce_validity(self, src.layout)
45 {
46 match src.layout.ty.kind() {
47 ty::RawPtr { .. } => {
48 if #[allow(non_exhaustive_omitted_patterns)] match src.layout.backend_repr {
rustc_abi::BackendRepr::ScalarPair { .. } => true,
_ => false,
}matches!(src.layout.backend_repr, rustc_abi::BackendRepr::ScalarPair { .. })
50 {
51 self.deref_pointer(src)?;
52 }
53 }
54 ty::FnPtr { .. } => {
55 let ptr = self.read_pointer(src)?;
56 self.get_ptr_fn(ptr)?;
57 }
58 ty::Closure(_closure, args) => {
59 let args = args.as_closure();
61 if !args.upvar_tys().is_empty() {
::core::panicking::panic("assertion failed: args.upvar_tys().is_empty()")
};assert!(args.upvar_tys().is_empty());
62 }
63 ty::Int(..)
66 | ty::Uint(..)
67 | ty::Float(..)
68 | ty::Bool
69 | ty::Char
70 | ty::FnDef(..) => {}
71
72 _ => {
73 ::rustc_span::macros::bug_impl(Some(self.cur_span()),
format_args!("unexpected input type in non-transmute/unsize cast: {0}",
src.layout.ty), Location::caller())span_bug!(
74 self.cur_span(),
75 "unexpected input type in non-transmute/unsize cast: {}",
76 src.layout.ty
77 )
78 }
79 }
80 }
81
82 match cast_kind {
83 CastKind::PointerCoercion(PointerCoercion::Unsize, _) => {
84 self.unsize_into(src, cast_layout, dest)?;
85 if M::enforce_validity(self, dest.layout()) {
89 self.validate_place(
90 dest,
91 M::enforce_validity_recursively(self, dest.layout()),
92 true,
93 )?;
94 }
95 }
96
97 CastKind::PointerExposeProvenance => {
98 let src = self.read_immediate(src)?;
99 let res = self.pointer_expose_provenance_cast(&src, cast_layout)?;
100 self.write_immediate(*res, dest)?;
101 }
102
103 CastKind::PointerWithExposedProvenance => {
104 let src = self.read_immediate(src)?;
105 let res = self.pointer_with_exposed_provenance_cast(&src, cast_layout)?;
106 self.write_immediate(*res, dest)?;
107 }
108
109 CastKind::IntToInt | CastKind::IntToFloat => {
110 let src = self.read_immediate(src)?;
111 let res = self.int_to_int_or_float(&src, cast_layout)?;
112 self.write_immediate(*res, dest)?;
113 }
114
115 CastKind::FloatToFloat | CastKind::FloatToInt => {
116 let src = self.read_immediate(src)?;
117 let res = self.float_to_float_or_int(&src, cast_layout)?;
118 self.write_immediate(*res, dest)?;
119 }
120
121 CastKind::FnPtrToPtr | CastKind::PtrToPtr => {
122 let src = self.read_immediate(src)?;
123 let res = self.ptr_to_ptr(&src, cast_layout)?;
124 self.write_immediate(*res, dest)?;
125 }
126
127 CastKind::PointerCoercion(
128 PointerCoercion::MutToConstPointer | PointerCoercion::ArrayToPointer,
129 _,
130 ) => {
131 ::rustc_span::macros::bug_impl(None,
format_args!("{0:?} casts are for borrowck only, not runtime MIR",
cast_kind), Location::caller());bug!("{cast_kind:?} casts are for borrowck only, not runtime MIR");
132 }
133
134 CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer(_), _) => {
135 ensure_monomorphic_enough(src.layout.ty)?;
137
138 match *src.layout.ty.kind() {
140 ty::FnDef(def_id, args) => {
141 let instance = {
142 let _trace = <M as
crate::interpret::Machine>::enter_trace_span(||
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("resolve",
"rustc_const_eval::interpret::cast", ::tracing::Level::INFO,
::tracing_core::__macro_support::Option::Some("/rustc-dev/f7575a9da8e4a4fca3b5668d5a2ea7476db44b3f/compiler/rustc_const_eval/src/interpret/cast.rs"),
::tracing_core::__macro_support::Option::Some(142u32),
::tracing_core::__macro_support::Option::Some("rustc_const_eval::interpret::cast"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("resolve")
}> =
::tracing::__macro_support::FieldName::new("resolve");
NAME.as_str()
},
{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("def_id")
}> =
::tracing::__macro_support::FieldName::new("def_id");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::INFO <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::INFO <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::display(&"resolve_for_fn_ptr")
as &dyn ::tracing::field::Value)),
(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&def_id)
as &dyn ::tracing::field::Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
})enter_trace_span!(M, resolve::resolve_for_fn_ptr, ?def_id);
143 ty::Instance::resolve_for_fn_ptr(
144 *self.tcx,
145 self.typing_env,
146 def_id,
147 args.no_bound_vars().unwrap(),
148 )
149 .ok_or_else(|| ::rustc_middle::mir::interpret::InterpErrorKind::InvalidProgram(::rustc_middle::mir::interpret::InvalidProgramInfo::TooGeneric)err_inval!(TooGeneric))?
150 };
151
152 let fn_ptr = self.fn_ptr(FnVal::Instance(instance));
153 self.write_pointer(fn_ptr, dest)?;
154 }
155 _ => ::rustc_span::macros::bug_impl(Some(self.cur_span()),
format_args!("reify fn pointer on {0}", src.layout.ty),
Location::caller())span_bug!(self.cur_span(), "reify fn pointer on {}", src.layout.ty),
156 }
157 }
158
159 CastKind::PointerCoercion(PointerCoercion::UnsafeFnPointer, _) => {
160 let src = self.read_immediate(src)?;
161 match cast_ty.kind() {
162 ty::FnPtr(..) => {
163 self.write_immediate(*src, dest)?;
165 }
166 _ => ::rustc_span::macros::bug_impl(Some(self.cur_span()),
format_args!("fn to unsafe fn cast on {0}", cast_ty), Location::caller())span_bug!(self.cur_span(), "fn to unsafe fn cast on {}", cast_ty),
167 }
168 }
169
170 CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(_), _) => {
171 ensure_monomorphic_enough(src.layout.ty)?;
173
174 match *src.layout.ty.kind() {
176 ty::Closure(def_id, args) => {
177 let instance = {
178 let _trace = <M as
crate::interpret::Machine>::enter_trace_span(||
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("resolve",
"rustc_const_eval::interpret::cast", ::tracing::Level::INFO,
::tracing_core::__macro_support::Option::Some("/rustc-dev/f7575a9da8e4a4fca3b5668d5a2ea7476db44b3f/compiler/rustc_const_eval/src/interpret/cast.rs"),
::tracing_core::__macro_support::Option::Some(178u32),
::tracing_core::__macro_support::Option::Some("rustc_const_eval::interpret::cast"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("resolve")
}> =
::tracing::__macro_support::FieldName::new("resolve");
NAME.as_str()
},
{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("def_id")
}> =
::tracing::__macro_support::FieldName::new("def_id");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::INFO <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::INFO <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::display(&"resolve_closure")
as &dyn ::tracing::field::Value)),
(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&def_id)
as &dyn ::tracing::field::Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
})enter_trace_span!(M, resolve::resolve_closure, ?def_id);
179 ty::Instance::resolve_closure(
180 *self.tcx,
181 def_id,
182 args,
183 ty::ClosureKind::FnOnce,
184 )
185 };
186 let fn_ptr = self.fn_ptr(FnVal::Instance(instance));
187 self.write_pointer(fn_ptr, dest)?;
188 }
189 _ => ::rustc_span::macros::bug_impl(Some(self.cur_span()),
format_args!("closure fn pointer on {0}", src.layout.ty),
Location::caller())span_bug!(self.cur_span(), "closure fn pointer on {}", src.layout.ty),
190 }
191 }
192
193 CastKind::Transmute | CastKind::Subtype | CastKind::BoxDerefTransmute => {
194 if !src.layout.is_sized() {
::core::panicking::panic("assertion failed: src.layout.is_sized()")
};assert!(src.layout.is_sized());
195 if !dest.layout.is_sized() {
::core::panicking::panic("assertion failed: dest.layout.is_sized()")
};assert!(dest.layout.is_sized());
196 {
match (&cast_ty, &dest.layout.ty) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(cast_ty, dest.layout.ty); if src.layout.size != dest.layout.size {
198 do yeet ::rustc_middle::mir::interpret::InterpErrorKind::UndefinedBehavior(::rustc_middle::mir::interpret::UndefinedBehaviorInfo::Ub(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("transmuting from {0}-byte type to {1}-byte type: `{2}` -> `{3}`",
src.layout.size.bytes(), dest.layout.size.bytes(),
src.layout.ty, dest.layout.ty))
})));throw_ub_format!(
199 "transmuting from {src_bytes}-byte type to {dest_bytes}-byte type: `{src}` -> `{dest}`",
200 src_bytes = src.layout.size.bytes(),
201 dest_bytes = dest.layout.size.bytes(),
202 src = src.layout.ty,
203 dest = dest.layout.ty,
204 );
205 }
206
207 if #[allow(non_exhaustive_omitted_patterns)] match cast_kind {
CastKind::BoxDerefTransmute => true,
_ => false,
}matches!(cast_kind, CastKind::BoxDerefTransmute) {
208 let ptr = self.read_immediate(src)?;
211 let pointee_ty = cast_ty.builtin_deref(true).unwrap();
212 let box_ty = Ty::new_box(*self.tcx, pointee_ty);
213 let ptr = ptr.transmute(self.layout_of(box_ty)?, self)?;
214 self.deref_pointer(&ptr)?;
215 }
216
217 self.copy_op_allow_transmute(src, dest)?;
219 }
220 }
221 interp_ok(())
222 }
223
224 pub fn int_to_int_or_float(
226 &self,
227 src: &ImmTy<'tcx, M::Provenance>,
228 cast_to: TyAndLayout<'tcx>,
229 ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
230 if !(src.layout.ty.is_integral() || src.layout.ty.is_char() ||
src.layout.ty.is_bool()) {
::core::panicking::panic("assertion failed: src.layout.ty.is_integral() || src.layout.ty.is_char() ||\n src.layout.ty.is_bool()")
};assert!(src.layout.ty.is_integral() || src.layout.ty.is_char() || src.layout.ty.is_bool());
231 if !(cast_to.ty.is_floating_point() || cast_to.ty.is_integral() ||
cast_to.ty.is_char()) {
::core::panicking::panic("assertion failed: cast_to.ty.is_floating_point() || cast_to.ty.is_integral() ||\n cast_to.ty.is_char()")
};assert!(cast_to.ty.is_floating_point() || cast_to.ty.is_integral() || cast_to.ty.is_char());
232
233 interp_ok(ImmTy::from_scalar(
234 self.cast_from_int_like(src.to_scalar(), src.layout, cast_to.ty)?,
235 cast_to,
236 ))
237 }
238
239 pub fn float_to_float_or_int(
241 &self,
242 src: &ImmTy<'tcx, M::Provenance>,
243 cast_to: TyAndLayout<'tcx>,
244 ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
245 let ty::Float(fty) = src.layout.ty.kind() else {
246 ::rustc_span::macros::bug_impl(None,
format_args!("FloatToFloat/FloatToInt cast: source type {0} is not a float type",
src.layout.ty), Location::caller())bug!("FloatToFloat/FloatToInt cast: source type {} is not a float type", src.layout.ty)
247 };
248 let val = match fty {
249 FloatTy::F16 => self.cast_from_float(src.to_scalar().to_f16()?, cast_to.ty),
250 FloatTy::F32 => self.cast_from_float(src.to_scalar().to_f32()?, cast_to.ty),
251 FloatTy::F64 => self.cast_from_float(src.to_scalar().to_f64()?, cast_to.ty),
252 FloatTy::F128 => self.cast_from_float(src.to_scalar().to_f128()?, cast_to.ty),
253 };
254 interp_ok(ImmTy::from_scalar(val, cast_to))
255 }
256
257 pub fn ptr_to_ptr(
259 &self,
260 src: &ImmTy<'tcx, M::Provenance>,
261 cast_to: TyAndLayout<'tcx>,
262 ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
263 if !src.layout.ty.is_any_ptr() {
::core::panicking::panic("assertion failed: src.layout.ty.is_any_ptr()")
};assert!(src.layout.ty.is_any_ptr());
264 if !cast_to.ty.is_raw_ptr() {
::core::panicking::panic("assertion failed: cast_to.ty.is_raw_ptr()")
};assert!(cast_to.ty.is_raw_ptr());
265 if cast_to.size == src.layout.size {
267 return interp_ok(ImmTy::from_immediate(**src, cast_to));
269 } else {
270 {
match (&src.layout.size, &(2 * self.pointer_size())) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(src.layout.size, 2 * self.pointer_size());
272 {
match (&cast_to.size, &self.pointer_size()) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(cast_to.size, self.pointer_size());
273 if !src.layout.ty.is_raw_ptr() {
::core::panicking::panic("assertion failed: src.layout.ty.is_raw_ptr()")
};assert!(src.layout.ty.is_raw_ptr());
274 return match **src {
275 Immediate::ScalarPair(data, _) => interp_ok(ImmTy::from_scalar(data, cast_to)),
276 Immediate::Scalar(..) => ::rustc_span::macros::bug_impl(Some(self.cur_span()),
format_args!("{0:?} input to a fat-to-thin cast ({1} -> {2})", *src,
src.layout.ty, cast_to.ty), Location::caller())span_bug!(
277 self.cur_span(),
278 "{:?} input to a fat-to-thin cast ({} -> {})",
279 *src,
280 src.layout.ty,
281 cast_to.ty
282 ),
283 Immediate::Uninit => do yeet ::rustc_middle::mir::interpret::InterpErrorKind::UndefinedBehavior(::rustc_middle::mir::interpret::UndefinedBehaviorInfo::InvalidUninitBytes(None))throw_ub!(InvalidUninitBytes(None)),
284 };
285 }
286 }
287
288 pub fn pointer_expose_provenance_cast(
289 &mut self,
290 src: &ImmTy<'tcx, M::Provenance>,
291 cast_to: TyAndLayout<'tcx>,
292 ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
293 {
match src.layout.ty.kind() {
ty::RawPtr(_, _) | ty::FnPtr(..) => {}
ref left_val => {
::core::panicking::assert_matches_failed(left_val,
"ty::RawPtr(_, _) | ty::FnPtr(..)",
::core::option::Option::None);
}
}
};assert_matches!(src.layout.ty.kind(), ty::RawPtr(_, _) | ty::FnPtr(..));
294 if !cast_to.ty.is_integral() {
::core::panicking::panic("assertion failed: cast_to.ty.is_integral()")
};assert!(cast_to.ty.is_integral());
295
296 let scalar = src.to_scalar();
297 let ptr = scalar.to_pointer(self);
298 match ptr.into_pointer_or_addr() {
299 Ok(ptr) => M::expose_provenance(self, ptr.provenance)?,
300 Err(_) => {} };
302 interp_ok(ImmTy::from_scalar(
303 self.cast_from_int_like(scalar, src.layout, cast_to.ty)?,
304 cast_to,
305 ))
306 }
307
308 pub fn pointer_with_exposed_provenance_cast(
309 &self,
310 src: &ImmTy<'tcx, M::Provenance>,
311 cast_to: TyAndLayout<'tcx>,
312 ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
313 if !src.layout.ty.is_integral() {
::core::panicking::panic("assertion failed: src.layout.ty.is_integral()")
};assert!(src.layout.ty.is_integral());
314 {
match cast_to.ty.kind() {
ty::RawPtr(_, _) => {}
ref left_val => {
::core::panicking::assert_matches_failed(left_val,
"ty::RawPtr(_, _)", ::core::option::Option::None);
}
}
};assert_matches!(cast_to.ty.kind(), ty::RawPtr(_, _));
315
316 let scalar = src.to_scalar();
318 let addr = self.cast_from_int_like(scalar, src.layout, self.tcx.types.usize)?;
319 let addr = addr.to_target_usize(self)?;
320
321 let ptr = M::ptr_from_addr_cast(self, addr)?;
323 interp_ok(ImmTy::from_scalar(Scalar::from_maybe_pointer(ptr, self), cast_to))
324 }
325
326 fn cast_from_int_like(
329 &self,
330 scalar: Scalar<M::Provenance>, src_layout: TyAndLayout<'tcx>,
332 cast_ty: Ty<'tcx>,
333 ) -> InterpResult<'tcx, Scalar<M::Provenance>> {
334 let signed = src_layout.backend_repr.is_signed(); let v = match src_layout.ty.kind() {
339 ty::Uint(_) | ty::RawPtr(..) | ty::FnPtr(..) => scalar.to_uint(src_layout.size)?,
340 ty::Int(_) => scalar.to_int(src_layout.size)? as u128, ty::Bool => scalar.to_bool()?.into(),
342 ty::Char => scalar.to_char()?.into(),
343 _ => ::rustc_span::macros::bug_impl(Some(self.cur_span()),
format_args!("invalid int-like cast from {0}", src_layout.ty),
Location::caller())span_bug!(self.cur_span(), "invalid int-like cast from {}", src_layout.ty),
344 };
345
346 interp_ok(match *cast_ty.kind() {
347 ty::Int(_) | ty::Uint(_) => {
349 let size = match *cast_ty.kind() {
350 ty::Int(t) => Integer::from_int_ty(self, t).size(),
351 ty::Uint(t) => Integer::from_uint_ty(self, t).size(),
352 _ => ::rustc_span::macros::bug_impl(None, format_args!("impossible case reached"),
Location::caller())bug!(),
353 };
354 let v = size.truncate(v);
355 Scalar::from_uint(v, size)
356 }
357
358 ty::Float(fty) if signed => {
360 let v = v as i128;
361 match fty {
362 FloatTy::F16 => Scalar::from_f16(Half::from_i128(v).value),
363 FloatTy::F32 => Scalar::from_f32(Single::from_i128(v).value),
364 FloatTy::F64 => Scalar::from_f64(Double::from_i128(v).value),
365 FloatTy::F128 => Scalar::from_f128(Quad::from_i128(v).value),
366 }
367 }
368 ty::Float(fty) => match fty {
370 FloatTy::F16 => Scalar::from_f16(Half::from_u128(v).value),
371 FloatTy::F32 => Scalar::from_f32(Single::from_u128(v).value),
372 FloatTy::F64 => Scalar::from_f64(Double::from_u128(v).value),
373 FloatTy::F128 => Scalar::from_f128(Quad::from_u128(v).value),
374 },
375
376 ty::Char => Scalar::from_u32(u8::try_from(v).unwrap().into()),
378
379 _ => ::rustc_span::macros::bug_impl(Some(self.cur_span()),
format_args!("invalid int to {0} cast", cast_ty), Location::caller())span_bug!(self.cur_span(), "invalid int to {} cast", cast_ty),
381 })
382 }
383
384 fn cast_from_float<F>(&self, f: F, dest_ty: Ty<'tcx>) -> Scalar<M::Provenance>
386 where
387 F: Float
388 + Into<Scalar<M::Provenance>>
389 + FloatConvert<Half>
390 + FloatConvert<Single>
391 + FloatConvert<Double>
392 + FloatConvert<Quad>,
393 {
394 match *dest_ty.kind() {
395 ty::Uint(t) => {
397 let size = Integer::from_uint_ty(self, t).size();
398 let v = f.to_u128(size.bits_usize()).value;
401 Scalar::from_uint(v, size)
403 }
404 ty::Int(t) => {
406 let size = Integer::from_int_ty(self, t).size();
407 let v = f.to_i128(size.bits_usize()).value;
410 Scalar::from_int(v, size)
411 }
412 ty::Float(fty) => match fty {
414 FloatTy::F16 => {
415 Scalar::from_f16(self.adjust_nan(f.convert(&mut false).value, &[f]))
416 }
417 FloatTy::F32 => {
418 Scalar::from_f32(self.adjust_nan(f.convert(&mut false).value, &[f]))
419 }
420 FloatTy::F64 => {
421 Scalar::from_f64(self.adjust_nan(f.convert(&mut false).value, &[f]))
422 }
423 FloatTy::F128 => {
424 Scalar::from_f128(self.adjust_nan(f.convert(&mut false).value, &[f]))
425 }
426 },
427 _ => ::rustc_span::macros::bug_impl(Some(self.cur_span()),
format_args!("invalid float to {0} cast", dest_ty), Location::caller())span_bug!(self.cur_span(), "invalid float to {} cast", dest_ty),
429 }
430 }
431
432 fn unsize_into_ptr(
435 &mut self,
436 src: &OpTy<'tcx, M::Provenance>,
437 dest: &impl Writeable<'tcx, M::Provenance>,
438 source_ty: Ty<'tcx>,
440 cast_ty: Ty<'tcx>,
441 ) -> InterpResult<'tcx> {
442 let (src_pointee_ty, dest_pointee_ty) =
444 self.tcx.struct_lockstep_tails_for_codegen(source_ty, cast_ty, self.typing_env);
445
446 match (src_pointee_ty.kind(), dest_pointee_ty.kind()) {
447 (&ty::Array(_, length), &ty::Slice(_)) => {
448 let ptr = self.read_pointer(src)?;
449 let val = Immediate::new_slice(
450 ptr,
451 length
452 .try_to_target_usize(*self.tcx)
453 .expect("expected monomorphic const in const eval"),
454 self,
455 );
456 self.write_immediate(val, dest)
457 }
458 (ty::Dynamic(data_a, _), ty::Dynamic(data_b, _)) => {
459 let val = self.read_immediate(src)?;
460 if data_a == data_b {
464 return self.write_immediate(*val, dest);
465 }
466 let (old_data, old_vptr) = val.to_scalar_pair();
468 let old_data = old_data.to_pointer(self);
469 let old_vptr = old_vptr.to_pointer(self);
470 let ty = self.get_ptr_vtable_ty(old_vptr, Some(data_a))?;
471
472 let vptr_entry_idx =
475 self.tcx.supertrait_vtable_slot((src_pointee_ty, dest_pointee_ty));
476 let vtable_entries = self.vtable_entries(data_a.principal(), ty);
477 if let Some(entry_idx) = vptr_entry_idx {
478 let Some(&ty::VtblEntry::TraitVPtr(upcast_trait_ref)) =
479 vtable_entries.get(entry_idx)
480 else {
481 ::rustc_span::macros::bug_impl(Some(self.cur_span()),
format_args!("invalid vtable entry index in {0} -> {1} upcast",
src_pointee_ty, dest_pointee_ty), Location::caller());span_bug!(
482 self.cur_span(),
483 "invalid vtable entry index in {} -> {} upcast",
484 src_pointee_ty,
485 dest_pointee_ty
486 );
487 };
488 let erased_trait_ref =
489 ty::ExistentialTraitRef::erase_self_ty(*self.tcx, upcast_trait_ref);
490 {
match (&data_b.principal().map(|b|
{
self.tcx.normalize_erasing_late_bound_regions(self.typing_env,
b)
}), &Some(erased_trait_ref)) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(
491 data_b.principal().map(|b| {
492 self.tcx.normalize_erasing_late_bound_regions(self.typing_env, b)
493 }),
494 Some(erased_trait_ref),
495 );
496 } else {
497 let vtable_entries_b = self.vtable_entries(data_b.principal(), ty);
501 if !(&vtable_entries[..vtable_entries_b.len()] == vtable_entries_b) {
::core::panicking::panic("assertion failed: &vtable_entries[..vtable_entries_b.len()] == vtable_entries_b")
};assert!(&vtable_entries[..vtable_entries_b.len()] == vtable_entries_b);
502 };
503
504 let new_vptr = self.get_vtable_ptr(ty, data_b)?;
506 self.write_immediate(Immediate::new_dyn_trait(old_data, new_vptr, self), dest)
507 }
508 (_, &ty::Dynamic(data, _)) => {
509 let vtable = self.get_vtable_ptr(src_pointee_ty, data)?;
511 let ptr = self.read_pointer(src)?;
512 let val = Immediate::new_dyn_trait(ptr, vtable, &*self.tcx);
513 self.write_immediate(val, dest)
514 }
515 _ => {
516 ensure_monomorphic_enough(src.layout.ty)?;
518 ensure_monomorphic_enough(cast_ty)?;
519
520 ::rustc_span::macros::bug_impl(Some(self.cur_span()),
format_args!("invalid pointer unsizing {0} -> {1}", src.layout.ty,
cast_ty), Location::caller())span_bug!(
521 self.cur_span(),
522 "invalid pointer unsizing {} -> {}",
523 src.layout.ty,
524 cast_ty
525 )
526 }
527 }
528 }
529
530 pub fn unsize_into(
532 &mut self,
533 src: &OpTy<'tcx, M::Provenance>,
534 cast_ty: TyAndLayout<'tcx>,
535 dest: &impl Writeable<'tcx, M::Provenance>,
536 ) -> InterpResult<'tcx> {
537 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/f7575a9da8e4a4fca3b5668d5a2ea7476db44b3f/compiler/rustc_const_eval/src/interpret/cast.rs:537",
"rustc_const_eval::interpret::cast",
::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("/rustc-dev/f7575a9da8e4a4fca3b5668d5a2ea7476db44b3f/compiler/rustc_const_eval/src/interpret/cast.rs"),
::tracing_core::__macro_support::Option::Some(537u32),
::tracing_core::__macro_support::Option::Some("rustc_const_eval::interpret::cast"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("Unsizing {0:?} of type {1} into {2}",
*src, src.layout.ty, cast_ty.ty) as
&dyn ::tracing::field::Value))])
});
} else { ; }
};trace!("Unsizing {:?} of type {} into {}", *src, src.layout.ty, cast_ty.ty);
538 match (src.layout.ty.kind(), cast_ty.ty.kind()) {
539 (&ty::Pat(_, s_pat), &ty::Pat(cast_ty, c_pat)) if s_pat == c_pat => {
540 let src = self.project_field(src, FieldIdx::ZERO)?;
541 let dest = self.project_field(dest, FieldIdx::ZERO)?;
542 let cast_ty = self.layout_of(cast_ty)?;
543 self.unsize_into(&src, cast_ty, &dest)
544 }
545 (&ty::Ref(_, s, _), &ty::Ref(_, c, _) | &ty::RawPtr(c, _))
546 | (&ty::RawPtr(s, _), &ty::RawPtr(c, _)) => self.unsize_into_ptr(src, dest, s, c),
547 (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
548 {
match (&def_a, &def_b) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(def_a, def_b); let mut found_cast_field = false;
554 for i in 0..src.layout.fields.count() {
555 let cast_ty_field = cast_ty.field(self, i);
556 let i = FieldIdx::from_usize(i);
557 let src_field = self.project_field(src, i)?;
558 let dst_field = self.project_field(dest, i)?;
559 if src_field.layout.is_1zst() && cast_ty_field.is_1zst() {
560 } else if src_field.layout.ty == cast_ty_field.ty {
562 self.copy_op_no_validate(
564 &src_field, &dst_field, false,
565 )?;
566 } else {
567 if found_cast_field {
568 ::rustc_span::macros::bug_impl(Some(self.cur_span()),
format_args!("unsize_into: more than one field to cast"),
Location::caller());span_bug!(self.cur_span(), "unsize_into: more than one field to cast");
569 }
570 found_cast_field = true;
571 self.unsize_into(&src_field, cast_ty_field, &dst_field)?;
572 }
573 }
574 interp_ok(())
575 }
576 _ => {
577 ensure_monomorphic_enough(src.layout.ty)?;
579 ensure_monomorphic_enough(cast_ty.ty)?;
580
581 ::rustc_span::macros::bug_impl(Some(self.cur_span()),
format_args!("unsize_into: invalid conversion: {0:?} -> {1:?}",
src.layout, dest.layout()), Location::caller())span_bug!(
582 self.cur_span(),
583 "unsize_into: invalid conversion: {:?} -> {:?}",
584 src.layout,
585 dest.layout()
586 )
587 }
588 }
589 }
590}