1//! This module provides a MIR interpreter, which is used in const eval.23use std::{borrow::Cow, cell::RefCell, fmt::Write, iter, mem, ops::Range};45use base_db::{Crate, target::TargetLoadError};6use either::Either;7use hir_def::{8 AdtId, DefWithBodyId, EnumVariantId, FunctionId, HasModule, ItemContainerId, Lookup, StaticId,9 VariantId,10 expr_store::{Body, ExpressionStore, HygieneId},11 item_tree::FieldsShape,12 lang_item::LangItems,13 layout::{TagEncoding, Variants},14 resolver::{HasResolver, ValueNs},15 signatures::{16 EnumSignature, FunctionSignature, StaticFlags, StaticSignature, StructFlags,17 StructSignature, TraitSignature,18 },19};20use hir_expand::{InFile, mod_path::path};21use la_arena::ArenaMap;22use macros::GenericTypeVisitable;23use rustc_abi::{Size, TargetDataLayout};24use rustc_apfloat::{25 Float,26 ieee::{Half as f16, Quad as f128},27};28use rustc_ast_ir::Mutability;29use rustc_hash::{FxHashMap, FxHashSet};30use rustc_type_ir::{31 AliasTyKind,32 inherent::{GenericArgs as _, IntoKind, Region as _, SliceLike, Ty as _},33};34use span::FileId;35use stdx::never;36use syntax::{SyntaxNodePtr, TextRange};37use triomphe::Arc;3839use crate::{40 CallableDefId, ComplexMemoryMap, InferBodyId, InferenceResult, MemoryMap, ParamEnvAndCrate,41 consteval::{self, ConstEvalError, try_const_usize},42 db::{GeneralConstId, HirDatabase, InternedClosureId},43 display::{ClosureStyle, DisplayTarget, HirDisplay},44 infer::PointerCast,45 layout::{Layout, LayoutError, RustcEnumVariantIdx},46 method_resolution::{is_dyn_method, lookup_impl_const},47 next_solver::{48 AliasTy, Allocation, AllocationData, Const, ConstKind, DbInterner, ErrorGuaranteed,49 GenericArgs, Region, StoredTy, Ty, TyKind, TypingMode, UnevaluatedConst, ValTree,50 infer::{DbInternerInferExt, InferCtxt, traits::ObligationCause},51 obligation_ctxt::ObligationCtxt,52 },53 traits::FnTrait,54 utils::detect_variant_from_bytes,55};5657use super::{58 AggregateKind, BasicBlockId, BinOp, CastKind, LocalId, MirBody, MirLowerError, MirSpan,59 Operand, OperandKind, Place, PlaceElem, PlaceRef, PlaceTy, ProjectionElem, Rvalue,60 StatementKind, TerminatorKind, UnOp, return_slot,61};6263mod shim;64#[cfg(test)]65mod tests;6667macro_rules! from_bytes {68 ($ty:tt, $value:expr) => {69 ($ty::from_le_bytes(match ($value).try_into() {70 Ok(it) => it,71 Err(_) => return Err(MirEvalError::InternalError(stringify!(mismatched size in constructing $ty).into())),72 }))73 };74 ($apfloat:tt, $bits:tt, $value:expr) => {75 // FIXME(#17451): Switch to builtin `f16` and `f128` once they are stable.76 $apfloat::from_bits($bits::from_le_bytes(match ($value).try_into() {77 Ok(it) => it,78 Err(_) => return Err(MirEvalError::InternalError(stringify!(mismatched size in constructing $apfloat).into())),79 }).into())80 };81}82use from_bytes;8384macro_rules! not_supported {85 ($it: expr) => {86 return Err($crate::mir::eval::MirEvalError::NotSupported(format!($it)))87 };88}89use not_supported;9091#[derive(Debug, Default, Clone, PartialEq, Eq, GenericTypeVisitable)]92pub struct VTableMap<'db> {93 ty_to_id: FxHashMap<Ty<'db>, usize>,94 id_to_ty: Vec<Ty<'db>>,95}9697impl<'db> VTableMap<'db> {98 const OFFSET: usize = 1000; // We should add some offset to ids to make 0 (null) an invalid id.99100 fn id(&mut self, ty: Ty<'db>) -> usize {101 if let Some(it) = self.ty_to_id.get(&ty) {102 return *it;103 }104 let id = self.id_to_ty.len() + VTableMap::OFFSET;105 self.id_to_ty.push(ty);106 self.ty_to_id.insert(ty, id);107 id108 }109110 pub(crate) fn ty(&self, id: usize) -> Result<'db, Ty<'db>> {111 id.checked_sub(VTableMap::OFFSET)112 .and_then(|id| self.id_to_ty.get(id).copied())113 .ok_or(MirEvalError::InvalidVTableId(id))114 }115116 fn ty_of_bytes(&self, bytes: &[u8]) -> Result<'db, Ty<'db>> {117 let id = from_bytes!(usize, bytes);118 self.ty(id)119 }120121 pub fn shrink_to_fit(&mut self) {122 self.id_to_ty.shrink_to_fit();123 self.ty_to_id.shrink_to_fit();124 }125126 fn is_empty(&self) -> bool {127 self.id_to_ty.is_empty() && self.ty_to_id.is_empty()128 }129}130131#[derive(Debug, Default, Clone, PartialEq, Eq)]132struct TlsData {133 keys: Vec<u128>,134}135136impl TlsData {137 fn create_key(&mut self) -> usize {138 self.keys.push(0);139 self.keys.len() - 1140 }141142 fn get_key(&mut self, key: usize) -> Result<'static, u128> {143 let r = self.keys.get(key).ok_or_else(|| {144 MirEvalError::UndefinedBehavior(format!("Getting invalid tls key {key}"))145 })?;146 Ok(*r)147 }148149 fn set_key(&mut self, key: usize, value: u128) -> Result<'static, ()> {150 let r = self.keys.get_mut(key).ok_or_else(|| {151 MirEvalError::UndefinedBehavior(format!("Setting invalid tls key {key}"))152 })?;153 *r = value;154 Ok(())155 }156}157158struct StackFrame<'a> {159 locals: Locals<'a>,160 destination: Option<BasicBlockId>,161 prev_stack_ptr: usize,162 span: (MirSpan, InferBodyId),163}164165#[derive(Clone)]166enum MirOrDynIndex<'a> {167 Mir(&'a MirBody),168 Dyn(usize),169}170171pub struct Evaluator<'a, 'db> {172 db: &'db dyn HirDatabase,173 param_env: ParamEnvAndCrate<'db>,174 target_data_layout: &'db TargetDataLayout,175 stack: Vec<u8>,176 heap: Vec<u8>,177 code_stack: Vec<StackFrame<'a>>,178 /// Stores the global location of the statics. We const evaluate every static first time we need it179 /// and see it's missing, then we add it to this to reuse.180 static_locations: FxHashMap<StaticId, Address>,181 /// We don't really have function pointers, i.e. pointers to some assembly instructions that we can run. Instead, we182 /// store the type as an interned id in place of function and vtable pointers, and we recover back the type at the183 /// time of use.184 vtable_map: VTableMap<'db>,185 thread_local_storage: TlsData,186 random_state: oorandom::Rand64,187 stdout: Vec<u8>,188 stderr: Vec<u8>,189 layout_cache: RefCell<FxHashMap<Ty<'db>, Arc<Layout>>>,190 projected_ty_cache: RefCell<FxHashMap<(PlaceTy<'db>, PlaceElem), PlaceTy<'db>>>,191 not_special_fn_cache: RefCell<FxHashSet<FunctionId>>,192 mir_or_dyn_index_cache: RefCell<FxHashMap<(FunctionId, GenericArgs<'db>), MirOrDynIndex<'a>>>,193 /// Constantly dropping and creating `Locals` is very costly. We store194 /// old locals that we normally want to drop here, to reuse their allocations195 /// later.196 unused_locals_store: RefCell<FxHashMap<InferBodyId, Vec<Locals<'a>>>>,197 cached_ptr_size: usize,198 cached_fn_trait_func: Option<FunctionId>,199 cached_fn_mut_trait_func: Option<FunctionId>,200 cached_fn_once_trait_func: Option<FunctionId>,201 crate_id: Crate,202 // FIXME: This is a workaround, see the comment on `interpret_mir`203 assert_placeholder_ty_is_unused: bool,204 /// A general limit on execution, to prevent non terminating programs from breaking r-a main process205 execution_limit: usize,206 /// An additional limit on stack depth, to prevent stack overflow207 stack_depth_limit: usize,208 /// Maximum count of bytes that heap and stack can grow209 memory_limit: usize,210 infcx: InferCtxt<'db>,211}212213#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]214enum Address {215 Stack(usize),216 Heap(usize),217 Invalid(usize),218}219220use Address::*;221222#[derive(Debug, Clone, Copy)]223struct Interval {224 addr: Address,225 size: usize,226}227228#[derive(Debug, Clone)]229struct IntervalAndTy<'db> {230 interval: Interval,231 ty: Ty<'db>,232}233234impl Interval {235 fn new(addr: Address, size: usize) -> Self {236 Self { addr, size }237 }238239 fn get<'b, 'a, 'db: 'a>(&self, memory: &'b Evaluator<'a, 'db>) -> Result<'db, &'b [u8]> {240 memory.read_memory(self.addr, self.size)241 }242243 fn write_from_bytes<'a, 'db: 'a>(244 &self,245 memory: &mut Evaluator<'a, 'db>,246 bytes: &[u8],247 ) -> Result<'db, ()> {248 memory.write_memory(self.addr, bytes)249 }250251 fn write_from_interval<'a, 'db: 'a>(252 &self,253 memory: &mut Evaluator<'a, 'db>,254 interval: Interval,255 ) -> Result<'db, ()> {256 memory.copy_from_interval(self.addr, interval)257 }258259 fn slice(self, range: Range<usize>) -> Interval {260 Interval { addr: self.addr.offset(range.start), size: range.len() }261 }262}263264impl<'db> IntervalAndTy<'db> {265 fn get<'b, 'a>(&self, memory: &'b Evaluator<'a, 'db>) -> Result<'db, &'b [u8]>266 where267 'db: 'a,268 {269 memory.read_memory(self.interval.addr, self.interval.size)270 }271272 fn new<'a>(273 addr: Address,274 ty: Ty<'db>,275 evaluator: &Evaluator<'a, 'db>,276 locals: &Locals<'a>,277 ) -> Result<'db, IntervalAndTy<'db>>278 where279 'db: 'a,280 {281 let size = evaluator.size_of_sized(ty, locals, "type of interval")?;282 Ok(IntervalAndTy { interval: Interval { addr, size }, ty })283 }284}285286enum IntervalOrOwned {287 Owned(Vec<u8>),288 Borrowed(Interval),289}290291impl From<Interval> for IntervalOrOwned {292 fn from(it: Interval) -> IntervalOrOwned {293 IntervalOrOwned::Borrowed(it)294 }295}296297impl IntervalOrOwned {298 fn get<'b, 'a, 'db: 'a>(&'b self, memory: &'b Evaluator<'a, 'db>) -> Result<'db, &'b [u8]> {299 Ok(match self {300 IntervalOrOwned::Owned(o) => o,301 IntervalOrOwned::Borrowed(b) => b.get(memory)?,302 })303 }304}305306#[cfg(target_pointer_width = "64")]307const STACK_OFFSET: usize = 1 << 60;308#[cfg(target_pointer_width = "64")]309const HEAP_OFFSET: usize = 1 << 59;310311#[cfg(target_pointer_width = "32")]312const STACK_OFFSET: usize = 1 << 30;313#[cfg(target_pointer_width = "32")]314const HEAP_OFFSET: usize = 1 << 29;315316impl Address {317 #[allow(clippy::double_parens)]318 fn from_bytes<'db>(it: &[u8]) -> Result<'db, Self> {319 Ok(Address::from_usize(from_bytes!(usize, it)))320 }321322 fn from_usize(it: usize) -> Self {323 if it > STACK_OFFSET {324 Stack(it - STACK_OFFSET)325 } else if it > HEAP_OFFSET {326 Heap(it - HEAP_OFFSET)327 } else {328 Invalid(it)329 }330 }331332 fn to_bytes(&self) -> [u8; size_of::<usize>()] {333 usize::to_le_bytes(self.to_usize())334 }335336 fn to_usize(&self) -> usize {337 match self {338 Stack(it) => *it + STACK_OFFSET,339 Heap(it) => *it + HEAP_OFFSET,340 Invalid(it) => *it,341 }342 }343344 fn map(&self, f: impl FnOnce(usize) -> usize) -> Address {345 match self {346 Stack(it) => Stack(f(*it)),347 Heap(it) => Heap(f(*it)),348 Invalid(it) => Invalid(f(*it)),349 }350 }351352 fn offset(&self, offset: usize) -> Address {353 self.map(|it| it + offset)354 }355}356357#[derive(Clone, PartialEq, Eq)]358pub enum MirEvalError {359 ConstEvalError(String, Box<ConstEvalError>),360 LayoutError(LayoutError, StoredTy),361 TargetDataLayoutNotAvailable(TargetLoadError),362 /// Means that code had undefined behavior. We don't try to actively detect UB, but if it was detected363 /// then use this type of error.364 UndefinedBehavior(String),365 Panic(String),366 // FIXME: This should be folded into ConstEvalError?367 MirLowerError(FunctionId, MirLowerError),368 MirLowerErrorForClosure(InternedClosureId, MirLowerError),369 TypeIsUnsized(StoredTy, &'static str),370 NotSupported(String),371 InvalidConst,372 InFunction(373 Box<MirEvalError>,374 Vec<(Either<FunctionId, InternedClosureId>, MirSpan, InferBodyId)>,375 ),376 ExecutionLimitExceeded,377 StackOverflow,378 /// FIXME: Fold this into InternalError379 InvalidVTableId(usize),380 /// ?381 CoerceUnsizedError(StoredTy),382 /// These should not occur, usually indicates a bug in mir lowering.383 InternalError(Box<str>),384}385386impl MirEvalError {387 pub fn pretty_print(388 &self,389 f: &mut String,390 db: &dyn HirDatabase,391 span_formatter: impl Fn(FileId, TextRange) -> String,392 display_target: DisplayTarget,393 ) -> std::result::Result<(), std::fmt::Error> {394 writeln!(f, "Mir eval error:")?;395 let mut err = self;396 while let MirEvalError::InFunction(e, stack) = err {397 err = e;398 for (func, span, def) in stack.iter().take(30).rev() {399 match func {400 Either::Left(func) => {401 let function_name = FunctionSignature::of(db, *func);402 writeln!(403 f,404 "In function {} ({:?})",405 function_name.name.display(db, display_target.edition),406 func407 )?;408 }409 Either::Right(closure) => {410 writeln!(f, "In {closure:?}")?;411 }412 }413 let (source_map, self_param_syntax) = match *def {414 InferBodyId::DefWithBodyId(def) => {415 let body = &Body::with_source_map(db, def).1;416 (&**body, body.self_param_syntax())417 }418 InferBodyId::AnonConstId(def) => {419 let store = ExpressionStore::with_source_map(db, def.loc(db).owner).1;420 (store, None)421 }422 };423 let span: InFile<SyntaxNodePtr> = match span {424 MirSpan::ExprId(e) => match source_map.expr_syntax(*e) {425 Ok(s) => s.map(|it| it.into()),426 Err(_) => continue,427 },428 MirSpan::PatId(p) => match source_map.pat_syntax(*p) {429 Ok(s) => s.map(|it| it.syntax_node_ptr()),430 Err(_) => continue,431 },432 MirSpan::BindingId(b) => {433 match source_map434 .patterns_for_binding(*b)435 .iter()436 .find_map(|p| source_map.pat_syntax(*p).ok())437 {438 Some(s) => s.map(|it| it.syntax_node_ptr()),439 None => continue,440 }441 }442 MirSpan::SelfParam => match self_param_syntax {443 Some(s) => s.map(|it| it.syntax_node_ptr()),444 None => continue,445 },446 MirSpan::Unknown => continue,447 };448 let file_id = span.file_id.original_file(db);449 let text_range = span.value.text_range();450 writeln!(f, "{}", span_formatter(file_id.file_id(db), text_range))?;451 }452 }453 match err {454 MirEvalError::InFunction(..) => unreachable!(),455 MirEvalError::LayoutError(err, ty) => {456 write!(457 f,458 "Layout for type `{}` is not available due {err:?}",459 ty.as_ref()460 .display(db, display_target)461 .with_closure_style(ClosureStyle::ClosureWithId)462 )?;463 }464 MirEvalError::MirLowerError(func, err) => {465 let function_name = FunctionSignature::of(db, *func);466 let self_ = match func.lookup(db).container {467 ItemContainerId::ImplId(impl_id) => Some({468 db.impl_self_ty(impl_id)469 .instantiate_identity()470 .skip_norm_wip()471 .display(db, display_target)472 .to_string()473 }),474 ItemContainerId::TraitId(it) => Some(475 TraitSignature::of(db, it)476 .name477 .display(db, display_target.edition)478 .to_string(),479 ),480 _ => None,481 };482 writeln!(483 f,484 "MIR lowering for function `{}{}{}` ({:?}) failed due:",485 self_.as_deref().unwrap_or_default(),486 if self_.is_some() { "::" } else { "" },487 function_name.name.display(db, display_target.edition),488 func489 )?;490 err.pretty_print(f, db, span_formatter, display_target)?;491 }492 MirEvalError::ConstEvalError(name, err) => {493 MirLowerError::ConstEvalError((**name).into(), err.clone()).pretty_print(494 f,495 db,496 span_formatter,497 display_target,498 )?;499 }500 MirEvalError::UndefinedBehavior(_)501 | MirEvalError::TargetDataLayoutNotAvailable(_)502 | MirEvalError::Panic(_)503 | MirEvalError::MirLowerErrorForClosure(_, _)504 | MirEvalError::TypeIsUnsized(_, _)505 | MirEvalError::NotSupported(_)506 | MirEvalError::InvalidConst507 | MirEvalError::ExecutionLimitExceeded508 | MirEvalError::StackOverflow509 | MirEvalError::CoerceUnsizedError(_)510 | MirEvalError::InternalError(_)511 | MirEvalError::InvalidVTableId(_) => writeln!(f, "{err:?}")?,512 }513 Ok(())514 }515516 pub fn is_panic(&self) -> Option<&str> {517 let mut err = self;518 while let MirEvalError::InFunction(e, _) = err {519 err = e;520 }521 match err {522 MirEvalError::Panic(msg) => Some(msg),523 _ => None,524 }525 }526}527528impl std::fmt::Debug for MirEvalError {529 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {530 match self {531 Self::ConstEvalError(arg0, arg1) => {532 f.debug_tuple("ConstEvalError").field(arg0).field(arg1).finish()533 }534 Self::LayoutError(arg0, arg1) => {535 f.debug_tuple("LayoutError").field(arg0).field(arg1).finish()536 }537 Self::UndefinedBehavior(arg0) => {538 f.debug_tuple("UndefinedBehavior").field(arg0).finish()539 }540 Self::Panic(msg) => write!(f, "Panic with message:\n{msg:?}"),541 Self::TargetDataLayoutNotAvailable(arg0) => {542 f.debug_tuple("TargetDataLayoutNotAvailable").field(arg0).finish()543 }544 Self::TypeIsUnsized(ty, it) => write!(f, "{ty:?} is unsized. {it} should be sized."),545 Self::ExecutionLimitExceeded => write!(f, "execution limit exceeded"),546 Self::StackOverflow => write!(f, "stack overflow"),547 Self::MirLowerError(arg0, arg1) => {548 f.debug_tuple("MirLowerError").field(arg0).field(arg1).finish()549 }550 Self::MirLowerErrorForClosure(arg0, arg1) => {551 f.debug_tuple("MirLowerError").field(arg0).field(arg1).finish()552 }553 Self::CoerceUnsizedError(arg0) => {554 f.debug_tuple("CoerceUnsizedError").field(arg0).finish()555 }556 Self::InternalError(arg0) => f.debug_tuple("InternalError").field(arg0).finish(),557 Self::InvalidVTableId(arg0) => f.debug_tuple("InvalidVTableId").field(arg0).finish(),558 Self::NotSupported(arg0) => f.debug_tuple("NotSupported").field(arg0).finish(),559 Self::InvalidConst => f.write_str("InvalidConst"),560 Self::InFunction(e, stack) => {561 f.debug_struct("WithStack").field("error", e).field("stack", &stack).finish()562 }563 }564 }565}566567type Result<'db, T> = std::result::Result<T, MirEvalError>;568569#[derive(Debug, Default)]570struct DropFlags<'db> {571 need_drop: FxHashSet<PlaceRef<'db>>,572}573574impl<'db> DropFlags<'db> {575 fn add_place(&mut self, p: PlaceRef<'db>) {576 if p.iterate_over_parents().any(|it| self.need_drop.contains(&it)) {577 return;578 }579 self.need_drop.retain(|it| !p.is_parent(*it));580 self.need_drop.insert(p);581 }582583 fn remove_place(&mut self, p: PlaceRef<'db>) -> bool {584 // FIXME: replace parents with parts585 if let Some(parent) = p.iterate_over_parents().find(|it| self.need_drop.contains(it)) {586 self.need_drop.remove(&parent);587 return true;588 }589 self.need_drop.remove(&p)590 }591592 fn clear(&mut self) {593 self.need_drop.clear();594 }595}596597#[derive(Debug)]598struct Locals<'a> {599 ptr: ArenaMap<LocalId, Interval>,600 body: &'a MirBody,601 drop_flags: DropFlags<'a>,602}603604pub struct MirOutput {605 stdout: Vec<u8>,606 stderr: Vec<u8>,607}608609impl MirOutput {610 pub fn stdout(&self) -> Cow<'_, str> {611 String::from_utf8_lossy(&self.stdout)612 }613 pub fn stderr(&self) -> Cow<'_, str> {614 String::from_utf8_lossy(&self.stderr)615 }616}617618pub fn interpret_mir<'a, 'db: 'a>(619 db: &'db dyn HirDatabase,620 body: &MirBody,621 // FIXME: This is workaround. Ideally, const generics should have a separate body (issue #7434), but now622 // they share their body with their parent, so in MIR lowering we have locals of the parent body, which623 // might have placeholders. With this argument, we (wrongly) assume that every placeholder type has624 // a zero size, hoping that they are all outside of our current body. Even without a fix for #7434, we can625 // (and probably should) do better here, for example by excluding bindings outside of the target expression.626 assert_placeholder_ty_is_unused: bool,627 trait_env: Option<ParamEnvAndCrate<'db>>,628) -> Result<'db, (Result<'db, Allocation<'db>>, MirOutput)> {629 let ty = body.locals[return_slot()].ty.as_ref();630 let mut evaluator = Evaluator::new(db, body.owner, assert_placeholder_ty_is_unused, trait_env)?;631 let it: Result<'db, Allocation<'db>> = (|| {632 if evaluator.ptr_size() != size_of::<usize>() {633 not_supported!("targets with different pointer size from host");634 }635 let interval = evaluator.interpret_mir(body, None.into_iter())?;636 let bytes = interval.get(&evaluator)?;637 let mut memory_map = evaluator.create_memory_map(638 bytes,639 ty,640 &Locals { ptr: ArenaMap::new(), body, drop_flags: DropFlags::default() },641 )?;642 let bytes = Box::from(bytes);643 let memory_map = if memory_map.memory.is_empty() && evaluator.vtable_map.is_empty() {644 MemoryMap::Empty645 } else {646 memory_map.vtable = mem::take(&mut evaluator.vtable_map);647 memory_map.vtable.shrink_to_fit();648 MemoryMap::Complex(Box::new(memory_map))649 };650 Ok(Allocation::new(AllocationData { ty, memory: bytes, memory_map }))651 })();652 Ok((it, MirOutput { stdout: evaluator.stdout, stderr: evaluator.stderr }))653}654655#[cfg(test)]656const EXECUTION_LIMIT: usize = 100_000;657#[cfg(not(test))]658const EXECUTION_LIMIT: usize = 10_000_000;659660impl<'a, 'db: 'a> Evaluator<'a, 'db> {661 pub fn new(662 db: &'db dyn HirDatabase,663 owner: InferBodyId,664 assert_placeholder_ty_is_unused: bool,665 trait_env: Option<ParamEnvAndCrate<'db>>,666 ) -> Result<'db, Evaluator<'a, 'db>> {667 let module = owner.module(db);668 let crate_id = module.krate(db);669 let target_data_layout = match db.target_data_layout(crate_id) {670 Ok(target_data_layout) => target_data_layout,671 Err(e) => return Err(MirEvalError::TargetDataLayoutNotAvailable(e)),672 };673 let cached_ptr_size = target_data_layout.pointer_size().bytes_usize();674 let interner = DbInterner::new_with(db, crate_id);675 let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis);676 let lang_items = interner.lang_items();677 Ok(Evaluator {678 target_data_layout,679 stack: vec![0],680 heap: vec![0],681 code_stack: vec![],682 vtable_map: VTableMap::default(),683 thread_local_storage: TlsData::default(),684 static_locations: Default::default(),685 db,686 random_state: oorandom::Rand64::new(0),687 param_env: trait_env.unwrap_or_else(|| ParamEnvAndCrate {688 param_env: db.trait_environment(owner.generic_def(db)),689 krate: crate_id,690 }),691 crate_id,692 stdout: vec![],693 stderr: vec![],694 assert_placeholder_ty_is_unused,695 stack_depth_limit: 100,696 execution_limit: EXECUTION_LIMIT,697 memory_limit: 1_000_000_000, // 2GB, 1GB for stack and 1GB for heap698 layout_cache: RefCell::new(Default::default()),699 projected_ty_cache: RefCell::new(Default::default()),700 not_special_fn_cache: RefCell::new(Default::default()),701 mir_or_dyn_index_cache: RefCell::new(Default::default()),702 unused_locals_store: RefCell::new(Default::default()),703 cached_ptr_size,704 cached_fn_trait_func: lang_items.Fn_call,705 cached_fn_mut_trait_func: lang_items.FnMut_call_mut,706 cached_fn_once_trait_func: lang_items.FnOnce_call_once,707 infcx,708 })709 }710711 #[inline]712 fn interner(&self) -> DbInterner<'db> {713 self.infcx.interner714 }715716 #[inline]717 fn lang_items(&self) -> &'db LangItems {718 self.infcx.interner.lang_items()719 }720721 fn place_addr(&self, p: &Place, locals: &Locals<'a>) -> Result<'db, Address> {722 Ok(self.place_addr_and_ty_and_metadata(p, locals)?.0)723 }724725 fn place_interval(&self, p: &Place, locals: &Locals<'a>) -> Result<'db, Interval> {726 let place_addr_and_ty = self.place_addr_and_ty_and_metadata(p, locals)?;727 Ok(Interval {728 addr: place_addr_and_ty.0,729 size: self.size_of_sized(730 place_addr_and_ty.1,731 locals,732 "Type of place that we need its interval",733 )?,734 })735 }736737 fn ptr_size(&self) -> usize {738 self.cached_ptr_size739 }740741 fn projected_ty(&self, ty: PlaceTy<'db>, proj: PlaceElem) -> PlaceTy<'db> {742 let pair = (ty, proj);743 if let Some(r) = self.projected_ty_cache.borrow().get(&pair) {744 return *r;745 }746 let (ty, proj) = pair;747 let r = ty.projection_ty(&self.infcx, &proj, self.param_env.param_env);748 self.projected_ty_cache.borrow_mut().insert((ty, proj), r);749 r750 }751752 fn place_addr_and_ty_and_metadata<'b>(753 &'b self,754 p: &Place,755 locals: &'b Locals<'a>,756 ) -> Result<'db, (Address, Ty<'db>, Option<IntervalOrOwned>)> {757 let mut addr = locals.ptr[p.local].addr;758 let mut ty = PlaceTy::from_ty(locals.body.locals[p.local].ty.as_ref());759 let mut metadata: Option<IntervalOrOwned> = None; // locals are always sized760 for proj in p.projection.lookup() {761 let prev_ty = ty;762 ty = self.projected_ty(ty, *proj);763 match proj {764 ProjectionElem::Deref => {765 metadata = if self.size_align_of(ty.ty, locals)?.is_none() {766 Some(767 Interval { addr: addr.offset(self.ptr_size()), size: self.ptr_size() }768 .into(),769 )770 } else {771 None772 };773 let it = from_bytes!(usize, self.read_memory(addr, self.ptr_size())?);774 addr = Address::from_usize(it);775 }776 ProjectionElem::Index(op) => {777 let offset = from_bytes!(778 usize,779 self.read_memory(locals.ptr[*op].addr, self.ptr_size())?780 );781 metadata = None; // Result of index is always sized782 let ty_size =783 self.size_of_sized(ty.ty, locals, "array inner type should be sized")?;784 addr = addr.offset(ty_size * offset);785 }786 &ProjectionElem::ConstantIndex { from_end, offset } => {787 let offset = if from_end {788 let len = match prev_ty.ty.kind() {789 TyKind::Array(_, c) => match try_const_usize(self.db, c) {790 Some(it) => it as u64,791 None => {792 not_supported!("indexing array with unknown const from end")793 }794 },795 TyKind::Slice(_) => match metadata {796 Some(it) => from_bytes!(u64, it.get(self)?),797 None => not_supported!("slice place without metadata"),798 },799 _ => not_supported!("bad type for const index"),800 };801 (len - offset - 1) as usize802 } else {803 offset as usize804 };805 metadata = None; // Result of index is always sized806 let ty_size =807 self.size_of_sized(ty.ty, locals, "array inner type should be sized")?;808 addr = addr.offset(ty_size * offset);809 }810 &ProjectionElem::Subslice { from, to } => {811 let inner_ty = match ty.ty.kind() {812 TyKind::Array(inner, _) | TyKind::Slice(inner) => inner,813 _ => Ty::new_error(self.interner(), ErrorGuaranteed),814 };815 metadata = match metadata {816 Some(it) => {817 let prev_len = from_bytes!(u64, it.get(self)?);818 Some(IntervalOrOwned::Owned(819 (prev_len - from - to).to_le_bytes().to_vec(),820 ))821 }822 None => None,823 };824 let ty_size =825 self.size_of_sized(inner_ty, locals, "array inner type should be sized")?;826 addr = addr.offset(ty_size * (from as usize));827 }828 ProjectionElem::Field(f) => {829 let layout = self.layout(prev_ty.ty)?;830 let variant_layout = match &layout.variants {831 Variants::Single { .. } | Variants::Empty => &layout,832 Variants::Multiple { variants, .. } => {833 &variants[match prev_ty.variant_id {834 Some(hir_def::VariantId::EnumVariantId(it)) => {835 RustcEnumVariantIdx(it.index(self.db))836 }837 _ => {838 return Err(MirEvalError::InternalError(839 "mismatched layout".into(),840 ));841 }842 }]843 }844 };845 let offset = variant_layout.fields.offset(f.0 as usize).bytes_usize();846 addr = addr.offset(offset);847 // Unsized field metadata is equal to the metadata of the struct848 if self.size_align_of(ty.ty, locals)?.is_some() {849 metadata = None;850 }851 }852 ProjectionElem::Downcast(_) => {853 // no runtime effect854 }855 }856 }857 Ok((addr, ty.ty, metadata))858 }859860 fn layout(&self, ty: Ty<'db>) -> Result<'db, Arc<Layout>> {861 if let Some(x) = self.layout_cache.borrow().get(&ty) {862 return Ok(x.clone());863 }864 let r = self865 .db866 .layout_of_ty(ty.store(), self.param_env.store())867 .map_err(|e| MirEvalError::LayoutError(e, ty.store()))?;868 self.layout_cache.borrow_mut().insert(ty, r.clone());869 Ok(r)870 }871872 fn layout_adt(&self, adt: AdtId, subst: GenericArgs<'db>) -> Result<'db, Arc<Layout>> {873 self.layout(Ty::new_adt(self.interner(), adt, subst))874 }875876 fn place_ty<'b>(&'b self, p: &Place, locals: &'b Locals<'a>) -> Result<'db, Ty<'db>> {877 Ok(self.place_addr_and_ty_and_metadata(p, locals)?.1)878 }879880 fn operand_ty(&self, o: &Operand, locals: &Locals<'a>) -> Result<'db, Ty<'db>> {881 Ok(match &o.kind {882 OperandKind::Copy(p) | OperandKind::Move(p) => self.place_ty(p, locals)?,883 OperandKind::Constant { konst: _, ty } => ty.as_ref(),884 OperandKind::Allocation { allocation } => allocation.as_ref().ty,885 &OperandKind::Static(s) => {886 let ty = InferenceResult::of(self.db, DefWithBodyId::from(s))887 .expr_ty(Body::of(self.db, s.into()).root_expr());888 Ty::new_ref(889 self.interner(),890 Region::new_static(self.interner()),891 ty,892 Mutability::Not,893 )894 }895 })896 }897898 fn operand_ty_and_eval(899 &mut self,900 o: &Operand,901 locals: &mut Locals<'a>,902 ) -> Result<'db, IntervalAndTy<'db>> {903 Ok(IntervalAndTy {904 interval: self.eval_operand(o, locals)?,905 ty: self.operand_ty(o, locals)?,906 })907 }908909 fn interpret_mir(910 &mut self,911 body: &'a MirBody,912 args: impl Iterator<Item = IntervalOrOwned>,913 ) -> Result<'db, Interval> {914 if let Some(it) = self.stack_depth_limit.checked_sub(1) {915 self.stack_depth_limit = it;916 } else {917 return Err(MirEvalError::StackOverflow);918 }919 let mut current_block_idx = body.start_block;920 let (mut locals, prev_stack_ptr) = self.create_locals_for_body(body, None)?;921 self.fill_locals_for_body(body, &mut locals, args)?;922 let prev_code_stack = mem::take(&mut self.code_stack);923 let span = (MirSpan::Unknown, body.owner);924 self.code_stack.push(StackFrame { locals, destination: None, prev_stack_ptr, span });925 'stack: loop {926 let Some(mut my_stack_frame) = self.code_stack.pop() else {927 not_supported!("missing stack frame");928 };929 let e = (|| {930 let locals = &mut my_stack_frame.locals;931 let body = locals.body.clone();932 loop {933 let current_block = &body.basic_blocks[current_block_idx];934 if let Some(it) = self.execution_limit.checked_sub(1) {935 self.execution_limit = it;936 } else {937 return Err(MirEvalError::ExecutionLimitExceeded);938 }939 for statement in ¤t_block.statements {940 match &statement.kind {941 StatementKind::Assign(l, r) => {942 let addr = self.place_addr(l, locals)?;943 let result = self.eval_rvalue(r, locals)?;944 self.copy_from_interval_or_owned(addr, result)?;945 locals.drop_flags.add_place(l.as_ref());946 }947 StatementKind::Deinit(_) => not_supported!("de-init statement"),948 StatementKind::StorageLive(_)949 | StatementKind::FakeRead(_)950 | StatementKind::StorageDead(_)951 | StatementKind::Nop => (),952 }953 }954 let Some(terminator) = current_block.terminator.as_ref() else {955 not_supported!("block without terminator");956 };957 match &terminator.kind {958 TerminatorKind::Goto { target } => {959 current_block_idx = *target;960 }961 TerminatorKind::Call {962 func,963 args,964 destination,965 target,966 cleanup: _,967 from_hir_call: _,968 } => {969 let destination_interval = self.place_interval(destination, locals)?;970 let fn_ty = self.operand_ty(func, locals)?;971 let args = args972 .iter()973 .map(|it| self.operand_ty_and_eval(it, locals))974 .collect::<Result<'db, Vec<_>>>()?;975 let stack_frame = match fn_ty.kind() {976 TyKind::FnPtr(..) => {977 let bytes = self.eval_operand(func, locals)?;978 self.exec_fn_pointer(979 bytes,980 destination_interval,981 &args,982 locals,983 *target,984 terminator.span,985 )?986 }987 TyKind::FnDef(def, generic_args) => self.exec_fn_def(988 def.0,989 generic_args,990 destination_interval,991 &args,992 locals,993 *target,994 terminator.span,995 )?,996 it => not_supported!("unknown function type {it:?}"),997 };998 locals.drop_flags.add_place(destination.as_ref());999 if let Some(stack_frame) = stack_frame {1000 self.code_stack.push(my_stack_frame);1001 current_block_idx = stack_frame.locals.body.start_block;1002 self.code_stack.push(stack_frame);1003 return Ok(None);1004 } else {1005 current_block_idx =1006 target.ok_or(MirEvalError::UndefinedBehavior(1007 "Diverging function returned".to_owned(),1008 ))?;1009 }1010 }1011 TerminatorKind::SwitchInt { discr, targets } => {1012 let val = u128::from_le_bytes(pad16(1013 self.eval_operand(discr, locals)?.get(self)?,1014 false,1015 ));1016 current_block_idx = targets.target_for_value(val);1017 }1018 TerminatorKind::Return => {1019 break;1020 }1021 TerminatorKind::Unreachable => {1022 return Err(MirEvalError::UndefinedBehavior(1023 "unreachable executed".to_owned(),1024 ));1025 }1026 TerminatorKind::Drop { place, target, unwind: _ } => {1027 self.drop_place(place, locals, terminator.span)?;1028 current_block_idx = *target;1029 }1030 _ => not_supported!("unknown terminator"),1031 }1032 }1033 Ok(Some(my_stack_frame))1034 })();1035 let my_stack_frame = match e {1036 Ok(None) => continue 'stack,1037 Ok(Some(x)) => x,1038 Err(e) => {1039 let my_code_stack = mem::replace(&mut self.code_stack, prev_code_stack);1040 let mut error_stack = vec![];1041 for frame in my_code_stack.into_iter().rev() {1042 if let Some(f) = frame.locals.body.owner.as_function() {1043 error_stack.push((Either::Left(f), frame.span.0, frame.span.1));1044 }1045 }1046 return Err(MirEvalError::InFunction(Box::new(e), error_stack));1047 }1048 };1049 let return_interval = my_stack_frame.locals.ptr[return_slot()];1050 self.unused_locals_store1051 .borrow_mut()1052 .entry(my_stack_frame.locals.body.owner)1053 .or_default()1054 .push(my_stack_frame.locals);1055 match my_stack_frame.destination {1056 None => {1057 self.code_stack = prev_code_stack;1058 self.stack_depth_limit += 1;1059 return Ok(return_interval);1060 }1061 Some(bb) => {1062 // We don't support const promotion, so we can't truncate the stack yet.1063 let _ = my_stack_frame.prev_stack_ptr;1064 // self.stack.truncate(my_stack_frame.prev_stack_ptr);1065 current_block_idx = bb;1066 }1067 }1068 }1069 }10701071 fn fill_locals_for_body(1072 &mut self,1073 body: &MirBody,1074 locals: &mut Locals<'a>,1075 args: impl Iterator<Item = IntervalOrOwned>,1076 ) -> Result<'db, ()> {1077 let mut remain_args = body.param_locals.len();1078 for ((l, interval), value) in locals.ptr.iter().skip(1).zip(args) {1079 locals.drop_flags.add_place(l.into());1080 match value {1081 IntervalOrOwned::Owned(value) => interval.write_from_bytes(self, &value)?,1082 IntervalOrOwned::Borrowed(value) => interval.write_from_interval(self, value)?,1083 }1084 if remain_args == 0 {1085 return Err(MirEvalError::InternalError("too many arguments".into()));1086 }1087 remain_args -= 1;1088 }1089 if remain_args > 0 {1090 return Err(MirEvalError::InternalError("too few arguments".into()));1091 }1092 Ok(())1093 }10941095 fn create_locals_for_body(1096 &mut self,1097 body: &'a MirBody,1098 destination: Option<Interval>,1099 ) -> Result<'db, (Locals<'a>, usize)> {1100 let mut locals =1101 match self.unused_locals_store.borrow_mut().entry(body.owner).or_default().pop() {1102 None => Locals { ptr: ArenaMap::new(), body, drop_flags: DropFlags::default() },1103 Some(mut l) => {1104 l.drop_flags.clear();1105 l.body = body;1106 l1107 }1108 };1109 let stack_size = {1110 let mut stack_ptr = self.stack.len();1111 for (id, it) in body.locals.iter() {1112 if id == return_slot()1113 && let Some(destination) = destination1114 {1115 locals.ptr.insert(id, destination);1116 continue;1117 }1118 let (size, align) = self.size_align_of_sized(1119 it.ty.as_ref(),1120 &locals,1121 "no unsized local in extending stack",1122 )?;1123 while !stack_ptr.is_multiple_of(align) {1124 stack_ptr += 1;1125 }1126 let my_ptr = stack_ptr;1127 stack_ptr += size;1128 locals.ptr.insert(id, Interval { addr: Stack(my_ptr), size });1129 }1130 stack_ptr - self.stack.len()1131 };1132 let prev_stack_pointer = self.stack.len();1133 if stack_size > self.memory_limit {1134 return Err(MirEvalError::Panic(format!(1135 "Stack overflow. Tried to grow stack to {stack_size} bytes"1136 )));1137 }1138 self.stack.extend(std::iter::repeat_n(0, stack_size));1139 Ok((locals, prev_stack_pointer))1140 }11411142 fn eval_rvalue(&mut self, r: &Rvalue, locals: &mut Locals<'a>) -> Result<'db, IntervalOrOwned> {1143 use IntervalOrOwned::*;1144 Ok(match r {1145 Rvalue::Use(it) => Borrowed(self.eval_operand(it, locals)?),1146 Rvalue::Ref(_, p) => {1147 let (addr, _, metadata) = self.place_addr_and_ty_and_metadata(p, locals)?;1148 let mut r = addr.to_bytes().to_vec();1149 if let Some(metadata) = metadata {1150 r.extend(metadata.get(self)?);1151 }1152 Owned(r)1153 }1154 Rvalue::Len(p) => {1155 let (_, _, metadata) = self.place_addr_and_ty_and_metadata(p, locals)?;1156 match metadata {1157 Some(m) => m,1158 None => {1159 return Err(MirEvalError::InternalError(1160 "type without metadata is used for Rvalue::Len".into(),1161 ));1162 }1163 }1164 }1165 Rvalue::UnaryOp(op, val) => {1166 let mut c = self.eval_operand(val, locals)?.get(self)?;1167 let mut ty = self.operand_ty(val, locals)?;1168 while let TyKind::Ref(_, z, _) = ty.kind() {1169 ty = z;1170 let size = self.size_of_sized(ty, locals, "operand of unary op")?;1171 c = self.read_memory(Address::from_bytes(c)?, size)?;1172 }1173 if let TyKind::Float(f) = ty.kind() {1174 match f {1175 rustc_type_ir::FloatTy::F16 => {1176 let c = -from_bytes!(f16, u16, c);1177 Owned(u16::try_from(c.to_bits()).unwrap().to_le_bytes().into())1178 }1179 rustc_type_ir::FloatTy::F32 => {1180 let c = -from_bytes!(f32, c);1181 Owned(c.to_le_bytes().into())1182 }1183 rustc_type_ir::FloatTy::F64 => {1184 let c = -from_bytes!(f64, c);1185 Owned(c.to_le_bytes().into())1186 }1187 rustc_type_ir::FloatTy::F128 => {1188 let c = -from_bytes!(f128, u128, c);1189 Owned(c.to_bits().to_le_bytes().into())1190 }1191 }1192 } else {1193 let mut c = c.to_vec();1194 if matches!(ty.kind(), TyKind::Bool) {1195 c[0] = 1 - c[0];1196 } else {1197 match op {1198 UnOp::Not => c.iter_mut().for_each(|it| *it = !*it),1199 UnOp::Neg => {1200 c.iter_mut().for_each(|it| *it = !*it);1201 for k in c.iter_mut() {1202 let o;1203 (*k, o) = k.overflowing_add(1);1204 if !o {1205 break;1206 }1207 }1208 }1209 }1210 }1211 Owned(c)1212 }1213 }1214 Rvalue::CheckedBinaryOp(op, lhs, rhs) => 'binary_op: {1215 let lc = self.eval_operand(lhs, locals)?;1216 let rc = self.eval_operand(rhs, locals)?;1217 let mut lc = lc.get(self)?;1218 let mut rc = rc.get(self)?;1219 let mut ty = self.operand_ty(lhs, locals)?;1220 while let TyKind::Ref(_, z, _) = ty.kind() {1221 ty = z;1222 let size = if ty.is_str() {1223 if *op != BinOp::Eq {1224 never!("Only eq is builtin for `str`");1225 }1226 let ls = from_bytes!(usize, &lc[self.ptr_size()..self.ptr_size() * 2]);1227 let rs = from_bytes!(usize, &rc[self.ptr_size()..self.ptr_size() * 2]);1228 if ls != rs {1229 break 'binary_op Owned(vec![0]);1230 }1231 lc = &lc[..self.ptr_size()];1232 rc = &rc[..self.ptr_size()];1233 lc = self.read_memory(Address::from_bytes(lc)?, ls)?;1234 rc = self.read_memory(Address::from_bytes(rc)?, ls)?;1235 break 'binary_op Owned(vec![u8::from(lc == rc)]);1236 } else {1237 self.size_of_sized(ty, locals, "operand of binary op")?1238 };1239 lc = self.read_memory(Address::from_bytes(lc)?, size)?;1240 rc = self.read_memory(Address::from_bytes(rc)?, size)?;1241 }1242 if let TyKind::Float(f) = ty.kind() {1243 match f {1244 rustc_type_ir::FloatTy::F16 => {1245 let l = from_bytes!(f16, u16, lc);1246 let r = from_bytes!(f16, u16, rc);1247 match op {1248 BinOp::Ge1249 | BinOp::Gt1250 | BinOp::Le1251 | BinOp::Lt1252 | BinOp::Eq1253 | BinOp::Ne => {1254 let r = op.run_compare(l, r) as u8;1255 Owned(vec![r])1256 }1257 BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div => {1258 let r = match op {1259 BinOp::Add => l + r,1260 BinOp::Sub => l - r,1261 BinOp::Mul => l * r,1262 BinOp::Div => l / r,1263 _ => unreachable!(),1264 };1265 Owned(1266 u16::try_from(r.value.to_bits())1267 .unwrap()1268 .to_le_bytes()1269 .into(),1270 )1271 }1272 it => not_supported!(1273 "invalid binop {it:?} on floating point operators"1274 ),1275 }1276 }1277 rustc_type_ir::FloatTy::F32 => {1278 let l = from_bytes!(f32, lc);1279 let r = from_bytes!(f32, rc);1280 match op {1281 BinOp::Ge1282 | BinOp::Gt1283 | BinOp::Le1284 | BinOp::Lt1285 | BinOp::Eq1286 | BinOp::Ne => {1287 let r = op.run_compare(l, r) as u8;1288 Owned(vec![r])1289 }1290 BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div => {1291 let r = match op {1292 BinOp::Add => l + r,1293 BinOp::Sub => l - r,1294 BinOp::Mul => l * r,1295 BinOp::Div => l / r,1296 _ => unreachable!(),1297 };1298 Owned(r.to_le_bytes().into())1299 }1300 it => not_supported!(1301 "invalid binop {it:?} on floating point operators"1302 ),1303 }1304 }1305 rustc_type_ir::FloatTy::F64 => {1306 let l = from_bytes!(f64, lc);1307 let r = from_bytes!(f64, rc);1308 match op {1309 BinOp::Ge1310 | BinOp::Gt1311 | BinOp::Le1312 | BinOp::Lt1313 | BinOp::Eq1314 | BinOp::Ne => {1315 let r = op.run_compare(l, r) as u8;1316 Owned(vec![r])1317 }1318 BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div => {1319 let r = match op {1320 BinOp::Add => l + r,1321 BinOp::Sub => l - r,1322 BinOp::Mul => l * r,1323 BinOp::Div => l / r,1324 _ => unreachable!(),1325 };1326 Owned(r.to_le_bytes().into())1327 }1328 it => not_supported!(1329 "invalid binop {it:?} on floating point operators"1330 ),1331 }1332 }1333 rustc_type_ir::FloatTy::F128 => {1334 let l = from_bytes!(f128, u128, lc);1335 let r = from_bytes!(f128, u128, rc);1336 match op {1337 BinOp::Ge1338 | BinOp::Gt1339 | BinOp::Le1340 | BinOp::Lt1341 | BinOp::Eq1342 | BinOp::Ne => {1343 let r = op.run_compare(l, r) as u8;1344 Owned(vec![r])1345 }1346 BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div => {1347 let r = match op {1348 BinOp::Add => l + r,1349 BinOp::Sub => l - r,1350 BinOp::Mul => l * r,1351 BinOp::Div => l / r,1352 _ => unreachable!(),1353 };1354 Owned(r.value.to_bits().to_le_bytes().into())1355 }1356 it => not_supported!(1357 "invalid binop {it:?} on floating point operators"1358 ),1359 }1360 }1361 }1362 } else {1363 let is_signed = matches!(ty.kind(), TyKind::Int(_));1364 let l128 = IntValue::from_bytes(lc, is_signed);1365 let r128 = IntValue::from_bytes(rc, is_signed);1366 match op {1367 BinOp::Ge | BinOp::Gt | BinOp::Le | BinOp::Lt | BinOp::Eq | BinOp::Ne => {1368 let r = op.run_compare(l128, r128) as u8;1369 Owned(vec![r])1370 }1371 BinOp::BitAnd1372 | BinOp::BitOr1373 | BinOp::BitXor1374 | BinOp::Add1375 | BinOp::Mul1376 | BinOp::Div1377 | BinOp::Rem1378 | BinOp::Sub => {1379 let r = match op {1380 BinOp::Add => l128.checked_add(r128).ok_or_else(|| {1381 MirEvalError::Panic(format!("Overflow in {op:?}"))1382 })?,1383 BinOp::Mul => l128.checked_mul(r128).ok_or_else(|| {1384 MirEvalError::Panic(format!("Overflow in {op:?}"))1385 })?,1386 BinOp::Div => l128.checked_div(r128).ok_or_else(|| {1387 MirEvalError::Panic(format!("Overflow in {op:?}"))1388 })?,1389 BinOp::Rem => l128.checked_rem(r128).ok_or_else(|| {1390 MirEvalError::Panic(format!("Overflow in {op:?}"))1391 })?,1392 BinOp::Sub => l128.checked_sub(r128).ok_or_else(|| {1393 MirEvalError::Panic(format!("Overflow in {op:?}"))1394 })?,1395 BinOp::BitAnd => l128 & r128,1396 BinOp::BitOr => l128 | r128,1397 BinOp::BitXor => l128 ^ r128,1398 _ => unreachable!(),1399 };1400 Owned(r.to_bytes())1401 }1402 BinOp::Shl | BinOp::Shr => {1403 let r = 'b: {1404 if let Some(shift_amount) = r128.as_u32() {1405 let r = match op {1406 BinOp::Shl => l128.checked_shl(shift_amount),1407 BinOp::Shr => l128.checked_shr(shift_amount),1408 _ => unreachable!(),1409 };1410 if shift_amount as usize >= lc.len() * 8 {1411 return Err(MirEvalError::Panic(format!(1412 "Overflow in {op:?}"1413 )));1414 }1415 if let Some(r) = r {1416 break 'b r;1417 }1418 };1419 return Err(MirEvalError::Panic(format!("Overflow in {op:?}")));1420 };1421 Owned(r.to_bytes())1422 }1423 BinOp::Offset => not_supported!("offset binop"),1424 }1425 }1426 }1427 Rvalue::Discriminant(p) => {1428 let ty = self.place_ty(p, locals)?;1429 let bytes = self.eval_place(p, locals)?.get(self)?;1430 let result = self.compute_discriminant(ty, bytes)?;1431 Owned(result.to_le_bytes().to_vec())1432 }1433 Rvalue::Repeat(it, len) => {1434 let len = match try_const_usize(self.db, len.as_ref()) {1435 Some(it) => it as usize,1436 None => not_supported!("non evaluatable array len in repeat Rvalue"),1437 };1438 let val = self.eval_operand(it, locals)?.get(self)?;1439 let size = len * val.len();1440 Owned(val.iter().copied().cycle().take(size).collect())1441 }1442 Rvalue::ShallowInitBox(_, _) => not_supported!("shallow init box"),1443 Rvalue::ShallowInitBoxWithAlloc(ty) => {1444 let Some((size, align)) = self.size_align_of(ty.as_ref(), locals)? else {1445 not_supported!("unsized box initialization");1446 };1447 let addr = self.heap_allocate(size, align)?;1448 Owned(addr.to_bytes().to_vec())1449 }1450 Rvalue::CopyForDeref(_) => not_supported!("copy for deref"),1451 Rvalue::Aggregate(kind, values) => {1452 let values = values1453 .iter()1454 .map(|it| self.eval_operand(it, locals))1455 .collect::<Result<'db, Vec<_>>>()?;1456 match kind {1457 AggregateKind::Array(_) => {1458 let mut r = vec![];1459 for it in values {1460 let value = it.get(self)?;1461 r.extend(value);1462 }1463 Owned(r)1464 }1465 AggregateKind::Tuple(ty) => {1466 let layout = self.layout(ty.as_ref())?;1467 Owned(self.construct_with_layout(1468 layout.size.bytes_usize(),1469 &layout,1470 None,1471 values.iter().map(|&it| it.into()),1472 )?)1473 }1474 AggregateKind::Union(it, f) => {1475 let layout =1476 self.layout_adt((*it).into(), GenericArgs::empty(self.interner()))?;1477 let offset = layout1478 .fields1479 .offset(u32::from(f.local_id.into_raw()) as usize)1480 .bytes_usize();1481 let op = values[0].get(self)?;1482 let mut result = vec![0; layout.size.bytes_usize()];1483 result[offset..offset + op.len()].copy_from_slice(op);1484 Owned(result)1485 }1486 AggregateKind::Adt(it, subst) => {1487 let (size, variant_layout, tag) =1488 self.layout_of_variant(*it, subst.as_ref(), locals)?;1489 Owned(self.construct_with_layout(1490 size,1491 &variant_layout,1492 tag,1493 values.iter().map(|&it| it.into()),1494 )?)1495 }1496 AggregateKind::Closure(ty) => {1497 let layout = self.layout(ty.as_ref())?;1498 Owned(self.construct_with_layout(1499 layout.size.bytes_usize(),1500 &layout,1501 None,1502 values.iter().map(|&it| it.into()),1503 )?)1504 }1505 }1506 }1507 Rvalue::Cast(kind, operand, target_ty) => match kind {1508 CastKind::PointerCoercion(cast) => match cast {1509 PointerCast::ReifyFnPointer | PointerCast::ClosureFnPointer(_) => {1510 let current_ty = self.operand_ty(operand, locals)?;1511 if let TyKind::FnDef(_, _) | TyKind::Closure(_, _) = current_ty.kind() {1512 let id = self.vtable_map.id(current_ty);1513 let ptr_size = self.ptr_size();1514 Owned(id.to_le_bytes()[0..ptr_size].to_vec())1515 } else {1516 not_supported!(1517 "creating a fn pointer from a non FnDef or Closure type"1518 );1519 }1520 }1521 PointerCast::Unsize => {1522 let current_ty = self.operand_ty(operand, locals)?;1523 let addr = self.eval_operand(operand, locals)?;1524 self.coerce_unsized(addr, current_ty, target_ty.as_ref())?1525 }1526 PointerCast::MutToConstPointer | PointerCast::UnsafeFnPointer => {1527 // This is no-op1528 Borrowed(self.eval_operand(operand, locals)?)1529 }1530 PointerCast::ArrayToPointer => {1531 // We should remove the metadata part if the current type is slice1532 Borrowed(self.eval_operand(operand, locals)?.slice(0..self.ptr_size()))1533 }1534 },1535 CastKind::DynStar => not_supported!("dyn star cast"),1536 CastKind::IntToInt1537 | CastKind::PtrToPtr1538 | CastKind::PointerExposeAddress1539 | CastKind::PointerFromExposedAddress => {1540 let current_ty = self.operand_ty(operand, locals)?;1541 let is_signed = matches!(current_ty.kind(), TyKind::Int(_));1542 let current = pad16(self.eval_operand(operand, locals)?.get(self)?, is_signed);1543 let dest_size = self.size_of_sized(1544 target_ty.as_ref(),1545 locals,1546 "destination of int to int cast",1547 )?;1548 Owned(current[0..dest_size].to_vec())1549 }1550 CastKind::FloatToInt => {1551 let ty = self.operand_ty(operand, locals)?;1552 let TyKind::Float(ty) = ty.kind() else {1553 not_supported!("invalid float to int cast");1554 };1555 let value = self.eval_operand(operand, locals)?.get(self)?;1556 let value = match ty {1557 rustc_type_ir::FloatTy::F32 => {1558 let value = value.try_into().unwrap();1559 f32::from_le_bytes(value) as f641560 }1561 rustc_type_ir::FloatTy::F64 => {1562 let value = value.try_into().unwrap();1563 f64::from_le_bytes(value)1564 }1565 rustc_type_ir::FloatTy::F16 | rustc_type_ir::FloatTy::F128 => {1566 not_supported!("unstable floating point type f16 and f128");1567 }1568 };1569 let is_signed = matches!(target_ty.as_ref().kind(), TyKind::Int(_));1570 let dest_size = self.size_of_sized(1571 target_ty.as_ref(),1572 locals,1573 "destination of float to int cast",1574 )?;1575 let dest_bits = dest_size * 8;1576 let (max, min) = if dest_bits == 128 {1577 (i128::MAX, i128::MIN)1578 } else if is_signed {1579 let max = 1i128 << (dest_bits - 1);1580 (max - 1, -max)1581 } else {1582 ((1i128 << dest_bits) - 1, 0)1583 };1584 let value = (value as i128).min(max).max(min);1585 let result = value.to_le_bytes();1586 Owned(result[0..dest_size].to_vec())1587 }1588 CastKind::FloatToFloat => {1589 let ty = self.operand_ty(operand, locals)?;1590 let TyKind::Float(ty) = ty.kind() else {1591 not_supported!("invalid float to int cast");1592 };1593 let value = self.eval_operand(operand, locals)?.get(self)?;1594 let value = match ty {1595 rustc_type_ir::FloatTy::F32 => {1596 let value = value.try_into().unwrap();1597 f32::from_le_bytes(value) as f641598 }1599 rustc_type_ir::FloatTy::F64 => {1600 let value = value.try_into().unwrap();1601 f64::from_le_bytes(value)1602 }1603 rustc_type_ir::FloatTy::F16 | rustc_type_ir::FloatTy::F128 => {1604 not_supported!("unstable floating point type f16 and f128");1605 }1606 };1607 let TyKind::Float(target_ty) = target_ty.as_ref().kind() else {1608 not_supported!("invalid float to float cast");1609 };1610 match target_ty {1611 rustc_type_ir::FloatTy::F32 => Owned((value as f32).to_le_bytes().to_vec()),1612 rustc_type_ir::FloatTy::F64 => Owned(value.to_le_bytes().to_vec()),1613 rustc_type_ir::FloatTy::F16 | rustc_type_ir::FloatTy::F128 => {1614 not_supported!("unstable floating point type f16 and f128");1615 }1616 }1617 }1618 CastKind::IntToFloat => {1619 let current_ty = self.operand_ty(operand, locals)?;1620 let is_signed = matches!(current_ty.kind(), TyKind::Int(_));1621 let value = pad16(self.eval_operand(operand, locals)?.get(self)?, is_signed);1622 let value = i128::from_le_bytes(value);1623 let TyKind::Float(target_ty) = target_ty.as_ref().kind() else {1624 not_supported!("invalid int to float cast");1625 };1626 match target_ty {1627 rustc_type_ir::FloatTy::F32 => Owned((value as f32).to_le_bytes().to_vec()),1628 rustc_type_ir::FloatTy::F64 => Owned((value as f64).to_le_bytes().to_vec()),1629 rustc_type_ir::FloatTy::F16 | rustc_type_ir::FloatTy::F128 => {1630 not_supported!("unstable floating point type f16 and f128");1631 }1632 }1633 }1634 CastKind::FnPtrToPtr => not_supported!("fn ptr to ptr cast"),1635 },1636 Rvalue::ThreadLocalRef(n)1637 | Rvalue::AddressOf(n)1638 | Rvalue::BinaryOp(n)1639 | Rvalue::NullaryOp(n) => match *n {},1640 })1641 }16421643 fn compute_discriminant(&self, ty: Ty<'db>, bytes: &[u8]) -> Result<'db, i128> {1644 let layout = self.layout(ty)?;1645 let TyKind::Adt(adt_def, _) = ty.kind() else {1646 return Ok(0);1647 };1648 let AdtId::EnumId(e) = adt_def.def_id() else {1649 return Ok(0);1650 };1651 match &layout.variants {1652 Variants::Empty => unreachable!(),1653 Variants::Single { index } => {1654 let r =1655 self.const_eval_discriminant(e.enum_variants(self.db).variants[index.0].0)?;1656 Ok(r)1657 }1658 Variants::Multiple { tag, tag_encoding, variants, .. } => {1659 let size = tag.size(self.target_data_layout).bytes_usize();1660 let offset = layout.fields.offset(0).bytes_usize(); // The only field on enum variants is the tag field1661 let is_signed = tag.is_signed();1662 match tag_encoding {1663 TagEncoding::Direct => {1664 let tag = &bytes[offset..offset + size];1665 Ok(i128::from_le_bytes(pad16(tag, is_signed)))1666 }1667 TagEncoding::Niche { untagged_variant, niche_start, .. } => {1668 let tag = &bytes[offset..offset + size];1669 let candidate_tag = i128::from_le_bytes(pad16(tag, is_signed))1670 .wrapping_sub(*niche_start as i128)1671 as usize;1672 let idx = variants1673 .iter_enumerated()1674 .map(|(it, _)| it)1675 .filter(|it| it != untagged_variant)1676 .nth(candidate_tag)1677 .unwrap_or(*untagged_variant)1678 .0;1679 let result =1680 self.const_eval_discriminant(e.enum_variants(self.db).variants[idx].0)?;1681 Ok(result)1682 }1683 }1684 }1685 }1686 }16871688 fn coerce_unsized_look_through_fields<T>(1689 &self,1690 ty: Ty<'db>,1691 goal: impl Fn(TyKind<'db>) -> Option<T>,1692 ) -> Result<'db, T> {1693 let kind = ty.kind();1694 if let Some(it) = goal(kind) {1695 return Ok(it);1696 }1697 match kind {1698 TyKind::Adt(adt_ef, subst) if let AdtId::StructId(struct_id) = adt_ef.def_id() => {1699 let field_types = self.db.field_types(struct_id.into());1700 if let Some(ty) = field_types1701 .iter()1702 .last()1703 .map(|it| it.1.ty().instantiate(self.interner(), subst))1704 {1705 return self.coerce_unsized_look_through_fields(ty.skip_norm_wip(), goal);1706 }1707 }1708 TyKind::Pat(ty, _) => return self.coerce_unsized_look_through_fields(ty, goal),1709 _ => (),1710 }1711 Err(MirEvalError::CoerceUnsizedError(ty.store()))1712 }17131714 fn coerce_unsized(1715 &mut self,1716 addr: Interval,1717 current_ty: Ty<'db>,1718 target_ty: Ty<'db>,1719 ) -> Result<'db, IntervalOrOwned> {1720 fn for_ptr<'db>(it: TyKind<'db>) -> Option<Ty<'db>> {1721 match it {1722 TyKind::RawPtr(ty, _) | TyKind::Ref(_, ty, _) => Some(ty),1723 _ => None,1724 }1725 }1726 let target_ty = self.coerce_unsized_look_through_fields(target_ty, for_ptr)?;1727 let current_ty = self.coerce_unsized_look_through_fields(current_ty, for_ptr)?;17281729 self.unsizing_ptr_from_addr(target_ty, current_ty, addr)1730 }17311732 /// Adds metadata to the address and create the fat pointer result of the unsizing operation.1733 fn unsizing_ptr_from_addr(1734 &mut self,1735 target_ty: Ty<'db>,1736 current_ty: Ty<'db>,1737 addr: Interval,1738 ) -> Result<'db, IntervalOrOwned> {1739 use IntervalOrOwned::*;1740 Ok(match &target_ty.kind() {1741 TyKind::Slice(_) => match ¤t_ty.kind() {1742 TyKind::Array(_, size) => {1743 let len = match try_const_usize(self.db, *size) {1744 None => {1745 not_supported!("unevaluatble len of array in coerce unsized")1746 }1747 Some(it) => it as usize,1748 };1749 let mut r = Vec::with_capacity(16);1750 let addr = addr.get(self)?;1751 r.extend(addr.iter().copied());1752 r.extend(len.to_le_bytes());1753 Owned(r)1754 }1755 t => {1756 not_supported!("slice unsizing from non array type {t:?}")1757 }1758 },1759 TyKind::Dynamic(..) => {1760 let vtable = self.vtable_map.id(current_ty);1761 let mut r = Vec::with_capacity(16);1762 let addr = addr.get(self)?;1763 r.extend(addr.iter().copied());1764 r.extend(vtable.to_le_bytes());1765 Owned(r)1766 }1767 TyKind::Adt(adt_def, target_subst) => match ¤t_ty.kind() {1768 TyKind::Adt(current_adt_def, current_subst) => {1769 let id = adt_def.def_id();1770 let current_id = current_adt_def.def_id();1771 if id != current_id {1772 not_supported!("unsizing struct with different type");1773 }1774 let id = match id {1775 AdtId::StructId(s) => s,1776 AdtId::UnionId(_) => not_supported!("unsizing unions"),1777 AdtId::EnumId(_) => not_supported!("unsizing enums"),1778 };1779 let Some((last_field, _)) = id.fields(self.db).fields().iter().next_back()1780 else {1781 not_supported!("unsizing struct without field");1782 };1783 let target_last_field = self.db.field_types(id.into())[last_field]1784 .ty()1785 .instantiate(self.interner(), target_subst)1786 .skip_norm_wip();1787 let current_last_field = self.db.field_types(id.into())[last_field]1788 .ty()1789 .instantiate(self.interner(), current_subst)1790 .skip_norm_wip();1791 return self.unsizing_ptr_from_addr(1792 target_last_field,1793 current_last_field,1794 addr,1795 );1796 }1797 _ => not_supported!("unsizing struct with non adt type"),1798 },1799 _ => not_supported!("unknown unsized cast"),1800 })1801 }18021803 fn layout_of_variant(1804 &mut self,1805 it: VariantId,1806 subst: GenericArgs<'db>,1807 locals: &Locals<'a>,1808 ) -> Result<'db, (usize, Arc<Layout>, Option<(usize, usize, i128)>)> {1809 let adt = it.adt_id(self.db);1810 if let Some(f) = locals.body.owner.as_variant()1811 && let VariantId::EnumVariantId(it) = it1812 && let AdtId::EnumId(e) = adt1813 && f.lookup(self.db).parent == e1814 {1815 // Computing the exact size of enums require resolving the enum discriminants. In order to prevent loops (and1816 // infinite sized type errors) we use a dummy layout1817 let i = self.const_eval_discriminant(it)?;1818 return Ok((16, self.layout(Ty::new_empty_tuple(self.interner()))?, Some((0, 16, i))));1819 }1820 let layout = self.layout_adt(adt, subst)?;1821 Ok(match &layout.variants {1822 Variants::Single { .. } | Variants::Empty => (layout.size.bytes_usize(), layout, None),1823 Variants::Multiple { variants, tag, tag_encoding, .. } => {1824 let enum_variant_id = match it {1825 VariantId::EnumVariantId(it) => it,1826 _ => not_supported!("multi variant layout for non-enums"),1827 };1828 let mut discriminant = self.const_eval_discriminant(enum_variant_id)?;1829 let rustc_enum_variant_idx = RustcEnumVariantIdx(enum_variant_id.index(self.db));1830 let variant_layout = variants[rustc_enum_variant_idx].clone();1831 let have_tag = match tag_encoding {1832 TagEncoding::Direct => true,1833 TagEncoding::Niche { untagged_variant, niche_variants: _, niche_start } => {1834 if *untagged_variant == rustc_enum_variant_idx {1835 false1836 } else {1837 discriminant = (variants1838 .iter_enumerated()1839 .filter(|(it, _)| it != untagged_variant)1840 .position(|(it, _)| it == rustc_enum_variant_idx)1841 .unwrap() as i128)1842 .wrapping_add(*niche_start as i128);1843 true1844 }1845 }1846 };1847 (1848 layout.size.bytes_usize(),1849 Arc::new(variant_layout),1850 if have_tag {1851 Some((1852 layout.fields.offset(0).bytes_usize(),1853 tag.size(self.target_data_layout).bytes_usize(),1854 discriminant,1855 ))1856 } else {1857 None1858 },1859 )1860 }1861 })1862 }18631864 fn construct_with_layout(1865 &mut self,1866 size: usize, // Not necessarily equal to variant_layout.size1867 variant_layout: &Layout,1868 tag: Option<(usize, usize, i128)>,1869 values: impl Iterator<Item = IntervalOrOwned>,1870 ) -> Result<'db, Vec<u8>> {1871 let mut result = vec![0; size];1872 if let Some((offset, size, value)) = tag {1873 match result.get_mut(offset..offset + size) {1874 Some(it) => it.copy_from_slice(&value.to_le_bytes()[0..size]),1875 None => {1876 return Err(MirEvalError::InternalError(1877 format!(1878 "encoded tag ({offset}, {size}, {value}) is out of bounds 0..{size}"1879 )1880 .into(),1881 ));1882 }1883 }1884 }1885 for (i, op) in values.enumerate() {1886 let offset = variant_layout.fields.offset(i).bytes_usize();1887 let op = op.get(self)?;1888 match result.get_mut(offset..offset + op.len()) {1889 Some(it) => it.copy_from_slice(op),1890 None => {1891 return Err(MirEvalError::InternalError(1892 format!("field offset ({offset}) is out of bounds 0..{size}").into(),1893 ));1894 }1895 }1896 }1897 Ok(result)1898 }18991900 fn eval_operand(&mut self, it: &Operand, locals: &mut Locals<'a>) -> Result<'db, Interval> {1901 Ok(match &it.kind {1902 OperandKind::Copy(p) | OperandKind::Move(p) => {1903 locals.drop_flags.remove_place(p.as_ref());1904 self.eval_place(p, locals)?1905 }1906 OperandKind::Static(st) => {1907 let addr = self.eval_static(*st, locals)?;1908 Interval::new(addr, self.ptr_size())1909 }1910 OperandKind::Constant { konst, .. } => {1911 self.allocate_const_in_heap(locals, konst.as_ref())?1912 }1913 OperandKind::Allocation { allocation } => {1914 self.allocate_allocation_in_heap(locals, allocation.as_ref())?1915 }1916 })1917 }19181919 fn allocate_valtree_in_heap(1920 &mut self,1921 ty: Ty<'db>,1922 valtree: ValTree<'db>,1923 ) -> Result<'db, Interval> {1924 match ty.kind() {1925 TyKind::Bool => {1926 let value = valtree.inner().to_leaf().try_to_bool().unwrap();1927 let addr = self.heap_allocate(1, 1)?;1928 self.write_memory(addr, &[u8::from(value)])?;1929 Ok(Interval::new(addr, 1))1930 }1931 TyKind::Char => {1932 let value = valtree.inner().to_leaf().to_u32();1933 let addr = self.heap_allocate(4, 4)?;1934 self.write_memory(addr, &value.to_le_bytes())?;1935 Ok(Interval::new(addr, 4))1936 }1937 TyKind::Int(int_ty) => {1938 let size = int_ty.bit_width().unwrap_or(self.ptr_size() as u64);1939 let value = valtree.inner().to_leaf().to_int(Size::from_bytes(size));1940 let addr = self.heap_allocate(size as usize, size as usize)?;1941 self.write_memory(addr, &value.to_le_bytes()[..size as usize])?;1942 Ok(Interval::new(addr, size as usize))1943 }1944 TyKind::Uint(uint_ty) => {1945 let size = uint_ty.bit_width().unwrap_or(self.ptr_size() as u64);1946 let value = valtree.inner().to_leaf().to_uint(Size::from_bytes(size));1947 let addr = self.heap_allocate(size as usize, size as usize)?;1948 self.write_memory(addr, &value.to_le_bytes()[..size as usize])?;1949 Ok(Interval::new(addr, size as usize))1950 }1951 TyKind::Float(float_ty) => {1952 let size = float_ty.bit_width();1953 let value = valtree.inner().to_leaf().to_uint(Size::from_bytes(size));1954 let addr = self.heap_allocate(size as usize, size as usize)?;1955 self.write_memory(addr, &value.to_le_bytes()[..size as usize])?;1956 Ok(Interval::new(addr, size as usize))1957 }1958 TyKind::RawPtr(..) => {1959 let size = self.ptr_size();1960 let value = valtree.inner().to_leaf().to_uint(Size::from_bytes(size));1961 let addr = self.heap_allocate(size, size)?;1962 self.write_memory(addr, &value.to_le_bytes()[..size])?;1963 Ok(Interval::new(addr, size))1964 }1965 TyKind::Ref(_, inner_ty, _) => match inner_ty.kind() {1966 TyKind::Str => {1967 let bytes = valtree1968 .inner()1969 .to_branch()1970 .iter()1971 .map(|konst| match konst.kind() {1972 ConstKind::Value(value) => Ok(value.value.inner().to_leaf().to_u8()),1973 _ => not_supported!("unsupported const"),1974 })1975 .collect::<Result<'_, Vec<_>>>()?;1976 let bytes_addr = self.heap_allocate(bytes.len(), 1)?;1977 self.write_memory(bytes_addr, &bytes)?;1978 let ref_addr = self.heap_allocate(self.ptr_size() * 2, self.ptr_size())?;1979 self.write_memory(ref_addr, &bytes_addr.to_bytes())?;1980 let mut len = [0; 16];1981 len[..size_of::<usize>()].copy_from_slice(&bytes.len().to_le_bytes());1982 self.write_memory(ref_addr.offset(self.ptr_size()), &len[..self.ptr_size()])?;1983 Ok(Interval::new(ref_addr, self.ptr_size() * 2))1984 }1985 TyKind::Slice(inner_ty) => {1986 let item_layout = self.layout(inner_ty)?;1987 let items = valtree1988 .inner()1989 .to_branch()1990 .iter()1991 .map(|konst| match konst.kind() {1992 ConstKind::Value(value) => {1993 self.allocate_valtree_in_heap(value.ty, value.value)1994 }1995 _ => not_supported!("unsupported const"),1996 })1997 .collect::<Result<'_, Vec<_>>>()?;1998 let items_addr = self.heap_allocate(1999 items.len() * (item_layout.size.bits() as usize),2000 item_layout.align.bits_usize(),
Findings
✓ No findings reported for this file.