]> git.lizzy.rs Git - rust.git/blob - library/core/src/intrinsics/mir.rs
Run the tools builder on all PRs
[rust.git] / library / core / src / 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_building/src/build/custom/mod.rs`.
12 //!
13 //! Typical usage will look like this:
14 //!
15 //! ```rust
16 //! #![feature(core_intrinsics, custom_mir)]
17 //!
18 //! extern crate core;
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 //!  - 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
56 //!    to later.
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.
60 //!
61 //! # Examples
62 //!
63 //! ```rust
64 //! #![feature(core_intrinsics, custom_mir)]
65 //!
66 //! extern crate core;
67 //! use core::intrinsics::mir::*;
68 //!
69 //! #[custom_mir(dialect = "built")]
70 //! pub fn choose_load(a: &i32, b: &i32, c: bool) -> i32 {
71 //!     mir!(
72 //!         {
73 //!             match c {
74 //!                 true => t,
75 //!                 _ => f,
76 //!             }
77 //!         }
78 //!
79 //!         t = {
80 //!             let temp = a;
81 //!             Goto(load_and_exit)
82 //!         }
83 //!
84 //!         f = {
85 //!             temp = b;
86 //!             Goto(load_and_exit)
87 //!         }
88 //!
89 //!         load_and_exit = {
90 //!             RET = *temp;
91 //!             Return()
92 //!         }
93 //!     )
94 //! }
95 //!
96 //! #[custom_mir(dialect = "built")]
97 //! fn unwrap_unchecked<T>(opt: Option<T>) -> T {
98 //!     mir!({
99 //!         RET = Move(Field(Variant(opt, 1), 0));
100 //!         Return()
101 //!     })
102 //! }
103 //!
104 //! #[custom_mir(dialect = "runtime", phase = "optimized")]
105 //! fn push_and_pop<T>(v: &mut Vec<T>, value: T) {
106 //!     mir!(
107 //!         let unused;
108 //!         let popped;
109 //!
110 //!         {
111 //!             Call(unused, pop, Vec::push(v, value))
112 //!         }
113 //!
114 //!         pop = {
115 //!             Call(popped, drop, Vec::pop(v))
116 //!         }
117 //!
118 //!         drop = {
119 //!             Drop(popped, ret)
120 //!         }
121 //!
122 //!         ret = {
123 //!             Return()
124 //!         }
125 //!     )
126 //! }
127 //! ```
128 //!
129 //! We can also set off compilation failures that happen in sufficiently late stages of the
130 //! compiler:
131 //!
132 //! ```rust,compile_fail
133 //! #![feature(core_intrinsics, custom_mir)]
134 //!
135 //! extern crate core;
136 //! use core::intrinsics::mir::*;
137 //!
138 //! #[custom_mir(dialect = "built")]
139 //! fn borrow_error(should_init: bool) -> i32 {
140 //!     mir!(
141 //!         let temp: i32;
142 //!
143 //!         {
144 //!             match should_init {
145 //!                 true => init,
146 //!                 _ => use_temp,
147 //!             }
148 //!         }
149 //!
150 //!         init = {
151 //!             temp = 0;
152 //!             Goto(use_temp)
153 //!         }
154 //!
155 //!         use_temp = {
156 //!             RET = temp;
157 //!             Return()
158 //!         }
159 //!     )
160 //! }
161 //! ```
162 //!
163 //! ```text
164 //! error[E0381]: used binding is possibly-uninitialized
165 //!   --> test.rs:24:13
166 //!    |
167 //! 8  | /     mir!(
168 //! 9  | |         let temp: i32;
169 //! 10 | |
170 //! 11 | |         {
171 //! ...  |
172 //! 19 | |             temp = 0;
173 //!    | |             -------- binding initialized here in some conditions
174 //! ...  |
175 //! 24 | |             RET = temp;
176 //!    | |             ^^^^^^^^^^ value used here but it is possibly-uninitialized
177 //! 25 | |             Return()
178 //! 26 | |         }
179 //! 27 | |     )
180 //!    | |_____- binding declared here but left uninitialized
181 //!
182 //! error: aborting due to previous error
183 //!
184 //! For more information about this error, try `rustc --explain E0381`.
185 //! ```
186 //!
187 //! # Syntax
188 //!
189 //! The lists below are an exhaustive description of how various MIR constructs can be created.
190 //! Anything missing from the list should be assumed to not be supported, PRs welcome.
191 //!
192 //! #### Locals
193 //!
194 //!  - The `_0` return local can always be accessed via `RET`.
195 //!  - Arguments can be accessed via their regular name.
196 //!  - All other locals need to be declared with `let` somewhere and then can be accessed by name.
197 //!
198 //! #### Places
199 //!  - Locals implicit convert to places.
200 //!  - Field accesses, derefs, and indexing work normally.
201 //!  - Fields in variants can be accessed via the [`Variant`] and [`Field`] associated functions,
202 //!    see their documentation for details.
203 //!
204 //! #### Operands
205 //!  - Places implicitly convert to `Copy` operands.
206 //!  - `Move` operands can be created via [`Move`].
207 //!  - Const blocks, literals, named constants, and const params all just work.
208 //!  - [`Static`] and [`StaticMut`] can be used to create `&T` and `*mut T`s to statics. These are
209 //!    constants in MIR and the only way to access statics.
210 //!
211 //! #### Statements
212 //!  - Assign statements work via normal Rust assignment.
213 //!  - [`Retag`], [`StorageLive`], [`StorageDead`], [`Deinit`] statements have an associated function.
214 //!
215 //! #### Rvalues
216 //!
217 //!  - Operands implicitly convert to `Use` rvalues.
218 //!  - `&`, `&mut`, `addr_of!`, and `addr_of_mut!` all work to create their associated rvalue.
219 //!  - [`Discriminant`] and [`Len`] have associated functions.
220 //!  - Unary and binary operations use their normal Rust syntax - `a * b`, `!c`, etc.
221 //!  - Checked binary operations are represented by wrapping the associated binop in [`Checked`].
222 //!  - Array repetition syntax (`[foo; 10]`) creates the associated rvalue.
223 //!
224 //! #### Terminators
225 //!
226 //! Custom MIR does not currently support cleanup blocks or non-trivial unwind paths. As such, there
227 //! are no resume and abort terminators, and terminators that might unwind do not have any way to
228 //! indicate the unwind block.
229 //!
230 //!  - [`Goto`], [`Return`], [`Unreachable`], [`Drop`](Drop()), and [`DropAndReplace`] have associated functions.
231 //!  - `match some_int_operand` becomes a `SwitchInt`. Each arm should be `literal => basic_block`
232 //!     - The exception is the last arm, which must be `_ => basic_block` and corresponds to the
233 //!       otherwise branch.
234 //!  - [`Call`] has an associated function as well. The third argument of this function is a normal
235 //!    function call expresion, for example `my_other_function(a, 5)`.
236 //!
237
238 #![unstable(
239     feature = "custom_mir",
240     reason = "MIR is an implementation detail and extremely unstable",
241     issue = "none"
242 )]
243 #![allow(unused_variables, non_snake_case, missing_debug_implementations)]
244
245 /// Type representing basic blocks.
246 ///
247 /// All terminators will have this type as a return type. It helps achieve some type safety.
248 pub struct BasicBlock;
249
250 macro_rules! define {
251     ($name:literal, $( #[ $meta:meta ] )* fn $($sig:tt)*) => {
252         #[rustc_diagnostic_item = $name]
253         $( #[ $meta ] )*
254         pub fn $($sig)* { panic!() }
255     }
256 }
257
258 define!("mir_return", fn Return() -> BasicBlock);
259 define!("mir_goto", fn Goto(destination: BasicBlock) -> BasicBlock);
260 define!("mir_unreachable", fn Unreachable() -> BasicBlock);
261 define!("mir_drop", fn Drop<T>(place: T, goto: BasicBlock));
262 define!("mir_drop_and_replace", fn DropAndReplace<T>(place: T, value: T, goto: BasicBlock));
263 define!("mir_call", fn Call<T>(place: T, goto: BasicBlock, call: T));
264 define!("mir_storage_live", fn StorageLive<T>(local: T));
265 define!("mir_storage_dead", fn StorageDead<T>(local: T));
266 define!("mir_deinit", fn Deinit<T>(place: T));
267 define!("mir_checked", fn Checked<T>(binop: T) -> (T, bool));
268 define!("mir_len", fn Len<T>(place: T) -> usize);
269 define!("mir_retag", fn Retag<T>(place: T));
270 define!("mir_move", fn Move<T>(place: T) -> T);
271 define!("mir_static", fn Static<T>(s: T) -> &'static T);
272 define!("mir_static_mut", fn StaticMut<T>(s: T) -> *mut T);
273 define!(
274     "mir_discriminant",
275     /// Gets the discriminant of a place.
276     fn Discriminant<T>(place: T) -> <T as ::core::marker::DiscriminantKind>::Discriminant
277 );
278 define!("mir_set_discriminant", fn SetDiscriminant<T>(place: T, index: u32));
279 define!(
280     "mir_field",
281     /// Access the field with the given index of some place.
282     ///
283     /// This only makes sense to use in conjunction with [`Variant`]. If the type you are looking to
284     /// access the field of does not have variants, you can use normal field projection syntax.
285     ///
286     /// There is no proper way to do a place projection to a variant in Rust, and so these two
287     /// functions are a workaround. You can access a field of a variant via `Field(Variant(place,
288     /// var_idx), field_idx)`, where `var_idx` and `field_idx` are appropriate literals. Some
289     /// caveats:
290     ///
291     ///  - The return type of `Variant` is always `()`. Don't worry about that, the correct MIR will
292     ///    still be generated.
293     ///  - In some situations, the return type of `Field` cannot be inferred. You may need to
294     ///    annotate it on the function in these cases.
295     ///  - Since `Field` is a function call which is not a place expression, using this on the left
296     ///    hand side of an expression is rejected by the compiler. [`place!`] is a macro provided to
297     ///    work around that issue. Wrap the left hand side of an assignment in the macro to convince
298     ///    the compiler that it's ok.
299     ///
300     /// # Examples
301     ///
302     /// ```rust
303     /// #![feature(custom_mir, core_intrinsics)]
304     ///
305     /// extern crate core;
306     /// use core::intrinsics::mir::*;
307     ///
308     /// #[custom_mir(dialect = "built")]
309     /// fn unwrap_deref(opt: Option<&i32>) -> i32 {
310     ///     mir!({
311     ///         RET = *Field::<&i32>(Variant(opt, 1), 0);
312     ///         Return()
313     ///     })
314     /// }
315     ///
316     /// #[custom_mir(dialect = "built")]
317     /// fn set(opt: &mut Option<i32>) {
318     ///     mir!({
319     ///         place!(Field(Variant(*opt, 1), 0)) = 5;
320     ///         Return()
321     ///     })
322     /// }
323     /// ```
324     fn Field<F>(place: (), field: u32) -> F
325 );
326 define!(
327     "mir_variant",
328     /// Adds a variant projection with the given index to the place.
329     ///
330     /// See [`Field`] for documentation.
331     fn Variant<T>(place: T, index: u32) -> ()
332 );
333 define!(
334     "mir_make_place",
335     #[doc(hidden)]
336     fn __internal_make_place<T>(place: T) -> *mut T
337 );
338
339 /// Macro for generating custom MIR.
340 ///
341 /// See the module documentation for syntax details. This macro is not magic - it only transforms
342 /// your MIR into something that is easier to parse in the compiler.
343 #[rustc_macro_transparency = "transparent"]
344 pub macro mir {
345     (
346         $(let $local_decl:ident $(: $local_decl_ty:ty)? ;)*
347
348         {
349             $($entry:tt)*
350         }
351
352         $(
353             $block_name:ident = {
354                 $($block:tt)*
355             }
356         )*
357     ) => {{
358         // First, we declare all basic blocks.
359         $(
360             let $block_name: ::core::intrinsics::mir::BasicBlock;
361         )*
362
363         {
364             // Now all locals
365             #[allow(non_snake_case)]
366             let RET;
367             $(
368                 let $local_decl $(: $local_decl_ty)? ;
369             )*
370
371             ::core::intrinsics::mir::__internal_extract_let!($($entry)*);
372             $(
373                 ::core::intrinsics::mir::__internal_extract_let!($($block)*);
374             )*
375
376             {
377                 // Finally, the contents of the basic blocks
378                 ::core::intrinsics::mir::__internal_remove_let!({
379                     {}
380                     { $($entry)* }
381                 });
382                 $(
383                     ::core::intrinsics::mir::__internal_remove_let!({
384                         {}
385                         { $($block)* }
386                     });
387                 )*
388
389                 RET
390             }
391         }
392     }}
393 }
394
395 /// Helper macro that allows you to treat a value expression like a place expression.
396 ///
397 /// See the documentation on [`Variant`] for why this is necessary and how to use it.
398 pub macro place($e:expr) {
399     (*::core::intrinsics::mir::__internal_make_place($e))
400 }
401
402 /// Helper macro that extracts the `let` declarations out of a bunch of statements.
403 ///
404 /// This macro is written using the "statement muncher" strategy. Each invocation parses the first
405 /// statement out of the input, does the appropriate thing with it, and then recursively calls the
406 /// same macro on the remainder of the input.
407 #[doc(hidden)]
408 pub macro __internal_extract_let {
409     // If it's a `let` like statement, keep the `let`
410     (
411         let $var:ident $(: $ty:ty)? = $expr:expr; $($rest:tt)*
412     ) => {
413         let $var $(: $ty)?;
414         ::core::intrinsics::mir::__internal_extract_let!($($rest)*);
415     },
416     // Due to #86730, we have to handle const blocks separately
417     (
418         let $var:ident $(: $ty:ty)? = const $block:block; $($rest:tt)*
419     ) => {
420         let $var $(: $ty)?;
421         ::core::intrinsics::mir::__internal_extract_let!($($rest)*);
422     },
423     // Otherwise, output nothing
424     (
425         $stmt:stmt; $($rest:tt)*
426     ) => {
427         ::core::intrinsics::mir::__internal_extract_let!($($rest)*);
428     },
429     (
430         $expr:expr
431     ) => {}
432 }
433
434 /// Helper macro that removes the `let` declarations from a bunch of statements.
435 ///
436 /// Because expression position macros cannot expand to statements + expressions, we need to be
437 /// slightly creative here. The general strategy is also statement munching as above, but the output
438 /// of the macro is "stored" in the subsequent macro invocation. Easiest understood via example:
439 /// ```text
440 /// invoke!(
441 ///     {
442 ///         {
443 ///             x = 5;
444 ///         }
445 ///         {
446 ///             let d = e;
447 ///             Call()
448 ///         }
449 ///     }
450 /// )
451 /// ```
452 /// becomes
453 /// ```text
454 /// invoke!(
455 ///     {
456 ///         {
457 ///             x = 5;
458 ///             d = e;
459 ///         }
460 ///         {
461 ///             Call()
462 ///         }
463 ///     }
464 /// )
465 /// ```
466 #[doc(hidden)]
467 pub macro __internal_remove_let {
468     // If it's a `let` like statement, remove the `let`
469     (
470         {
471             {
472                 $($already_parsed:tt)*
473             }
474             {
475                 let $var:ident $(: $ty:ty)? = $expr:expr;
476                 $($rest:tt)*
477             }
478         }
479     ) => { ::core::intrinsics::mir::__internal_remove_let!(
480         {
481             {
482                 $($already_parsed)*
483                 $var = $expr;
484             }
485             {
486                 $($rest)*
487             }
488         }
489     )},
490     // Due to #86730 , we have to handle const blocks separately
491     (
492         {
493             {
494                 $($already_parsed:tt)*
495             }
496             {
497                 let $var:ident $(: $ty:ty)? = const $block:block;
498                 $($rest:tt)*
499             }
500         }
501     ) => { ::core::intrinsics::mir::__internal_remove_let!(
502         {
503             {
504                 $($already_parsed)*
505                 $var = const $block;
506             }
507             {
508                 $($rest)*
509             }
510         }
511     )},
512     // Otherwise, keep going
513     (
514         {
515             {
516                 $($already_parsed:tt)*
517             }
518             {
519                 $stmt:stmt;
520                 $($rest:tt)*
521             }
522         }
523     ) => { ::core::intrinsics::mir::__internal_remove_let!(
524         {
525             {
526                 $($already_parsed)*
527                 $stmt;
528             }
529             {
530                 $($rest)*
531             }
532         }
533     )},
534     (
535         {
536             {
537                 $($already_parsed:tt)*
538             }
539             {
540                 $expr:expr
541             }
542         }
543     ) => {
544         {
545             $($already_parsed)*
546             $expr
547         }
548     },
549 }