@@ -434,6 +434,89 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
434
434
helper. do_call ( self , & mut bx, fn_abi, llfn, & args, None , cleanup) ;
435
435
}
436
436
437
+ /// Returns `true` if this is indeed a panic intrinsic and codegen is done.
438
+ fn codegen_panic_intrinsic (
439
+ & mut self ,
440
+ helper : & TerminatorCodegenHelper < ' tcx > ,
441
+ bx : & mut Bx ,
442
+ intrinsic : Option < & str > ,
443
+ instance : Option < Instance < ' tcx > > ,
444
+ span : Span ,
445
+ destination : & Option < ( mir:: Place < ' tcx > , mir:: BasicBlock ) > ,
446
+ cleanup : Option < mir:: BasicBlock > ,
447
+ ) -> bool {
448
+ // Emit a panic or a no-op for `panic_if_uninhabited`.
449
+ // These are intrinsics that compile to panics so that we can get a message
450
+ // which mentions the offending type, even from a const context.
451
+ #[ derive( Debug , PartialEq ) ]
452
+ enum PanicIntrinsic {
453
+ IfUninhabited ,
454
+ IfZeroInvalid ,
455
+ IfAnyInvalid ,
456
+ } ;
457
+ let panic_intrinsic = intrinsic. and_then ( |i| match i {
458
+ // FIXME: Move to symbols instead of strings.
459
+ "panic_if_uninhabited" => Some ( PanicIntrinsic :: IfUninhabited ) ,
460
+ "panic_if_zero_invalid" => Some ( PanicIntrinsic :: IfZeroInvalid ) ,
461
+ "panic_if_any_invalid" => Some ( PanicIntrinsic :: IfAnyInvalid ) ,
462
+ _ => None ,
463
+ } ) ;
464
+ if let Some ( intrinsic) = panic_intrinsic {
465
+ use PanicIntrinsic :: * ;
466
+ let ty = instance. unwrap ( ) . substs . type_at ( 0 ) ;
467
+ let layout = bx. layout_of ( ty) ;
468
+ let do_panic = match intrinsic {
469
+ IfUninhabited => layout. abi . is_uninhabited ( ) ,
470
+ // We unwrap as the error type is `!`.
471
+ IfZeroInvalid => !layout. might_permit_raw_init ( bx, /*zero:*/ true ) . unwrap ( ) ,
472
+ // We unwrap as the error type is `!`.
473
+ IfAnyInvalid => !layout. might_permit_raw_init ( bx, /*zero:*/ false ) . unwrap ( ) ,
474
+ } ;
475
+ if do_panic {
476
+ let msg_str = if layout. abi . is_uninhabited ( ) {
477
+ // Use this error even for the other intrinsics as it is more precise.
478
+ format ! ( "attempted to instantiate uninhabited type `{}`" , ty)
479
+ } else if intrinsic == IfZeroInvalid {
480
+ format ! ( "attempted to zero-initialize type `{}`, which is invalid" , ty)
481
+ } else {
482
+ format ! ( "attempted to leave type `{}` uninitialized, which is invalid" , ty)
483
+ } ;
484
+ let msg = bx. const_str ( Symbol :: intern ( & msg_str) ) ;
485
+ let location = self . get_caller_location ( bx, span) . immediate ( ) ;
486
+
487
+ // Obtain the panic entry point.
488
+ // FIXME: dedup this with `codegen_assert_terminator` above.
489
+ let def_id =
490
+ common:: langcall ( bx. tcx ( ) , Some ( span) , "" , lang_items:: PanicFnLangItem ) ;
491
+ let instance = ty:: Instance :: mono ( bx. tcx ( ) , def_id) ;
492
+ let fn_abi = FnAbi :: of_instance ( bx, instance, & [ ] ) ;
493
+ let llfn = bx. get_fn_addr ( instance) ;
494
+
495
+ if let Some ( ( _, target) ) = destination. as_ref ( ) {
496
+ helper. maybe_sideeffect ( self . mir , bx, & [ * target] ) ;
497
+ }
498
+ // Codegen the actual panic invoke/call.
499
+ helper. do_call (
500
+ self ,
501
+ bx,
502
+ fn_abi,
503
+ llfn,
504
+ & [ msg. 0 , msg. 1 , location] ,
505
+ destination. as_ref ( ) . map ( |( _, bb) | ( ReturnDest :: Nothing , * bb) ) ,
506
+ cleanup,
507
+ ) ;
508
+ } else {
509
+ // a NOP
510
+ let target = destination. as_ref ( ) . unwrap ( ) . 1 ;
511
+ helper. maybe_sideeffect ( self . mir , bx, & [ target] ) ;
512
+ helper. funclet_br ( self , bx, target)
513
+ }
514
+ true
515
+ } else {
516
+ false
517
+ }
518
+ }
519
+
437
520
fn codegen_call_terminator (
438
521
& mut self ,
439
522
helper : TerminatorCodegenHelper < ' tcx > ,
@@ -520,41 +603,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
520
603
bug ! ( "`miri_start_panic` should never end up in compiled code" ) ;
521
604
}
522
605
523
- // Emit a panic or a no-op for `panic_if_uninhabited`.
524
- if intrinsic == Some ( "panic_if_uninhabited" ) {
525
- let ty = instance. unwrap ( ) . substs . type_at ( 0 ) ;
526
- let layout = bx. layout_of ( ty) ;
527
- if layout. abi . is_uninhabited ( ) {
528
- let msg_str = format ! ( "Attempted to instantiate uninhabited type {}" , ty) ;
529
- let msg = bx. const_str ( Symbol :: intern ( & msg_str) ) ;
530
- let location = self . get_caller_location ( & mut bx, span) . immediate ( ) ;
531
-
532
- // Obtain the panic entry point.
533
- let def_id =
534
- common:: langcall ( bx. tcx ( ) , Some ( span) , "" , lang_items:: PanicFnLangItem ) ;
535
- let instance = ty:: Instance :: mono ( bx. tcx ( ) , def_id) ;
536
- let fn_abi = FnAbi :: of_instance ( & bx, instance, & [ ] ) ;
537
- let llfn = bx. get_fn_addr ( instance) ;
538
-
539
- if let Some ( ( _, target) ) = destination. as_ref ( ) {
540
- helper. maybe_sideeffect ( self . mir , & mut bx, & [ * target] ) ;
541
- }
542
- // Codegen the actual panic invoke/call.
543
- helper. do_call (
544
- self ,
545
- & mut bx,
546
- fn_abi,
547
- llfn,
548
- & [ msg. 0 , msg. 1 , location] ,
549
- destination. as_ref ( ) . map ( |( _, bb) | ( ReturnDest :: Nothing , * bb) ) ,
550
- cleanup,
551
- ) ;
552
- } else {
553
- // a NOP
554
- let target = destination. as_ref ( ) . unwrap ( ) . 1 ;
555
- helper. maybe_sideeffect ( self . mir , & mut bx, & [ target] ) ;
556
- helper. funclet_br ( self , & mut bx, target)
557
- }
606
+ if self . codegen_panic_intrinsic (
607
+ & helper,
608
+ & mut bx,
609
+ intrinsic,
610
+ instance,
611
+ span,
612
+ destination,
613
+ cleanup,
614
+ ) {
558
615
return ;
559
616
}
560
617
0 commit comments