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