@@ -434,6 +434,89 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
434434 helper. do_call ( self , & mut bx, fn_abi, llfn, & args, None , cleanup) ;
435435 }
436436
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+
437520 fn codegen_call_terminator (
438521 & mut self ,
439522 helper : TerminatorCodegenHelper < ' tcx > ,
@@ -520,41 +603,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
520603 bug ! ( "`miri_start_panic` should never end up in compiled code" ) ;
521604 }
522605
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+ ) {
558615 return ;
559616 }
560617
0 commit comments