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" ] |
261 | pub 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" ] |
270 | pub 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 | |
278 | pub use UnwindTerminateReason::Abi as ReasonAbi; |
279 | pub use UnwindTerminateReason::InCleanup as ReasonInCleanup; |
280 | |
281 | macro_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 |
291 | pub struct UnwindActionArg; |
292 | define!( |
293 | "mir_unwind_continue" , |
294 | /// An unwind action that continues unwinding. |
295 | fn UnwindContinue() -> UnwindActionArg |
296 | ); |
297 | define!( |
298 | "mir_unwind_unreachable" , |
299 | /// An unwind action that triggers undefined behaviour. |
300 | fn UnwindUnreachable() -> UnwindActionArg |
301 | ); |
302 | define!( |
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 | ); |
309 | define!( |
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` |
316 | pub struct ReturnToArg; |
317 | define!("mir_return_to" , fn ReturnTo(goto: BasicBlock) -> ReturnToArg); |
318 | |
319 | // Terminators |
320 | define!("mir_return" , fn Return() -> BasicBlock); |
321 | define!("mir_goto" , fn Goto(destination: BasicBlock) -> BasicBlock); |
322 | define!("mir_unreachable" , fn Unreachable() -> BasicBlock); |
323 | define!("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 | ); |
338 | define!("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 | ); |
353 | define!("mir_unwind_resume" , |
354 | /// A terminator that resumes the unwinding. |
355 | fn UnwindResume() |
356 | ); |
357 | |
358 | define!("mir_storage_live" , fn StorageLive<T>(local: T)); |
359 | define!("mir_storage_dead" , fn StorageDead<T>(local: T)); |
360 | #[cfg (not(bootstrap))] |
361 | define!("mir_assume" , fn Assume(operand: bool)); |
362 | define!("mir_deinit" , fn Deinit<T>(place: T)); |
363 | define!("mir_checked" , fn Checked<T>(binop: T) -> (T, bool)); |
364 | define!("mir_len" , fn Len<T>(place: T) -> usize); |
365 | define!("mir_copy_for_deref" , fn CopyForDeref<T>(place: T) -> T); |
366 | define!("mir_retag" , fn Retag<T>(place: T)); |
367 | define!("mir_move" , fn Move<T>(place: T) -> T); |
368 | define!("mir_static" , fn Static<T>(s: T) -> &'static T); |
369 | define!("mir_static_mut" , fn StaticMut<T>(s: T) -> *mut T); |
370 | define!( |
371 | "mir_discriminant" , |
372 | /// Gets the discriminant of a place. |
373 | fn Discriminant<T>(place: T) -> <T as ::core::marker::DiscriminantKind>::Discriminant |
374 | ); |
375 | define!("mir_set_discriminant" , fn SetDiscriminant<T>(place: T, index: u32)); |
376 | define!("mir_offset" , fn Offset<T, U>(ptr: T, count: U) -> T); |
377 | define!( |
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 | ); |
424 | define!( |
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 | ); |
431 | define!( |
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 | ); |
439 | define!( |
440 | "mir_make_place" , |
441 | #[doc (hidden)] |
442 | fn __internal_make_place<T>(place: T) -> *mut T |
443 | ); |
444 | define!( |
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" ] |
455 | pub 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. |
516 | pub 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)] |
526 | pub 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)] |
585 | pub 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)] |
671 | pub 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 | |