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