Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/mir/eval/shim.rs')
| -rw-r--r-- | crates/hir-ty/src/mir/eval/shim.rs | 137 |
1 files changed, 67 insertions, 70 deletions
diff --git a/crates/hir-ty/src/mir/eval/shim.rs b/crates/hir-ty/src/mir/eval/shim.rs index 4b1adecf8c..76c8701ea2 100644 --- a/crates/hir-ty/src/mir/eval/shim.rs +++ b/crates/hir-ty/src/mir/eval/shim.rs @@ -3,39 +3,32 @@ //! use std::cmp::{self, Ordering}; -use hir_def::{CrateRootModuleId, resolver::HasResolver, signatures::FunctionSignature}; +use hir_def::{attrs::AttrFlags, signatures::FunctionSignature}; use hir_expand::name::Name; -use intern::{Symbol, sym}; +use intern::sym; use rustc_type_ir::inherent::{AdtDef, IntoKind, SliceLike, Ty as _}; use stdx::never; use crate::{ + InferenceResult, display::DisplayTarget, drop::{DropGlue, has_drop_glue}, mir::eval::{ Address, AdtId, Arc, Evaluator, FunctionId, GenericArgs, HasModule, HirDisplay, - InternedClosure, Interval, IntervalAndTy, IntervalOrOwned, ItemContainerId, LangItem, - Layout, Locals, Lookup, MirEvalError, MirSpan, Mutability, Result, Ty, TyKind, pad16, + InternedClosure, Interval, IntervalAndTy, IntervalOrOwned, ItemContainerId, Layout, Locals, + Lookup, MirEvalError, MirSpan, Mutability, Result, Ty, TyKind, from_bytes, not_supported, + pad16, }, next_solver::Region, }; mod simd; -macro_rules! from_bytes { - ($ty:tt, $value:expr) => { - ($ty::from_le_bytes(match ($value).try_into() { - Ok(it) => it, - #[allow(unreachable_patterns)] - Err(_) => return Err(MirEvalError::InternalError("mismatched size".into())), - })) - }; -} - -macro_rules! not_supported { - ($it: expr) => { - return Err(MirEvalError::NotSupported(format!($it))) - }; +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum EvalLangItem { + BeginPanic, + SliceLen, + DropInPlace, } impl<'db> Evaluator<'db> { @@ -44,7 +37,7 @@ impl<'db> Evaluator<'db> { def: FunctionId, args: &[IntervalAndTy<'db>], generic_args: GenericArgs<'db>, - locals: &Locals<'db>, + locals: &Locals, destination: Interval, span: MirSpan, ) -> Result<'db, bool> { @@ -53,7 +46,7 @@ impl<'db> Evaluator<'db> { } let function_data = self.db.function_signature(def); - let attrs = self.db.attrs(def.into()); + let attrs = AttrFlags::query(self.db, def.into()); let is_intrinsic = FunctionSignature::is_intrinsic(self.db, def); if is_intrinsic { @@ -65,7 +58,7 @@ impl<'db> Evaluator<'db> { locals, span, !function_data.has_body() - || attrs.by_key(sym::rustc_intrinsic_must_be_overridden).exists(), + || attrs.contains(AttrFlags::RUSTC_INTRINSIC_MUST_BE_OVERRIDDEN), ); } let is_extern_c = match def.lookup(self.db).container { @@ -85,18 +78,13 @@ impl<'db> Evaluator<'db> { .map(|()| true); } - let alloc_fn = - attrs.iter().filter_map(|it| it.path().as_ident()).map(|it| it.symbol()).find(|it| { - [ - &sym::rustc_allocator, - &sym::rustc_deallocator, - &sym::rustc_reallocator, - &sym::rustc_allocator_zeroed, - ] - .contains(it) - }); - if let Some(alloc_fn) = alloc_fn { - self.exec_alloc_fn(alloc_fn, args, destination)?; + if attrs.intersects( + AttrFlags::RUSTC_ALLOCATOR + | AttrFlags::RUSTC_DEALLOCATOR + | AttrFlags::RUSTC_REALLOCATOR + | AttrFlags::RUSTC_ALLOCATOR_ZEROED, + ) { + self.exec_alloc_fn(attrs, args, destination)?; return Ok(true); } if let Some(it) = self.detect_lang_function(def) { @@ -105,7 +93,7 @@ impl<'db> Evaluator<'db> { return Ok(true); } if let ItemContainerId::TraitId(t) = def.lookup(self.db).container - && self.db.lang_attr(t.into()) == Some(LangItem::Clone) + && Some(t) == self.lang_items().Clone { let [self_ty] = generic_args.as_slice() else { not_supported!("wrong generic arg count for clone"); @@ -131,12 +119,8 @@ impl<'db> Evaluator<'db> { def: FunctionId, ) -> Result<'db, Option<FunctionId>> { // `PanicFmt` is redirected to `ConstPanicFmt` - if let Some(LangItem::PanicFmt) = self.db.lang_attr(def.into()) { - let resolver = CrateRootModuleId::from(self.crate_id).resolver(self.db); - - let Some(const_panic_fmt) = - LangItem::ConstPanicFmt.resolve_function(self.db, resolver.krate()) - else { + if Some(def) == self.lang_items().PanicFmt { + let Some(const_panic_fmt) = self.lang_items().ConstPanicFmt else { not_supported!("const_panic_fmt lang item not found or not a function"); }; return Ok(Some(const_panic_fmt)); @@ -150,7 +134,7 @@ impl<'db> Evaluator<'db> { def: FunctionId, args: &[IntervalAndTy<'db>], self_ty: Ty<'db>, - locals: &Locals<'db>, + locals: &Locals, destination: Interval, span: MirSpan, ) -> Result<'db, ()> { @@ -169,7 +153,7 @@ impl<'db> Evaluator<'db> { }; let addr = Address::from_bytes(arg.get(self)?)?; let InternedClosure(closure_owner, _) = self.db.lookup_intern_closure(id.0); - let infer = self.db.infer(closure_owner); + let infer = InferenceResult::for_body(self.db, closure_owner); let (captures, _) = infer.closure_info(id.0); let layout = self.layout(self_ty)?; let db = self.db; @@ -196,7 +180,7 @@ impl<'db> Evaluator<'db> { self.exec_fn_with_args( def, args, - GenericArgs::new_from_iter(self.interner(), [self_ty.into()]), + GenericArgs::new_from_slice(&[self_ty.into()]), locals, destination, None, @@ -213,7 +197,7 @@ impl<'db> Evaluator<'db> { layout: Arc<Layout>, addr: Address, def: FunctionId, - locals: &Locals<'db>, + locals: &Locals, destination: Interval, span: MirSpan, ) -> Result<'db, ()> { @@ -245,12 +229,14 @@ impl<'db> Evaluator<'db> { fn exec_alloc_fn( &mut self, - alloc_fn: &Symbol, + alloc_fn: AttrFlags, args: &[IntervalAndTy<'db>], destination: Interval, ) -> Result<'db, ()> { match alloc_fn { - _ if *alloc_fn == sym::rustc_allocator_zeroed || *alloc_fn == sym::rustc_allocator => { + _ if alloc_fn + .intersects(AttrFlags::RUSTC_ALLOCATOR_ZEROED | AttrFlags::RUSTC_ALLOCATOR) => + { let [size, align] = args else { return Err(MirEvalError::InternalError( "rustc_allocator args are not provided".into(), @@ -261,8 +247,8 @@ impl<'db> Evaluator<'db> { let result = self.heap_allocate(size, align)?; destination.write_from_bytes(self, &result.to_bytes())?; } - _ if *alloc_fn == sym::rustc_deallocator => { /* no-op for now */ } - _ if *alloc_fn == sym::rustc_reallocator => { + _ if alloc_fn.contains(AttrFlags::RUSTC_DEALLOCATOR) => { /* no-op for now */ } + _ if alloc_fn.contains(AttrFlags::RUSTC_REALLOCATOR) => { let [ptr, old_size, align, new_size] = args else { return Err(MirEvalError::InternalError( "rustc_allocator args are not provided".into(), @@ -286,19 +272,26 @@ impl<'db> Evaluator<'db> { Ok(()) } - fn detect_lang_function(&self, def: FunctionId) -> Option<LangItem> { - use LangItem::*; - let attrs = self.db.attrs(def.into()); + fn detect_lang_function(&self, def: FunctionId) -> Option<EvalLangItem> { + use EvalLangItem::*; + let lang_items = self.lang_items(); + let attrs = AttrFlags::query(self.db, def.into()); - if attrs.by_key(sym::rustc_const_panic_str).exists() { + if attrs.contains(AttrFlags::RUSTC_CONST_PANIC_STR) { // `#[rustc_const_panic_str]` is treated like `lang = "begin_panic"` by rustc CTFE. - return Some(LangItem::BeginPanic); + return Some(BeginPanic); } - let candidate = attrs.lang_item()?; // We want to execute these functions with special logic // `PanicFmt` is not detected here as it's redirected later. - if [BeginPanic, SliceLen, DropInPlace].contains(&candidate) { + if let Some((_, candidate)) = [ + (lang_items.BeginPanic, BeginPanic), + (lang_items.SliceLen, SliceLen), + (lang_items.DropInPlace, DropInPlace), + ] + .iter() + .find(|&(candidate, _)| candidate == Some(def)) + { return Some(candidate); } @@ -307,13 +300,13 @@ impl<'db> Evaluator<'db> { fn exec_lang_item( &mut self, - it: LangItem, + it: EvalLangItem, generic_args: GenericArgs<'db>, args: &[IntervalAndTy<'db>], - locals: &Locals<'db>, + locals: &Locals, span: MirSpan, ) -> Result<'db, Vec<u8>> { - use LangItem::*; + use EvalLangItem::*; let mut args = args.iter(); match it { BeginPanic => { @@ -374,7 +367,6 @@ impl<'db> Evaluator<'db> { )?; Ok(vec![]) } - it => not_supported!("Executing lang item {it:?}"), } } @@ -383,7 +375,7 @@ impl<'db> Evaluator<'db> { id: i64, args: &[IntervalAndTy<'db>], destination: Interval, - _locals: &Locals<'db>, + _locals: &Locals, _span: MirSpan, ) -> Result<'db, ()> { match id { @@ -414,7 +406,7 @@ impl<'db> Evaluator<'db> { args: &[IntervalAndTy<'db>], _generic_args: GenericArgs<'db>, destination: Interval, - locals: &Locals<'db>, + locals: &Locals, span: MirSpan, ) -> Result<'db, ()> { match as_str { @@ -580,7 +572,7 @@ impl<'db> Evaluator<'db> { args: &[IntervalAndTy<'db>], generic_args: GenericArgs<'db>, destination: Interval, - locals: &Locals<'db>, + locals: &Locals, span: MirSpan, needs_override: bool, ) -> Result<'db, bool> { @@ -833,7 +825,7 @@ impl<'db> Evaluator<'db> { "size_of generic arg is not provided".into(), )); }; - let result = match has_drop_glue(&self.infcx, ty, self.trait_env.clone()) { + let result = match has_drop_glue(&self.infcx, ty, self.param_env.param_env) { DropGlue::HasDropGlue => true, DropGlue::None => false, DropGlue::DependOnParams => { @@ -1219,7 +1211,7 @@ impl<'db> Evaluator<'db> { let addr = tuple.interval.addr.offset(offset); args.push(IntervalAndTy::new(addr, field, self, locals)?); } - if let Some(target) = LangItem::FnOnce.resolve_trait(self.db, self.crate_id) + if let Some(target) = self.lang_items().FnOnce && let Some(def) = target .trait_items(self.db) .method_by_name(&Name::new_symbol_root(sym::call_once)) @@ -1228,7 +1220,7 @@ impl<'db> Evaluator<'db> { def, &args, // FIXME: wrong for manual impls of `FnOnce` - GenericArgs::new_from_iter(self.interner(), []), + GenericArgs::empty(self.interner()), locals, destination, None, @@ -1329,7 +1321,7 @@ impl<'db> Evaluator<'db> { { result = (l as i8).cmp(&(r as i8)); } - if let Some(e) = LangItem::Ordering.resolve_enum(self.db, self.crate_id) { + if let Some(e) = self.lang_items().Ordering { let ty = self.db.ty(e.into()).skip_binder(); let r = self.compute_discriminant(ty, &[result as i8 as u8])?; destination.write_from_bytes(self, &r.to_le_bytes()[0..destination.size])?; @@ -1362,7 +1354,7 @@ impl<'db> Evaluator<'db> { &mut self, ty: Ty<'db>, metadata: Interval, - locals: &Locals<'db>, + locals: &Locals, ) -> Result<'db, (usize, usize)> { Ok(match ty.kind() { TyKind::Str => (from_bytes!(usize, metadata.get(self)?), 1), @@ -1384,8 +1376,13 @@ impl<'db> Evaluator<'db> { _ => not_supported!("unsized enum or union"), }; let field_types = self.db.field_types(id.into()); - let last_field_ty = - field_types.iter().next_back().unwrap().1.instantiate(self.interner(), subst); + let last_field_ty = field_types + .iter() + .next_back() + .unwrap() + .1 + .get() + .instantiate(self.interner(), subst); let sized_part_size = layout.fields.offset(field_types.iter().count() - 1).bytes_usize(); let sized_part_align = layout.align.bytes() as usize; @@ -1416,7 +1413,7 @@ impl<'db> Evaluator<'db> { args: &[IntervalAndTy<'db>], generic_args: GenericArgs<'db>, destination: Interval, - locals: &Locals<'db>, + locals: &Locals, _span: MirSpan, ) -> Result<'db, ()> { // We are a single threaded runtime with no UB checking and no optimization, so |