Rollup merge of #118694 - celinval:smir-alloc-methods, r=ouz-a
Add instance evaluation and methods to read an allocation in StableMIR The instance evaluation is needed to handle intrinsics such as `type_id` and `type_name`. Since we now use Allocation to represent all evaluated constants, provide a few methods to help process the data inside an allocation. I've also started to add a structured way to get information about the compilation target machine. For now, I've only added information needed to process an allocation. r? ``````@ouz-a``````
This commit is contained in:
commit
1889e5a00b
15 changed files with 458 additions and 29 deletions
|
@ -4494,6 +4494,7 @@ dependencies = [
|
||||||
name = "rustc_smir"
|
name = "rustc_smir"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"rustc_abi",
|
||||||
"rustc_data_structures",
|
"rustc_data_structures",
|
||||||
"rustc_hir",
|
"rustc_hir",
|
||||||
"rustc_middle",
|
"rustc_middle",
|
||||||
|
|
|
@ -5,6 +5,7 @@ edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# tidy-alphabetical-start
|
# tidy-alphabetical-start
|
||||||
|
rustc_abi = { path = "../rustc_abi" }
|
||||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||||
rustc_hir = { path = "../rustc_hir" }
|
rustc_hir = { path = "../rustc_hir" }
|
||||||
rustc_middle = { path = "../rustc_middle" }
|
rustc_middle = { path = "../rustc_middle" }
|
||||||
|
|
|
@ -2,6 +2,7 @@ use rustc_middle::mir::{
|
||||||
interpret::{alloc_range, AllocRange, Pointer},
|
interpret::{alloc_range, AllocRange, Pointer},
|
||||||
ConstValue,
|
ConstValue,
|
||||||
};
|
};
|
||||||
|
use stable_mir::Error;
|
||||||
|
|
||||||
use crate::rustc_smir::{Stable, Tables};
|
use crate::rustc_smir::{Stable, Tables};
|
||||||
use stable_mir::mir::Mutability;
|
use stable_mir::mir::Mutability;
|
||||||
|
@ -26,23 +27,35 @@ pub fn new_allocation<'tcx>(
|
||||||
const_value: ConstValue<'tcx>,
|
const_value: ConstValue<'tcx>,
|
||||||
tables: &mut Tables<'tcx>,
|
tables: &mut Tables<'tcx>,
|
||||||
) -> Allocation {
|
) -> Allocation {
|
||||||
match const_value {
|
try_new_allocation(ty, const_value, tables).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(rustc::usage_of_qualified_ty)]
|
||||||
|
pub fn try_new_allocation<'tcx>(
|
||||||
|
ty: rustc_middle::ty::Ty<'tcx>,
|
||||||
|
const_value: ConstValue<'tcx>,
|
||||||
|
tables: &mut Tables<'tcx>,
|
||||||
|
) -> Result<Allocation, Error> {
|
||||||
|
Ok(match const_value {
|
||||||
ConstValue::Scalar(scalar) => {
|
ConstValue::Scalar(scalar) => {
|
||||||
let size = scalar.size();
|
let size = scalar.size();
|
||||||
let align = tables
|
let align = tables
|
||||||
.tcx
|
.tcx
|
||||||
.layout_of(rustc_middle::ty::ParamEnv::reveal_all().and(ty))
|
.layout_of(rustc_middle::ty::ParamEnv::reveal_all().and(ty))
|
||||||
.unwrap()
|
.map_err(|e| e.stable(tables))?
|
||||||
.align;
|
.align;
|
||||||
let mut allocation = rustc_middle::mir::interpret::Allocation::uninit(size, align.abi);
|
let mut allocation = rustc_middle::mir::interpret::Allocation::uninit(size, align.abi);
|
||||||
allocation
|
allocation
|
||||||
.write_scalar(&tables.tcx, alloc_range(rustc_target::abi::Size::ZERO, size), scalar)
|
.write_scalar(&tables.tcx, alloc_range(rustc_target::abi::Size::ZERO, size), scalar)
|
||||||
.unwrap();
|
.map_err(|e| e.stable(tables))?;
|
||||||
allocation.stable(tables)
|
allocation.stable(tables)
|
||||||
}
|
}
|
||||||
ConstValue::ZeroSized => {
|
ConstValue::ZeroSized => {
|
||||||
let align =
|
let align = tables
|
||||||
tables.tcx.layout_of(rustc_middle::ty::ParamEnv::empty().and(ty)).unwrap().align;
|
.tcx
|
||||||
|
.layout_of(rustc_middle::ty::ParamEnv::empty().and(ty))
|
||||||
|
.map_err(|e| e.stable(tables))?
|
||||||
|
.align;
|
||||||
new_empty_allocation(align.abi)
|
new_empty_allocation(align.abi)
|
||||||
}
|
}
|
||||||
ConstValue::Slice { data, meta } => {
|
ConstValue::Slice { data, meta } => {
|
||||||
|
@ -51,8 +64,10 @@ pub fn new_allocation<'tcx>(
|
||||||
let scalar_ptr = rustc_middle::mir::interpret::Scalar::from_pointer(ptr, &tables.tcx);
|
let scalar_ptr = rustc_middle::mir::interpret::Scalar::from_pointer(ptr, &tables.tcx);
|
||||||
let scalar_meta =
|
let scalar_meta =
|
||||||
rustc_middle::mir::interpret::Scalar::from_target_usize(meta, &tables.tcx);
|
rustc_middle::mir::interpret::Scalar::from_target_usize(meta, &tables.tcx);
|
||||||
let layout =
|
let layout = tables
|
||||||
tables.tcx.layout_of(rustc_middle::ty::ParamEnv::reveal_all().and(ty)).unwrap();
|
.tcx
|
||||||
|
.layout_of(rustc_middle::ty::ParamEnv::reveal_all().and(ty))
|
||||||
|
.map_err(|e| e.stable(tables))?;
|
||||||
let mut allocation =
|
let mut allocation =
|
||||||
rustc_middle::mir::interpret::Allocation::uninit(layout.size, layout.align.abi);
|
rustc_middle::mir::interpret::Allocation::uninit(layout.size, layout.align.abi);
|
||||||
allocation
|
allocation
|
||||||
|
@ -61,14 +76,14 @@ pub fn new_allocation<'tcx>(
|
||||||
alloc_range(rustc_target::abi::Size::ZERO, tables.tcx.data_layout.pointer_size),
|
alloc_range(rustc_target::abi::Size::ZERO, tables.tcx.data_layout.pointer_size),
|
||||||
scalar_ptr,
|
scalar_ptr,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.map_err(|e| e.stable(tables))?;
|
||||||
allocation
|
allocation
|
||||||
.write_scalar(
|
.write_scalar(
|
||||||
&tables.tcx,
|
&tables.tcx,
|
||||||
alloc_range(tables.tcx.data_layout.pointer_size, scalar_meta.size()),
|
alloc_range(tables.tcx.data_layout.pointer_size, scalar_meta.size()),
|
||||||
scalar_meta,
|
scalar_meta,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.map_err(|e| e.stable(tables))?;
|
||||||
allocation.stable(tables)
|
allocation.stable(tables)
|
||||||
}
|
}
|
||||||
ConstValue::Indirect { alloc_id, offset } => {
|
ConstValue::Indirect { alloc_id, offset } => {
|
||||||
|
@ -76,11 +91,11 @@ pub fn new_allocation<'tcx>(
|
||||||
let ty_size = tables
|
let ty_size = tables
|
||||||
.tcx
|
.tcx
|
||||||
.layout_of(rustc_middle::ty::ParamEnv::reveal_all().and(ty))
|
.layout_of(rustc_middle::ty::ParamEnv::reveal_all().and(ty))
|
||||||
.unwrap()
|
.map_err(|e| e.stable(tables))?
|
||||||
.size;
|
.size;
|
||||||
allocation_filter(&alloc.0, alloc_range(offset, ty_size), tables)
|
allocation_filter(&alloc.0, alloc_range(offset, ty_size), tables)
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an `Allocation` only from information within the `AllocRange`.
|
/// Creates an `Allocation` only from information within the `AllocRange`.
|
||||||
|
|
|
@ -11,18 +11,29 @@ use stable_mir::compiler_interface::Context;
|
||||||
use stable_mir::mir::alloc::GlobalAlloc;
|
use stable_mir::mir::alloc::GlobalAlloc;
|
||||||
use stable_mir::mir::mono::{InstanceDef, StaticDef};
|
use stable_mir::mir::mono::{InstanceDef, StaticDef};
|
||||||
use stable_mir::mir::Body;
|
use stable_mir::mir::Body;
|
||||||
|
use stable_mir::target::{MachineInfo, MachineSize};
|
||||||
use stable_mir::ty::{
|
use stable_mir::ty::{
|
||||||
AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, GenericArgs,
|
AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, GenericArgs,
|
||||||
LineInfo, PolyFnSig, RigidTy, Span, TyKind, VariantDef,
|
LineInfo, PolyFnSig, RigidTy, Span, Ty, TyKind, VariantDef,
|
||||||
};
|
};
|
||||||
use stable_mir::{self, Crate, CrateItem, DefId, Error, Filename, ItemKind, Symbol};
|
use stable_mir::{self, Crate, CrateItem, DefId, Error, Filename, ItemKind, Symbol};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
|
||||||
use crate::rustc_internal::{internal, RustcInternal};
|
use crate::rustc_internal::{internal, RustcInternal};
|
||||||
use crate::rustc_smir::builder::BodyBuilder;
|
use crate::rustc_smir::builder::BodyBuilder;
|
||||||
use crate::rustc_smir::{new_item_kind, smir_crate, Stable, Tables};
|
use crate::rustc_smir::{alloc, new_item_kind, smir_crate, Stable, Tables};
|
||||||
|
|
||||||
impl<'tcx> Context for TablesWrapper<'tcx> {
|
impl<'tcx> Context for TablesWrapper<'tcx> {
|
||||||
|
fn target_info(&self) -> MachineInfo {
|
||||||
|
let mut tables = self.0.borrow_mut();
|
||||||
|
MachineInfo {
|
||||||
|
endian: tables.tcx.data_layout.endian.stable(&mut *tables),
|
||||||
|
pointer_width: MachineSize::from_bits(
|
||||||
|
tables.tcx.data_layout.pointer_size.bits().try_into().unwrap(),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn entry_fn(&self) -> Option<stable_mir::CrateItem> {
|
fn entry_fn(&self) -> Option<stable_mir::CrateItem> {
|
||||||
let mut tables = self.0.borrow_mut();
|
let mut tables = self.0.borrow_mut();
|
||||||
let tcx = tables.tcx;
|
let tcx = tables.tcx;
|
||||||
|
@ -382,6 +393,21 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
||||||
Instance::resolve_closure(tables.tcx, def_id, args_ref, closure_kind).stable(&mut *tables)
|
Instance::resolve_closure(tables.tcx, def_id, args_ref, closure_kind).stable(&mut *tables)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn eval_instance(&self, def: InstanceDef, const_ty: Ty) -> Result<Allocation, Error> {
|
||||||
|
let mut tables = self.0.borrow_mut();
|
||||||
|
let instance = tables.instances[def];
|
||||||
|
let result = tables.tcx.const_eval_instance(
|
||||||
|
ParamEnv::reveal_all(),
|
||||||
|
instance,
|
||||||
|
Some(tables.tcx.def_span(instance.def_id())),
|
||||||
|
);
|
||||||
|
result
|
||||||
|
.map(|const_val| {
|
||||||
|
alloc::try_new_allocation(const_ty.internal(&mut *tables), const_val, &mut *tables)
|
||||||
|
})
|
||||||
|
.map_err(|e| e.stable(&mut *tables))?
|
||||||
|
}
|
||||||
|
|
||||||
fn eval_static_initializer(&self, def: StaticDef) -> Result<Allocation, Error> {
|
fn eval_static_initializer(&self, def: StaticDef) -> Result<Allocation, Error> {
|
||||||
let mut tables = self.0.borrow_mut();
|
let mut tables = self.0.borrow_mut();
|
||||||
let def_id = def.0.internal(&mut *tables);
|
let def_id = def.0.internal(&mut *tables);
|
||||||
|
|
22
compiler/rustc_smir/src/rustc_smir/convert/error.rs
Normal file
22
compiler/rustc_smir/src/rustc_smir/convert/error.rs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
//! Handle the conversion of different internal errors into a stable version.
|
||||||
|
//!
|
||||||
|
//! Currently we encode everything as [stable_mir::Error], which is represented as a string.
|
||||||
|
use crate::rustc_smir::{Stable, Tables};
|
||||||
|
use rustc_middle::mir::interpret::AllocError;
|
||||||
|
use rustc_middle::ty::layout::LayoutError;
|
||||||
|
|
||||||
|
impl<'tcx> Stable<'tcx> for LayoutError<'tcx> {
|
||||||
|
type T = stable_mir::Error;
|
||||||
|
|
||||||
|
fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
|
||||||
|
stable_mir::Error::new(format!("{self:?}"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> Stable<'tcx> for AllocError {
|
||||||
|
type T = stable_mir::Error;
|
||||||
|
|
||||||
|
fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
|
||||||
|
stable_mir::Error::new(format!("{self:?}"))
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,6 +5,7 @@ use stable_mir::ty::{IndexedVal, VariantIdx};
|
||||||
|
|
||||||
use crate::rustc_smir::{Stable, Tables};
|
use crate::rustc_smir::{Stable, Tables};
|
||||||
|
|
||||||
|
mod error;
|
||||||
mod mir;
|
mod mir;
|
||||||
mod ty;
|
mod ty;
|
||||||
|
|
||||||
|
@ -76,3 +77,14 @@ impl<'tcx> Stable<'tcx> for rustc_span::Span {
|
||||||
tables.create_span(*self)
|
tables.create_span(*self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'tcx> Stable<'tcx> for rustc_abi::Endian {
|
||||||
|
type T = stable_mir::target::Endian;
|
||||||
|
|
||||||
|
fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
|
||||||
|
match self {
|
||||||
|
rustc_abi::Endian::Little => stable_mir::target::Endian::Little,
|
||||||
|
rustc_abi::Endian::Big => stable_mir::target::Endian::Big,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ use std::cell::Cell;
|
||||||
use crate::mir::alloc::{AllocId, GlobalAlloc};
|
use crate::mir::alloc::{AllocId, GlobalAlloc};
|
||||||
use crate::mir::mono::{Instance, InstanceDef, StaticDef};
|
use crate::mir::mono::{Instance, InstanceDef, StaticDef};
|
||||||
use crate::mir::Body;
|
use crate::mir::Body;
|
||||||
|
use crate::target::MachineInfo;
|
||||||
use crate::ty::{
|
use crate::ty::{
|
||||||
AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, GenericArgs,
|
AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, GenericArgs,
|
||||||
GenericPredicates, Generics, ImplDef, ImplTrait, LineInfo, PolyFnSig, RigidTy, Span, TraitDecl,
|
GenericPredicates, Generics, ImplDef, ImplTrait, LineInfo, PolyFnSig, RigidTy, Span, TraitDecl,
|
||||||
|
@ -150,6 +151,9 @@ pub trait Context {
|
||||||
/// Evaluate a static's initializer.
|
/// Evaluate a static's initializer.
|
||||||
fn eval_static_initializer(&self, def: StaticDef) -> Result<Allocation, Error>;
|
fn eval_static_initializer(&self, def: StaticDef) -> Result<Allocation, Error>;
|
||||||
|
|
||||||
|
/// Try to evaluate an instance into a constant.
|
||||||
|
fn eval_instance(&self, def: InstanceDef, const_ty: Ty) -> Result<Allocation, Error>;
|
||||||
|
|
||||||
/// Retrieve global allocation for the given allocation ID.
|
/// Retrieve global allocation for the given allocation ID.
|
||||||
fn global_alloc(&self, id: AllocId) -> GlobalAlloc;
|
fn global_alloc(&self, id: AllocId) -> GlobalAlloc;
|
||||||
|
|
||||||
|
@ -157,6 +161,9 @@ pub trait Context {
|
||||||
fn vtable_allocation(&self, global_alloc: &GlobalAlloc) -> Option<AllocId>;
|
fn vtable_allocation(&self, global_alloc: &GlobalAlloc) -> Option<AllocId>;
|
||||||
fn krate(&self, def_id: DefId) -> Crate;
|
fn krate(&self, def_id: DefId) -> Crate;
|
||||||
fn instance_name(&self, def: InstanceDef, trimmed: bool) -> Symbol;
|
fn instance_name(&self, def: InstanceDef, trimmed: bool) -> Symbol;
|
||||||
|
|
||||||
|
/// Return information about the target machine.
|
||||||
|
fn target_info(&self) -> MachineInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
|
|
|
@ -6,11 +6,11 @@
|
||||||
|
|
||||||
use std::convert::From;
|
use std::convert::From;
|
||||||
use std::fmt::{Debug, Display, Formatter};
|
use std::fmt::{Debug, Display, Formatter};
|
||||||
use std::{error, fmt};
|
use std::{error, fmt, io};
|
||||||
|
|
||||||
macro_rules! error {
|
macro_rules! error {
|
||||||
($fmt: literal $(,)?) => { Error(format!($fmt)) };
|
($fmt: literal $(,)?) => { Error(format!($fmt)) };
|
||||||
($fmt: literal, $($arg:tt)*) => { Error(format!($fmt, $($arg:tt)*)) };
|
($fmt: literal, $($arg:tt)*) => { Error(format!($fmt, $($arg)*)) };
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An error type used to represent an error that has already been reported by the compiler.
|
/// An error type used to represent an error that has already been reported by the compiler.
|
||||||
|
@ -79,3 +79,9 @@ where
|
||||||
|
|
||||||
impl error::Error for Error {}
|
impl error::Error for Error {}
|
||||||
impl<T> error::Error for CompilerError<T> where T: Display + Debug {}
|
impl<T> error::Error for CompilerError<T> where T: Display + Debug {}
|
||||||
|
|
||||||
|
impl From<io::Error> for Error {
|
||||||
|
fn from(value: io::Error) -> Self {
|
||||||
|
Error(value.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@ pub mod compiler_interface;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod mir;
|
pub mod mir;
|
||||||
|
pub mod target;
|
||||||
pub mod ty;
|
pub mod ty;
|
||||||
pub mod visitor;
|
pub mod visitor;
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
//! This module provides methods to retrieve allocation information, such as static variables.
|
//! This module provides methods to retrieve allocation information, such as static variables.
|
||||||
use crate::mir::mono::{Instance, StaticDef};
|
use crate::mir::mono::{Instance, StaticDef};
|
||||||
|
use crate::target::{Endian, MachineInfo};
|
||||||
use crate::ty::{Allocation, Binder, ExistentialTraitRef, IndexedVal, Ty};
|
use crate::ty::{Allocation, Binder, ExistentialTraitRef, IndexedVal, Ty};
|
||||||
use crate::with;
|
use crate::{with, Error};
|
||||||
|
use std::io::Read;
|
||||||
|
|
||||||
/// An allocation in the SMIR global memory can be either a function pointer,
|
/// An allocation in the SMIR global memory can be either a function pointer,
|
||||||
/// a static, or a "real" allocation with some data in it.
|
/// a static, or a "real" allocation with some data in it.
|
||||||
|
@ -38,7 +40,7 @@ impl GlobalAlloc {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A unique identification number for each provenance
|
/// A unique identification number for each provenance
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
|
||||||
pub struct AllocId(usize);
|
pub struct AllocId(usize);
|
||||||
|
|
||||||
impl IndexedVal for AllocId {
|
impl IndexedVal for AllocId {
|
||||||
|
@ -49,3 +51,33 @@ impl IndexedVal for AllocId {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Utility function used to read an allocation data into a unassigned integer.
|
||||||
|
pub(crate) fn read_target_uint(mut bytes: &[u8]) -> Result<u128, Error> {
|
||||||
|
let mut buf = [0u8; std::mem::size_of::<u128>()];
|
||||||
|
match MachineInfo::target_endianess() {
|
||||||
|
Endian::Little => {
|
||||||
|
bytes.read(&mut buf)?;
|
||||||
|
Ok(u128::from_le_bytes(buf))
|
||||||
|
}
|
||||||
|
Endian::Big => {
|
||||||
|
bytes.read(&mut buf[16 - bytes.len()..])?;
|
||||||
|
Ok(u128::from_be_bytes(buf))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Utility function used to read an allocation data into an assigned integer.
|
||||||
|
pub(crate) fn read_target_int(mut bytes: &[u8]) -> Result<i128, Error> {
|
||||||
|
let mut buf = [0u8; std::mem::size_of::<i128>()];
|
||||||
|
match MachineInfo::target_endianess() {
|
||||||
|
Endian::Little => {
|
||||||
|
bytes.read(&mut buf)?;
|
||||||
|
Ok(i128::from_le_bytes(buf))
|
||||||
|
}
|
||||||
|
Endian::Big => {
|
||||||
|
bytes.read(&mut buf[16 - bytes.len()..])?;
|
||||||
|
Ok(i128::from_be_bytes(buf))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ pub struct Body {
|
||||||
pub(super) arg_count: usize,
|
pub(super) arg_count: usize,
|
||||||
|
|
||||||
/// Debug information pertaining to user variables, including captures.
|
/// Debug information pertaining to user variables, including captures.
|
||||||
pub(super) var_debug_info: Vec<VarDebugInfo>,
|
pub var_debug_info: Vec<VarDebugInfo>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type BasicBlockIdx = usize;
|
pub type BasicBlockIdx = usize;
|
||||||
|
@ -616,6 +616,24 @@ pub struct VarDebugInfo {
|
||||||
pub argument_index: Option<u16>,
|
pub argument_index: Option<u16>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl VarDebugInfo {
|
||||||
|
/// Return a local variable if this info is related to one.
|
||||||
|
pub fn local(&self) -> Option<Local> {
|
||||||
|
match &self.value {
|
||||||
|
VarDebugInfoContents::Place(place) if place.projection.is_empty() => Some(place.local),
|
||||||
|
VarDebugInfoContents::Place(_) | VarDebugInfoContents::Const(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return a constant if this info is related to one.
|
||||||
|
pub fn constant(&self) -> Option<&ConstOperand> {
|
||||||
|
match &self.value {
|
||||||
|
VarDebugInfoContents::Place(_) => None,
|
||||||
|
VarDebugInfoContents::Const(const_op) => Some(const_op),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub type SourceScope = u32;
|
pub type SourceScope = u32;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
|
@ -832,7 +850,7 @@ pub enum MutBorrowKind {
|
||||||
ClosureCapture,
|
ClosureCapture,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub enum Mutability {
|
pub enum Mutability {
|
||||||
Not,
|
Not,
|
||||||
Mut,
|
Mut,
|
||||||
|
|
|
@ -132,6 +132,14 @@ impl Instance {
|
||||||
pub fn is_empty_shim(&self) -> bool {
|
pub fn is_empty_shim(&self) -> bool {
|
||||||
self.kind == InstanceKind::Shim && with(|cx| cx.is_empty_drop_shim(self.def))
|
self.kind == InstanceKind::Shim && with(|cx| cx.is_empty_drop_shim(self.def))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Try to constant evaluate the instance into a constant with the given type.
|
||||||
|
///
|
||||||
|
/// This can be used to retrieve a constant that represents an intrinsic return such as
|
||||||
|
/// `type_id`.
|
||||||
|
pub fn try_const_eval(&self, const_ty: Ty) -> Result<Allocation, Error> {
|
||||||
|
with(|cx| cx.eval_instance(self.def, const_ty))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Instance {
|
impl Debug for Instance {
|
||||||
|
@ -212,7 +220,7 @@ impl TryFrom<CrateItem> for StaticDef {
|
||||||
type Error = crate::Error;
|
type Error = crate::Error;
|
||||||
|
|
||||||
fn try_from(value: CrateItem) -> Result<Self, Self::Error> {
|
fn try_from(value: CrateItem) -> Result<Self, Self::Error> {
|
||||||
if matches!(value.kind(), ItemKind::Static | ItemKind::Const) {
|
if matches!(value.kind(), ItemKind::Static) {
|
||||||
Ok(StaticDef(value.0))
|
Ok(StaticDef(value.0))
|
||||||
} else {
|
} else {
|
||||||
Err(Error::new(format!("Expected a static item, but found: {value:?}")))
|
Err(Error::new(format!("Expected a static item, but found: {value:?}")))
|
||||||
|
|
50
compiler/stable_mir/src/target.rs
Normal file
50
compiler/stable_mir/src/target.rs
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
//! Provide information about the machine that this is being compiled into.
|
||||||
|
|
||||||
|
use crate::compiler_interface::with;
|
||||||
|
|
||||||
|
/// The properties of the target machine being compiled into.
|
||||||
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
|
pub struct MachineInfo {
|
||||||
|
pub endian: Endian,
|
||||||
|
pub pointer_width: MachineSize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MachineInfo {
|
||||||
|
pub fn target() -> MachineInfo {
|
||||||
|
with(|cx| cx.target_info().clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn target_endianess() -> Endian {
|
||||||
|
with(|cx| cx.target_info().endian)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn target_pointer_width() -> MachineSize {
|
||||||
|
with(|cx| cx.target_info().pointer_width)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||||
|
pub enum Endian {
|
||||||
|
Little,
|
||||||
|
Big,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Represent the size of a component.
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub struct MachineSize {
|
||||||
|
num_bits: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MachineSize {
|
||||||
|
pub fn bytes(self) -> usize {
|
||||||
|
self.num_bits / 8
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bits(self) -> usize {
|
||||||
|
self.num_bits
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_bits(num_bits: usize) -> MachineSize {
|
||||||
|
MachineSize { num_bits }
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,9 +4,11 @@ use super::{
|
||||||
with, DefId, Error, Symbol,
|
with, DefId, Error, Symbol,
|
||||||
};
|
};
|
||||||
use crate::crate_def::CrateDef;
|
use crate::crate_def::CrateDef;
|
||||||
use crate::mir::alloc::AllocId;
|
use crate::mir::alloc::{read_target_int, read_target_uint, AllocId};
|
||||||
|
use crate::target::MachineInfo;
|
||||||
use crate::{Filename, Opaque};
|
use crate::{Filename, Opaque};
|
||||||
use std::fmt::{self, Debug, Display, Formatter};
|
use std::fmt::{self, Debug, Display, Formatter};
|
||||||
|
use std::ops::Range;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
|
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
|
||||||
pub struct Ty(pub usize);
|
pub struct Ty(pub usize);
|
||||||
|
@ -366,6 +368,19 @@ pub enum IntTy {
|
||||||
I128,
|
I128,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl IntTy {
|
||||||
|
pub fn num_bytes(self) -> usize {
|
||||||
|
match self {
|
||||||
|
IntTy::Isize => crate::target::MachineInfo::target_pointer_width().bytes().into(),
|
||||||
|
IntTy::I8 => 1,
|
||||||
|
IntTy::I16 => 2,
|
||||||
|
IntTy::I32 => 4,
|
||||||
|
IntTy::I64 => 8,
|
||||||
|
IntTy::I128 => 16,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
pub enum UintTy {
|
pub enum UintTy {
|
||||||
Usize,
|
Usize,
|
||||||
|
@ -376,6 +391,19 @@ pub enum UintTy {
|
||||||
U128,
|
U128,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl UintTy {
|
||||||
|
pub fn num_bytes(self) -> usize {
|
||||||
|
match self {
|
||||||
|
UintTy::Usize => crate::target::MachineInfo::target_pointer_width().bytes().into(),
|
||||||
|
UintTy::U8 => 1,
|
||||||
|
UintTy::U16 => 2,
|
||||||
|
UintTy::U32 => 4,
|
||||||
|
UintTy::U64 => 8,
|
||||||
|
UintTy::U128 => 16,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
pub enum FloatTy {
|
pub enum FloatTy {
|
||||||
F32,
|
F32,
|
||||||
|
@ -821,21 +849,21 @@ pub struct BoundTy {
|
||||||
pub type Bytes = Vec<Option<u8>>;
|
pub type Bytes = Vec<Option<u8>>;
|
||||||
pub type Size = usize;
|
pub type Size = usize;
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
|
||||||
pub struct Prov(pub AllocId);
|
pub struct Prov(pub AllocId);
|
||||||
pub type Align = u64;
|
pub type Align = u64;
|
||||||
pub type Promoted = u32;
|
pub type Promoted = u32;
|
||||||
pub type InitMaskMaterialized = Vec<u64>;
|
pub type InitMaskMaterialized = Vec<u64>;
|
||||||
|
|
||||||
/// Stores the provenance information of pointers stored in memory.
|
/// Stores the provenance information of pointers stored in memory.
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
|
||||||
pub struct ProvenanceMap {
|
pub struct ProvenanceMap {
|
||||||
/// Provenance in this map applies from the given offset for an entire pointer-size worth of
|
/// Provenance in this map applies from the given offset for an entire pointer-size worth of
|
||||||
/// bytes. Two entries in this map are always at least a pointer size apart.
|
/// bytes. Two entries in this map are always at least a pointer size apart.
|
||||||
pub ptrs: Vec<(Size, Prov)>,
|
pub ptrs: Vec<(Size, Prov)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
|
||||||
pub struct Allocation {
|
pub struct Allocation {
|
||||||
pub bytes: Bytes,
|
pub bytes: Bytes,
|
||||||
pub provenance: ProvenanceMap,
|
pub provenance: ProvenanceMap,
|
||||||
|
@ -843,6 +871,74 @@ pub struct Allocation {
|
||||||
pub mutability: Mutability,
|
pub mutability: Mutability,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Allocation {
|
||||||
|
/// Get a vector of bytes for an Allocation that has been fully initialized
|
||||||
|
pub fn raw_bytes(&self) -> Result<Vec<u8>, Error> {
|
||||||
|
self.bytes
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.collect::<Option<Vec<_>>>()
|
||||||
|
.ok_or_else(|| error!("Found uninitialized bytes: `{:?}`", self.bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read a uint value from the specified range.
|
||||||
|
pub fn read_partial_uint(&self, range: Range<usize>) -> Result<u128, Error> {
|
||||||
|
if range.end - range.start > 16 {
|
||||||
|
return Err(error!("Allocation is bigger than largest integer"));
|
||||||
|
}
|
||||||
|
if range.end > self.bytes.len() {
|
||||||
|
return Err(error!(
|
||||||
|
"Range is out of bounds. Allocation length is `{}`, but requested range `{:?}`",
|
||||||
|
self.bytes.len(),
|
||||||
|
range
|
||||||
|
));
|
||||||
|
}
|
||||||
|
let raw = self.bytes[range]
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.collect::<Option<Vec<_>>>()
|
||||||
|
.ok_or_else(|| error!("Found uninitialized bytes: `{:?}`", self.bytes))?;
|
||||||
|
read_target_uint(&raw)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read this allocation and try to convert it to an unassigned integer.
|
||||||
|
pub fn read_uint(&self) -> Result<u128, Error> {
|
||||||
|
if self.bytes.len() > 16 {
|
||||||
|
return Err(error!("Allocation is bigger than largest integer"));
|
||||||
|
}
|
||||||
|
let raw = self.raw_bytes()?;
|
||||||
|
read_target_uint(&raw)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read this allocation and try to convert it to a signed integer.
|
||||||
|
pub fn read_int(&self) -> Result<i128, Error> {
|
||||||
|
if self.bytes.len() > 16 {
|
||||||
|
return Err(error!("Allocation is bigger than largest integer"));
|
||||||
|
}
|
||||||
|
let raw = self.raw_bytes()?;
|
||||||
|
read_target_int(&raw)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read this allocation and try to convert it to a boolean.
|
||||||
|
pub fn read_bool(&self) -> Result<bool, Error> {
|
||||||
|
match self.read_int()? {
|
||||||
|
0 => Ok(false),
|
||||||
|
1 => Ok(true),
|
||||||
|
val @ _ => Err(error!("Unexpected value for bool: `{val}`")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read this allocation as a pointer and return whether it represents a `null` pointer.
|
||||||
|
pub fn is_null(&self) -> Result<bool, Error> {
|
||||||
|
let len = self.bytes.len();
|
||||||
|
let ptr_len = MachineInfo::target_pointer_width().bytes();
|
||||||
|
if len != ptr_len {
|
||||||
|
return Err(error!("Expected width of pointer (`{ptr_len}`), but found: `{len}`"));
|
||||||
|
}
|
||||||
|
Ok(self.read_uint()? == 0 && self.provenance.ptrs.is_empty())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub enum ConstantKind {
|
pub enum ConstantKind {
|
||||||
Allocated(Allocation),
|
Allocated(Allocation),
|
||||||
|
|
|
@ -23,12 +23,16 @@ extern crate stable_mir;
|
||||||
|
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_smir::rustc_internal;
|
use rustc_smir::rustc_internal;
|
||||||
use stable_mir::{CrateItem, CrateItems, ItemKind};
|
|
||||||
use stable_mir::crate_def::CrateDef;
|
use stable_mir::crate_def::CrateDef;
|
||||||
use stable_mir::mir::alloc::GlobalAlloc;
|
use stable_mir::mir::alloc::GlobalAlloc;
|
||||||
use stable_mir::mir::mono::StaticDef;
|
use stable_mir::mir::mono::{Instance, InstanceKind, StaticDef};
|
||||||
|
use stable_mir::mir::{Body, TerminatorKind};
|
||||||
|
use stable_mir::ty::{Allocation, ConstantKind, RigidTy, TyKind};
|
||||||
|
use stable_mir::{CrateItem, CrateItems, ItemKind};
|
||||||
use std::ascii::Char;
|
use std::ascii::Char;
|
||||||
use std::assert_matches::assert_matches;
|
use std::assert_matches::assert_matches;
|
||||||
|
use std::cmp::{max, min};
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::ops::ControlFlow;
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
|
@ -40,6 +44,9 @@ fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
|
||||||
let items = stable_mir::all_local_items();
|
let items = stable_mir::all_local_items();
|
||||||
check_foo(*get_item(&items, (ItemKind::Static, "FOO")).unwrap());
|
check_foo(*get_item(&items, (ItemKind::Static, "FOO")).unwrap());
|
||||||
check_bar(*get_item(&items, (ItemKind::Static, "BAR")).unwrap());
|
check_bar(*get_item(&items, (ItemKind::Static, "BAR")).unwrap());
|
||||||
|
check_len(*get_item(&items, (ItemKind::Static, "LEN")).unwrap());
|
||||||
|
check_other_consts(*get_item(&items, (ItemKind::Fn, "other_consts")).unwrap());
|
||||||
|
check_type_id(*get_item(&items, (ItemKind::Fn, "check_type_id")).unwrap());
|
||||||
ControlFlow::Continue(())
|
ControlFlow::Continue(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,6 +83,110 @@ fn check_bar(item: CrateItem) {
|
||||||
assert_eq!(allocation.bytes[0].unwrap(), Char::CapitalB.to_u8());
|
assert_eq!(allocation.bytes[0].unwrap(), Char::CapitalB.to_u8());
|
||||||
assert_eq!(allocation.bytes[1].unwrap(), Char::SmallA.to_u8());
|
assert_eq!(allocation.bytes[1].unwrap(), Char::SmallA.to_u8());
|
||||||
assert_eq!(allocation.bytes[2].unwrap(), Char::SmallR.to_u8());
|
assert_eq!(allocation.bytes[2].unwrap(), Char::SmallR.to_u8());
|
||||||
|
assert_eq!(std::str::from_utf8(&allocation.raw_bytes().unwrap()), Ok("Bar"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check the allocation data for constants used in `other_consts` function.
|
||||||
|
fn check_other_consts(item: CrateItem) {
|
||||||
|
// Instance body will force constant evaluation.
|
||||||
|
let body = Instance::try_from(item).unwrap().body().unwrap();
|
||||||
|
let assigns = collect_consts(&body);
|
||||||
|
assert_eq!(assigns.len(), 9);
|
||||||
|
for (name, alloc) in assigns {
|
||||||
|
match name.as_str() {
|
||||||
|
"_max_u128" => {
|
||||||
|
assert_eq!(alloc.read_uint(), Ok(u128::MAX), "Failed parsing allocation: {alloc:?}")
|
||||||
|
}
|
||||||
|
"_min_i128" => {
|
||||||
|
assert_eq!(alloc.read_int(), Ok(i128::MIN), "Failed parsing allocation: {alloc:?}")
|
||||||
|
}
|
||||||
|
"_max_i8" => {
|
||||||
|
assert_eq!(
|
||||||
|
alloc.read_int().unwrap() as i8,
|
||||||
|
i8::MAX,
|
||||||
|
"Failed parsing allocation: {alloc:?}"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
"_char" => {
|
||||||
|
assert_eq!(
|
||||||
|
char::from_u32(alloc.read_uint().unwrap() as u32),
|
||||||
|
Some('x'),
|
||||||
|
"Failed parsing allocation: {alloc:?}"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
"_false" => {
|
||||||
|
assert_eq!(alloc.read_bool(), Ok(false), "Failed parsing allocation: {alloc:?}")
|
||||||
|
}
|
||||||
|
"_true" => {
|
||||||
|
assert_eq!(alloc.read_bool(), Ok(true), "Failed parsing allocation: {alloc:?}")
|
||||||
|
}
|
||||||
|
"_ptr" => {
|
||||||
|
assert_eq!(alloc.is_null(), Ok(false), "Failed parsing allocation: {alloc:?}")
|
||||||
|
}
|
||||||
|
"_null_ptr" => {
|
||||||
|
assert_eq!(alloc.is_null(), Ok(true), "Failed parsing allocation: {alloc:?}")
|
||||||
|
}
|
||||||
|
"_tuple" => {
|
||||||
|
// The order of fields is not guaranteed.
|
||||||
|
let first = alloc.read_partial_uint(0..4).unwrap();
|
||||||
|
let second = alloc.read_partial_uint(4..8).unwrap();
|
||||||
|
assert_eq!(max(first, second) as u32, u32::MAX);
|
||||||
|
assert_eq!(min(first, second), 10);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!("{name} -- {alloc:?}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check that we can retrieve the type id of char and bool, and that they have different values.
|
||||||
|
fn check_type_id(item: CrateItem) {
|
||||||
|
let body = Instance::try_from(item).unwrap().body().unwrap();
|
||||||
|
let mut ids: Vec<u128> = vec![];
|
||||||
|
for term in body.blocks.iter().map(|bb| &bb.terminator) {
|
||||||
|
match &term.kind {
|
||||||
|
TerminatorKind::Call { func, destination, .. } => {
|
||||||
|
let TyKind::RigidTy(ty) = func.ty(body.locals()).unwrap().kind() else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
let RigidTy::FnDef(def, args) = ty else { unreachable!() };
|
||||||
|
let instance = Instance::resolve(def, &args).unwrap();
|
||||||
|
assert_eq!(instance.kind, InstanceKind::Intrinsic);
|
||||||
|
let dest_ty = destination.ty(body.locals()).unwrap();
|
||||||
|
let alloc = instance.try_const_eval(dest_ty).unwrap();
|
||||||
|
ids.push(alloc.read_uint().unwrap());
|
||||||
|
}
|
||||||
|
_ => { /* Do nothing */ }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert_eq!(ids.len(), 2);
|
||||||
|
assert_ne!(ids[0], ids[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Collects all the constant assignments.
|
||||||
|
pub fn collect_consts(body: &Body) -> HashMap<String, &Allocation> {
|
||||||
|
body.var_debug_info
|
||||||
|
.iter()
|
||||||
|
.filter_map(|info| {
|
||||||
|
info.constant().map(|const_op| {
|
||||||
|
let ConstantKind::Allocated(alloc) = const_op.const_.kind() else { unreachable!() };
|
||||||
|
(info.name.clone(), alloc)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect::<HashMap<_, _>>()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check the allocation data for `LEN`.
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// static LEN: usize = 2;
|
||||||
|
/// ```
|
||||||
|
fn check_len(item: CrateItem) {
|
||||||
|
let def = StaticDef::try_from(item).unwrap();
|
||||||
|
let alloc = def.eval_initializer().unwrap();
|
||||||
|
assert!(alloc.provenance.ptrs.is_empty());
|
||||||
|
assert_eq!(alloc.read_uint(), Ok(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use internal API to find a function in a crate.
|
// Use internal API to find a function in a crate.
|
||||||
|
@ -83,9 +194,7 @@ fn get_item<'a>(
|
||||||
items: &'a CrateItems,
|
items: &'a CrateItems,
|
||||||
item: (ItemKind, &str),
|
item: (ItemKind, &str),
|
||||||
) -> Option<&'a stable_mir::CrateItem> {
|
) -> Option<&'a stable_mir::CrateItem> {
|
||||||
items.iter().find(|crate_item| {
|
items.iter().find(|crate_item| (item.0 == crate_item.kind()) && crate_item.name() == item.1)
|
||||||
(item.0 == crate_item.kind()) && crate_item.name() == item.1
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This test will generate and analyze a dummy crate using the stable mir.
|
/// This test will generate and analyze a dummy crate using the stable mir.
|
||||||
|
@ -109,11 +218,36 @@ fn generate_input(path: &str) -> std::io::Result<()> {
|
||||||
write!(
|
write!(
|
||||||
file,
|
file,
|
||||||
r#"
|
r#"
|
||||||
|
#![feature(core_intrinsics)]
|
||||||
|
use std::intrinsics::type_id;
|
||||||
|
|
||||||
|
static LEN: usize = 2;
|
||||||
static FOO: [&str; 2] = ["hi", "there"];
|
static FOO: [&str; 2] = ["hi", "there"];
|
||||||
static BAR: &str = "Bar";
|
static BAR: &str = "Bar";
|
||||||
|
const NULL: *const u8 = std::ptr::null();
|
||||||
|
const TUPLE: (u32, u32) = (10, u32::MAX);
|
||||||
|
|
||||||
|
fn other_consts() {{
|
||||||
|
let _max_u128 = u128::MAX;
|
||||||
|
let _min_i128 = i128::MIN;
|
||||||
|
let _max_i8 = i8::MAX;
|
||||||
|
let _char = 'x';
|
||||||
|
let _false = false;
|
||||||
|
let _true = true;
|
||||||
|
let _ptr = &BAR;
|
||||||
|
let _null_ptr: *const u8 = NULL;
|
||||||
|
let _tuple = TUPLE;
|
||||||
|
}}
|
||||||
|
|
||||||
|
fn check_type_id() {{
|
||||||
|
let _char_id = type_id::<char>();
|
||||||
|
let _bool_id = type_id::<bool>();
|
||||||
|
}}
|
||||||
|
|
||||||
pub fn main() {{
|
pub fn main() {{
|
||||||
println!("{{FOO:?}}! {{BAR}}");
|
println!("{{FOO:?}}! {{BAR}}");
|
||||||
|
assert_eq!(FOO.len(), LEN);
|
||||||
|
other_consts();
|
||||||
}}"#
|
}}"#
|
||||||
)?;
|
)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue