1//! Rustc internal tooling for hand-writing MIR.
2//!
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).
8//!
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_build/src/build/custom/mod.rs`.
12//!
13//! Typical usage will look like this:
14//!
15//! ```rust
16//! #![feature(core_intrinsics, custom_mir)]
17//! #![allow(internal_features)]
18//!
19//! use core::intrinsics::mir::*;
20//!
21//! #[custom_mir(dialect = "built")]
22//! pub fn simple(x: i32) -> i32 {
23//! mir!(
24//! let temp2: i32;
25//!
26//! {
27//! let temp1 = x;
28//! Goto(my_second_block)
29//! }
30//!
31//! my_second_block = {
32//! temp2 = Move(temp1);
33//! RET = temp2;
34//! Return()
35//! }
36//! )
37//! }
38//! ```
39//!
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.
46//!
47//! [dialect docs]:
48//! https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/enum.MirPhase.html
49//!
50//! The input to the [`mir!`] macro is:
51//!
52//! - An optional return type annotation in the form of `type RET = ...;`. This may be required
53//! if the compiler cannot infer the type of RET.
54//! - A possibly empty list of local declarations. Locals can also be declared inline on
55//! assignments via `let`. Type inference generally works. Shadowing does not.
56//! - A list of basic blocks. The first of these is the start block and is where execution begins.
57//! All blocks other than the start block need to be given a name, so that they can be referred
58//! to later.
59//! - Each block is a list of semicolon terminated statements, followed by a terminator. The
60//! syntax for the various statements and terminators is designed to be as similar as possible
61//! to the syntax for analogous concepts in native Rust. See below for a list.
62//!
63//! # Examples
64//!
65//! ```rust
66//! #![feature(core_intrinsics, custom_mir)]
67//! #![allow(internal_features)]
68//! #![allow(unused_assignments)]
69//!
70//! use core::intrinsics::mir::*;
71//!
72//! #[custom_mir(dialect = "built")]
73//! pub fn choose_load(a: &i32, b: &i32, c: bool) -> i32 {
74//! mir!(
75//! {
76//! match c {
77//! true => t,
78//! _ => f,
79//! }
80//! }
81//!
82//! t = {
83//! let temp = a;
84//! Goto(load_and_exit)
85//! }
86//!
87//! f = {
88//! temp = b;
89//! Goto(load_and_exit)
90//! }
91//!
92//! load_and_exit = {
93//! RET = *temp;
94//! Return()
95//! }
96//! )
97//! }
98//!
99//! #[custom_mir(dialect = "built")]
100//! fn unwrap_unchecked<T>(opt: Option<T>) -> T {
101//! mir!({
102//! RET = Move(Field(Variant(opt, 1), 0));
103//! Return()
104//! })
105//! }
106//!
107//! #[custom_mir(dialect = "runtime", phase = "optimized")]
108#![cfg_attr(bootstrap, doc = "#[cfg(any())]")] // disable the following function in doctests when `bootstrap` is set
109//! fn push_and_pop<T>(v: &mut Vec<T>, value: T) {
110//! mir!(
111//! let _unused;
112//! let popped;
113//!
114//! {
115//! Call(_unused = Vec::push(v, value), ReturnTo(pop), UnwindContinue())
116//! }
117//!
118//! pop = {
119//! Call(popped = Vec::pop(v), ReturnTo(drop), UnwindContinue())
120//! }
121//!
122//! drop = {
123//! Drop(popped, ReturnTo(ret), UnwindContinue())
124//! }
125//!
126//! ret = {
127//! Return()
128//! }
129//! )
130//! }
131//!
132//! #[custom_mir(dialect = "runtime", phase = "optimized")]
133//! fn annotated_return_type() -> (i32, bool) {
134//! mir!(
135//! type RET = (i32, bool);
136//! {
137//! RET.0 = 1;
138//! RET.1 = true;
139//! Return()
140//! }
141//! )
142//! }
143//! ```
144//!
145//! We can also set off compilation failures that happen in sufficiently late stages of the
146//! compiler:
147//!
148//! ```rust,compile_fail
149//! #![feature(core_intrinsics, custom_mir)]
150//!
151//! extern crate core;
152//! use core::intrinsics::mir::*;
153//!
154//! #[custom_mir(dialect = "built")]
155//! fn borrow_error(should_init: bool) -> i32 {
156//! mir!(
157//! let temp: i32;
158//!
159//! {
160//! match should_init {
161//! true => init,
162//! _ => use_temp,
163//! }
164//! }
165//!
166//! init = {
167//! temp = 0;
168//! Goto(use_temp)
169//! }
170//!
171//! use_temp = {
172//! RET = temp;
173//! Return()
174//! }
175//! )
176//! }
177//! ```
178//!
179//! ```text
180//! error[E0381]: used binding is possibly-uninitialized
181//! --> test.rs:24:13
182//! |
183//! 8 | / mir!(
184//! 9 | | let temp: i32;
185//! 10 | |
186//! 11 | | {
187//! ... |
188//! 19 | | temp = 0;
189//! | | -------- binding initialized here in some conditions
190//! ... |
191//! 24 | | RET = temp;
192//! | | ^^^^^^^^^^ value used here but it is possibly-uninitialized
193//! 25 | | Return()
194//! 26 | | }
195//! 27 | | )
196//! | |_____- binding declared here but left uninitialized
197//!
198//! error: aborting due to 1 previous error
199//!
200//! For more information about this error, try `rustc --explain E0381`.
201//! ```
202//!
203//! # Syntax
204//!
205//! The lists below are an exhaustive description of how various MIR constructs can be created.
206//! Anything missing from the list should be assumed to not be supported, PRs welcome.
207//!
208//! #### Locals
209//!
210//! - The `_0` return local can always be accessed via `RET`.
211//! - Arguments can be accessed via their regular name.
212//! - All other locals need to be declared with `let` somewhere and then can be accessed by name.
213//!
214//! #### Places
215//! - Locals implicit convert to places.
216//! - Field accesses, derefs, and indexing work normally.
217//! - Fields in variants can be accessed via the [`Variant`] and [`Field`] associated functions,
218//! see their documentation for details.
219//!
220//! #### Operands
221//! - Places implicitly convert to `Copy` operands.
222//! - `Move` operands can be created via [`Move`].
223//! - Const blocks, literals, named constants, and const params all just work.
224//! - [`Static`] and [`StaticMut`] can be used to create `&T` and `*mut T`s to statics. These are
225//! constants in MIR and the only way to access statics.
226//!
227//! #### Statements
228//! - Assign statements work via normal Rust assignment.
229//! - [`Retag`], [`StorageLive`], [`StorageDead`], [`Deinit`] statements have an associated function.
230//!
231//! #### Rvalues
232//!
233//! - Operands implicitly convert to `Use` rvalues.
234//! - `&`, `&mut`, `addr_of!`, and `addr_of_mut!` all work to create their associated rvalue.
235//! - [`Discriminant`], [`Len`], and [`CopyForDeref`] have associated functions.
236//! - Unary and binary operations use their normal Rust syntax - `a * b`, `!c`, etc.
237//! - The binary operation `Offset` can be created via [`Offset`].
238//! - Checked binary operations are represented by wrapping the associated binop in [`Checked`].
239//! - Array repetition syntax (`[foo; 10]`) creates the associated rvalue.
240//!
241//! #### Terminators
242//!
243//! - [`Goto`], [`Return`], [`Unreachable`] and [`Drop`](Drop()) have associated functions.
244//! - `match some_int_operand` becomes a `SwitchInt`. Each arm should be `literal => basic_block`
245//! - The exception is the last arm, which must be `_ => basic_block` and corresponds to the
246//! otherwise branch.
247//! - [`Call`] has an associated function as well, with special syntax:
248//! `Call(ret_val = function(arg1, arg2, ...), ReturnTo(next_block), UnwindContinue())`.
249
250#![unstable(
251 feature = "custom_mir",
252 reason = "MIR is an implementation detail and extremely unstable",
253 issue = "none"
254)]
255#![allow(unused_variables, non_snake_case, missing_debug_implementations)]
256
257/// Type representing basic blocks.
258///
259/// All terminators will have this type as a return type. It helps achieve some type safety.
260#[rustc_diagnostic_item = "mir_basic_block"]
261pub enum BasicBlock {
262 /// A non-cleanup basic block.
263 Normal,
264 /// A basic block that lies on an unwind path.
265 Cleanup,
266}
267
268/// The reason we are terminating the process during unwinding.
269#[rustc_diagnostic_item = "mir_unwind_terminate_reason"]
270pub enum UnwindTerminateReason {
271 /// Unwinding is just not possible given the ABI of this function.
272 Abi,
273 /// We were already cleaning up for an ongoing unwind, and a *second*, *nested* unwind was
274 /// triggered by the drop glue.
275 InCleanup,
276}
277
278pub use UnwindTerminateReason::Abi as ReasonAbi;
279pub use UnwindTerminateReason::InCleanup as ReasonInCleanup;
280
281macro_rules! define {
282 ($name:literal, $( #[ $meta:meta ] )* fn $($sig:tt)*) => {
283 #[rustc_diagnostic_item = $name]
284 #[inline]
285 $( #[ $meta ] )*
286 pub fn $($sig)* { panic!() }
287 }
288}
289
290// Unwind actions
291pub struct UnwindActionArg;
292define!(
293 "mir_unwind_continue",
294 /// An unwind action that continues unwinding.
295 fn UnwindContinue() -> UnwindActionArg
296);
297define!(
298 "mir_unwind_unreachable",
299 /// An unwind action that triggers undefined behaviour.
300 fn UnwindUnreachable() -> UnwindActionArg
301);
302define!(
303 "mir_unwind_terminate",
304 /// An unwind action that terminates the execution.
305 ///
306 /// `UnwindTerminate` can also be used as a terminator.
307 fn UnwindTerminate(reason: UnwindTerminateReason) -> UnwindActionArg
308);
309define!(
310 "mir_unwind_cleanup",
311 /// An unwind action that continues execution in a given basic blok.
312 fn UnwindCleanup(goto: BasicBlock) -> UnwindActionArg
313);
314
315// Return destination for `Call`
316pub struct ReturnToArg;
317define!("mir_return_to", fn ReturnTo(goto: BasicBlock) -> ReturnToArg);
318
319// Terminators
320define!("mir_return", fn Return() -> BasicBlock);
321define!("mir_goto", fn Goto(destination: BasicBlock) -> BasicBlock);
322define!("mir_unreachable", fn Unreachable() -> BasicBlock);
323define!("mir_drop",
324 /// Drop the contents of a place.
325 ///
326 /// The first argument must be a place.
327 ///
328 /// The second argument must be of the form `ReturnTo(bb)`, where `bb` is the basic block that
329 /// will be jumped to after the destructor returns.
330 ///
331 /// The third argument describes what happens on unwind. It can be one of:
332 /// - [`UnwindContinue`]
333 /// - [`UnwindUnreachable`]
334 /// - [`UnwindTerminate`]
335 /// - [`UnwindCleanup`]
336 fn Drop<T>(place: T, goto: ReturnToArg, unwind_action: UnwindActionArg)
337);
338define!("mir_call",
339 /// Call a function.
340 ///
341 /// The first argument must be of the form `ret_val = fun(arg1, arg2, ...)`.
342 ///
343 /// The second argument must be of the form `ReturnTo(bb)`, where `bb` is the basic block that
344 /// will be jumped to after the function returns.
345 ///
346 /// The third argument describes what happens on unwind. It can be one of:
347 /// - [`UnwindContinue`]
348 /// - [`UnwindUnreachable`]
349 /// - [`UnwindTerminate`]
350 /// - [`UnwindCleanup`]
351 fn Call(call: (), goto: ReturnToArg, unwind_action: UnwindActionArg)
352);
353define!("mir_unwind_resume",
354 /// A terminator that resumes the unwinding.
355 fn UnwindResume()
356);
357
358define!("mir_storage_live", fn StorageLive<T>(local: T));
359define!("mir_storage_dead", fn StorageDead<T>(local: T));
360#[cfg(not(bootstrap))]
361define!("mir_assume", fn Assume(operand: bool));
362define!("mir_deinit", fn Deinit<T>(place: T));
363define!("mir_checked", fn Checked<T>(binop: T) -> (T, bool));
364define!("mir_len", fn Len<T>(place: T) -> usize);
365define!("mir_copy_for_deref", fn CopyForDeref<T>(place: T) -> T);
366define!("mir_retag", fn Retag<T>(place: T));
367define!("mir_move", fn Move<T>(place: T) -> T);
368define!("mir_static", fn Static<T>(s: T) -> &'static T);
369define!("mir_static_mut", fn StaticMut<T>(s: T) -> *mut T);
370define!(
371 "mir_discriminant",
372 /// Gets the discriminant of a place.
373 fn Discriminant<T>(place: T) -> <T as ::core::marker::DiscriminantKind>::Discriminant
374);
375define!("mir_set_discriminant", fn SetDiscriminant<T>(place: T, index: u32));
376define!("mir_offset", fn Offset<T, U>(ptr: T, count: U) -> T);
377define!(
378 "mir_field",
379 /// Access the field with the given index of some place.
380 ///
381 /// This only makes sense to use in conjunction with [`Variant`]. If the type you are looking to
382 /// access the field of does not have variants, you can use normal field projection syntax.
383 ///
384 /// There is no proper way to do a place projection to a variant in Rust, and so these two
385 /// functions are a workaround. You can access a field of a variant via `Field(Variant(place,
386 /// var_idx), field_idx)`, where `var_idx` and `field_idx` are appropriate literals. Some
387 /// caveats:
388 ///
389 /// - The return type of `Variant` is always `()`. Don't worry about that, the correct MIR will
390 /// still be generated.
391 /// - In some situations, the return type of `Field` cannot be inferred. You may need to
392 /// annotate it on the function in these cases.
393 /// - Since `Field` is a function call which is not a place expression, using this on the left
394 /// hand side of an expression is rejected by the compiler. [`place!`] is a macro provided to
395 /// work around that issue. Wrap the left hand side of an assignment in the macro to convince
396 /// the compiler that it's ok.
397 ///
398 /// # Examples
399 ///
400 /// ```rust
401 /// #![allow(internal_features)]
402 /// #![feature(custom_mir, core_intrinsics)]
403 ///
404 /// use core::intrinsics::mir::*;
405 ///
406 /// #[custom_mir(dialect = "built")]
407 /// fn unwrap_deref(opt: Option<&i32>) -> i32 {
408 /// mir!({
409 /// RET = *Field::<&i32>(Variant(opt, 1), 0);
410 /// Return()
411 /// })
412 /// }
413 ///
414 /// #[custom_mir(dialect = "built")]
415 /// fn set(opt: &mut Option<i32>) {
416 /// mir!({
417 /// place!(Field(Variant(*opt, 1), 0)) = 5;
418 /// Return()
419 /// })
420 /// }
421 /// ```
422 fn Field<F>(place: (), field: u32) -> F
423);
424define!(
425 "mir_variant",
426 /// Adds a variant projection with the given index to the place.
427 ///
428 /// See [`Field`] for documentation.
429 fn Variant<T>(place: T, index: u32) -> ()
430);
431define!(
432 "mir_cast_transmute",
433 /// Emits a `CastKind::Transmute` cast.
434 ///
435 /// Needed to test the UB when `sizeof(T) != sizeof(U)`, which can't be
436 /// generated via the normal `mem::transmute`.
437 fn CastTransmute<T, U>(operand: T) -> U
438);
439define!(
440 "mir_make_place",
441 #[doc(hidden)]
442 fn __internal_make_place<T>(place: T) -> *mut T
443);
444define!(
445 "mir_debuginfo",
446 #[doc(hidden)]
447 fn __debuginfo<T>(name: &'static str, s: T)
448);
449
450/// Macro for generating custom MIR.
451///
452/// See the module documentation for syntax details. This macro is not magic - it only transforms
453/// your MIR into something that is easier to parse in the compiler.
454#[rustc_macro_transparency = "transparent"]
455pub macro mir {
456 (
457 $(type RET = $ret_ty:ty ;)?
458 $(let $local_decl:ident $(: $local_decl_ty:ty)? ;)*
459 $(debug $dbg_name:ident => $dbg_data:expr ;)*
460
461 {
462 $($entry:tt)*
463 }
464
465 $(
466 $block_name:ident $(($block_cleanup:ident))? = {
467 $($block:tt)*
468 }
469 )*
470 ) => {{
471 // First, we declare all basic blocks.
472 __internal_declare_basic_blocks!($(
473 $block_name $(($block_cleanup))?
474 )*);
475 {
476 // Now all locals
477 #[allow(non_snake_case)]
478 let RET $(: $ret_ty)?;
479 $(
480 let $local_decl $(: $local_decl_ty)? ;
481 )*
482 ::core::intrinsics::mir::__internal_extract_let!($($entry)*);
483 $(
484 ::core::intrinsics::mir::__internal_extract_let!($($block)*);
485 )*
486
487 {
488 // Now debuginfo
489 $(
490 __debuginfo(stringify!($dbg_name), $dbg_data);
491 )*
492
493 {
494 // Finally, the contents of the basic blocks
495 ::core::intrinsics::mir::__internal_remove_let!({
496 {}
497 { $($entry)* }
498 });
499 $(
500 ::core::intrinsics::mir::__internal_remove_let!({
501 {}
502 { $($block)* }
503 });
504 )*
505
506 RET
507 }
508 }
509 }
510 }}
511}
512
513/// Helper macro that allows you to treat a value expression like a place expression.
514///
515/// See the documentation on [`Variant`] for why this is necessary and how to use it.
516pub macro place($e:expr) {
517 (*::core::intrinsics::mir::__internal_make_place($e))
518}
519
520/// Helper macro that extracts the `let` declarations out of a bunch of statements.
521///
522/// This macro is written using the "statement muncher" strategy. Each invocation parses the first
523/// statement out of the input, does the appropriate thing with it, and then recursively calls the
524/// same macro on the remainder of the input.
525#[doc(hidden)]
526pub macro __internal_extract_let {
527 // If it's a `let` like statement, keep the `let`
528 (
529 let $var:ident $(: $ty:ty)? = $expr:expr; $($rest:tt)*
530 ) => {
531 let $var $(: $ty)?;
532 ::core::intrinsics::mir::__internal_extract_let!($($rest)*);
533 },
534 // Due to #86730, we have to handle const blocks separately
535 (
536 let $var:ident $(: $ty:ty)? = const $block:block; $($rest:tt)*
537 ) => {
538 let $var $(: $ty)?;
539 ::core::intrinsics::mir::__internal_extract_let!($($rest)*);
540 },
541 // Otherwise, output nothing
542 (
543 $stmt:stmt; $($rest:tt)*
544 ) => {
545 ::core::intrinsics::mir::__internal_extract_let!($($rest)*);
546 },
547 (
548 $expr:expr
549 ) => {}
550}
551
552/// Helper macro that removes the `let` declarations from a bunch of statements.
553///
554/// Because expression position macros cannot expand to statements + expressions, we need to be
555/// slightly creative here. The general strategy is also statement munching as above, but the output
556/// of the macro is "stored" in the subsequent macro invocation. Easiest understood via example:
557/// ```text
558/// invoke!(
559/// {
560/// {
561/// x = 5;
562/// }
563/// {
564/// let d = e;
565/// Call()
566/// }
567/// }
568/// )
569/// ```
570/// becomes
571/// ```text
572/// invoke!(
573/// {
574/// {
575/// x = 5;
576/// d = e;
577/// }
578/// {
579/// Call()
580/// }
581/// }
582/// )
583/// ```
584#[doc(hidden)]
585pub macro __internal_remove_let {
586 // If it's a `let` like statement, remove the `let`
587 (
588 {
589 {
590 $($already_parsed:tt)*
591 }
592 {
593 let $var:ident $(: $ty:ty)? = $expr:expr;
594 $($rest:tt)*
595 }
596 }
597 ) => { ::core::intrinsics::mir::__internal_remove_let!(
598 {
599 {
600 $($already_parsed)*
601 $var = $expr;
602 }
603 {
604 $($rest)*
605 }
606 }
607 )},
608 // Due to #86730 , we have to handle const blocks separately
609 (
610 {
611 {
612 $($already_parsed:tt)*
613 }
614 {
615 let $var:ident $(: $ty:ty)? = const $block:block;
616 $($rest:tt)*
617 }
618 }
619 ) => { ::core::intrinsics::mir::__internal_remove_let!(
620 {
621 {
622 $($already_parsed)*
623 $var = const $block;
624 }
625 {
626 $($rest)*
627 }
628 }
629 )},
630 // Otherwise, keep going
631 (
632 {
633 {
634 $($already_parsed:tt)*
635 }
636 {
637 $stmt:stmt;
638 $($rest:tt)*
639 }
640 }
641 ) => { ::core::intrinsics::mir::__internal_remove_let!(
642 {
643 {
644 $($already_parsed)*
645 $stmt;
646 }
647 {
648 $($rest)*
649 }
650 }
651 )},
652 (
653 {
654 {
655 $($already_parsed:tt)*
656 }
657 {
658 $expr:expr
659 }
660 }
661 ) => {
662 {
663 $($already_parsed)*
664 $expr
665 }
666 },
667}
668
669/// Helper macro that declares the basic blocks.
670#[doc(hidden)]
671pub macro __internal_declare_basic_blocks {
672 () => {},
673 ($name:ident (cleanup) $($rest:tt)*) => {
674 let $name = ::core::intrinsics::mir::BasicBlock::Cleanup;
675 __internal_declare_basic_blocks!($($rest)*)
676 },
677 ($name:ident $($rest:tt)*) => {
678 let $name = ::core::intrinsics::mir::BasicBlock::Normal;
679 __internal_declare_basic_blocks!($($rest)*)
680 },
681}
682