Auto merge of #126963 - runtimeverification:smir_serde_derive, r=celinval

Add basic Serde serialization capabilities to Stable MIR

This PR adds basic Serde serialization capabilities to Stable MIR. It is intentionally minimal (just wrapping all stable MIR types with a Serde `derive`), so that any important design decisions can be discussed before going further. A simple test is included with this PR to validate that JSON can actually be emitted.

## Notes

When I wrapped the Stable MIR error types in `compiler/stable_mir/src/error.rs`, it caused test failures (though I'm not sure why) so I backed those out.

## Future Work

So, this PR will support serializing basic stable MIR, but it _does not_ support serializing interned values beneath `Ty`s and `AllocId`s, etc... My current thinking about how to handle this is as follows:

1.  Add new `visited_X` fields to the `Tables` struct for each interned category of interest.

2.  As serialization is occuring, serialize interned values as usual _and_ also record the interned value we referenced in `visited_X`.

    (Possibly) In addition, if an interned value recursively references other interned values, record those interned values as well.

3.  Teach the stable MIR `Context` how to access the `visited_X` values and expose them with wrappers in `stable_mir/src/lib.rs` to users (e.g. to serialize and/or further analyze them).

### Pros

This approach does not commit to any specific serialization format regarding interned values or other more complex cases, which avoids us locking into any behaviors that may not be desired long-term.

### Cons

The user will need to manually handle serializing interned values.

### Alternatives

1.  We can directly provide access to the underlying `Tables` maps for interned values; the disadvantage of this approach is that it either requires extra processing for users to filter out to only use the values that they need _or_ users may serialize extra values that they don't need. The advantage is that the implementation is even simpler. The other pros/cons are similar to the above.

2.  We can directly serialize interned values by expanding them in-place. The pro is that this may make some basic inputs easier to consume. However, the cons are that there will need to be special provisions for dealing with cyclical values on both the producer and consumer _and_ global values will possibly need to be de-duplicated on the consumer side.
This commit is contained in:
bors 2024-07-25 20:27:51 +00:00
commit 7120fdac7a
11 changed files with 242 additions and 139 deletions

View File

@ -5205,6 +5205,7 @@ name = "stable_mir"
version = "0.1.0-preview"
dependencies = [
"scoped-tls",
"serde",
]
[[package]]

View File

@ -5,3 +5,4 @@ edition = "2021"
[dependencies]
scoped-tls = "1.0"
serde = { version = "1.0.125", features = [ "derive" ] }

View File

@ -5,12 +5,13 @@ use crate::target::{MachineInfo, MachineSize as Size};
use crate::ty::{Align, IndexedVal, Ty, VariantIdx};
use crate::Error;
use crate::Opaque;
use serde::Serialize;
use std::fmt::{self, Debug};
use std::num::NonZero;
use std::ops::RangeInclusive;
/// A function ABI definition.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
pub struct FnAbi {
/// The types of each argument.
pub args: Vec<ArgAbi>,
@ -31,7 +32,7 @@ pub struct FnAbi {
}
/// Information about the ABI of a function's argument, or return value.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
pub struct ArgAbi {
pub ty: Ty,
pub layout: Layout,
@ -39,7 +40,7 @@ pub struct ArgAbi {
}
/// How a function argument should be passed in to the target function.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
pub enum PassMode {
/// Ignore the argument.
///
@ -60,14 +61,14 @@ pub enum PassMode {
}
/// The layout of a type, alongside the type itself.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)]
pub struct TyAndLayout {
pub ty: Ty,
pub layout: Layout,
}
/// The layout of a type in memory.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
pub struct LayoutShape {
/// The fields location withing the layout
pub fields: FieldsShape,
@ -108,7 +109,7 @@ impl LayoutShape {
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)]
pub struct Layout(usize);
impl Layout {
@ -127,7 +128,7 @@ impl IndexedVal for Layout {
}
/// Describes how the fields of a type are shaped in memory.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
pub enum FieldsShape {
/// Scalar primitives and `!`, which never have fields.
Primitive,
@ -177,7 +178,7 @@ impl FieldsShape {
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
pub enum VariantsShape {
/// Single enum variants, structs/tuples, unions, and all non-ADTs.
Single { index: VariantIdx },
@ -196,7 +197,7 @@ pub enum VariantsShape {
},
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
pub enum TagEncoding {
/// The tag directly stores the discriminant, but possibly with a smaller layout
/// (so converting the tag to the discriminant can require sign extension).
@ -221,7 +222,7 @@ pub enum TagEncoding {
/// Describes how values of the type are passed by target ABIs,
/// in terms of categories of C types there are ABI rules for.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
pub enum ValueAbi {
Uninhabited,
Scalar(Scalar),
@ -250,7 +251,7 @@ impl ValueAbi {
}
/// Information about one scalar component of a Rust type.
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Serialize)]
pub enum Scalar {
Initialized {
/// The primitive type used to represent this value.
@ -280,7 +281,7 @@ impl Scalar {
}
/// Fundamental unit of memory access and layout.
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Serialize)]
pub enum Primitive {
/// The `bool` is the signedness of the `Integer` type.
///
@ -310,7 +311,7 @@ impl Primitive {
}
/// Enum representing the existing integer lengths.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)]
pub enum IntegerLength {
I8,
I16,
@ -320,7 +321,7 @@ pub enum IntegerLength {
}
/// Enum representing the existing float lengths.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)]
pub enum FloatLength {
F16,
F32,
@ -354,7 +355,7 @@ impl FloatLength {
/// An identifier that specifies the address space that some operation
/// should operate on. Special address spaces have an effect on code generation,
/// depending on the target and the address spaces it implements.
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
pub struct AddressSpace(pub u32);
impl AddressSpace {
@ -369,7 +370,7 @@ impl AddressSpace {
/// sequence:
///
/// 254 (-2), 255 (-1), 0, 1, 2
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize)]
pub struct WrappingRange {
pub start: u128,
pub end: u128,
@ -420,7 +421,7 @@ impl Debug for WrappingRange {
}
/// General language calling conventions.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)]
pub enum CallConvention {
C,
Rust,

View File

@ -3,9 +3,10 @@
use crate::ty::{GenericArgs, Span, Ty};
use crate::{with, Crate, Symbol};
use serde::Serialize;
/// A unique identification number for each item accessible for the current compilation unit.
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize)]
pub struct DefId(pub(crate) usize);
/// A trait for retrieving information about a particular definition.

View File

@ -27,6 +27,7 @@ pub use crate::error::*;
use crate::mir::Body;
use crate::mir::Mutability;
use crate::ty::{ForeignModuleDef, ImplDef, IndexedVal, Span, TraitDef, Ty};
use serde::Serialize;
pub mod abi;
#[macro_use]
@ -74,7 +75,7 @@ pub type TraitDecls = Vec<TraitDef>;
pub type ImplTraitDecls = Vec<ImplDef>;
/// Holds information about a crate.
#[derive(Clone, PartialEq, Eq, Debug)]
#[derive(Clone, PartialEq, Eq, Debug, Serialize)]
pub struct Crate {
pub id: CrateNum,
pub name: Symbol,
@ -98,7 +99,7 @@ impl Crate {
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Serialize)]
pub enum ItemKind {
Fn,
Static,
@ -106,7 +107,7 @@ pub enum ItemKind {
Ctor(CtorKind),
}
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Serialize)]
pub enum CtorKind {
Const,
Fn,
@ -116,6 +117,7 @@ pub type Filename = String;
crate_def_with_ty! {
/// Holds information about an item in a crate.
#[derive(Serialize)]
pub CrateItem;
}
@ -188,7 +190,7 @@ pub fn all_trait_impls() -> ImplTraitDecls {
}
/// A type that provides internal information but that can still be used for debug purpose.
#[derive(Clone, PartialEq, Eq, Hash)]
#[derive(Clone, PartialEq, Eq, Hash, Serialize)]
pub struct Opaque(String);
impl std::fmt::Display for Opaque {

View File

@ -4,11 +4,12 @@ use crate::mir::mono::{Instance, StaticDef};
use crate::target::{Endian, MachineInfo};
use crate::ty::{Allocation, Binder, ExistentialTraitRef, IndexedVal, Ty};
use crate::{with, Error};
use serde::Serialize;
use std::io::Read;
/// An allocation in the SMIR global memory can be either a function pointer,
/// a static, or a "real" allocation with some data in it.
#[derive(Debug, Clone, Eq, PartialEq)]
#[derive(Debug, Clone, Eq, PartialEq, Serialize)]
pub enum GlobalAlloc {
/// The alloc ID is used as a function pointer.
Function(Instance),
@ -41,7 +42,7 @@ impl GlobalAlloc {
}
/// A unique identification number for each provenance
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Serialize)]
pub struct AllocId(usize);
impl IndexedVal for AllocId {

View File

@ -5,10 +5,11 @@ use crate::ty::{
TyConst, TyKind, VariantIdx,
};
use crate::{Error, Opaque, Span, Symbol};
use serde::Serialize;
use std::io;
/// The SMIR representation of a single function.
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Serialize)]
pub struct Body {
pub blocks: Vec<BasicBlock>,
@ -104,20 +105,20 @@ impl Body {
type LocalDecls = Vec<LocalDecl>;
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct LocalDecl {
pub ty: Ty,
pub span: Span,
pub mutability: Mutability,
}
#[derive(Clone, PartialEq, Eq, Debug)]
#[derive(Clone, PartialEq, Eq, Debug, Serialize)]
pub struct BasicBlock {
pub statements: Vec<Statement>,
pub terminator: Terminator,
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct Terminator {
pub kind: TerminatorKind,
pub span: Span,
@ -131,7 +132,7 @@ impl Terminator {
pub type Successors = Vec<BasicBlockIdx>;
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub enum TerminatorKind {
Goto {
target: BasicBlockIdx,
@ -221,7 +222,7 @@ impl TerminatorKind {
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct InlineAsmOperand {
pub in_value: Option<Operand>,
pub out_place: Option<Place>,
@ -230,7 +231,7 @@ pub struct InlineAsmOperand {
pub raw_rpr: String,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
pub enum UnwindAction {
Continue,
Unreachable,
@ -238,7 +239,7 @@ pub enum UnwindAction {
Cleanup(BasicBlockIdx),
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub enum AssertMessage {
BoundsCheck { len: Operand, index: Operand },
Overflow(BinOp, Operand, Operand),
@ -307,7 +308,7 @@ impl AssertMessage {
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
pub enum BinOp {
Add,
AddUnchecked,
@ -342,7 +343,7 @@ impl BinOp {
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
pub enum UnOp {
Not,
Neg,
@ -357,20 +358,20 @@ impl UnOp {
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub enum CoroutineKind {
Desugared(CoroutineDesugaring, CoroutineSource),
Coroutine(Movability),
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
pub enum CoroutineSource {
Block,
Closure,
Fn,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
pub enum CoroutineDesugaring {
Async,
@ -386,7 +387,7 @@ pub(crate) type LocalDefId = Opaque;
pub(crate) type Coverage = Opaque;
/// The FakeReadCause describes the type of pattern why a FakeRead statement exists.
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub enum FakeReadCause {
ForMatchGuard,
ForMatchedPlace(LocalDefId),
@ -396,7 +397,7 @@ pub enum FakeReadCause {
}
/// Describes what kind of retag is to be performed
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
pub enum RetagKind {
FnEntry,
TwoPhase,
@ -404,7 +405,7 @@ pub enum RetagKind {
Default,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
pub enum Variance {
Covariant,
Invariant,
@ -412,26 +413,26 @@ pub enum Variance {
Bivariant,
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct CopyNonOverlapping {
pub src: Operand,
pub dst: Operand,
pub count: Operand,
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub enum NonDivergingIntrinsic {
Assume(Operand),
CopyNonOverlapping(CopyNonOverlapping),
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct Statement {
pub kind: StatementKind,
pub span: Span,
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub enum StatementKind {
Assign(Place, Rvalue),
FakeRead(FakeReadCause, Place),
@ -448,7 +449,7 @@ pub enum StatementKind {
Nop,
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub enum Rvalue {
/// Creates a pointer with the indicated mutability to the place.
///
@ -622,7 +623,7 @@ impl Rvalue {
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub enum AggregateKind {
Array(Ty),
Tuple,
@ -633,14 +634,14 @@ pub enum AggregateKind {
RawPtr(Ty, Mutability),
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub enum Operand {
Copy(Place),
Move(Place),
Constant(ConstOperand),
}
#[derive(Clone, Eq, PartialEq)]
#[derive(Clone, Eq, PartialEq, Serialize)]
pub struct Place {
pub local: Local,
/// projection out of a place (access a field, deref a pointer, etc)
@ -653,7 +654,7 @@ impl From<Local> for Place {
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct ConstOperand {
pub span: Span,
pub user_ty: Option<UserTypeAnnotationIndex>,
@ -661,7 +662,7 @@ pub struct ConstOperand {
}
/// Debug information pertaining to a user variable.
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct VarDebugInfo {
/// The variable name.
pub name: Symbol,
@ -703,19 +704,19 @@ impl VarDebugInfo {
pub type SourceScope = u32;
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct SourceInfo {
pub span: Span,
pub scope: SourceScope,
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct VarDebugInfoFragment {
pub ty: Ty,
pub projection: Vec<ProjectionElem>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub enum VarDebugInfoContents {
Place(Place),
Const(ConstOperand),
@ -726,7 +727,7 @@ pub enum VarDebugInfoContents {
// ProjectionElem<Local, Ty>) and user-provided type annotations (for which the projection elements
// are of type ProjectionElem<(), ()>). In SMIR we don't need this generality, so we just use
// ProjectionElem for Places.
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub enum ProjectionElem {
/// Dereference projections (e.g. `*_1`) project to the address referenced by the base place.
Deref,
@ -800,7 +801,7 @@ pub enum ProjectionElem {
Subtype(Ty),
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct UserTypeProjection {
pub base: UserTypeAnnotationIndex,
@ -830,7 +831,7 @@ pub type FieldIdx = usize;
type UserTypeAnnotationIndex = usize;
/// The possible branch sites of a [TerminatorKind::SwitchInt].
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct SwitchTargets {
/// The conditional branches where the first element represents the value that guards this
/// branch, and the second element is the branch target.
@ -867,7 +868,7 @@ impl SwitchTargets {
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
pub enum BorrowKind {
/// Data must be immutable and is aliasable.
Shared,
@ -894,14 +895,14 @@ impl BorrowKind {
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
pub enum MutBorrowKind {
Default,
TwoPhaseBorrow,
ClosureCapture,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
pub enum FakeBorrowKind {
/// A shared (deep) borrow. Data must be immutable and is aliasable.
Deep,
@ -912,19 +913,19 @@ pub enum FakeBorrowKind {
Shallow,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)]
pub enum Mutability {
Not,
Mut,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
pub enum Safety {
Safe,
Unsafe,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
pub enum PointerCoercion {
/// Go from a fn-item type to a fn-pointer type.
ReifyFnPointer,
@ -951,7 +952,7 @@ pub enum PointerCoercion {
Unsize,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
pub enum CastKind {
// FIXME(smir-rename): rename this to PointerExposeProvenance
PointerExposeAddress,
@ -967,7 +968,7 @@ pub enum CastKind {
Transmute,
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub enum NullOp {
/// Returns the size of a value of that type.
SizeOf,

View File

@ -3,17 +3,18 @@ use crate::crate_def::CrateDef;
use crate::mir::Body;
use crate::ty::{Allocation, ClosureDef, ClosureKind, FnDef, GenericArgs, IndexedVal, Ty};
use crate::{with, CrateItem, DefId, Error, ItemKind, Opaque, Symbol};
use serde::Serialize;
use std::fmt::{Debug, Formatter};
use std::io;
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
pub enum MonoItem {
Fn(Instance),
Static(StaticDef),
GlobalAsm(Opaque),
}
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
#[derive(Copy, Clone, PartialEq, Eq, Hash, Serialize)]
pub struct Instance {
/// The type of instance.
pub kind: InstanceKind,
@ -22,7 +23,7 @@ pub struct Instance {
pub def: InstanceDef,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)]
pub enum InstanceKind {
/// A user defined item.
Item,
@ -240,7 +241,7 @@ impl From<StaticDef> for CrateItem {
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize)]
pub struct InstanceDef(usize);
impl CrateDef for InstanceDef {
@ -251,6 +252,7 @@ impl CrateDef for InstanceDef {
crate_def! {
/// Holds information about a static variable definition.
#[derive(Serialize)]
pub StaticDef;
}

View File

@ -1,9 +1,10 @@
//! Provide information about the machine that this is being compiled into.
use crate::compiler_interface::with;
use serde::Serialize;
/// The properties of the target machine being compiled into.
#[derive(Clone, PartialEq, Eq)]
#[derive(Clone, PartialEq, Eq, Serialize)]
pub struct MachineInfo {
pub endian: Endian,
pub pointer_width: MachineSize,
@ -23,14 +24,14 @@ impl MachineInfo {
}
}
#[derive(Copy, Clone, PartialEq, Eq)]
#[derive(Copy, Clone, PartialEq, Eq, Serialize)]
pub enum Endian {
Little,
Big,
}
/// Represent the size of a component.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)]
pub struct MachineSize {
num_bits: usize,
}

View File

@ -8,10 +8,11 @@ use crate::mir::alloc::{read_target_int, read_target_uint, AllocId};
use crate::mir::mono::StaticDef;
use crate::target::MachineInfo;
use crate::{Filename, Opaque};
use serde::Serialize;
use std::fmt::{self, Debug, Display, Formatter};
use std::ops::Range;
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Serialize)]
pub struct Ty(usize);
impl Debug for Ty {
@ -100,13 +101,13 @@ impl Ty {
}
/// Represents a pattern in the type system
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub enum Pattern {
Range { start: Option<TyConst>, end: Option<TyConst>, include_end: bool },
}
/// Represents a constant in the type system
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct TyConst {
pub(crate) kind: TyConstKind,
pub id: TyConstId,
@ -133,7 +134,7 @@ impl TyConst {
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub enum TyConstKind {
Param(ParamConst),
Bound(DebruijnIndex, BoundVar),
@ -144,11 +145,11 @@ pub enum TyConstKind {
ZSTValue(Ty),
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
pub struct TyConstId(usize);
/// Represents a constant in MIR
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct MirConst {
/// The constant kind.
pub(crate) kind: ConstantKind,
@ -205,17 +206,17 @@ impl MirConst {
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
pub struct MirConstId(usize);
type Ident = Opaque;
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct Region {
pub kind: RegionKind,
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub enum RegionKind {
ReEarlyParam(EarlyParamRegion),
ReBound(DebruijnIndex, BoundRegion),
@ -226,7 +227,7 @@ pub enum RegionKind {
pub(crate) type DebruijnIndex = u32;
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct EarlyParamRegion {
pub index: u32,
pub name: Symbol,
@ -234,7 +235,7 @@ pub struct EarlyParamRegion {
pub(crate) type BoundVar = u32;
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct BoundRegion {
pub var: BoundVar,
pub kind: BoundRegionKind,
@ -242,13 +243,13 @@ pub struct BoundRegion {
pub(crate) type UniverseIndex = u32;
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct Placeholder<T> {
pub universe: UniverseIndex,
pub bound: T,
}
#[derive(Clone, Copy, PartialEq, Eq)]
#[derive(Clone, Copy, PartialEq, Eq, Serialize)]
pub struct Span(usize);
impl Debug for Span {
@ -272,7 +273,7 @@ impl Span {
}
}
#[derive(Clone, Copy, Debug)]
#[derive(Clone, Copy, Debug, Serialize)]
/// Information you get from `Span` in a struct form.
/// Line and col start from 1.
pub struct LineInfo {
@ -282,7 +283,7 @@ pub struct LineInfo {
pub end_col: usize,
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub enum TyKind {
RigidTy(RigidTy),
Alias(AliasKind, AliasTy),
@ -521,7 +522,7 @@ pub struct TypeAndMut {
pub mutability: Mutability,
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub enum RigidTy {
Bool,
Char,
@ -560,7 +561,7 @@ impl From<RigidTy> for TyKind {
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
pub enum IntTy {
Isize,
I8,
@ -583,7 +584,7 @@ impl IntTy {
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
pub enum UintTy {
Usize,
U8,
@ -606,7 +607,7 @@ impl UintTy {
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
pub enum FloatTy {
F16,
F32,
@ -614,13 +615,14 @@ pub enum FloatTy {
F128,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
pub enum Movability {
Static,
Movable,
}
crate_def! {
#[derive(Serialize)]
pub ForeignModuleDef;
}
@ -643,6 +645,7 @@ impl ForeignModule {
crate_def_with_ty! {
/// Hold information about a ForeignItem in a crate.
#[derive(Serialize)]
pub ForeignDef;
}
@ -652,7 +655,7 @@ impl ForeignDef {
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Serialize)]
pub enum ForeignItemKind {
Fn(FnDef),
Static(StaticDef),
@ -661,6 +664,7 @@ pub enum ForeignItemKind {
crate_def_with_ty! {
/// Hold information about a function definition in a crate.
#[derive(Serialize)]
pub FnDef;
}
@ -694,6 +698,7 @@ impl FnDef {
}
crate_def_with_ty! {
#[derive(Serialize)]
pub IntrinsicDef;
}
@ -718,26 +723,31 @@ impl From<IntrinsicDef> for FnDef {
}
crate_def! {
#[derive(Serialize)]
pub ClosureDef;
}
crate_def! {
#[derive(Serialize)]
pub CoroutineDef;
}
crate_def! {
#[derive(Serialize)]
pub ParamDef;
}
crate_def! {
#[derive(Serialize)]
pub BrNamedDef;
}
crate_def_with_ty! {
crate_def! {
#[derive(Serialize)]
pub AdtDef;
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Serialize)]
pub enum AdtKind {
Enum,
Union,
@ -791,7 +801,7 @@ impl AdtDef {
}
/// Definition of a variant, which can be either a struct / union field or an enum variant.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize)]
pub struct VariantDef {
/// The variant index.
///
@ -820,7 +830,7 @@ impl VariantDef {
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct FieldDef {
/// The field definition.
///
@ -871,11 +881,13 @@ impl AdtKind {
}
crate_def! {
#[derive(Serialize)]
pub AliasDef;
}
crate_def! {
/// A trait's definition.
#[derive(Serialize)]
pub TraitDef;
}
@ -886,15 +898,18 @@ impl TraitDef {
}
crate_def! {
#[derive(Serialize)]
pub GenericDef;
}
crate_def_with_ty! {
#[derive(Serialize)]
pub ConstDef;
}
crate_def! {
/// A trait impl definition.
#[derive(Serialize)]
pub ImplDef;
}
@ -906,15 +921,17 @@ impl ImplDef {
}
crate_def! {
#[derive(Serialize)]
pub RegionDef;
}
crate_def! {
#[derive(Serialize)]
pub CoroutineWitnessDef;
}
/// A list of generic arguments.
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct GenericArgs(pub Vec<GenericArgKind>);
impl std::ops::Index<ParamTy> for GenericArgs {
@ -933,7 +950,7 @@ impl std::ops::Index<ParamConst> for GenericArgs {
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub enum GenericArgKind {
Lifetime(Region),
Type(Ty),
@ -970,13 +987,13 @@ impl GenericArgKind {
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub enum TermKind {
Type(Ty),
Const(TyConst),
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub enum AliasKind {
Projection,
Inherent,
@ -984,13 +1001,13 @@ pub enum AliasKind {
Weak,
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct AliasTy {
pub def_id: AliasDef,
pub args: GenericArgs,
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct AliasTerm {
pub def_id: AliasDef,
pub args: GenericArgs,
@ -1008,7 +1025,7 @@ impl PolyFnSig {
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct FnSig {
pub inputs_and_output: Vec<Ty>,
pub c_variadic: bool,
@ -1026,7 +1043,7 @@ impl FnSig {
}
}
#[derive(Clone, PartialEq, Eq, Debug)]
#[derive(Clone, PartialEq, Eq, Debug, Serialize)]
pub enum Abi {
Rust,
C { unwind: bool },
@ -1055,7 +1072,7 @@ pub enum Abi {
}
/// A binder represents a possibly generic type and its bound vars.
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct Binder<T> {
pub value: T,
pub bound_vars: Vec<BoundVariableKind>,
@ -1095,38 +1112,38 @@ impl<T> Binder<T> {
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct EarlyBinder<T> {
pub value: T,
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub enum BoundVariableKind {
Ty(BoundTyKind),
Region(BoundRegionKind),
Const,
}
#[derive(Clone, PartialEq, Eq, Debug)]
#[derive(Clone, PartialEq, Eq, Debug, Serialize)]
pub enum BoundTyKind {
Anon,
Param(ParamDef, String),
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub enum BoundRegionKind {
BrAnon,
BrNamed(BrNamedDef, String),
BrEnv,
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub enum DynKind {
Dyn,
DynStar,
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub enum ExistentialPredicate {
Trait(ExistentialTraitRef),
Projection(ExistentialProjection),
@ -1136,7 +1153,7 @@ pub enum ExistentialPredicate {
/// 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, Serialize)]
pub struct ExistentialTraitRef {
pub def_id: TraitDef,
pub generic_args: GenericArgs,
@ -1154,20 +1171,20 @@ impl ExistentialTraitRef {
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct ExistentialProjection {
pub def_id: TraitDef,
pub generic_args: GenericArgs,
pub term: TermKind,
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct ParamTy {
pub index: u32,
pub name: String,
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct BoundTy {
pub var: usize,
pub kind: BoundTyKind,
@ -1178,7 +1195,7 @@ pub type Bytes = Vec<Option<u8>>;
/// Size in bytes.
pub type Size = usize;
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Serialize)]
pub struct Prov(pub AllocId);
pub type Align = u64;
@ -1186,14 +1203,14 @@ pub type Promoted = u32;
pub type InitMaskMaterialized = Vec<u64>;
/// Stores the provenance information of pointers stored in memory.
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
pub struct ProvenanceMap {
/// 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.
pub ptrs: Vec<(Size, Prov)>,
}
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
pub struct Allocation {
pub bytes: Bytes,
pub provenance: ProvenanceMap,
@ -1269,7 +1286,7 @@ impl Allocation {
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub enum ConstantKind {
Ty(TyConst),
Allocated(Allocation),
@ -1280,27 +1297,27 @@ pub enum ConstantKind {
ZeroSized,
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct ParamConst {
pub index: u32,
pub name: String,
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct UnevaluatedConst {
pub def: ConstDef,
pub args: GenericArgs,
pub promoted: Option<Promoted>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
pub enum TraitSpecializationKind {
None,
Marker,
AlwaysApplicable,
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct TraitDecl {
pub def_id: TraitDef,
pub safety: Safety,
@ -1333,7 +1350,7 @@ impl TraitDecl {
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, Serialize)]
pub struct TraitRef {
pub def_id: TraitDef,
/// The generic arguments for this definition.
@ -1367,7 +1384,7 @@ impl TraitRef {
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct Generics {
pub parent: Option<GenericDef>,
pub parent_count: usize,
@ -1378,14 +1395,14 @@ pub struct Generics {
pub host_effect_index: Option<usize>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub enum GenericParamDefKind {
Lifetime,
Type { has_default: bool, synthetic: bool },
Const { has_default: bool },
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct GenericParamDef {
pub name: super::Symbol,
pub def_id: GenericDef,
@ -1399,7 +1416,7 @@ pub struct GenericPredicates {
pub predicates: Vec<(PredicateKind, Span)>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub enum PredicateKind {
Clause(ClauseKind),
ObjectSafe(TraitDef),
@ -1410,7 +1427,7 @@ pub enum PredicateKind {
AliasRelate(TermKind, TermKind, AliasRelationDirection),
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub enum ClauseKind {
Trait(TraitPredicate),
RegionOutlives(RegionOutlivesPredicate),
@ -1421,57 +1438,57 @@ pub enum ClauseKind {
ConstEvaluatable(TyConst),
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub enum ClosureKind {
Fn,
FnMut,
FnOnce,
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct SubtypePredicate {
pub a: Ty,
pub b: Ty,
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct CoercePredicate {
pub a: Ty,
pub b: Ty,
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub enum AliasRelationDirection {
Equate,
Subtype,
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct TraitPredicate {
pub trait_ref: TraitRef,
pub polarity: PredicatePolarity,
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct OutlivesPredicate<A, B>(pub A, pub B);
pub type RegionOutlivesPredicate = OutlivesPredicate<Region, Region>;
pub type TypeOutlivesPredicate = OutlivesPredicate<Ty, Region>;
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct ProjectionPredicate {
pub projection_term: AliasTerm,
pub term: TermKind,
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub enum ImplPolarity {
Positive,
Negative,
Reservation,
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub enum PredicatePolarity {
Positive,
Negative,
@ -1514,7 +1531,7 @@ index_impl!(Span);
/// `a` is in the variant with the `VariantIdx` of `0`,
/// `c` is in the variant with the `VariantIdx` of `1`, and
/// `g` is in the variant with the `VariantIdx` of `0`.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize)]
pub struct VariantIdx(usize);
index_impl!(VariantIdx);

View File

@ -0,0 +1,75 @@
//@ run-pass
//! Test that users are able to use serialize stable MIR constructs.
//@ ignore-stage1
//@ ignore-cross-compile
//@ ignore-remote
//@ ignore-windows-gnu mingw has troubles with linking https://github.com/rust-lang/rust/pull/116837
//@ edition: 2021
#![feature(rustc_private)]
#![feature(assert_matches)]
#![feature(control_flow_enum)]
#[macro_use]
extern crate rustc_smir;
extern crate rustc_driver;
extern crate rustc_interface;
extern crate rustc_middle;
extern crate stable_mir;
extern crate serde;
extern crate serde_json;
use rustc_middle::ty::TyCtxt;
use rustc_smir::rustc_internal;
use stable_mir::mir::Body;
use std::io::{Write, BufWriter};
use std::ops::ControlFlow;
use serde_json::to_string;
const CRATE_NAME: &str = "input";
fn serialize_to_json(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
let path = "output.json";
let mut writer = BufWriter::new(std::fs::File::create(path)
.expect("Failed to create path"));
let local_crate = stable_mir::local_crate();
let items: Vec<Body> = stable_mir::all_local_items()
.iter()
.map(|item| { item.body() })
.collect();
let crate_data = ( local_crate.name, items );
writer.write_all(to_string(&crate_data)
.expect("serde_json failed")
.as_bytes()).expect("JSON serialization failed");
ControlFlow::Continue(())
}
/// This test will generate and analyze a dummy crate using the stable mir.
/// For that, it will first write the dummy crate into a file.
/// Then it will create a `StableMir` using custom arguments and then
/// it will run the compiler.
fn main() {
let path = "internal_input.rs";
generate_input(&path).unwrap();
let args = vec![
"rustc".to_string(),
"--crate-name".to_string(),
CRATE_NAME.to_string(),
path.to_string(),
];
run_with_tcx!(args, serialize_to_json).unwrap();
}
fn generate_input(path: &str) -> std::io::Result<()> {
let mut file = std::fs::File::create(path)?;
write!(
file,
r#"
pub fn main() {{
}}
"#
)?;
Ok(())
}