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.rs137
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