@@ -11,6 +11,7 @@ use rustc_middle::{
1111 ty:: { self , FloatTy } ,
1212} ;
1313use rustc_target:: abi:: Size ;
14+ use rustc_span:: { sym, Symbol } ;
1415
1516use crate :: * ;
1617use atomic:: EvalContextExt as _;
@@ -26,12 +27,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
2627 dest : & MPlaceTy < ' tcx , Provenance > ,
2728 ret : Option < mir:: BasicBlock > ,
2829 _unwind : mir:: UnwindAction ,
29- ) -> InterpResult < ' tcx > {
30+ ) -> InterpResult < ' tcx , Option < ty :: Instance < ' tcx > > > {
3031 let this = self . eval_context_mut ( ) ;
3132
3233 // See if the core engine can handle this intrinsic.
3334 if this. emulate_intrinsic ( instance, args, dest, ret) ? {
34- return Ok ( ( ) ) ;
35+ return Ok ( None ) ;
3536 }
3637 let intrinsic_name = this. tcx . item_name ( instance. def_id ( ) ) ;
3738 let intrinsic_name = intrinsic_name. as_str ( ) ;
@@ -48,32 +49,50 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
4849
4950 // All remaining supported intrinsics have a return place.
5051 let ret = match ret {
52+ // FIXME: add fallback body support once we actually have a diverging intrinsic with a fallback body
5153 None => throw_unsup_format ! ( "unimplemented (diverging) intrinsic: `{intrinsic_name}`" ) ,
5254 Some ( p) => p,
5355 } ;
5456
5557 // Some intrinsics are special and need the "ret".
5658 match intrinsic_name {
57- "catch_unwind" => return this. handle_catch_unwind ( args, dest, ret) ,
59+ "catch_unwind" => {
60+ this. handle_catch_unwind ( args, dest, ret) ?;
61+ return Ok ( None ) ;
62+ }
5863 _ => { }
5964 }
6065
6166 // The rest jumps to `ret` immediately.
62- this. emulate_intrinsic_by_name ( intrinsic_name, instance. args , args, dest) ?;
67+ if !this. emulate_intrinsic_by_name ( intrinsic_name, instance. args , args, dest) ? {
68+ // We haven't handled the intrinsic, let's see if we can use a fallback body.
69+ if this. tcx . intrinsic ( instance. def_id ( ) ) . unwrap ( ) . must_be_overridden {
70+ throw_unsup_format ! ( "unimplemented intrinsic: `{intrinsic_name}`" )
71+ }
72+ let intrinsic_fallback_checks_ub = Symbol :: intern ( "intrinsic_fallback_checks_ub" ) ;
73+ if this. tcx . get_attrs_by_path ( instance. def_id ( ) , & [ sym:: miri, intrinsic_fallback_checks_ub] ) . next ( ) . is_none ( ) {
74+ throw_unsup_format ! ( "miri can only use intrinsic fallback bodies that check UB. After verifying that `{intrinsic_name}` does so, add the `#[miri::intrinsic_fallback_checks_ub]` attribute to it; also ping @rust-lang/miri when you do that" ) ;
75+ }
76+ return Ok ( Some ( ty:: Instance {
77+ def : ty:: InstanceDef :: Item ( instance. def_id ( ) ) ,
78+ args : instance. args ,
79+ } ) )
80+ }
6381
6482 trace ! ( "{:?}" , this. dump_place( & dest. clone( ) . into( ) ) ) ;
6583 this. go_to_block ( ret) ;
66- Ok ( ( ) )
84+ Ok ( None )
6785 }
6886
6987 /// Emulates a Miri-supported intrinsic (not supported by the core engine).
88+ /// Returns `Ok(true)` if the intrinsic was handled.
7089 fn emulate_intrinsic_by_name (
7190 & mut self ,
7291 intrinsic_name : & str ,
7392 generic_args : ty:: GenericArgsRef < ' tcx > ,
7493 args : & [ OpTy < ' tcx , Provenance > ] ,
7594 dest : & MPlaceTy < ' tcx , Provenance > ,
76- ) -> InterpResult < ' tcx > {
95+ ) -> InterpResult < ' tcx , bool > {
7796 let this = self . eval_context_mut ( ) ;
7897
7998 if let Some ( name) = intrinsic_name. strip_prefix ( "atomic_" ) {
@@ -84,24 +103,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
84103 }
85104
86105 match intrinsic_name {
87- // Miri overwriting CTFE intrinsics.
88- "ptr_guaranteed_cmp" => {
89- let [ left, right] = check_arg_count ( args) ?;
90- let left = this. read_immediate ( left) ?;
91- let right = this. read_immediate ( right) ?;
92- let val = this. wrapping_binary_op ( mir:: BinOp :: Eq , & left, & right) ?;
93- // We're type punning a bool as an u8 here.
94- this. write_scalar ( val. to_scalar ( ) , dest) ?;
95- }
96- "const_allocate" => {
97- // For now, for compatibility with the run-time implementation of this, we just return null.
98- // See <https://github.com/rust-lang/rust/issues/93935>.
99- this. write_null ( dest) ?;
100- }
101- "const_deallocate" => {
102- // complete NOP
103- }
104-
105106 // Raw memory accesses
106107 "volatile_load" => {
107108 let [ place] = check_arg_count ( args) ?;
@@ -425,9 +426,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
425426 throw_machine_stop ! ( TerminationInfo :: Abort ( format!( "trace/breakpoint trap" ) ) )
426427 }
427428
428- name => throw_unsup_format ! ( "unimplemented intrinsic: `{name}`" ) ,
429+ _ => return Ok ( false ) ,
429430 }
430431
431- Ok ( ( ) )
432+ Ok ( true )
432433 }
433434}
0 commit comments