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 | //! - [`Discriminant`], [`Len`], and [`CopyForDeref`] have associated functions. |
237 | //! - Unary and binary operations use their normal Rust syntax - `a * b`, `!c`, etc. |
238 | //! - The binary operation `Offset` can be created via [`Offset`]. |
239 | //! - Checked binary operations are represented by wrapping the associated binop in [`Checked`]. |
240 | //! - Array repetition syntax (`[foo; 10]`) creates the associated rvalue. |
241 | //! |
242 | //! #### Terminators |
243 | //! |
244 | //! - [`Goto`], [`Return`], [`Unreachable`] and [`Drop`](Drop()) have associated functions. |
245 | //! - `match some_int_operand` becomes a `SwitchInt`. Each arm should be `literal => basic_block` |
246 | //! - The exception is the last arm, which must be `_ => basic_block` and corresponds to the |
247 | //! otherwise branch. |
248 | //! - [`Call`] has an associated function as well, with special syntax: |
249 | //! `Call(ret_val = function(arg1, arg2, ...), ReturnTo(next_block), UnwindContinue())`. |
250 | //! - [`TailCall`] does not have a return destination or next block, so its syntax is just |
251 | //! `TailCall(function(arg1, arg2, ...))`. |
252 | //! |
253 | //! #### Debuginfo |
254 | //! |
255 | //! Debuginfo associates source code variable names (of variables that may not exist any more) with |
256 | //! MIR expressions that indicate where the value of that variable is stored. The syntax to do so |
257 | //! is: |
258 | //! ```text |
259 | //! debug source_var_name => expression; |
260 | //! ``` |
261 | //! Both places and constants are supported in the `expression`. |
262 | //! |
263 | //! ```rust |
264 | //! #![allow(internal_features)] |
265 | //! #![feature(core_intrinsics, custom_mir)] |
266 | //! |
267 | //! use core::intrinsics::mir::*; |
268 | //! |
269 | //! #[custom_mir(dialect = "built" )] |
270 | //! fn debuginfo(arg: Option<&i32>) { |
271 | //! mir!( |
272 | //! // Debuginfo for a source variable `plain_local` that just duplicates `arg`. |
273 | //! debug plain_local => arg; |
274 | //! // Debuginfo for a source variable `projection` that can be computed by dereferencing |
275 | //! // a field of `arg`. |
276 | //! debug projection => *Field::<&i32>(Variant(arg, 1), 0); |
277 | //! // Debuginfo for a source variable `constant` that always holds the value `5`. |
278 | //! debug constant => 5_usize; |
279 | //! { |
280 | //! Return() |
281 | //! } |
282 | //! ) |
283 | //! } |
284 | //! ``` |
285 | |
286 | #![unstable ( |
287 | feature = "custom_mir" , |
288 | reason = "MIR is an implementation detail and extremely unstable" , |
289 | issue = "none" |
290 | )] |
291 | #![allow (unused_variables, non_snake_case, missing_debug_implementations)] |
292 | |
293 | /// Type representing basic blocks. |
294 | /// |
295 | /// All terminators will have this type as a return type. It helps achieve some type safety. |
296 | #[rustc_diagnostic_item = "mir_basic_block" ] |
297 | pub enum BasicBlock { |
298 | /// A non-cleanup basic block. |
299 | Normal, |
300 | /// A basic block that lies on an unwind path. |
301 | Cleanup, |
302 | } |
303 | |
304 | /// The reason we are terminating the process during unwinding. |
305 | #[rustc_diagnostic_item = "mir_unwind_terminate_reason" ] |
306 | pub enum UnwindTerminateReason { |
307 | /// Unwinding is just not possible given the ABI of this function. |
308 | Abi, |
309 | /// We were already cleaning up for an ongoing unwind, and a *second*, *nested* unwind was |
310 | /// triggered by the drop glue. |
311 | InCleanup, |
312 | } |
313 | |
314 | pub use UnwindTerminateReason::{Abi as ReasonAbi, InCleanup as ReasonInCleanup}; |
315 | |
316 | macro_rules! define { |
317 | ($name:literal, $( #[ $meta:meta ] )* fn $($sig:tt)*) => { |
318 | #[rustc_diagnostic_item = $name] |
319 | #[inline] |
320 | $( #[ $meta ] )* |
321 | pub fn $($sig)* { panic!() } |
322 | } |
323 | } |
324 | |
325 | // Unwind actions |
326 | pub struct UnwindActionArg; |
327 | define!( |
328 | "mir_unwind_continue" , |
329 | /// An unwind action that continues unwinding. |
330 | fn UnwindContinue() -> UnwindActionArg |
331 | ); |
332 | define!( |
333 | "mir_unwind_unreachable" , |
334 | /// An unwind action that triggers undefined behavior. |
335 | fn UnwindUnreachable() -> UnwindActionArg |
336 | ); |
337 | define!( |
338 | "mir_unwind_terminate" , |
339 | /// An unwind action that terminates the execution. |
340 | /// |
341 | /// `UnwindTerminate` can also be used as a terminator. |
342 | fn UnwindTerminate(reason: UnwindTerminateReason) -> UnwindActionArg |
343 | ); |
344 | define!( |
345 | "mir_unwind_cleanup" , |
346 | /// An unwind action that continues execution in a given basic block. |
347 | fn UnwindCleanup(goto: BasicBlock) -> UnwindActionArg |
348 | ); |
349 | |
350 | // Return destination for `Call` |
351 | pub struct ReturnToArg; |
352 | define!("mir_return_to" , fn ReturnTo(goto: BasicBlock) -> ReturnToArg); |
353 | |
354 | // Terminators |
355 | define!("mir_return" , fn Return() -> BasicBlock); |
356 | define!("mir_goto" , fn Goto(destination: BasicBlock) -> BasicBlock); |
357 | define!("mir_unreachable" , fn Unreachable() -> BasicBlock); |
358 | define!("mir_drop" , |
359 | /// Drop the contents of a place. |
360 | /// |
361 | /// The first argument must be a place. |
362 | /// |
363 | /// The second argument must be of the form `ReturnTo(bb)`, where `bb` is the basic block that |
364 | /// will be jumped to after the destructor returns. |
365 | /// |
366 | /// The third argument describes what happens on unwind. It can be one of: |
367 | /// - [`UnwindContinue`] |
368 | /// - [`UnwindUnreachable`] |
369 | /// - [`UnwindTerminate`] |
370 | /// - [`UnwindCleanup`] |
371 | fn Drop<T>(place: T, goto: ReturnToArg, unwind_action: UnwindActionArg) |
372 | ); |
373 | define!("mir_call" , |
374 | /// Call a function. |
375 | /// |
376 | /// The first argument must be of the form `ret_val = fun(arg1, arg2, ...)`. |
377 | /// |
378 | /// The second argument must be of the form `ReturnTo(bb)`, where `bb` is the basic block that |
379 | /// will be jumped to after the function returns. |
380 | /// |
381 | /// The third argument describes what happens on unwind. It can be one of: |
382 | /// - [`UnwindContinue`] |
383 | /// - [`UnwindUnreachable`] |
384 | /// - [`UnwindTerminate`] |
385 | /// - [`UnwindCleanup`] |
386 | fn Call(call: (), goto: ReturnToArg, unwind_action: UnwindActionArg) |
387 | ); |
388 | define!("mir_tail_call" , |
389 | /// Call a function. |
390 | /// |
391 | /// The argument must be of the form `fun(arg1, arg2, ...)`. |
392 | fn TailCall<T>(call: T) |
393 | ); |
394 | define!("mir_unwind_resume" , |
395 | /// A terminator that resumes the unwinding. |
396 | fn UnwindResume() |
397 | ); |
398 | |
399 | define!("mir_storage_live" , fn StorageLive<T>(local: T)); |
400 | define!("mir_storage_dead" , fn StorageDead<T>(local: T)); |
401 | define!("mir_assume" , fn Assume(operand: bool)); |
402 | define!("mir_deinit" , fn Deinit<T>(place: T)); |
403 | define!("mir_checked" , fn Checked<T>(binop: T) -> (T, bool)); |
404 | define!("mir_len" , fn Len<T>(place: T) -> usize); |
405 | define!( |
406 | "mir_ptr_metadata" , |
407 | fn PtrMetadata<P: ?Sized>(place: *const P) -> <P as ::core::ptr::Pointee>::Metadata |
408 | ); |
409 | define!("mir_copy_for_deref" , fn CopyForDeref<T>(place: T) -> T); |
410 | define!("mir_retag" , fn Retag<T>(place: T)); |
411 | define!("mir_move" , fn Move<T>(place: T) -> T); |
412 | define!("mir_static" , fn Static<T>(s: T) -> &'static T); |
413 | define!("mir_static_mut" , fn StaticMut<T>(s: T) -> *mut T); |
414 | define!( |
415 | "mir_discriminant" , |
416 | /// Gets the discriminant of a place. |
417 | fn Discriminant<T>(place: T) -> <T as ::core::marker::DiscriminantKind>::Discriminant |
418 | ); |
419 | define!("mir_set_discriminant" , fn SetDiscriminant<T>(place: T, index: u32)); |
420 | define!("mir_offset" , fn Offset<T, U>(ptr: T, count: U) -> T); |
421 | define!( |
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 | ); |
472 | define!( |
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 | ); |
479 | define!( |
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 | ); |
487 | define!( |
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 | ); |
494 | define!( |
495 | "mir_make_place" , |
496 | #[doc (hidden)] |
497 | fn __internal_make_place<T>(place: T) -> *mut T |
498 | ); |
499 | define!( |
500 | "mir_debuginfo" , |
501 | #[doc (hidden)] |
502 | fn __debuginfo<T>(name: &'static str, s: T) |
503 | ); |
504 | |
505 | /// Macro for generating custom MIR. |
506 | /// |
507 | /// See the module documentation for syntax details. This macro is not magic - it only transforms |
508 | /// your MIR into something that is easier to parse in the compiler. |
509 | #[rustc_macro_transparency = "transparent" ] |
510 | pub macro mir { |
511 | { |
512 | $(type RET = $ret_ty:ty ;)? |
513 | $(let $local_decl:ident $(: $local_decl_ty:ty)? ;)* |
514 | $(debug $dbg_name:ident => $dbg_data:expr ;)* |
515 | |
516 | { |
517 | $($entry:tt)* |
518 | } |
519 | |
520 | $( |
521 | $block_name:ident $(($block_cleanup:ident))? = { |
522 | $($block:tt)* |
523 | } |
524 | )* |
525 | } => {{ |
526 | // First, we declare all basic blocks. |
527 | __internal_declare_basic_blocks!($( |
528 | $block_name $(($block_cleanup))? |
529 | )*); |
530 | { |
531 | // Now all locals |
532 | #[allow(non_snake_case)] |
533 | let RET $(: $ret_ty)?; |
534 | $( |
535 | let $local_decl $(: $local_decl_ty)? ; |
536 | )* |
537 | ::core::intrinsics::mir::__internal_extract_let!($($entry)*); |
538 | $( |
539 | ::core::intrinsics::mir::__internal_extract_let!($($block)*); |
540 | )* |
541 | |
542 | { |
543 | // Now debuginfo |
544 | $( |
545 | __debuginfo(stringify!($dbg_name), $dbg_data); |
546 | )* |
547 | |
548 | { |
549 | // Finally, the contents of the basic blocks |
550 | ::core::intrinsics::mir::__internal_remove_let!({ |
551 | {} |
552 | { $($entry)* } |
553 | }); |
554 | $( |
555 | ::core::intrinsics::mir::__internal_remove_let!({ |
556 | {} |
557 | { $($block)* } |
558 | }); |
559 | )* |
560 | |
561 | RET |
562 | } |
563 | } |
564 | } |
565 | }} |
566 | } |
567 | |
568 | /// Helper macro that allows you to treat a value expression like a place expression. |
569 | /// |
570 | /// See the documentation on [`Variant`] for why this is necessary and how to use it. |
571 | pub macro place($e:expr) { |
572 | (*::core::intrinsics::mir::__internal_make_place($e)) |
573 | } |
574 | |
575 | /// Helper macro that extracts the `let` declarations out of a bunch of statements. |
576 | /// |
577 | /// This macro is written using the "statement muncher" strategy. Each invocation parses the first |
578 | /// statement out of the input, does the appropriate thing with it, and then recursively calls the |
579 | /// same macro on the remainder of the input. |
580 | #[doc (hidden)] |
581 | pub macro __internal_extract_let { |
582 | // If it's a `let` like statement, keep the `let` |
583 | ( |
584 | let $var:ident $(: $ty:ty)? = $expr:expr; $($rest:tt)* |
585 | ) => { |
586 | let $var $(: $ty)?; |
587 | ::core::intrinsics::mir::__internal_extract_let!($($rest)*); |
588 | }, |
589 | // Due to #86730, we have to handle const blocks separately |
590 | ( |
591 | let $var:ident $(: $ty:ty)? = const $block:block; $($rest:tt)* |
592 | ) => { |
593 | let $var $(: $ty)?; |
594 | ::core::intrinsics::mir::__internal_extract_let!($($rest)*); |
595 | }, |
596 | // Otherwise, output nothing |
597 | ( |
598 | $stmt:stmt; $($rest:tt)* |
599 | ) => { |
600 | ::core::intrinsics::mir::__internal_extract_let!($($rest)*); |
601 | }, |
602 | ( |
603 | $expr:expr |
604 | ) => {} |
605 | } |
606 | |
607 | /// Helper macro that removes the `let` declarations from a bunch of statements. |
608 | /// |
609 | /// Because expression position macros cannot expand to statements + expressions, we need to be |
610 | /// slightly creative here. The general strategy is also statement munching as above, but the output |
611 | /// of the macro is "stored" in the subsequent macro invocation. Easiest understood via example: |
612 | /// ```text |
613 | /// invoke!( |
614 | /// { |
615 | /// { |
616 | /// x = 5; |
617 | /// } |
618 | /// { |
619 | /// let d = e; |
620 | /// Call() |
621 | /// } |
622 | /// } |
623 | /// ) |
624 | /// ``` |
625 | /// becomes |
626 | /// ```text |
627 | /// invoke!( |
628 | /// { |
629 | /// { |
630 | /// x = 5; |
631 | /// d = e; |
632 | /// } |
633 | /// { |
634 | /// Call() |
635 | /// } |
636 | /// } |
637 | /// ) |
638 | /// ``` |
639 | #[doc (hidden)] |
640 | pub macro __internal_remove_let { |
641 | // If it's a `let` like statement, remove the `let` |
642 | ( |
643 | { |
644 | { |
645 | $($already_parsed:tt)* |
646 | } |
647 | { |
648 | let $var:ident $(: $ty:ty)? = $expr:expr; |
649 | $($rest:tt)* |
650 | } |
651 | } |
652 | ) => { ::core::intrinsics::mir::__internal_remove_let!( |
653 | { |
654 | { |
655 | $($already_parsed)* |
656 | $var = $expr; |
657 | } |
658 | { |
659 | $($rest)* |
660 | } |
661 | } |
662 | )}, |
663 | // Due to #86730 , we have to handle const blocks separately |
664 | ( |
665 | { |
666 | { |
667 | $($already_parsed:tt)* |
668 | } |
669 | { |
670 | let $var:ident $(: $ty:ty)? = const $block:block; |
671 | $($rest:tt)* |
672 | } |
673 | } |
674 | ) => { ::core::intrinsics::mir::__internal_remove_let!( |
675 | { |
676 | { |
677 | $($already_parsed)* |
678 | $var = const $block; |
679 | } |
680 | { |
681 | $($rest)* |
682 | } |
683 | } |
684 | )}, |
685 | // Otherwise, keep going |
686 | ( |
687 | { |
688 | { |
689 | $($already_parsed:tt)* |
690 | } |
691 | { |
692 | $stmt:stmt; |
693 | $($rest:tt)* |
694 | } |
695 | } |
696 | ) => { ::core::intrinsics::mir::__internal_remove_let!( |
697 | { |
698 | { |
699 | $($already_parsed)* |
700 | $stmt; |
701 | } |
702 | { |
703 | $($rest)* |
704 | } |
705 | } |
706 | )}, |
707 | ( |
708 | { |
709 | { |
710 | $($already_parsed:tt)* |
711 | } |
712 | { |
713 | $expr:expr |
714 | } |
715 | } |
716 | ) => { |
717 | { |
718 | $($already_parsed)* |
719 | $expr |
720 | } |
721 | }, |
722 | } |
723 | |
724 | /// Helper macro that declares the basic blocks. |
725 | #[doc (hidden)] |
726 | pub macro __internal_declare_basic_blocks { |
727 | () => {}, |
728 | ($name:ident (cleanup) $($rest:tt)*) => { |
729 | let $name = ::core::intrinsics::mir::BasicBlock::Cleanup; |
730 | __internal_declare_basic_blocks!($($rest)*) |
731 | }, |
732 | ($name:ident $($rest:tt)*) => { |
733 | let $name = ::core::intrinsics::mir::BasicBlock::Normal; |
734 | __internal_declare_basic_blocks!($($rest)*) |
735 | }, |
736 | } |
737 | |