1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
//! 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<T>(place: T));
define!("mir_retag_raw", fn RetagRaw<T>(place: T));
define!("mir_move", fn Move<T>(place: T) -> T);
define!("mir_static", fn Static<T>(s: T) -> &'static T);
define!("mir_static_mut", fn StaticMut<T>(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
}
},
}