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