1 //! Rustc internal tooling for hand-writing MIR.
3 //! If for some reasons you are not writing rustc tests and have found yourself considering using
4 //! this feature, turn back. This is *exceptionally* unstable. There is no attempt at all to make
5 //! anything work besides those things which the rustc test suite happened to need. If you make a
6 //! typo you'll probably ICE. Really, this is not the solution to your problems. Consider instead
7 //! supporting the [stable MIR project group](https://github.com/rust-lang/project-stable-mir).
9 //! The documentation for this module describes how to use this feature. If you are interested in
10 //! hacking on the implementation, most of that documentation lives at
11 //! `rustc_mir_building/src/build/custom/mod.rs`.
13 //! Typical usage will look like this:
16 //! #![feature(core_intrinsics, custom_mir)]
18 //! extern crate core;
19 //! use core::intrinsics::mir::*;
21 //! #[custom_mir(dialect = "built")]
22 //! pub fn simple(x: i32) -> i32 {
28 //! Goto(my_second_block)
31 //! my_second_block = {
32 //! temp2 = Move(temp1);
40 //! The `custom_mir` attribute tells the compiler to treat the function as being custom MIR. This
41 //! attribute only works on functions - there is no way to insert custom MIR into the middle of
42 //! another function. The `dialect` and `phase` parameters indicate which [version of MIR][dialect
43 //! docs] you are inserting here. Generally you'll want to use `#![custom_mir(dialect = "built")]`
44 //! if you want your MIR to be modified by the full MIR pipeline, or `#![custom_mir(dialect =
45 //! "runtime", phase = "optimized")] if you don't.
48 //! https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/enum.MirPhase.html
50 //! The input to the [`mir!`] macro is:
52 //! - A possibly empty list of local declarations. Locals can also be declared inline on
53 //! assignments via `let`. Type inference generally works. Shadowing does not.
54 //! - A list of basic blocks. The first of these is the start block and is where execution begins.
55 //! All blocks other than the start block need to be given a name, so that they can be referred
57 //! - Each block is a list of semicolon terminated statements, followed by a terminator. The
58 //! syntax for the various statements and terminators is designed to be as similar as possible
59 //! to the syntax for analogous concepts in native Rust. See below for a list.
63 #![cfg_attr(bootstrap, doc = "```rust,compile_fail")]
64 #![cfg_attr(not(bootstrap), doc = "```rust")]
65 //! #![feature(core_intrinsics, custom_mir)]
67 //! extern crate core;
68 //! use core::intrinsics::mir::*;
70 //! #[custom_mir(dialect = "built")]
71 //! pub fn choose_load(a: &i32, b: &i32, c: bool) -> i32 {
82 //! Goto(load_and_exit)
87 //! Goto(load_and_exit)
97 //! #[custom_mir(dialect = "built")]
98 //! fn unwrap_unchecked<T>(opt: Option<T>) -> T {
100 //! RET = Move(Field(Variant(opt, 1), 0));
105 //! #[custom_mir(dialect = "runtime", phase = "optimized")]
106 //! fn push_and_pop<T>(v: &mut Vec<T>, value: T) {
112 //! Call(unused, pop, Vec::push(v, value))
116 //! Call(popped, drop, Vec::pop(v))
120 //! Drop(popped, ret)
130 //! We can also set off compilation failures that happen in sufficiently late stages of the
133 //! ```rust,compile_fail
134 //! #![feature(core_intrinsics, custom_mir)]
136 //! extern crate core;
137 //! use core::intrinsics::mir::*;
139 //! #[custom_mir(dialect = "built")]
140 //! fn borrow_error(should_init: bool) -> i32 {
145 //! match should_init {
165 //! error[E0381]: used binding is possibly-uninitialized
166 //! --> test.rs:24:13
169 //! 9 | | let temp: i32;
174 //! | | -------- binding initialized here in some conditions
176 //! 24 | | RET = temp;
177 //! | | ^^^^^^^^^^ value used here but it is possibly-uninitialized
181 //! | |_____- binding declared here but left uninitialized
183 //! error: aborting due to previous error
185 //! For more information about this error, try `rustc --explain E0381`.
190 //! The lists below are an exhaustive description of how various MIR constructs can be created.
191 //! Anything missing from the list should be assumed to not be supported, PRs welcome.
195 //! - The `_0` return local can always be accessed via `RET`.
196 //! - Arguments can be accessed via their regular name.
197 //! - All other locals need to be declared with `let` somewhere and then can be accessed by name.
200 //! - Locals implicit convert to places.
201 //! - Field accesses, derefs, and indexing work normally.
202 //! - Fields in variants can be accessed via the [`Variant`] and [`Field`] associated functions,
203 //! see their documentation for details.
206 //! - Places implicitly convert to `Copy` operands.
207 //! - `Move` operands can be created via [`Move`].
208 //! - Const blocks, literals, named constants, and const params all just work.
209 //! - [`Static`] and [`StaticMut`] can be used to create `&T` and `*mut T`s to statics. These are
210 //! constants in MIR and the only way to access statics.
213 //! - Assign statements work via normal Rust assignment.
214 //! - [`Retag`] statements have an associated function.
218 //! - Operands implicitly convert to `Use` rvalues.
219 //! - `&`, `&mut`, `addr_of!`, and `addr_of_mut!` all work to create their associated rvalue.
220 //! - [`Discriminant`] has an associated function.
224 //! Custom MIR does not currently support cleanup blocks or non-trivial unwind paths. As such, there
225 //! are no resume and abort terminators, and terminators that might unwind do not have any way to
226 //! indicate the unwind block.
228 //! - [`Goto`], [`Return`], [`Unreachable`], [`Drop`](Drop()), and [`DropAndReplace`] have associated functions.
229 //! - `match some_int_operand` becomes a `SwitchInt`. Each arm should be `literal => basic_block`
230 //! - The exception is the last arm, which must be `_ => basic_block` and corresponds to the
231 //! otherwise branch.
232 //! - [`Call`] has an associated function as well. The third argument of this function is a normal
233 //! function call expresion, for example `my_other_function(a, 5)`.
237 feature = "custom_mir",
238 reason = "MIR is an implementation detail and extremely unstable",
241 #![allow(unused_variables, non_snake_case, missing_debug_implementations)]
243 /// Type representing basic blocks.
245 /// All terminators will have this type as a return type. It helps achieve some type safety.
246 pub struct BasicBlock;
248 macro_rules! define {
249 ($name:literal, $( #[ $meta:meta ] )* fn $($sig:tt)*) => {
250 #[rustc_diagnostic_item = $name]
252 pub fn $($sig)* { panic!() }
256 define!("mir_return", fn Return() -> BasicBlock);
257 define!("mir_goto", fn Goto(destination: BasicBlock) -> BasicBlock);
258 define!("mir_unreachable", fn Unreachable() -> BasicBlock);
259 define!("mir_drop", fn Drop<T>(place: T, goto: BasicBlock));
260 define!("mir_drop_and_replace", fn DropAndReplace<T>(place: T, value: T, goto: BasicBlock));
261 define!("mir_call", fn Call<T>(place: T, goto: BasicBlock, call: T));
262 define!("mir_retag", fn Retag<T>(place: T));
263 define!("mir_move", fn Move<T>(place: T) -> T);
264 define!("mir_static", fn Static<T>(s: T) -> &'static T);
265 define!("mir_static_mut", fn StaticMut<T>(s: T) -> *mut T);
268 /// Gets the discriminant of a place.
269 fn Discriminant<T>(place: T) -> <T as ::core::marker::DiscriminantKind>::Discriminant
271 define!("mir_set_discriminant", fn SetDiscriminant<T>(place: T, index: u32));
274 /// Access the field with the given index of some place.
276 /// This only makes sense to use in conjunction with [`Variant`]. If the type you are looking to
277 /// access the field of does not have variants, you can use normal field projection syntax.
279 /// There is no proper way to do a place projection to a variant in Rust, and so these two
280 /// functions are a workaround. You can access a field of a variant via `Field(Variant(place,
281 /// var_idx), field_idx)`, where `var_idx` and `field_idx` are appropriate literals. Some
284 /// - The return type of `Variant` is always `()`. Don't worry about that, the correct MIR will
285 /// still be generated.
286 /// - In some situations, the return type of `Field` cannot be inferred. You may need to
287 /// annotate it on the function in these cases.
288 /// - Since `Field` is a function call which is not a place expression, using this on the left
289 /// hand side of an expression is rejected by the compiler. [`place!`] is a macro provided to
290 /// work around that issue. Wrap the left hand side of an assignment in the macro to convince
291 /// the compiler that it's ok.
295 #[cfg_attr(bootstrap, doc = "```rust,compile_fail")]
296 #[cfg_attr(not(bootstrap), doc = "```rust")]
297 /// #![feature(custom_mir, core_intrinsics)]
299 /// extern crate core;
300 /// use core::intrinsics::mir::*;
302 /// #[custom_mir(dialect = "built")]
303 /// fn unwrap_deref(opt: Option<&i32>) -> i32 {
305 /// RET = *Field::<&i32>(Variant(opt, 1), 0);
310 /// #[custom_mir(dialect = "built")]
311 /// fn set(opt: &mut Option<i32>) {
313 /// place!(Field(Variant(*opt, 1), 0)) = 5;
318 fn Field<F>(place: (), field: u32) -> F
322 /// Adds a variant projection with the given index to the place.
324 /// See [`Field`] for documentation.
325 fn Variant<T>(place: T, index: u32) -> ()
330 fn __internal_make_place<T>(place: T) -> *mut T
333 /// Macro for generating custom MIR.
335 /// See the module documentation for syntax details. This macro is not magic - it only transforms
336 /// your MIR into something that is easier to parse in the compiler.
337 #[rustc_macro_transparency = "transparent"]
340 $(let $local_decl:ident $(: $local_decl_ty:ty)? ;)*
347 $block_name:ident = {
352 // First, we declare all basic blocks.
354 let $block_name: ::core::intrinsics::mir::BasicBlock;
359 #[allow(non_snake_case)]
362 let $local_decl $(: $local_decl_ty)? ;
365 ::core::intrinsics::mir::__internal_extract_let!($($entry)*);
367 ::core::intrinsics::mir::__internal_extract_let!($($block)*);
371 // Finally, the contents of the basic blocks
372 ::core::intrinsics::mir::__internal_remove_let!({
377 ::core::intrinsics::mir::__internal_remove_let!({
389 /// Helper macro that allows you to treat a value expression like a place expression.
391 /// See the documentation on [`Variant`] for why this is necessary and how to use it.
392 pub macro place($e:expr) {
393 (*::core::intrinsics::mir::__internal_make_place($e))
396 /// Helper macro that extracts the `let` declarations out of a bunch of statements.
398 /// This macro is written using the "statement muncher" strategy. Each invocation parses the first
399 /// statement out of the input, does the appropriate thing with it, and then recursively calls the
400 /// same macro on the remainder of the input.
402 pub macro __internal_extract_let {
403 // If it's a `let` like statement, keep the `let`
405 let $var:ident $(: $ty:ty)? = $expr:expr; $($rest:tt)*
408 ::core::intrinsics::mir::__internal_extract_let!($($rest)*);
410 // Due to #86730, we have to handle const blocks separately
412 let $var:ident $(: $ty:ty)? = const $block:block; $($rest:tt)*
415 ::core::intrinsics::mir::__internal_extract_let!($($rest)*);
417 // Otherwise, output nothing
419 $stmt:stmt; $($rest:tt)*
421 ::core::intrinsics::mir::__internal_extract_let!($($rest)*);
428 /// Helper macro that removes the `let` declarations from a bunch of statements.
430 /// Because expression position macros cannot expand to statements + expressions, we need to be
431 /// slightly creative here. The general strategy is also statement munching as above, but the output
432 /// of the macro is "stored" in the subsequent macro invocation. Easiest understood via example:
461 pub macro __internal_remove_let {
462 // If it's a `let` like statement, remove the `let`
466 $($already_parsed:tt)*
469 let $var:ident $(: $ty:ty)? = $expr:expr;
473 ) => { ::core::intrinsics::mir::__internal_remove_let!(
484 // Due to #86730 , we have to handle const blocks separately
488 $($already_parsed:tt)*
491 let $var:ident $(: $ty:ty)? = const $block:block;
495 ) => { ::core::intrinsics::mir::__internal_remove_let!(
506 // Otherwise, keep going
510 $($already_parsed:tt)*
517 ) => { ::core::intrinsics::mir::__internal_remove_let!(
531 $($already_parsed:tt)*