]> git.lizzy.rs Git - rust.git/blob - library/core/src/intrinsics/mir.rs
Auto merge of #106224 - bjorn3:staticlib_fixes, r=wesleywiser
[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 #![cfg_attr(bootstrap, doc = "```rust,compile_fail")]
64 #![cfg_attr(not(bootstrap), doc = "```rust")]
65 //! #![feature(core_intrinsics, custom_mir)]
66 //!
67 //! extern crate core;
68 //! use core::intrinsics::mir::*;
69 //!
70 //! #[custom_mir(dialect = "built")]
71 //! pub fn choose_load(a: &i32, b: &i32, c: bool) -> i32 {
72 //!     mir!(
73 //!         {
74 //!             match c {
75 //!                 true => t,
76 //!                 _ => f,
77 //!             }
78 //!         }
79 //!
80 //!         t = {
81 //!             let temp = a;
82 //!             Goto(load_and_exit)
83 //!         }
84 //!
85 //!         f = {
86 //!             temp = b;
87 //!             Goto(load_and_exit)
88 //!         }
89 //!
90 //!         load_and_exit = {
91 //!             RET = *temp;
92 //!             Return()
93 //!         }
94 //!     )
95 //! }
96 //!
97 //! #[custom_mir(dialect = "built")]
98 //! fn unwrap_unchecked<T>(opt: Option<T>) -> T {
99 //!     mir!({
100 //!         RET = Move(Field(Variant(opt, 1), 0));
101 //!         Return()
102 //!     })
103 //! }
104 //!
105 //! #[custom_mir(dialect = "runtime", phase = "optimized")]
106 //! fn push_and_pop<T>(v: &mut Vec<T>, value: T) {
107 //!     mir!(
108 //!         let unused;
109 //!         let popped;
110 //!
111 //!         {
112 //!             Call(unused, pop, Vec::push(v, value))
113 //!         }
114 //!
115 //!         pop = {
116 //!             Call(popped, drop, Vec::pop(v))
117 //!         }
118 //!
119 //!         drop = {
120 //!             Drop(popped, ret)
121 //!         }
122 //!
123 //!         ret = {
124 //!             Return()
125 //!         }
126 //!     )
127 //! }
128 //! ```
129 //!
130 //! We can also set off compilation failures that happen in sufficiently late stages of the
131 //! compiler:
132 //!
133 //! ```rust,compile_fail
134 //! #![feature(core_intrinsics, custom_mir)]
135 //!
136 //! extern crate core;
137 //! use core::intrinsics::mir::*;
138 //!
139 //! #[custom_mir(dialect = "built")]
140 //! fn borrow_error(should_init: bool) -> i32 {
141 //!     mir!(
142 //!         let temp: i32;
143 //!
144 //!         {
145 //!             match should_init {
146 //!                 true => init,
147 //!                 _ => use_temp,
148 //!             }
149 //!         }
150 //!
151 //!         init = {
152 //!             temp = 0;
153 //!             Goto(use_temp)
154 //!         }
155 //!
156 //!         use_temp = {
157 //!             RET = temp;
158 //!             Return()
159 //!         }
160 //!     )
161 //! }
162 //! ```
163 //!
164 //! ```text
165 //! error[E0381]: used binding is possibly-uninitialized
166 //!   --> test.rs:24:13
167 //!    |
168 //! 8  | /     mir!(
169 //! 9  | |         let temp: i32;
170 //! 10 | |
171 //! 11 | |         {
172 //! ...  |
173 //! 19 | |             temp = 0;
174 //!    | |             -------- binding initialized here in some conditions
175 //! ...  |
176 //! 24 | |             RET = temp;
177 //!    | |             ^^^^^^^^^^ value used here but it is possibly-uninitialized
178 //! 25 | |             Return()
179 //! 26 | |         }
180 //! 27 | |     )
181 //!    | |_____- binding declared here but left uninitialized
182 //!
183 //! error: aborting due to previous error
184 //!
185 //! For more information about this error, try `rustc --explain E0381`.
186 //! ```
187 //!
188 //! # Syntax
189 //!
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.
192 //!
193 //! #### Locals
194 //!
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.
198 //!
199 //! #### Places
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.
204 //!
205 //! #### Operands
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.
211 //!
212 //! #### Statements
213 //!  - Assign statements work via normal Rust assignment.
214 //!  - [`Retag`] statements have an associated function.
215 //!
216 //! #### Rvalues
217 //!
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.
221 //!
222 //! #### Terminators
223 //!
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.
227 //!
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)`.
234 //!
235
236 #![unstable(
237     feature = "custom_mir",
238     reason = "MIR is an implementation detail and extremely unstable",
239     issue = "none"
240 )]
241 #![allow(unused_variables, non_snake_case, missing_debug_implementations)]
242
243 /// Type representing basic blocks.
244 ///
245 /// All terminators will have this type as a return type. It helps achieve some type safety.
246 pub struct BasicBlock;
247
248 macro_rules! define {
249     ($name:literal, $( #[ $meta:meta ] )* fn $($sig:tt)*) => {
250         #[rustc_diagnostic_item = $name]
251         $( #[ $meta ] )*
252         pub fn $($sig)* { panic!() }
253     }
254 }
255
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);
266 define!(
267     "mir_discriminant",
268     /// Gets the discriminant of a place.
269     fn Discriminant<T>(place: T) -> <T as ::core::marker::DiscriminantKind>::Discriminant
270 );
271 define!("mir_set_discriminant", fn SetDiscriminant<T>(place: T, index: u32));
272 define!(
273     "mir_field",
274     /// Access the field with the given index of some place.
275     ///
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.
278     ///
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
282     /// caveats:
283     ///
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.
292     ///
293     /// # Examples
294     ///
295     #[cfg_attr(bootstrap, doc = "```rust,compile_fail")]
296     #[cfg_attr(not(bootstrap), doc = "```rust")]
297     /// #![feature(custom_mir, core_intrinsics)]
298     ///
299     /// extern crate core;
300     /// use core::intrinsics::mir::*;
301     ///
302     /// #[custom_mir(dialect = "built")]
303     /// fn unwrap_deref(opt: Option<&i32>) -> i32 {
304     ///     mir!({
305     ///         RET = *Field::<&i32>(Variant(opt, 1), 0);
306     ///         Return()
307     ///     })
308     /// }
309     ///
310     /// #[custom_mir(dialect = "built")]
311     /// fn set(opt: &mut Option<i32>) {
312     ///     mir!({
313     ///         place!(Field(Variant(*opt, 1), 0)) = 5;
314     ///         Return()
315     ///     })
316     /// }
317     /// ```
318     fn Field<F>(place: (), field: u32) -> F
319 );
320 define!(
321     "mir_variant",
322     /// Adds a variant projection with the given index to the place.
323     ///
324     /// See [`Field`] for documentation.
325     fn Variant<T>(place: T, index: u32) -> ()
326 );
327 define!(
328     "mir_make_place",
329     #[doc(hidden)]
330     fn __internal_make_place<T>(place: T) -> *mut T
331 );
332
333 /// Macro for generating custom MIR.
334 ///
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"]
338 pub macro mir {
339     (
340         $(let $local_decl:ident $(: $local_decl_ty:ty)? ;)*
341
342         {
343             $($entry:tt)*
344         }
345
346         $(
347             $block_name:ident = {
348                 $($block:tt)*
349             }
350         )*
351     ) => {{
352         // First, we declare all basic blocks.
353         $(
354             let $block_name: ::core::intrinsics::mir::BasicBlock;
355         )*
356
357         {
358             // Now all locals
359             #[allow(non_snake_case)]
360             let RET;
361             $(
362                 let $local_decl $(: $local_decl_ty)? ;
363             )*
364
365             ::core::intrinsics::mir::__internal_extract_let!($($entry)*);
366             $(
367                 ::core::intrinsics::mir::__internal_extract_let!($($block)*);
368             )*
369
370             {
371                 // Finally, the contents of the basic blocks
372                 ::core::intrinsics::mir::__internal_remove_let!({
373                     {}
374                     { $($entry)* }
375                 });
376                 $(
377                     ::core::intrinsics::mir::__internal_remove_let!({
378                         {}
379                         { $($block)* }
380                     });
381                 )*
382
383                 RET
384             }
385         }
386     }}
387 }
388
389 /// Helper macro that allows you to treat a value expression like a place expression.
390 ///
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))
394 }
395
396 /// Helper macro that extracts the `let` declarations out of a bunch of statements.
397 ///
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.
401 #[doc(hidden)]
402 pub macro __internal_extract_let {
403     // If it's a `let` like statement, keep the `let`
404     (
405         let $var:ident $(: $ty:ty)? = $expr:expr; $($rest:tt)*
406     ) => {
407         let $var $(: $ty)?;
408         ::core::intrinsics::mir::__internal_extract_let!($($rest)*);
409     },
410     // Due to #86730, we have to handle const blocks separately
411     (
412         let $var:ident $(: $ty:ty)? = const $block:block; $($rest:tt)*
413     ) => {
414         let $var $(: $ty)?;
415         ::core::intrinsics::mir::__internal_extract_let!($($rest)*);
416     },
417     // Otherwise, output nothing
418     (
419         $stmt:stmt; $($rest:tt)*
420     ) => {
421         ::core::intrinsics::mir::__internal_extract_let!($($rest)*);
422     },
423     (
424         $expr:expr
425     ) => {}
426 }
427
428 /// Helper macro that removes the `let` declarations from a bunch of statements.
429 ///
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:
433 /// ```text
434 /// invoke!(
435 ///     {
436 ///         {
437 ///             x = 5;
438 ///         }
439 ///         {
440 ///             let d = e;
441 ///             Call()
442 ///         }
443 ///     }
444 /// )
445 /// ```
446 /// becomes
447 /// ```text
448 /// invoke!(
449 ///     {
450 ///         {
451 ///             x = 5;
452 ///             d = e;
453 ///         }
454 ///         {
455 ///             Call()
456 ///         }
457 ///     }
458 /// )
459 /// ```
460 #[doc(hidden)]
461 pub macro __internal_remove_let {
462     // If it's a `let` like statement, remove the `let`
463     (
464         {
465             {
466                 $($already_parsed:tt)*
467             }
468             {
469                 let $var:ident $(: $ty:ty)? = $expr:expr;
470                 $($rest:tt)*
471             }
472         }
473     ) => { ::core::intrinsics::mir::__internal_remove_let!(
474         {
475             {
476                 $($already_parsed)*
477                 $var = $expr;
478             }
479             {
480                 $($rest)*
481             }
482         }
483     )},
484     // Due to #86730 , we have to handle const blocks separately
485     (
486         {
487             {
488                 $($already_parsed:tt)*
489             }
490             {
491                 let $var:ident $(: $ty:ty)? = const $block:block;
492                 $($rest:tt)*
493             }
494         }
495     ) => { ::core::intrinsics::mir::__internal_remove_let!(
496         {
497             {
498                 $($already_parsed)*
499                 $var = const $block;
500             }
501             {
502                 $($rest)*
503             }
504         }
505     )},
506     // Otherwise, keep going
507     (
508         {
509             {
510                 $($already_parsed:tt)*
511             }
512             {
513                 $stmt:stmt;
514                 $($rest:tt)*
515             }
516         }
517     ) => { ::core::intrinsics::mir::__internal_remove_let!(
518         {
519             {
520                 $($already_parsed)*
521                 $stmt;
522             }
523             {
524                 $($rest)*
525             }
526         }
527     )},
528     (
529         {
530             {
531                 $($already_parsed:tt)*
532             }
533             {
534                 $expr:expr
535             }
536         }
537     ) => {
538         {
539             $($already_parsed)*
540             $expr
541         }
542     },
543 }