Auto merge of #118003 - matthiaskrgr:rollup-80t3uky, r=matthiaskrgr
Rollup of 3 pull requests Successful merges: - #115476 (document ABI compatibility) - #117688 (Misc changes to StableMIR required to Kani use case.) - #117998 (On resolve error of `[rest..]`, suggest `[rest @ ..]`) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
ee5ef3aac9
21 changed files with 784 additions and 80 deletions
|
@ -603,6 +603,8 @@ struct DiagnosticMetadata<'ast> {
|
||||||
/// Only used for better errors on `let <pat>: <expr, not type>;`.
|
/// Only used for better errors on `let <pat>: <expr, not type>;`.
|
||||||
current_let_binding: Option<(Span, Option<Span>, Option<Span>)>,
|
current_let_binding: Option<(Span, Option<Span>, Option<Span>)>,
|
||||||
|
|
||||||
|
current_pat: Option<&'ast Pat>,
|
||||||
|
|
||||||
/// Used to detect possible `if let` written without `let` and to provide structured suggestion.
|
/// Used to detect possible `if let` written without `let` and to provide structured suggestion.
|
||||||
in_if_condition: Option<&'ast Expr>,
|
in_if_condition: Option<&'ast Expr>,
|
||||||
|
|
||||||
|
@ -703,6 +705,12 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
|
||||||
fn visit_expr(&mut self, expr: &'ast Expr) {
|
fn visit_expr(&mut self, expr: &'ast Expr) {
|
||||||
self.resolve_expr(expr, None);
|
self.resolve_expr(expr, None);
|
||||||
}
|
}
|
||||||
|
fn visit_pat(&mut self, p: &'ast Pat) {
|
||||||
|
let prev = self.diagnostic_metadata.current_pat;
|
||||||
|
self.diagnostic_metadata.current_pat = Some(p);
|
||||||
|
visit::walk_pat(self, p);
|
||||||
|
self.diagnostic_metadata.current_pat = prev;
|
||||||
|
}
|
||||||
fn visit_local(&mut self, local: &'ast Local) {
|
fn visit_local(&mut self, local: &'ast Local) {
|
||||||
let local_spans = match local.pat.kind {
|
let local_spans = match local.pat.kind {
|
||||||
// We check for this to avoid tuple struct fields.
|
// We check for this to avoid tuple struct fields.
|
||||||
|
|
|
@ -431,6 +431,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
||||||
code,
|
code,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
self.suggest_at_operator_in_slice_pat_with_range(&mut err, path);
|
||||||
self.suggest_swapping_misplaced_self_ty_and_trait(&mut err, source, res, base_error.span);
|
self.suggest_swapping_misplaced_self_ty_and_trait(&mut err, source, res, base_error.span);
|
||||||
|
|
||||||
if let Some((span, label)) = base_error.span_label {
|
if let Some((span, label)) = base_error.span_label {
|
||||||
|
@ -1063,6 +1064,32 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn suggest_at_operator_in_slice_pat_with_range(
|
||||||
|
&mut self,
|
||||||
|
err: &mut Diagnostic,
|
||||||
|
path: &[Segment],
|
||||||
|
) {
|
||||||
|
if let Some(pat) = self.diagnostic_metadata.current_pat
|
||||||
|
&& let ast::PatKind::Range(Some(start), None, range) = &pat.kind
|
||||||
|
&& let ExprKind::Path(None, range_path) = &start.kind
|
||||||
|
&& let [segment] = &range_path.segments[..]
|
||||||
|
&& let [s] = path
|
||||||
|
&& segment.ident == s.ident
|
||||||
|
{
|
||||||
|
// We've encountered `[first, rest..]` where the user might have meant
|
||||||
|
// `[first, rest @ ..]` (#88404).
|
||||||
|
err.span_suggestion_verbose(
|
||||||
|
segment.ident.span.between(range.span),
|
||||||
|
format!(
|
||||||
|
"if you meant to collect the rest of the slice in `{}`, use the at operator",
|
||||||
|
segment.ident,
|
||||||
|
),
|
||||||
|
" @ ",
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn suggest_swapping_misplaced_self_ty_and_trait(
|
fn suggest_swapping_misplaced_self_ty_and_trait(
|
||||||
&mut self,
|
&mut self,
|
||||||
err: &mut Diagnostic,
|
err: &mut Diagnostic,
|
||||||
|
|
|
@ -6,11 +6,23 @@
|
||||||
// Prefer importing stable_mir over internal rustc constructs to make this file more readable.
|
// Prefer importing stable_mir over internal rustc constructs to make this file more readable.
|
||||||
use crate::rustc_smir::Tables;
|
use crate::rustc_smir::Tables;
|
||||||
use rustc_middle::ty::{self as rustc_ty, Ty as InternalTy};
|
use rustc_middle::ty::{self as rustc_ty, Ty as InternalTy};
|
||||||
use stable_mir::ty::{Const, GenericArgKind, GenericArgs, Region, Ty};
|
use rustc_span::Symbol;
|
||||||
use stable_mir::DefId;
|
use stable_mir::mir::mono::{Instance, MonoItem, StaticDef};
|
||||||
|
use stable_mir::ty::{
|
||||||
|
Binder, BoundRegionKind, BoundTyKind, BoundVariableKind, ClosureKind, Const, GenericArgKind,
|
||||||
|
GenericArgs, Region, TraitRef, Ty,
|
||||||
|
};
|
||||||
|
use stable_mir::{AllocId, CrateItem, DefId};
|
||||||
|
|
||||||
use super::RustcInternal;
|
use super::RustcInternal;
|
||||||
|
|
||||||
|
impl<'tcx> RustcInternal<'tcx> for CrateItem {
|
||||||
|
type T = rustc_span::def_id::DefId;
|
||||||
|
fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
||||||
|
self.0.internal(tables)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'tcx> RustcInternal<'tcx> for DefId {
|
impl<'tcx> RustcInternal<'tcx> for DefId {
|
||||||
type T = rustc_span::def_id::DefId;
|
type T = rustc_span::def_id::DefId;
|
||||||
fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
||||||
|
@ -38,8 +50,9 @@ impl<'tcx> RustcInternal<'tcx> for GenericArgKind {
|
||||||
|
|
||||||
impl<'tcx> RustcInternal<'tcx> for Region {
|
impl<'tcx> RustcInternal<'tcx> for Region {
|
||||||
type T = rustc_ty::Region<'tcx>;
|
type T = rustc_ty::Region<'tcx>;
|
||||||
fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T {
|
fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
||||||
todo!()
|
// Cannot recover region. Use erased instead.
|
||||||
|
tables.tcx.lifetimes.re_erased
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,3 +78,118 @@ impl<'tcx> RustcInternal<'tcx> for Const {
|
||||||
tables.constants[self.id]
|
tables.constants[self.id]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'tcx> RustcInternal<'tcx> for MonoItem {
|
||||||
|
type T = rustc_middle::mir::mono::MonoItem<'tcx>;
|
||||||
|
|
||||||
|
fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
||||||
|
use rustc_middle::mir::mono as rustc_mono;
|
||||||
|
match self {
|
||||||
|
MonoItem::Fn(instance) => rustc_mono::MonoItem::Fn(instance.internal(tables)),
|
||||||
|
MonoItem::Static(def) => rustc_mono::MonoItem::Static(def.internal(tables)),
|
||||||
|
MonoItem::GlobalAsm(_) => {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> RustcInternal<'tcx> for Instance {
|
||||||
|
type T = rustc_ty::Instance<'tcx>;
|
||||||
|
|
||||||
|
fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
||||||
|
tables.instances[self.def]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> RustcInternal<'tcx> for StaticDef {
|
||||||
|
type T = rustc_span::def_id::DefId;
|
||||||
|
|
||||||
|
fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
||||||
|
self.0.internal(tables)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(rustc::usage_of_qualified_ty)]
|
||||||
|
impl<'tcx, T> RustcInternal<'tcx> for Binder<T>
|
||||||
|
where
|
||||||
|
T: RustcInternal<'tcx>,
|
||||||
|
T::T: rustc_ty::TypeVisitable<rustc_ty::TyCtxt<'tcx>>,
|
||||||
|
{
|
||||||
|
type T = rustc_ty::Binder<'tcx, T::T>;
|
||||||
|
|
||||||
|
fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
||||||
|
rustc_ty::Binder::bind_with_vars(
|
||||||
|
self.value.internal(tables),
|
||||||
|
tables.tcx.mk_bound_variable_kinds_from_iter(
|
||||||
|
self.bound_vars.iter().map(|bound| bound.internal(tables)),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> RustcInternal<'tcx> for BoundVariableKind {
|
||||||
|
type T = rustc_ty::BoundVariableKind;
|
||||||
|
|
||||||
|
fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
||||||
|
match self {
|
||||||
|
BoundVariableKind::Ty(kind) => rustc_ty::BoundVariableKind::Ty(match kind {
|
||||||
|
BoundTyKind::Anon => rustc_ty::BoundTyKind::Anon,
|
||||||
|
BoundTyKind::Param(def, symbol) => {
|
||||||
|
rustc_ty::BoundTyKind::Param(def.0.internal(tables), Symbol::intern(&symbol))
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
BoundVariableKind::Region(kind) => rustc_ty::BoundVariableKind::Region(match kind {
|
||||||
|
BoundRegionKind::BrAnon => rustc_ty::BoundRegionKind::BrAnon,
|
||||||
|
BoundRegionKind::BrNamed(def, symbol) => rustc_ty::BoundRegionKind::BrNamed(
|
||||||
|
def.0.internal(tables),
|
||||||
|
Symbol::intern(&symbol),
|
||||||
|
),
|
||||||
|
BoundRegionKind::BrEnv => rustc_ty::BoundRegionKind::BrEnv,
|
||||||
|
}),
|
||||||
|
BoundVariableKind::Const => rustc_ty::BoundVariableKind::Const,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> RustcInternal<'tcx> for TraitRef {
|
||||||
|
type T = rustc_ty::TraitRef<'tcx>;
|
||||||
|
|
||||||
|
fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
||||||
|
rustc_ty::TraitRef::new(
|
||||||
|
tables.tcx,
|
||||||
|
self.def_id.0.internal(tables),
|
||||||
|
self.args().internal(tables),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> RustcInternal<'tcx> for AllocId {
|
||||||
|
type T = rustc_middle::mir::interpret::AllocId;
|
||||||
|
fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
||||||
|
tables.alloc_ids[*self]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> RustcInternal<'tcx> for ClosureKind {
|
||||||
|
type T = rustc_ty::ClosureKind;
|
||||||
|
|
||||||
|
fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T {
|
||||||
|
match self {
|
||||||
|
ClosureKind::Fn => rustc_ty::ClosureKind::Fn,
|
||||||
|
ClosureKind::FnMut => rustc_ty::ClosureKind::FnMut,
|
||||||
|
ClosureKind::FnOnce => rustc_ty::ClosureKind::FnOnce,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx, T> RustcInternal<'tcx> for &T
|
||||||
|
where
|
||||||
|
T: RustcInternal<'tcx>,
|
||||||
|
{
|
||||||
|
type T = T::T;
|
||||||
|
|
||||||
|
fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
||||||
|
(*self).internal(tables)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ use rustc_span::def_id::{CrateNum, DefId};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use scoped_tls::scoped_thread_local;
|
use scoped_tls::scoped_thread_local;
|
||||||
use stable_mir::ty::IndexedVal;
|
use stable_mir::ty::IndexedVal;
|
||||||
|
use stable_mir::Error;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
@ -21,11 +22,11 @@ use std::ops::Index;
|
||||||
|
|
||||||
mod internal;
|
mod internal;
|
||||||
|
|
||||||
pub fn stable<'tcx, S: Stable<'tcx>>(item: &S) -> S::T {
|
pub fn stable<'tcx, S: Stable<'tcx>>(item: S) -> S::T {
|
||||||
with_tables(|tables| item.stable(tables))
|
with_tables(|tables| item.stable(tables))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn internal<'tcx, S: RustcInternal<'tcx>>(item: &S) -> S::T {
|
pub fn internal<'tcx, S: RustcInternal<'tcx>>(item: S) -> S::T {
|
||||||
with_tables(|tables| item.internal(tables))
|
with_tables(|tables| item.internal(tables))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,12 +145,13 @@ pub fn crate_num(item: &stable_mir::Crate) -> CrateNum {
|
||||||
// datastructures and stable MIR datastructures
|
// datastructures and stable MIR datastructures
|
||||||
scoped_thread_local! (static TLV: Cell<*const ()>);
|
scoped_thread_local! (static TLV: Cell<*const ()>);
|
||||||
|
|
||||||
pub(crate) fn init<'tcx>(tables: &TablesWrapper<'tcx>, f: impl FnOnce()) {
|
pub(crate) fn init<'tcx, F, T>(tables: &TablesWrapper<'tcx>, f: F) -> T
|
||||||
|
where
|
||||||
|
F: FnOnce() -> T,
|
||||||
|
{
|
||||||
assert!(!TLV.is_set());
|
assert!(!TLV.is_set());
|
||||||
let ptr = tables as *const _ as *const ();
|
let ptr = tables as *const _ as *const ();
|
||||||
TLV.set(&Cell::new(ptr), || {
|
TLV.set(&Cell::new(ptr), || f())
|
||||||
f();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Loads the current context and calls a function with it.
|
/// Loads the current context and calls a function with it.
|
||||||
|
@ -165,7 +167,10 @@ pub(crate) fn with_tables<'tcx, R>(f: impl FnOnce(&mut Tables<'tcx>) -> R) -> R
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(tcx: TyCtxt<'_>, f: impl FnOnce()) {
|
pub fn run<F, T>(tcx: TyCtxt<'_>, f: F) -> Result<T, Error>
|
||||||
|
where
|
||||||
|
F: FnOnce() -> T,
|
||||||
|
{
|
||||||
let tables = TablesWrapper(RefCell::new(Tables {
|
let tables = TablesWrapper(RefCell::new(Tables {
|
||||||
tcx,
|
tcx,
|
||||||
def_ids: IndexMap::default(),
|
def_ids: IndexMap::default(),
|
||||||
|
@ -175,7 +180,7 @@ pub fn run(tcx: TyCtxt<'_>, f: impl FnOnce()) {
|
||||||
instances: IndexMap::default(),
|
instances: IndexMap::default(),
|
||||||
constants: IndexMap::default(),
|
constants: IndexMap::default(),
|
||||||
}));
|
}));
|
||||||
stable_mir::run(&tables, || init(&tables, f));
|
stable_mir::run(&tables, || init(&tables, f))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
|
@ -241,7 +246,8 @@ macro_rules! run {
|
||||||
queries.global_ctxt().unwrap().enter(|tcx| {
|
queries.global_ctxt().unwrap().enter(|tcx| {
|
||||||
rustc_internal::run(tcx, || {
|
rustc_internal::run(tcx, || {
|
||||||
self.result = Some((self.callback)(tcx));
|
self.result = Some((self.callback)(tcx));
|
||||||
});
|
})
|
||||||
|
.unwrap();
|
||||||
if self.result.as_ref().is_some_and(|val| val.is_continue()) {
|
if self.result.as_ref().is_some_and(|val| val.is_continue()) {
|
||||||
Compilation::Continue
|
Compilation::Continue
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -19,10 +19,15 @@ impl<'tcx> BodyBuilder<'tcx> {
|
||||||
BodyBuilder { tcx, instance }
|
BodyBuilder { tcx, instance }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Build a stable monomorphic body for a given instance based on the MIR body.
|
||||||
|
///
|
||||||
|
/// Note that we skip instantiation for static and constants. Trying to do so can cause ICE.
|
||||||
|
///
|
||||||
|
/// We do monomorphize non-generic functions to eval unevaluated constants.
|
||||||
pub fn build(mut self, tables: &mut Tables<'tcx>) -> stable_mir::mir::Body {
|
pub fn build(mut self, tables: &mut Tables<'tcx>) -> stable_mir::mir::Body {
|
||||||
let mut body = self.tcx.instance_mir(self.instance.def).clone();
|
let mut body = self.tcx.instance_mir(self.instance.def).clone();
|
||||||
let generics = self.tcx.generics_of(self.instance.def_id());
|
if self.tcx.def_kind(self.instance.def_id()).is_fn_like() || !self.instance.args.is_empty()
|
||||||
if generics.requires_monomorphization(self.tcx) {
|
{
|
||||||
self.visit_body(&mut body);
|
self.visit_body(&mut body);
|
||||||
}
|
}
|
||||||
body.stable(tables)
|
body.stable(tables)
|
||||||
|
@ -49,6 +54,20 @@ impl<'tcx> MutVisitor<'tcx> for BodyBuilder<'tcx> {
|
||||||
*ty = self.monomorphize(*ty);
|
*ty = self.monomorphize(*ty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_constant(&mut self, constant: &mut mir::ConstOperand<'tcx>, location: mir::Location) {
|
||||||
|
let const_ = self.monomorphize(constant.const_);
|
||||||
|
let val = match const_.eval(self.tcx, ty::ParamEnv::reveal_all(), None) {
|
||||||
|
Ok(v) => v,
|
||||||
|
Err(mir::interpret::ErrorHandled::Reported(..)) => return,
|
||||||
|
Err(mir::interpret::ErrorHandled::TooGeneric(..)) => {
|
||||||
|
unreachable!("Failed to evaluate instance constant: {:?}", const_)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let ty = constant.ty();
|
||||||
|
constant.const_ = mir::Const::Val(val, ty);
|
||||||
|
self.super_constant(constant, location);
|
||||||
|
}
|
||||||
|
|
||||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||||
self.tcx
|
self.tcx
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,9 +8,9 @@
|
||||||
//! For now, we are developing everything inside `rustc`, thus, we keep this module private.
|
//! For now, we are developing everything inside `rustc`, thus, we keep this module private.
|
||||||
|
|
||||||
use crate::rustc_internal::{IndexMap, RustcInternal};
|
use crate::rustc_internal::{IndexMap, RustcInternal};
|
||||||
use crate::rustc_smir::hir::def::DefKind;
|
use crate::rustc_smir::stable_mir::ty::{BoundRegion, Region};
|
||||||
use crate::rustc_smir::stable_mir::ty::{BoundRegion, EarlyParamRegion, Region};
|
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
|
use rustc_hir::def::DefKind;
|
||||||
use rustc_middle::mir;
|
use rustc_middle::mir;
|
||||||
use rustc_middle::mir::interpret::{alloc_range, AllocId};
|
use rustc_middle::mir::interpret::{alloc_range, AllocId};
|
||||||
use rustc_middle::mir::mono::MonoItem;
|
use rustc_middle::mir::mono::MonoItem;
|
||||||
|
@ -20,10 +20,11 @@ use rustc_target::abi::FieldIdx;
|
||||||
use stable_mir::mir::mono::InstanceDef;
|
use stable_mir::mir::mono::InstanceDef;
|
||||||
use stable_mir::mir::{Body, CopyNonOverlapping, Statement, UserTypeProjection, VariantIdx};
|
use stable_mir::mir::{Body, CopyNonOverlapping, Statement, UserTypeProjection, VariantIdx};
|
||||||
use stable_mir::ty::{
|
use stable_mir::ty::{
|
||||||
Const, ConstId, ConstantKind, FloatTy, GenericParamDef, IntTy, LineInfo, Movability, RigidTy,
|
AdtDef, AdtKind, ClosureDef, ClosureKind, Const, ConstId, ConstantKind, EarlyParamRegion,
|
||||||
Span, TyKind, UintTy,
|
FloatTy, FnDef, GenericArgs, GenericParamDef, IntTy, LineInfo, Movability, RigidTy, Span,
|
||||||
|
TyKind, UintTy,
|
||||||
};
|
};
|
||||||
use stable_mir::{self, opaque, Context, Filename};
|
use stable_mir::{self, opaque, Context, CrateItem, Filename, ItemKind};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
|
@ -85,9 +86,23 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
||||||
LineInfo { start_line: lines.1, start_col: lines.2, end_line: lines.3, end_col: lines.4 }
|
LineInfo { start_line: lines.1, start_col: lines.2, end_line: lines.3, end_col: lines.4 }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn def_kind(&self, def_id: stable_mir::DefId) -> stable_mir::DefKind {
|
fn item_kind(&self, item: CrateItem) -> ItemKind {
|
||||||
|
let tables = self.0.borrow();
|
||||||
|
new_item_kind(tables.tcx.def_kind(tables[item.0]))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn adt_kind(&self, def: AdtDef) -> AdtKind {
|
||||||
let mut tables = self.0.borrow_mut();
|
let mut tables = self.0.borrow_mut();
|
||||||
tables.tcx.def_kind(tables[def_id]).stable(&mut *tables)
|
let ty = tables.tcx.type_of(def.0.internal(&mut *tables)).instantiate_identity().kind();
|
||||||
|
let ty::TyKind::Adt(def, _) = ty else {
|
||||||
|
panic!("Expected an ADT definition, but found: {ty:?}")
|
||||||
|
};
|
||||||
|
def.adt_kind().stable(&mut *tables)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn def_ty(&self, item: stable_mir::DefId) -> stable_mir::ty::Ty {
|
||||||
|
let mut tables = self.0.borrow_mut();
|
||||||
|
tables.tcx.type_of(item.internal(&mut *tables)).instantiate_identity().stable(&mut *tables)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn span_of_an_item(&self, def_id: stable_mir::DefId) -> Span {
|
fn span_of_an_item(&self, def_id: stable_mir::DefId) -> Span {
|
||||||
|
@ -198,10 +213,12 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn instance_body(&self, def: InstanceDef) -> Body {
|
fn instance_body(&self, def: InstanceDef) -> Option<Body> {
|
||||||
let mut tables = self.0.borrow_mut();
|
let mut tables = self.0.borrow_mut();
|
||||||
let instance = tables.instances[def];
|
let instance = tables.instances[def];
|
||||||
builder::BodyBuilder::new(tables.tcx, instance).build(&mut *tables)
|
tables
|
||||||
|
.has_body(instance)
|
||||||
|
.then(|| builder::BodyBuilder::new(tables.tcx, instance).build(&mut *tables))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn instance_ty(&self, def: InstanceDef) -> stable_mir::ty::Ty {
|
fn instance_ty(&self, def: InstanceDef) -> stable_mir::ty::Ty {
|
||||||
|
@ -249,6 +266,38 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
||||||
Ok(None) | Err(_) => None,
|
Ok(None) | Err(_) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn resolve_drop_in_place(&self, ty: stable_mir::ty::Ty) -> stable_mir::mir::mono::Instance {
|
||||||
|
let mut tables = self.0.borrow_mut();
|
||||||
|
let internal_ty = ty.internal(&mut *tables);
|
||||||
|
let instance = Instance::resolve_drop_in_place(tables.tcx, internal_ty);
|
||||||
|
instance.stable(&mut *tables)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_for_fn_ptr(
|
||||||
|
&self,
|
||||||
|
def: FnDef,
|
||||||
|
args: &GenericArgs,
|
||||||
|
) -> Option<stable_mir::mir::mono::Instance> {
|
||||||
|
let mut tables = self.0.borrow_mut();
|
||||||
|
let def_id = def.0.internal(&mut *tables);
|
||||||
|
let args_ref = args.internal(&mut *tables);
|
||||||
|
Instance::resolve_for_fn_ptr(tables.tcx, ParamEnv::reveal_all(), def_id, args_ref)
|
||||||
|
.stable(&mut *tables)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_closure(
|
||||||
|
&self,
|
||||||
|
def: ClosureDef,
|
||||||
|
args: &GenericArgs,
|
||||||
|
kind: ClosureKind,
|
||||||
|
) -> Option<stable_mir::mir::mono::Instance> {
|
||||||
|
let mut tables = self.0.borrow_mut();
|
||||||
|
let def_id = def.0.internal(&mut *tables);
|
||||||
|
let args_ref = args.internal(&mut *tables);
|
||||||
|
let closure_kind = kind.internal(&mut *tables);
|
||||||
|
Instance::resolve_closure(tables.tcx, def_id, args_ref, closure_kind).stable(&mut *tables)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct TablesWrapper<'tcx>(pub(crate) RefCell<Tables<'tcx>>);
|
pub(crate) struct TablesWrapper<'tcx>(pub(crate) RefCell<Tables<'tcx>>);
|
||||||
|
@ -271,6 +320,17 @@ impl<'tcx> Tables<'tcx> {
|
||||||
fn intern_const(&mut self, constant: mir::Const<'tcx>) -> ConstId {
|
fn intern_const(&mut self, constant: mir::Const<'tcx>) -> ConstId {
|
||||||
self.constants.create_or_fetch(constant)
|
self.constants.create_or_fetch(constant)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn has_body(&self, instance: Instance<'tcx>) -> bool {
|
||||||
|
let def_id = instance.def_id();
|
||||||
|
self.tcx.is_mir_available(def_id)
|
||||||
|
|| !matches!(
|
||||||
|
instance.def,
|
||||||
|
ty::InstanceDef::Virtual(..)
|
||||||
|
| ty::InstanceDef::Intrinsic(..)
|
||||||
|
| ty::InstanceDef::Item(..)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build a stable mir crate from a given crate number.
|
/// Build a stable mir crate from a given crate number.
|
||||||
|
@ -281,6 +341,40 @@ fn smir_crate(tcx: TyCtxt<'_>, crate_num: CrateNum) -> stable_mir::Crate {
|
||||||
stable_mir::Crate { id: crate_num.into(), name: crate_name, is_local }
|
stable_mir::Crate { id: crate_num.into(), name: crate_name, is_local }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn new_item_kind(kind: DefKind) -> ItemKind {
|
||||||
|
match kind {
|
||||||
|
DefKind::Mod
|
||||||
|
| DefKind::Struct
|
||||||
|
| DefKind::Union
|
||||||
|
| DefKind::Enum
|
||||||
|
| DefKind::Variant
|
||||||
|
| DefKind::Trait
|
||||||
|
| DefKind::TyAlias
|
||||||
|
| DefKind::ForeignTy
|
||||||
|
| DefKind::TraitAlias
|
||||||
|
| DefKind::AssocTy
|
||||||
|
| DefKind::TyParam
|
||||||
|
| DefKind::ConstParam
|
||||||
|
| DefKind::Macro(_)
|
||||||
|
| DefKind::ExternCrate
|
||||||
|
| DefKind::Use
|
||||||
|
| DefKind::ForeignMod
|
||||||
|
| DefKind::OpaqueTy
|
||||||
|
| DefKind::Field
|
||||||
|
| DefKind::LifetimeParam
|
||||||
|
| DefKind::Impl { .. }
|
||||||
|
| DefKind::Ctor(_, _)
|
||||||
|
| DefKind::GlobalAsm => {
|
||||||
|
unreachable!("Not a valid item kind: {kind:?}");
|
||||||
|
}
|
||||||
|
DefKind::Closure | DefKind::Coroutine | DefKind::AssocFn | DefKind::Fn => ItemKind::Fn,
|
||||||
|
DefKind::Const | DefKind::InlineConst | DefKind::AssocConst | DefKind::AnonConst => {
|
||||||
|
ItemKind::Const
|
||||||
|
}
|
||||||
|
DefKind::Static(_) => ItemKind::Static,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Trait used to convert between an internal MIR type to a Stable MIR type.
|
/// Trait used to convert between an internal MIR type to a Stable MIR type.
|
||||||
pub trait Stable<'tcx> {
|
pub trait Stable<'tcx> {
|
||||||
/// The stable representation of the type implementing Stable.
|
/// The stable representation of the type implementing Stable.
|
||||||
|
@ -926,6 +1020,18 @@ impl<'tcx> Stable<'tcx> for mir::AggregateKind<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'tcx> Stable<'tcx> for ty::AdtKind {
|
||||||
|
type T = AdtKind;
|
||||||
|
|
||||||
|
fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
|
||||||
|
match self {
|
||||||
|
ty::AdtKind::Struct => AdtKind::Struct,
|
||||||
|
ty::AdtKind::Union => AdtKind::Union,
|
||||||
|
ty::AdtKind::Enum => AdtKind::Enum,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'tcx> Stable<'tcx> for rustc_hir::CoroutineSource {
|
impl<'tcx> Stable<'tcx> for rustc_hir::CoroutineSource {
|
||||||
type T = stable_mir::mir::CoroutineSource;
|
type T = stable_mir::mir::CoroutineSource;
|
||||||
fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
|
fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
|
||||||
|
@ -1062,8 +1168,6 @@ impl<'tcx> Stable<'tcx> for mir::TerminatorKind<'tcx> {
|
||||||
impl<'tcx> Stable<'tcx> for ty::GenericArgs<'tcx> {
|
impl<'tcx> Stable<'tcx> for ty::GenericArgs<'tcx> {
|
||||||
type T = stable_mir::ty::GenericArgs;
|
type T = stable_mir::ty::GenericArgs;
|
||||||
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
||||||
use stable_mir::ty::GenericArgs;
|
|
||||||
|
|
||||||
GenericArgs(self.iter().map(|arg| arg.unpack().stable(tables)).collect())
|
GenericArgs(self.iter().map(|arg| arg.unpack().stable(tables)).collect())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1486,7 +1590,7 @@ impl<'tcx> Stable<'tcx> for ty::TraitRef<'tcx> {
|
||||||
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
||||||
use stable_mir::ty::TraitRef;
|
use stable_mir::ty::TraitRef;
|
||||||
|
|
||||||
TraitRef { def_id: tables.trait_def(self.def_id), args: self.args.stable(tables) }
|
TraitRef::try_new(tables.trait_def(self.def_id), self.args.stable(tables)).unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1762,15 +1866,6 @@ impl<'tcx> Stable<'tcx> for rustc_span::Span {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Stable<'tcx> for DefKind {
|
|
||||||
type T = stable_mir::DefKind;
|
|
||||||
|
|
||||||
fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
|
|
||||||
// FIXME: add a real implementation of stable DefKind
|
|
||||||
opaque(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> Stable<'tcx> for ty::Instance<'tcx> {
|
impl<'tcx> Stable<'tcx> for ty::Instance<'tcx> {
|
||||||
type T = stable_mir::mir::mono::Instance;
|
type T = stable_mir::mir::mono::Instance;
|
||||||
|
|
||||||
|
@ -1805,3 +1900,25 @@ impl<'tcx> Stable<'tcx> for MonoItem<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'tcx, T> Stable<'tcx> for &T
|
||||||
|
where
|
||||||
|
T: Stable<'tcx>,
|
||||||
|
{
|
||||||
|
type T = T::T;
|
||||||
|
|
||||||
|
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
||||||
|
(*self).stable(tables)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx, T> Stable<'tcx> for Option<T>
|
||||||
|
where
|
||||||
|
T: Stable<'tcx>,
|
||||||
|
{
|
||||||
|
type T = Option<T::T>;
|
||||||
|
|
||||||
|
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
||||||
|
self.as_ref().map(|value| value.stable(tables))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@ pub mod mir;
|
||||||
pub mod ty;
|
pub mod ty;
|
||||||
pub mod visitor;
|
pub mod visitor;
|
||||||
|
|
||||||
|
use crate::ty::{AdtDef, AdtKind, ClosureDef, ClosureKind};
|
||||||
pub use error::*;
|
pub use error::*;
|
||||||
use mir::mono::Instance;
|
use mir::mono::Instance;
|
||||||
use ty::{FnDef, GenericArgs};
|
use ty::{FnDef, GenericArgs};
|
||||||
|
@ -47,7 +48,7 @@ pub type Symbol = String;
|
||||||
pub type CrateNum = usize;
|
pub type CrateNum = usize;
|
||||||
|
|
||||||
/// A unique identification number for each item accessible for the current compilation unit.
|
/// A unique identification number for each item accessible for the current compilation unit.
|
||||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
pub struct DefId(usize);
|
pub struct DefId(usize);
|
||||||
|
|
||||||
impl Debug for DefId {
|
impl Debug for DefId {
|
||||||
|
@ -99,7 +100,13 @@ pub struct Crate {
|
||||||
pub is_local: bool,
|
pub is_local: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type DefKind = Opaque;
|
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
|
||||||
|
pub enum ItemKind {
|
||||||
|
Fn,
|
||||||
|
Static,
|
||||||
|
Const,
|
||||||
|
}
|
||||||
|
|
||||||
pub type Filename = Opaque;
|
pub type Filename = Opaque;
|
||||||
|
|
||||||
/// Holds information about an item in the crate.
|
/// Holds information about an item in the crate.
|
||||||
|
@ -119,13 +126,17 @@ impl CrateItem {
|
||||||
with(|cx| cx.name_of_def_id(self.0))
|
with(|cx| cx.name_of_def_id(self.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn kind(&self) -> DefKind {
|
pub fn kind(&self) -> ItemKind {
|
||||||
with(|cx| cx.def_kind(self.0))
|
with(|cx| cx.item_kind(*self))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn requires_monomorphization(&self) -> bool {
|
pub fn requires_monomorphization(&self) -> bool {
|
||||||
with(|cx| cx.requires_monomorphization(self.0))
|
with(|cx| cx.requires_monomorphization(self.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn ty(&self) -> Ty {
|
||||||
|
with(|cx| cx.def_ty(self.0))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the function where execution starts if the current
|
/// Return the function where execution starts if the current
|
||||||
|
@ -204,7 +215,13 @@ pub trait Context {
|
||||||
fn get_lines(&self, span: &Span) -> LineInfo;
|
fn get_lines(&self, span: &Span) -> LineInfo;
|
||||||
|
|
||||||
/// Returns the `kind` of given `DefId`
|
/// Returns the `kind` of given `DefId`
|
||||||
fn def_kind(&self, def_id: DefId) -> DefKind;
|
fn item_kind(&self, item: CrateItem) -> ItemKind;
|
||||||
|
|
||||||
|
/// Returns the kind of a given algebraic data type
|
||||||
|
fn adt_kind(&self, def: AdtDef) -> AdtKind;
|
||||||
|
|
||||||
|
/// Returns the type of given crate item.
|
||||||
|
fn def_ty(&self, item: DefId) -> Ty;
|
||||||
|
|
||||||
/// `Span` of an item
|
/// `Span` of an item
|
||||||
fn span_of_an_item(&self, def_id: DefId) -> Span;
|
fn span_of_an_item(&self, def_id: DefId) -> Span;
|
||||||
|
@ -214,7 +231,7 @@ pub trait Context {
|
||||||
|
|
||||||
/// Get the body of an Instance.
|
/// Get the body of an Instance.
|
||||||
/// FIXME: Monomorphize the body.
|
/// FIXME: Monomorphize the body.
|
||||||
fn instance_body(&self, instance: InstanceDef) -> Body;
|
fn instance_body(&self, instance: InstanceDef) -> Option<Body>;
|
||||||
|
|
||||||
/// Get the instance type with generic substitutions applied and lifetimes erased.
|
/// Get the instance type with generic substitutions applied and lifetimes erased.
|
||||||
fn instance_ty(&self, instance: InstanceDef) -> Ty;
|
fn instance_ty(&self, instance: InstanceDef) -> Ty;
|
||||||
|
@ -234,18 +251,36 @@ pub trait Context {
|
||||||
|
|
||||||
/// Resolve an instance from the given function definition and generic arguments.
|
/// Resolve an instance from the given function definition and generic arguments.
|
||||||
fn resolve_instance(&self, def: FnDef, args: &GenericArgs) -> Option<Instance>;
|
fn resolve_instance(&self, def: FnDef, args: &GenericArgs) -> Option<Instance>;
|
||||||
|
|
||||||
|
/// Resolve an instance for drop_in_place for the given type.
|
||||||
|
fn resolve_drop_in_place(&self, ty: Ty) -> Instance;
|
||||||
|
|
||||||
|
/// Resolve instance for a function pointer.
|
||||||
|
fn resolve_for_fn_ptr(&self, def: FnDef, args: &GenericArgs) -> Option<Instance>;
|
||||||
|
|
||||||
|
/// Resolve instance for a closure with the requested type.
|
||||||
|
fn resolve_closure(
|
||||||
|
&self,
|
||||||
|
def: ClosureDef,
|
||||||
|
args: &GenericArgs,
|
||||||
|
kind: ClosureKind,
|
||||||
|
) -> Option<Instance>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// A thread local variable that stores a pointer to the tables mapping between TyCtxt
|
// A thread local variable that stores a pointer to the tables mapping between TyCtxt
|
||||||
// datastructures and stable MIR datastructures
|
// datastructures and stable MIR datastructures
|
||||||
scoped_thread_local! (static TLV: Cell<*const ()>);
|
scoped_thread_local! (static TLV: Cell<*const ()>);
|
||||||
|
|
||||||
pub fn run(context: &dyn Context, f: impl FnOnce()) {
|
pub fn run<F, T>(context: &dyn Context, f: F) -> Result<T, Error>
|
||||||
assert!(!TLV.is_set());
|
where
|
||||||
let ptr: *const () = &context as *const &_ as _;
|
F: FnOnce() -> T,
|
||||||
TLV.set(&Cell::new(ptr), || {
|
{
|
||||||
f();
|
if TLV.is_set() {
|
||||||
});
|
Err(Error::from("StableMIR already running"))
|
||||||
|
} else {
|
||||||
|
let ptr: *const () = &context as *const &_ as _;
|
||||||
|
TLV.set(&Cell::new(ptr), || Ok(f()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Loads the current context and calls a function with it.
|
/// Loads the current context and calls a function with it.
|
||||||
|
@ -260,7 +295,7 @@ pub fn with<R>(f: impl FnOnce(&dyn Context) -> R) -> R {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A type that provides internal information but that can still be used for debug purpose.
|
/// A type that provides internal information but that can still be used for debug purpose.
|
||||||
#[derive(Clone, Eq, PartialEq)]
|
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct Opaque(String);
|
pub struct Opaque(String);
|
||||||
|
|
||||||
impl std::fmt::Display for Opaque {
|
impl std::fmt::Display for Opaque {
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
use crate::mir::Body;
|
use crate::mir::Body;
|
||||||
use crate::ty::{FnDef, GenericArgs, IndexedVal, Ty};
|
use crate::ty::{ClosureDef, ClosureKind, FnDef, GenericArgs, IndexedVal, Ty};
|
||||||
use crate::{with, CrateItem, DefId, Error, Opaque};
|
use crate::{with, CrateItem, DefId, Error, ItemKind, Opaque};
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub enum MonoItem {
|
pub enum MonoItem {
|
||||||
Fn(Instance),
|
Fn(Instance),
|
||||||
Static(StaticDef),
|
Static(StaticDef),
|
||||||
GlobalAsm(Opaque),
|
GlobalAsm(Opaque),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct Instance {
|
pub struct Instance {
|
||||||
/// The type of instance.
|
/// The type of instance.
|
||||||
pub kind: InstanceKind,
|
pub kind: InstanceKind,
|
||||||
|
@ -19,7 +19,7 @@ pub struct Instance {
|
||||||
pub def: InstanceDef,
|
pub def: InstanceDef,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub enum InstanceKind {
|
pub enum InstanceKind {
|
||||||
/// A user defined item.
|
/// A user defined item.
|
||||||
Item,
|
Item,
|
||||||
|
@ -33,7 +33,7 @@ pub enum InstanceKind {
|
||||||
|
|
||||||
impl Instance {
|
impl Instance {
|
||||||
/// Get the body of an Instance. The body will be eagerly monomorphized.
|
/// Get the body of an Instance. The body will be eagerly monomorphized.
|
||||||
pub fn body(&self) -> Body {
|
pub fn body(&self) -> Option<Body> {
|
||||||
with(|context| context.instance_body(self.def))
|
with(|context| context.instance_body(self.def))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,6 +54,33 @@ impl Instance {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Resolve the drop in place for a given type.
|
||||||
|
pub fn resolve_drop_in_place(ty: Ty) -> Instance {
|
||||||
|
with(|cx| cx.resolve_drop_in_place(ty))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resolve an instance for a given function pointer.
|
||||||
|
pub fn resolve_for_fn_ptr(def: FnDef, args: &GenericArgs) -> Result<Instance, crate::Error> {
|
||||||
|
with(|context| {
|
||||||
|
context.resolve_for_fn_ptr(def, args).ok_or_else(|| {
|
||||||
|
crate::Error::new(format!("Failed to resolve `{def:?}` with `{args:?}`"))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resolve a closure with the expected kind.
|
||||||
|
pub fn resolve_closure(
|
||||||
|
def: ClosureDef,
|
||||||
|
args: &GenericArgs,
|
||||||
|
kind: ClosureKind,
|
||||||
|
) -> Result<Instance, crate::Error> {
|
||||||
|
with(|context| {
|
||||||
|
context.resolve_closure(def, args, kind).ok_or_else(|| {
|
||||||
|
crate::Error::new(format!("Failed to resolve `{def:?}` with `{args:?}`"))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Try to convert a crate item into an instance.
|
/// Try to convert a crate item into an instance.
|
||||||
|
@ -86,12 +113,36 @@ impl TryFrom<Instance> for CrateItem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
impl From<Instance> for MonoItem {
|
||||||
|
fn from(value: Instance) -> Self {
|
||||||
|
MonoItem::Fn(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct InstanceDef(usize);
|
pub struct InstanceDef(usize);
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
|
||||||
pub struct StaticDef(pub DefId);
|
pub struct StaticDef(pub DefId);
|
||||||
|
|
||||||
|
impl TryFrom<CrateItem> for StaticDef {
|
||||||
|
type Error = crate::Error;
|
||||||
|
|
||||||
|
fn try_from(value: CrateItem) -> Result<Self, Self::Error> {
|
||||||
|
if matches!(value.kind(), ItemKind::Static | ItemKind::Const) {
|
||||||
|
Ok(StaticDef(value.0))
|
||||||
|
} else {
|
||||||
|
Err(Error::new(format!("Expected a static item, but found: {value:?}")))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StaticDef {
|
||||||
|
pub fn ty(&self) -> Ty {
|
||||||
|
with(|cx| cx.def_ty(self.0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl IndexedVal for InstanceDef {
|
impl IndexedVal for InstanceDef {
|
||||||
fn to_val(index: usize) -> Self {
|
fn to_val(index: usize) -> Self {
|
||||||
InstanceDef(index)
|
InstanceDef(index)
|
||||||
|
|
|
@ -142,7 +142,7 @@ pub trait MirVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
let local_start = arg_count + 1;
|
let local_start = arg_count + 1;
|
||||||
for (idx, arg) in body.arg_locals().iter().enumerate() {
|
for (idx, arg) in body.inner_locals().iter().enumerate() {
|
||||||
self.visit_local_decl(idx + local_start, arg)
|
self.visit_local_decl(idx + local_start, arg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -417,7 +417,7 @@ pub trait MirVisitor {
|
||||||
fn visit_opaque(_: &Opaque) {}
|
fn visit_opaque(_: &Opaque) {}
|
||||||
|
|
||||||
/// The location of a statement / terminator in the code and the CFG.
|
/// The location of a statement / terminator in the code and the CFG.
|
||||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
pub struct Location(Span);
|
pub struct Location(Span);
|
||||||
|
|
||||||
impl Location {
|
impl Location {
|
||||||
|
|
|
@ -4,7 +4,7 @@ use super::{
|
||||||
with, AllocId, DefId, Symbol,
|
with, AllocId, DefId, Symbol,
|
||||||
};
|
};
|
||||||
use crate::{Filename, Opaque};
|
use crate::{Filename, Opaque};
|
||||||
use std::fmt::{self, Debug, Formatter};
|
use std::fmt::{self, Debug, Display, Formatter};
|
||||||
|
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
|
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
|
||||||
pub struct Ty(pub usize);
|
pub struct Ty(pub usize);
|
||||||
|
@ -135,6 +135,46 @@ pub enum TyKind {
|
||||||
Bound(usize, BoundTy),
|
Bound(usize, BoundTy),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TyKind {
|
||||||
|
pub fn rigid(&self) -> Option<&RigidTy> {
|
||||||
|
if let TyKind::RigidTy(inner) = self { Some(inner) } else { None }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_unit(&self) -> bool {
|
||||||
|
matches!(self, TyKind::RigidTy(RigidTy::Tuple(data)) if data.len() == 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_trait(&self) -> bool {
|
||||||
|
matches!(self, TyKind::RigidTy(RigidTy::Dynamic(_, _, DynKind::Dyn)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_enum(&self) -> bool {
|
||||||
|
matches!(self, TyKind::RigidTy(RigidTy::Adt(def, _)) if def.kind() == AdtKind::Enum)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_struct(&self) -> bool {
|
||||||
|
matches!(self, TyKind::RigidTy(RigidTy::Adt(def, _)) if def.kind() == AdtKind::Struct)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_union(&self) -> bool {
|
||||||
|
matches!(self, TyKind::RigidTy(RigidTy::Adt(def, _)) if def.kind() == AdtKind::Union)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn trait_principal(&self) -> Option<Binder<ExistentialTraitRef>> {
|
||||||
|
if let TyKind::RigidTy(RigidTy::Dynamic(predicates, _, _)) = self {
|
||||||
|
if let Some(Binder { value: ExistentialPredicate::Trait(trait_ref), bound_vars }) =
|
||||||
|
predicates.first()
|
||||||
|
{
|
||||||
|
Some(Binder { value: trait_ref.clone(), bound_vars: bound_vars.clone() })
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub enum RigidTy {
|
pub enum RigidTy {
|
||||||
Bool,
|
Bool,
|
||||||
|
@ -218,6 +258,43 @@ pub struct BrNamedDef(pub DefId);
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
pub struct AdtDef(pub DefId);
|
pub struct AdtDef(pub DefId);
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
|
||||||
|
pub enum AdtKind {
|
||||||
|
Enum,
|
||||||
|
Union,
|
||||||
|
Struct,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AdtDef {
|
||||||
|
pub fn kind(&self) -> AdtKind {
|
||||||
|
with(|cx| cx.adt_kind(*self))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for AdtKind {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
|
f.write_str(match self {
|
||||||
|
AdtKind::Enum => "enum",
|
||||||
|
AdtKind::Union => "union",
|
||||||
|
AdtKind::Struct => "struct",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AdtKind {
|
||||||
|
pub fn is_enum(&self) -> bool {
|
||||||
|
matches!(self, AdtKind::Enum)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_struct(&self) -> bool {
|
||||||
|
matches!(self, AdtKind::Struct)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_union(&self) -> bool {
|
||||||
|
matches!(self, AdtKind::Union)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
pub struct AliasDef(pub DefId);
|
pub struct AliasDef(pub DefId);
|
||||||
|
|
||||||
|
@ -355,6 +432,30 @@ pub struct Binder<T> {
|
||||||
pub bound_vars: Vec<BoundVariableKind>,
|
pub bound_vars: Vec<BoundVariableKind>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T> Binder<T> {
|
||||||
|
pub fn skip_binder(self) -> T {
|
||||||
|
self.value
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn map_bound_ref<F, U>(&self, f: F) -> Binder<U>
|
||||||
|
where
|
||||||
|
F: FnOnce(&T) -> U,
|
||||||
|
{
|
||||||
|
let Binder { value, bound_vars } = self;
|
||||||
|
let new_value = f(value);
|
||||||
|
Binder { value: new_value, bound_vars: bound_vars.clone() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn map_bound<F, U>(self, f: F) -> Binder<U>
|
||||||
|
where
|
||||||
|
F: FnOnce(T) -> U,
|
||||||
|
{
|
||||||
|
let Binder { value, bound_vars } = self;
|
||||||
|
let new_value = f(value);
|
||||||
|
Binder { value: new_value, bound_vars }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub struct EarlyBinder<T> {
|
pub struct EarlyBinder<T> {
|
||||||
pub value: T,
|
pub value: T,
|
||||||
|
@ -393,12 +494,27 @@ pub enum ExistentialPredicate {
|
||||||
AutoTrait(TraitDef),
|
AutoTrait(TraitDef),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An existential reference to a trait where `Self` is not included.
|
||||||
|
///
|
||||||
|
/// The `generic_args` will include any other known argument.
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub struct ExistentialTraitRef {
|
pub struct ExistentialTraitRef {
|
||||||
pub def_id: TraitDef,
|
pub def_id: TraitDef,
|
||||||
pub generic_args: GenericArgs,
|
pub generic_args: GenericArgs,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Binder<ExistentialTraitRef> {
|
||||||
|
pub fn with_self_ty(&self, self_ty: Ty) -> Binder<TraitRef> {
|
||||||
|
self.map_bound_ref(|trait_ref| trait_ref.with_self_ty(self_ty))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExistentialTraitRef {
|
||||||
|
pub fn with_self_ty(&self, self_ty: Ty) -> TraitRef {
|
||||||
|
TraitRef::new(self.def_id, self_ty, &self.generic_args)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub struct ExistentialProjection {
|
pub struct ExistentialProjection {
|
||||||
pub def_id: TraitDef,
|
pub def_id: TraitDef,
|
||||||
|
@ -504,10 +620,39 @@ impl TraitDecl {
|
||||||
|
|
||||||
pub type ImplTrait = EarlyBinder<TraitRef>;
|
pub type ImplTrait = EarlyBinder<TraitRef>;
|
||||||
|
|
||||||
|
/// A complete reference to a trait, i.e., one where `Self` is known.
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub struct TraitRef {
|
pub struct TraitRef {
|
||||||
pub def_id: TraitDef,
|
pub def_id: TraitDef,
|
||||||
pub args: GenericArgs,
|
/// The generic arguments for this definition.
|
||||||
|
/// The first element must always be type, and it represents `Self`.
|
||||||
|
args: GenericArgs,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TraitRef {
|
||||||
|
pub fn new(def_id: TraitDef, self_ty: Ty, gen_args: &GenericArgs) -> TraitRef {
|
||||||
|
let mut args = vec![GenericArgKind::Type(self_ty)];
|
||||||
|
args.extend_from_slice(&gen_args.0);
|
||||||
|
TraitRef { def_id, args: GenericArgs(args) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_new(def_id: TraitDef, args: GenericArgs) -> Result<TraitRef, ()> {
|
||||||
|
match &args.0[..] {
|
||||||
|
[GenericArgKind::Type(_), ..] => Ok(TraitRef { def_id, args }),
|
||||||
|
_ => Err(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn args(&self) -> &GenericArgs {
|
||||||
|
&self.args
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn self_ty(&self) -> Ty {
|
||||||
|
let GenericArgKind::Type(self_ty) = self.args.0[0] else {
|
||||||
|
panic!("Self must be a type, but found: {:?}", self.args.0[0])
|
||||||
|
};
|
||||||
|
self_ty
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
|
|
|
@ -119,7 +119,7 @@
|
||||||
//! # Representation
|
//! # Representation
|
||||||
//!
|
//!
|
||||||
//! Rust guarantees to optimize the following types `T` such that
|
//! Rust guarantees to optimize the following types `T` such that
|
||||||
//! [`Option<T>`] has the same size and alignment as `T`. In some
|
//! [`Option<T>`] has the same size, alignment, and [function call ABI] as `T`. In some
|
||||||
//! of these cases, Rust further guarantees that
|
//! of these cases, Rust further guarantees that
|
||||||
//! `transmute::<_, Option<T>>([0u8; size_of::<T>()])` is sound and
|
//! `transmute::<_, Option<T>>([0u8; size_of::<T>()])` is sound and
|
||||||
//! produces `Option::<T>::None`. These cases are identified by the
|
//! produces `Option::<T>::None`. These cases are identified by the
|
||||||
|
@ -127,7 +127,7 @@
|
||||||
//!
|
//!
|
||||||
//! | `T` | `transmute::<_, Option<T>>([0u8; size_of::<T>()])` sound? |
|
//! | `T` | `transmute::<_, Option<T>>([0u8; size_of::<T>()])` sound? |
|
||||||
//! |---------------------------------------------------------------------|----------------------------------------------------------------------|
|
//! |---------------------------------------------------------------------|----------------------------------------------------------------------|
|
||||||
//! | [`Box<U>`] | when `U: Sized` |
|
//! | [`Box<U>`] (specifically, only `Box<U, Global>`) | when `U: Sized` |
|
||||||
//! | `&U` | when `U: Sized` |
|
//! | `&U` | when `U: Sized` |
|
||||||
//! | `&mut U` | when `U: Sized` |
|
//! | `&mut U` | when `U: Sized` |
|
||||||
//! | `fn`, `extern "C" fn`[^extern_fn] | always |
|
//! | `fn`, `extern "C" fn`[^extern_fn] | always |
|
||||||
|
@ -135,11 +135,12 @@
|
||||||
//! | [`ptr::NonNull<U>`] | when `U: Sized` |
|
//! | [`ptr::NonNull<U>`] | when `U: Sized` |
|
||||||
//! | `#[repr(transparent)]` struct around one of the types in this list. | when it holds for the inner type |
|
//! | `#[repr(transparent)]` struct around one of the types in this list. | when it holds for the inner type |
|
||||||
//!
|
//!
|
||||||
//! [^extern_fn]: this remains true for any other ABI: `extern "abi" fn` (_e.g._, `extern "system" fn`)
|
//! [^extern_fn]: this remains true for any argument/return types and any other ABI: `extern "abi" fn` (_e.g._, `extern "system" fn`)
|
||||||
//!
|
//!
|
||||||
//! [`Box<U>`]: ../../std/boxed/struct.Box.html
|
//! [`Box<U>`]: ../../std/boxed/struct.Box.html
|
||||||
//! [`num::NonZero*`]: crate::num
|
//! [`num::NonZero*`]: crate::num
|
||||||
//! [`ptr::NonNull<U>`]: crate::ptr::NonNull
|
//! [`ptr::NonNull<U>`]: crate::ptr::NonNull
|
||||||
|
//! [function call ABI]: ../primitive.fn.html#abi-compatibility
|
||||||
//!
|
//!
|
||||||
//! This is called the "null pointer optimization" or NPO.
|
//! This is called the "null pointer optimization" or NPO.
|
||||||
//!
|
//!
|
||||||
|
|
|
@ -1493,7 +1493,7 @@ mod prim_ref {}
|
||||||
///
|
///
|
||||||
/// ### Casting to and from integers
|
/// ### Casting to and from integers
|
||||||
///
|
///
|
||||||
/// You cast function pointers directly to integers:
|
/// You can cast function pointers directly to integers:
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// let fnptr: fn(i32) -> i32 = |x| x+2;
|
/// let fnptr: fn(i32) -> i32 = |x| x+2;
|
||||||
|
@ -1519,6 +1519,114 @@ mod prim_ref {}
|
||||||
/// Note that all of this is not portable to platforms where function pointers and data pointers
|
/// Note that all of this is not portable to platforms where function pointers and data pointers
|
||||||
/// have different sizes.
|
/// have different sizes.
|
||||||
///
|
///
|
||||||
|
/// ### ABI compatibility
|
||||||
|
///
|
||||||
|
/// Generally, when a function is declared with one signature and called via a function pointer with
|
||||||
|
/// a different signature, the two signatures must be *ABI-compatible* or else calling the function
|
||||||
|
/// via that function pointer is Undefined Behavior. ABI compatibility is a lot stricter than merely
|
||||||
|
/// having the same memory layout; for example, even if `i32` and `f32` have the same size and
|
||||||
|
/// alignment, they might be passed in different registers and hence not be ABI-compatible.
|
||||||
|
///
|
||||||
|
/// ABI compatibility as a concern only arises in code that alters the type of function pointers,
|
||||||
|
/// code that imports functions via `extern` blocks, and in code that combines `#[target_feature]`
|
||||||
|
/// with `extern fn`. Altering the type of function pointers is wildly unsafe (as in, a lot more
|
||||||
|
/// unsafe than even [`transmute_copy`][mem::transmute_copy]), and should only occur in the most
|
||||||
|
/// exceptional circumstances. Most Rust code just imports functions via `use`. `#[target_feature]`
|
||||||
|
/// is also used rarely. So, most likely you do not have to worry about ABI compatibility.
|
||||||
|
///
|
||||||
|
/// But assuming such circumstances, what are the rules? For this section, we are only considering
|
||||||
|
/// the ABI of direct Rust-to-Rust calls, not linking in general -- once functions are imported via
|
||||||
|
/// `extern` blocks, there are more things to consider that we do not go into here.
|
||||||
|
///
|
||||||
|
/// For two signatures to be considered *ABI-compatible*, they must use a compatible ABI string,
|
||||||
|
/// must take the same number of arguments, the individual argument types and the return types must
|
||||||
|
/// be ABI-compatible, and the target feature requirements must be met (see the subsection below for
|
||||||
|
/// the last point). The ABI string is declared via `extern "ABI" fn(...) -> ...`; note that
|
||||||
|
/// `fn name(...) -> ...` implicitly uses the `"Rust"` ABI string and `extern fn name(...) -> ...`
|
||||||
|
/// implicitly uses the `"C"` ABI string.
|
||||||
|
///
|
||||||
|
/// The ABI strings are guaranteed to be compatible if they are the same, or if the caller ABI
|
||||||
|
/// string is `$X-unwind` and the callee ABI string is `$X`, where `$X` is one of the following:
|
||||||
|
/// "C", "aapcs", "fastcall", "stdcall", "system", "sysv64", "thiscall", "vectorcall", "win64".
|
||||||
|
///
|
||||||
|
/// The following types are guaranteed to be ABI-compatible:
|
||||||
|
///
|
||||||
|
/// - `*const T`, `*mut T`, `&T`, `&mut T`, `Box<T>` (specifically, only `Box<T, Global>`), and
|
||||||
|
/// `NonNull<T>` are all ABI-compatible with each other for all `T`. They are also ABI-compatible
|
||||||
|
/// with each other for _different_ `T` if they have the same metadata type (`<T as
|
||||||
|
/// Pointee>::Metadata`).
|
||||||
|
/// - `usize` is ABI-compatible with the `uN` integer type of the same size, and likewise `isize` is
|
||||||
|
/// ABI-compatible with the `iN` integer type of the same size.
|
||||||
|
/// - Any two `fn` (function pointer) types are ABI-compatible with each other if they have the same
|
||||||
|
/// ABI string or the ABI string only differs in a trailing `-unwind`, independent of the rest of
|
||||||
|
/// their signature. (This means you can pass `fn()` to a function expecting `fn(i32)`, and the
|
||||||
|
/// call will be valid ABI-wise. The callee receives the result of transmuting the function pointer
|
||||||
|
/// from `fn()` to `fn(i32)`; that transmutation is itself a well-defined operation, it's just
|
||||||
|
/// almost certainly UB to later call that function pointer.)
|
||||||
|
/// - Any two types with size 0 and alignment 1 are ABI-compatible.
|
||||||
|
/// - A `repr(transparent)` type `T` is ABI-compatible with its unique non-trivial field, i.e., the
|
||||||
|
/// unique field that doesn't have size 0 and alignment 1 (if there is such a field).
|
||||||
|
/// - `i32` is ABI-compatible with `NonZeroI32`, and similar for all other integer types with their
|
||||||
|
/// matching `NonZero*` type.
|
||||||
|
/// - If `T` is guaranteed to be subject to the [null pointer
|
||||||
|
/// optimization](option/index.html#representation), then `T` and `Option<T>` are ABI-compatible.
|
||||||
|
///
|
||||||
|
/// Furthermore, ABI compatibility satisfies the following general properties:
|
||||||
|
///
|
||||||
|
/// - Every type is ABI-compatible with itself.
|
||||||
|
/// - If `T1` and `T2` are ABI-compatible, then two `repr(C)` types that only differ because one
|
||||||
|
/// field type was changed from `T1` to `T2` are ABI-compatible.
|
||||||
|
/// - If `T1` and `T2` are ABI-compatible and `T2` and `T3` are ABI-compatible, then so are `T1` and
|
||||||
|
/// `T3` (i.e., ABI-compatibility is transitive).
|
||||||
|
/// - If `T1` and `T2` are ABI-compatible, then so are `T2` and `T1` (i.e., ABI-compatibility is
|
||||||
|
/// symmetric).
|
||||||
|
///
|
||||||
|
/// More signatures can be ABI-compatible on specific targets, but that should not be relied upon
|
||||||
|
/// since it is not portable and not a stable guarantee.
|
||||||
|
///
|
||||||
|
/// Noteworthy cases of types *not* being ABI-compatible in general are:
|
||||||
|
/// * `bool` vs `u8`, and `i32` vs `u32`: on some targets, the calling conventions for these types
|
||||||
|
/// differ in terms of what they guarantee for the remaining bits in the register that are not
|
||||||
|
/// used by the value.
|
||||||
|
/// * `i32` vs `f32` are not compatible either, as has already been mentioned above.
|
||||||
|
/// * `struct Foo(u32)` and `u32` are not compatible (without `repr(transparent)`) since structs are
|
||||||
|
/// aggregate types and often passed in a different way than primitives like `i32`.
|
||||||
|
///
|
||||||
|
/// Note that these rules describe when two completely known types are ABI-compatible. When
|
||||||
|
/// considering ABI compatibility of a type declared in another crate (including the standard
|
||||||
|
/// library), consider that any type that has a private field or the `#[non_exhaustive]` attribute
|
||||||
|
/// may change its layout as a non-breaking update unless documented otherwise -- so for instance,
|
||||||
|
/// even if such a type is a 1-ZST or `repr(transparent)` right now, this might change with any
|
||||||
|
/// library version bump.
|
||||||
|
///
|
||||||
|
/// If the declared signature and the signature of the function pointer are ABI-compatible, then the
|
||||||
|
/// function call behaves as if every argument was [`transmute`d][mem::transmute] from the
|
||||||
|
/// type in the function pointer to the type at the function declaration, and the return value is
|
||||||
|
/// [`transmute`d][mem::transmute] from the type in the declaration to the type in the
|
||||||
|
/// pointer. All the usual caveats and concerns around transmutation apply; for instance, if the
|
||||||
|
/// function expects a `NonNullI32` and the function pointer uses the ABI-compatible type
|
||||||
|
/// `Option<NonNullI32>`, and the value used for the argument is `None`, then this call is Undefined
|
||||||
|
/// Behavior since transmuting `None::<NonNullI32>` to `NonNullI32` violates the non-null
|
||||||
|
/// requirement.
|
||||||
|
///
|
||||||
|
/// #### Requirements concerning target features
|
||||||
|
///
|
||||||
|
/// Under some conditions, the signature used by the caller and the callee can be ABI-incompatible
|
||||||
|
/// even if the exact same ABI string and types are being used. As an example, the
|
||||||
|
/// `std::arch::x86_64::__m256` type has a different `extern "C"` ABI when the `avx` feature is
|
||||||
|
/// enabled vs when it is not enabled.
|
||||||
|
///
|
||||||
|
/// Therefore, to ensure ABI compatibility when code using different target features is combined
|
||||||
|
/// (such as via `#[target_feature]`), we further require that one of the following conditions is
|
||||||
|
/// met:
|
||||||
|
///
|
||||||
|
/// - The function uses the `"Rust"` ABI string (which is the default without `extern`).
|
||||||
|
/// - Caller and callee are using the exact same set of target features. For the callee we consider
|
||||||
|
/// the features enabled (via `#[target_feature]` and `-C target-feature`/`-C target-cpu`) at the
|
||||||
|
/// declaration site; for the caller we consider the features enabled at the call site.
|
||||||
|
/// - Neither any argument nor the return value involves a SIMD type (`#[repr(simd)]`) that is not
|
||||||
|
/// behind a pointer indirection (i.e., `*mut __m256` is fine, but `(i32, __m256)` is not).
|
||||||
|
///
|
||||||
/// ### Trait implementations
|
/// ### Trait implementations
|
||||||
///
|
///
|
||||||
/// In this documentation the shorthand `fn (T₁, T₂, …, Tₙ)` is used to represent non-variadic
|
/// In this documentation the shorthand `fn (T₁, T₂, …, Tₙ)` is used to represent non-variadic
|
||||||
|
|
|
@ -49,7 +49,7 @@ fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
|
||||||
assert!(generic.iter().all(|item| mir::mono::Instance::try_from(*item).is_err()));
|
assert!(generic.iter().all(|item| mir::mono::Instance::try_from(*item).is_err()));
|
||||||
|
|
||||||
for instance in instances {
|
for instance in instances {
|
||||||
test_body(instance.body())
|
test_body(instance.body().unwrap())
|
||||||
}
|
}
|
||||||
ControlFlow::Continue(())
|
ControlFlow::Continue(())
|
||||||
}
|
}
|
||||||
|
@ -61,8 +61,10 @@ fn test_body(body: mir::Body) {
|
||||||
Call { func, .. } => {
|
Call { func, .. } => {
|
||||||
let TyKind::RigidTy(ty) = func.ty(body.locals()).kind() else { unreachable!() };
|
let TyKind::RigidTy(ty) = func.ty(body.locals()).kind() else { unreachable!() };
|
||||||
let RigidTy::FnDef(def, args) = ty else { unreachable!() };
|
let RigidTy::FnDef(def, args) = ty else { unreachable!() };
|
||||||
let result = Instance::resolve(def, &args);
|
let instance = Instance::resolve(def, &args).unwrap();
|
||||||
assert!(result.is_ok());
|
let mangled_name = instance.mangled_name();
|
||||||
|
let body = instance.body();
|
||||||
|
assert!(body.is_some() || mangled_name == "setpwent", "Failed: {func:?}");
|
||||||
}
|
}
|
||||||
Goto { .. } | Assert { .. } | SwitchInt { .. } | Return | Drop { .. } => {
|
Goto { .. } | Assert { .. } | SwitchInt { .. } | Return | Drop { .. } => {
|
||||||
/* Do nothing */
|
/* Do nothing */
|
||||||
|
@ -105,10 +107,16 @@ fn generate_input(path: &str) -> std::io::Result<()> {
|
||||||
LEN > 0 && a[0]
|
LEN > 0 && a[0]
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
extern "C" {{
|
||||||
|
// Body should not be available.
|
||||||
|
fn setpwent();
|
||||||
|
}}
|
||||||
|
|
||||||
pub fn monomorphic() {{
|
pub fn monomorphic() {{
|
||||||
let v = vec![10];
|
let v = vec![10];
|
||||||
let dup = ty_param(&v);
|
let dup = ty_param(&v);
|
||||||
assert_eq!(v, dup);
|
assert_eq!(v, dup);
|
||||||
|
unsafe {{ setpwent() }};
|
||||||
}}
|
}}
|
||||||
|
|
||||||
pub mod foo {{
|
pub mod foo {{
|
||||||
|
|
|
@ -22,6 +22,7 @@ extern crate stable_mir;
|
||||||
use rustc_hir::def::DefKind;
|
use rustc_hir::def::DefKind;
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_smir::rustc_internal;
|
use rustc_smir::rustc_internal;
|
||||||
|
use stable_mir::ItemKind;
|
||||||
use stable_mir::mir::mono::Instance;
|
use stable_mir::mir::mono::Instance;
|
||||||
use stable_mir::ty::{RigidTy, TyKind};
|
use stable_mir::ty::{RigidTy, TyKind};
|
||||||
use std::assert_matches::assert_matches;
|
use std::assert_matches::assert_matches;
|
||||||
|
@ -120,13 +121,13 @@ fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
|
||||||
|
|
||||||
let monomorphic = get_item(&items, (DefKind::Fn, "monomorphic")).unwrap();
|
let monomorphic = get_item(&items, (DefKind::Fn, "monomorphic")).unwrap();
|
||||||
let instance = Instance::try_from(monomorphic.clone()).unwrap();
|
let instance = Instance::try_from(monomorphic.clone()).unwrap();
|
||||||
for block in instance.body().blocks {
|
for block in instance.body().unwrap().blocks {
|
||||||
match &block.terminator.kind {
|
match &block.terminator.kind {
|
||||||
stable_mir::mir::TerminatorKind::Call { func, .. } => {
|
stable_mir::mir::TerminatorKind::Call { func, .. } => {
|
||||||
let TyKind::RigidTy(ty) = func.ty(&body.locals()).kind() else { unreachable!() };
|
let TyKind::RigidTy(ty) = func.ty(&body.locals()).kind() else { unreachable!() };
|
||||||
let RigidTy::FnDef(def, args) = ty else { unreachable!() };
|
let RigidTy::FnDef(def, args) = ty else { unreachable!() };
|
||||||
let next_func = Instance::resolve(def, &args).unwrap();
|
let next_func = Instance::resolve(def, &args).unwrap();
|
||||||
match next_func.body().locals()[1].ty.kind() {
|
match next_func.body().unwrap().locals()[1].ty.kind() {
|
||||||
TyKind::RigidTy(RigidTy::Uint(_)) | TyKind::RigidTy(RigidTy::Tuple(_)) => {}
|
TyKind::RigidTy(RigidTy::Uint(_)) | TyKind::RigidTy(RigidTy::Tuple(_)) => {}
|
||||||
other => panic!("{other:?}"),
|
other => panic!("{other:?}"),
|
||||||
}
|
}
|
||||||
|
@ -172,7 +173,8 @@ fn get_item<'a>(
|
||||||
item: (DefKind, &str),
|
item: (DefKind, &str),
|
||||||
) -> Option<&'a stable_mir::CrateItem> {
|
) -> Option<&'a stable_mir::CrateItem> {
|
||||||
items.iter().find(|crate_item| {
|
items.iter().find(|crate_item| {
|
||||||
crate_item.kind().to_string() == format!("{:?}", item.0) && crate_item.name() == item.1
|
matches!((item.0, crate_item.kind()), (DefKind::Fn, ItemKind::Fn) | (DefKind::Const,
|
||||||
|
ItemKind::Const)) && crate_item.name() == item.1
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,11 +19,11 @@ extern crate rustc_driver;
|
||||||
extern crate rustc_interface;
|
extern crate rustc_interface;
|
||||||
extern crate stable_mir;
|
extern crate stable_mir;
|
||||||
|
|
||||||
use rustc_hir::def::DefKind;
|
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_smir::rustc_internal;
|
use rustc_smir::rustc_internal;
|
||||||
use stable_mir::mir::{ProjectionElem, Rvalue, StatementKind};
|
use stable_mir::mir::{ProjectionElem, Rvalue, StatementKind};
|
||||||
use stable_mir::ty::{RigidTy, TyKind};
|
use stable_mir::ty::{RigidTy, TyKind};
|
||||||
|
use stable_mir::ItemKind;
|
||||||
use std::assert_matches::assert_matches;
|
use std::assert_matches::assert_matches;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::ops::ControlFlow;
|
use std::ops::ControlFlow;
|
||||||
|
@ -33,7 +33,7 @@ const CRATE_NAME: &str = "input";
|
||||||
/// Tests projections within Place objects
|
/// Tests projections within Place objects
|
||||||
fn test_place_projections(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
|
fn test_place_projections(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
|
||||||
let items = stable_mir::all_local_items();
|
let items = stable_mir::all_local_items();
|
||||||
let body = get_item(&items, (DefKind::Fn, "projections")).unwrap().body();
|
let body = get_item(&items, (ItemKind::Fn, "projections")).unwrap().body();
|
||||||
assert_eq!(body.blocks.len(), 4);
|
assert_eq!(body.blocks.len(), 4);
|
||||||
// The first statement assigns `&s.c` to a local. The projections include a deref for `s`, since
|
// The first statement assigns `&s.c` to a local. The projections include a deref for `s`, since
|
||||||
// `s` is passed as a reference argument, and a field access for field `c`.
|
// `s` is passed as a reference argument, and a field access for field `c`.
|
||||||
|
@ -131,10 +131,10 @@ fn test_place_projections(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
|
||||||
// Use internal API to find a function in a crate.
|
// Use internal API to find a function in a crate.
|
||||||
fn get_item<'a>(
|
fn get_item<'a>(
|
||||||
items: &'a stable_mir::CrateItems,
|
items: &'a stable_mir::CrateItems,
|
||||||
item: (DefKind, &str),
|
item: (ItemKind, &str),
|
||||||
) -> Option<&'a stable_mir::CrateItem> {
|
) -> Option<&'a stable_mir::CrateItem> {
|
||||||
items.iter().find(|crate_item| {
|
items.iter().find(|crate_item| {
|
||||||
crate_item.kind().to_string() == format!("{:?}", item.0) && crate_item.name() == item.1
|
crate_item.kind() == item.0 && crate_item.name() == item.1
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,7 @@ fn test_visitor(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
|
||||||
let exit_fn = main_visitor.calls.last().unwrap();
|
let exit_fn = main_visitor.calls.last().unwrap();
|
||||||
assert!(exit_fn.mangled_name().contains("exit_fn"), "Unexpected last function: {exit_fn:?}");
|
assert!(exit_fn.mangled_name().contains("exit_fn"), "Unexpected last function: {exit_fn:?}");
|
||||||
|
|
||||||
let exit_body = exit_fn.body();
|
let exit_body = exit_fn.body().unwrap();
|
||||||
let exit_visitor = TestVisitor::collect(&exit_body);
|
let exit_visitor = TestVisitor::collect(&exit_body);
|
||||||
assert!(exit_visitor.ret_val.is_some());
|
assert!(exit_visitor.ret_val.is_some());
|
||||||
assert_eq!(exit_visitor.args.len(), 1);
|
assert_eq!(exit_visitor.args.len(), 1);
|
||||||
|
|
|
@ -231,8 +231,7 @@ macro_rules! test_abi_compatible {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compatibility of pointers is probably de-facto guaranteed,
|
// Compatibility of pointers.
|
||||||
// but that does not seem to be documented.
|
|
||||||
test_abi_compatible!(ptr_mut, *const i32, *mut i32);
|
test_abi_compatible!(ptr_mut, *const i32, *mut i32);
|
||||||
test_abi_compatible!(ptr_pointee, *const i32, *const Vec<i32>);
|
test_abi_compatible!(ptr_pointee, *const i32, *const Vec<i32>);
|
||||||
test_abi_compatible!(ref_mut, &i32, &mut i32);
|
test_abi_compatible!(ref_mut, &i32, &mut i32);
|
||||||
|
@ -241,14 +240,15 @@ test_abi_compatible!(box_ptr, Box<i32>, *const i32);
|
||||||
test_abi_compatible!(nonnull_ptr, NonNull<i32>, *const i32);
|
test_abi_compatible!(nonnull_ptr, NonNull<i32>, *const i32);
|
||||||
test_abi_compatible!(fn_fn, fn(), fn(i32) -> i32);
|
test_abi_compatible!(fn_fn, fn(), fn(i32) -> i32);
|
||||||
|
|
||||||
// Some further guarantees we will likely (have to) make.
|
// Compatibility of 1-ZST.
|
||||||
test_abi_compatible!(zst_unit, Zst, ());
|
test_abi_compatible!(zst_unit, Zst, ());
|
||||||
#[cfg(not(any(target_arch = "sparc64")))]
|
#[cfg(not(any(target_arch = "sparc64")))]
|
||||||
test_abi_compatible!(zst_array, Zst, [u8; 0]);
|
test_abi_compatible!(zst_array, Zst, [u8; 0]);
|
||||||
test_abi_compatible!(nonzero_int, NonZeroI32, i32);
|
test_abi_compatible!(nonzero_int, NonZeroI32, i32);
|
||||||
|
|
||||||
// `DispatchFromDyn` relies on ABI compatibility.
|
// `DispatchFromDyn` relies on ABI compatibility.
|
||||||
// This is interesting since these types are not `repr(transparent)`.
|
// This is interesting since these types are not `repr(transparent)`. So this is not part of our
|
||||||
|
// public ABI guarantees, but is relied on by the compiler.
|
||||||
test_abi_compatible!(rc, Rc<i32>, *mut i32);
|
test_abi_compatible!(rc, Rc<i32>, *mut i32);
|
||||||
test_abi_compatible!(arc, Arc<i32>, *mut i32);
|
test_abi_compatible!(arc, Arc<i32>, *mut i32);
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,11 @@ error[E0425]: cannot find value `a` in this scope
|
||||||
|
|
|
|
||||||
LL | [a.., a] => {}
|
LL | [a.., a] => {}
|
||||||
| ^ not found in this scope
|
| ^ not found in this scope
|
||||||
|
|
|
||||||
|
help: if you meant to collect the rest of the slice in `a`, use the at operator
|
||||||
|
|
|
||||||
|
LL | [a @ .., a] => {}
|
||||||
|
| +
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
fn main() {
|
||||||
|
match &[1, 2, 3][..] {
|
||||||
|
[1, rest..] => println!("{rest:?}"),
|
||||||
|
//~^ ERROR cannot find value `rest` in this scope
|
||||||
|
//~| ERROR cannot find value `rest` in this scope
|
||||||
|
//~| ERROR `X..` patterns in slices are experimental
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
error[E0425]: cannot find value `rest` in this scope
|
||||||
|
--> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:3:13
|
||||||
|
|
|
||||||
|
LL | [1, rest..] => println!("{rest:?}"),
|
||||||
|
| ^^^^ not found in this scope
|
||||||
|
|
|
||||||
|
help: if you meant to collect the rest of the slice in `rest`, use the at operator
|
||||||
|
|
|
||||||
|
LL | [1, rest @ ..] => println!("{rest:?}"),
|
||||||
|
| +
|
||||||
|
|
||||||
|
error[E0425]: cannot find value `rest` in this scope
|
||||||
|
--> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:3:35
|
||||||
|
|
|
||||||
|
LL | [1, rest..] => println!("{rest:?}"),
|
||||||
|
| ^^^^ not found in this scope
|
||||||
|
|
||||||
|
error[E0658]: `X..` patterns in slices are experimental
|
||||||
|
--> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:3:13
|
||||||
|
|
|
||||||
|
LL | [1, rest..] => println!("{rest:?}"),
|
||||||
|
| ^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #67264 <https://github.com/rust-lang/rust/issues/67264> for more information
|
||||||
|
= help: add `#![feature(half_open_range_patterns_in_slices)]` to the crate attributes to enable
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0425, E0658.
|
||||||
|
For more information about an error, try `rustc --explain E0425`.
|
|
@ -3,6 +3,11 @@ error[E0425]: cannot find value `_y` in this scope
|
||||||
|
|
|
|
||||||
LL | let [_y..] = [Box::new(1), Box::new(2)];
|
LL | let [_y..] = [Box::new(1), Box::new(2)];
|
||||||
| ^^ not found in this scope
|
| ^^ not found in this scope
|
||||||
|
|
|
||||||
|
help: if you meant to collect the rest of the slice in `_y`, use the at operator
|
||||||
|
|
|
||||||
|
LL | let [_y @ ..] = [Box::new(1), Box::new(2)];
|
||||||
|
| +
|
||||||
|
|
||||||
error[E0658]: `X..` patterns in slices are experimental
|
error[E0658]: `X..` patterns in slices are experimental
|
||||||
--> $DIR/issue-105946.rs:6:10
|
--> $DIR/issue-105946.rs:6:10
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue