//! Rustc internal tooling for hand-writing MIR. //! //! If for some reasons you are not writing rustc tests and have found yourself considering using //! this feature, turn back. This is *exceptionally* unstable. There is no attempt at all to make //! anything work besides those things which the rustc test suite happened to need. If you make a //! typo you'll probably ICE. Really, this is not the solution to your problems. Consider instead //! supporting the [stable MIR project group](https://github.com/rust-lang/project-stable-mir). //! //! The documentation for this module describes how to use this feature. If you are interested in //! hacking on the implementation, most of that documentation lives at //! `rustc_mir_building/src/build/custom/mod.rs`. //! //! Typical usage will look like this: //! //! ```rust //! #![feature(core_intrinsics, custom_mir)] //! //! extern crate core; //! use core::intrinsics::mir::*; //! //! #[custom_mir(dialect = "built")] //! pub fn simple(x: i32) -> i32 { //! mir!( //! let temp1: i32; //! let temp2: _; //! //! { //! temp1 = x; //! Goto(exit) //! } //! //! exit = { //! temp2 = Move(temp1); //! RET = temp2; //! Return() //! } //! ) //! } //! ``` //! //! Hopefully most of this is fairly self-explanatory. Expanding on some notable details: //! //! - The `custom_mir` attribute tells the compiler to treat the function as being custom MIR. This //! attribute only works on functions - there is no way to insert custom MIR into the middle of //! another function. //! - The `dialect` and `phase` parameters indicate which version of MIR you are inserting here. //! This will normally be the phase that corresponds to the thing you are trying to test. The //! phase can be omitted for dialects that have just one. //! - You should define your function signature like you normally would. Externally, this function //! can be called like any other function. //! - Type inference works - you don't have to spell out the type of all of your locals. //! //! For now, all statements and terminators are parsed from nested invocations of the special //! functions provided in this module. We additionally want to (but do not yet) support more //! "normal" Rust syntax in places where it makes sense. Also, most kinds of instructions are not //! supported yet. //! #![unstable( feature = "custom_mir", reason = "MIR is an implementation detail and extremely unstable", issue = "none" )] #![allow(unused_variables, non_snake_case, missing_debug_implementations)] /// Type representing basic blocks. /// /// All terminators will have this type as a return type. It helps achieve some type safety. pub struct BasicBlock; macro_rules! define { ($name:literal, $($sig:tt)*) => { #[rustc_diagnostic_item = $name] pub $($sig)* { panic!() } } } define!("mir_return", fn Return() -> BasicBlock); define!("mir_goto", fn Goto(destination: BasicBlock) -> BasicBlock); define!("mir_retag", fn Retag(place: T)); define!("mir_retag_raw", fn RetagRaw(place: T)); define!("mir_move", fn Move(place: T) -> T); define!("mir_static", fn Static(s: T) -> &'static T); define!("mir_static_mut", fn StaticMut(s: T) -> *mut T); /// Convenience macro for generating custom MIR. /// /// See the module documentation for syntax details. This macro is not magic - it only transforms /// your MIR into something that is easier to parse in the compiler. #[rustc_macro_transparency = "transparent"] pub macro mir { ( $(let $local_decl:ident $(: $local_decl_ty:ty)? ;)* { $($entry:tt)* } $( $block_name:ident = { $($block:tt)* } )* ) => {{ // First, we declare all basic blocks. $( let $block_name: ::core::intrinsics::mir::BasicBlock; )* { // Now all locals #[allow(non_snake_case)] let RET; $( let $local_decl $(: $local_decl_ty)? ; )* ::core::intrinsics::mir::__internal_extract_let!($($entry)*); $( ::core::intrinsics::mir::__internal_extract_let!($($block)*); )* { // Finally, the contents of the basic blocks ::core::intrinsics::mir::__internal_remove_let!({ {} { $($entry)* } }); $( ::core::intrinsics::mir::__internal_remove_let!({ {} { $($block)* } }); )* RET } } }} } /// Helper macro that extracts the `let` declarations out of a bunch of statements. /// /// This macro is written using the "statement muncher" strategy. Each invocation parses the first /// statement out of the input, does the appropriate thing with it, and then recursively calls the /// same macro on the remainder of the input. #[doc(hidden)] pub macro __internal_extract_let { // If it's a `let` like statement, keep the `let` ( let $var:ident $(: $ty:ty)? = $expr:expr; $($rest:tt)* ) => { let $var $(: $ty)?; ::core::intrinsics::mir::__internal_extract_let!($($rest)*); }, // Due to #86730, we have to handle const blocks separately ( let $var:ident $(: $ty:ty)? = const $block:block; $($rest:tt)* ) => { let $var $(: $ty)?; ::core::intrinsics::mir::__internal_extract_let!($($rest)*); }, // Otherwise, output nothing ( $stmt:stmt; $($rest:tt)* ) => { ::core::intrinsics::mir::__internal_extract_let!($($rest)*); }, ( $expr:expr ) => {} } /// Helper macro that removes the `let` declarations from a bunch of statements. /// /// Because expression position macros cannot expand to statements + expressions, we need to be /// slightly creative here. The general strategy is also statement munching as above, but the output /// of the macro is "stored" in the subsequent macro invocation. Easiest understood via example: /// ```text /// invoke!( /// { /// { /// x = 5; /// } /// { /// let d = e; /// Call() /// } /// } /// ) /// ``` /// becomes /// ```text /// invoke!( /// { /// { /// x = 5; /// d = e; /// } /// { /// Call() /// } /// } /// ) /// ``` #[doc(hidden)] pub macro __internal_remove_let { // If it's a `let` like statement, remove the `let` ( { { $($already_parsed:tt)* } { let $var:ident $(: $ty:ty)? = $expr:expr; $($rest:tt)* } } ) => { ::core::intrinsics::mir::__internal_remove_let!( { { $($already_parsed)* $var = $expr; } { $($rest)* } } )}, // Due to #86730 , we have to handle const blocks separately ( { { $($already_parsed:tt)* } { let $var:ident $(: $ty:ty)? = const $block:block; $($rest:tt)* } } ) => { ::core::intrinsics::mir::__internal_remove_let!( { { $($already_parsed)* $var = const $block; } { $($rest)* } } )}, // Otherwise, keep going ( { { $($already_parsed:tt)* } { $stmt:stmt; $($rest:tt)* } } ) => { ::core::intrinsics::mir::__internal_remove_let!( { { $($already_parsed)* $stmt; } { $($rest)* } } )}, ( { { $($already_parsed:tt)* } { $expr:expr } } ) => { { $($already_parsed)* $expr } }, }