110
110
//! let popped;
111
111
//!
112
112
//! {
113
- //! Call(_unused = Vec::push(v, value), pop)
113
+ //! Call(_unused = Vec::push(v, value), pop, UnwindContinue() )
114
114
//! }
115
115
//!
116
116
//! pop = {
117
- //! Call(popped = Vec::pop(v), drop)
117
+ //! Call(popped = Vec::pop(v), drop, UnwindContinue() )
118
118
//! }
119
119
//!
120
120
//! drop = {
121
- //! Drop(popped, ret)
121
+ //! Drop(popped, ret, UnwindContinue() )
122
122
//! }
123
123
//!
124
124
//! ret = {
238
238
//!
239
239
//! #### Terminators
240
240
//!
241
- //! Custom MIR does not currently support cleanup blocks or non-trivial unwind paths. As such, there
242
- //! are no resume and abort terminators, and terminators that might unwind do not have any way to
243
- //! indicate the unwind block.
244
- //!
245
241
//! - [`Goto`], [`Return`], [`Unreachable`] and [`Drop`](Drop()) have associated functions.
246
242
//! - `match some_int_operand` becomes a `SwitchInt`. Each arm should be `literal => basic_block`
247
243
//! - The exception is the last arm, which must be `_ => basic_block` and corresponds to the
260
256
/// Type representing basic blocks.
261
257
///
262
258
/// All terminators will have this type as a return type. It helps achieve some type safety.
263
- pub struct BasicBlock ;
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 ;
264
279
265
280
macro_rules! define {
266
281
( $name: literal, $( #[ $meta: meta ] ) * fn $( $sig: tt) * ) => {
@@ -271,11 +286,41 @@ macro_rules! define {
271
286
}
272
287
}
273
288
289
+ // Unwind actions
290
+ define ! (
291
+ "mir_unwind_continue" ,
292
+ /// An unwind action that continues unwinding.
293
+ fn UnwindContinue ( )
294
+ ) ;
295
+ define ! (
296
+ "mir_unwind_unreachable" ,
297
+ /// An unwind action that triggers undefined behaviour.
298
+ fn UnwindUnreachable ( ) -> BasicBlock
299
+ ) ;
300
+ define ! (
301
+ "mir_unwind_terminate" ,
302
+ /// An unwind action that terminates the execution.
303
+ ///
304
+ /// `UnwindTerminate` can also be used as a terminator.
305
+ fn UnwindTerminate ( reason: UnwindTerminateReason )
306
+ ) ;
307
+ define ! (
308
+ "mir_unwind_cleanup" ,
309
+ /// An unwind action that continues execution in a given basic blok.
310
+ fn UnwindCleanup ( goto: BasicBlock )
311
+ ) ;
312
+
313
+ // Terminators
274
314
define ! ( "mir_return" , fn Return ( ) -> BasicBlock ) ;
275
315
define ! ( "mir_goto" , fn Goto ( destination: BasicBlock ) -> BasicBlock ) ;
276
316
define ! ( "mir_unreachable" , fn Unreachable ( ) -> BasicBlock ) ;
277
- define ! ( "mir_drop" , fn Drop <T >( place: T , goto: BasicBlock ) ) ;
278
- define ! ( "mir_call" , fn Call ( call: ( ) , goto: BasicBlock ) ) ;
317
+ define ! ( "mir_drop" , fn Drop <T , U >( place: T , goto: BasicBlock , unwind_action: U ) ) ;
318
+ define ! ( "mir_call" , fn Call <U >( call: ( ) , goto: BasicBlock , unwind_action: U ) ) ;
319
+ define ! ( "mir_unwind_resume" ,
320
+ /// A terminator that resumes the unwinding.
321
+ fn UnwindResume ( )
322
+ ) ;
323
+
279
324
define ! ( "mir_storage_live" , fn StorageLive <T >( local: T ) ) ;
280
325
define ! ( "mir_storage_dead" , fn StorageDead <T >( local: T ) ) ;
281
326
define ! ( "mir_deinit" , fn Deinit <T >( place: T ) ) ;
@@ -382,16 +427,15 @@ pub macro mir {
382
427
}
383
428
384
429
$(
385
- $block_name: ident = {
430
+ $block_name: ident $ ( ( $block_cleanup : ident ) ) ? = {
386
431
$( $block: tt) *
387
432
}
388
433
) *
389
434
) => { {
390
435
// First, we declare all basic blocks.
391
- $(
392
- let $block_name: :: core:: intrinsics:: mir:: BasicBlock ;
393
- ) *
394
-
436
+ __internal_declare_basic_blocks ! ( $(
437
+ $block_name $( ( $block_cleanup) ) ?
438
+ ) * ) ;
395
439
{
396
440
// Now all locals
397
441
#[ allow( non_snake_case) ]
@@ -585,3 +629,17 @@ pub macro __internal_remove_let {
585
629
}
586
630
} ,
587
631
}
632
+
633
+ /// Helper macro that declares the basic blocks.
634
+ #[ doc ( hidden) ]
635
+ pub macro __internal_declare_basic_blocks {
636
+ ( ) => { } ,
637
+ ( $name: ident ( cleanup) $( $rest: tt) * ) => {
638
+ let $name = :: core:: intrinsics:: mir:: BasicBlock :: Cleanup ;
639
+ __internal_declare_basic_blocks ! ( $( $rest) * )
640
+ } ,
641
+ ( $name: ident $( $rest: tt) * ) => {
642
+ let $name = :: core:: intrinsics:: mir:: BasicBlock :: Normal ;
643
+ __internal_declare_basic_blocks ! ( $( $rest) * )
644
+ } ,
645
+ }
0 commit comments