diff options
Diffstat (limited to 'compiler/rustc_const_eval/src')
5 files changed, 46 insertions, 12 deletions
diff --git a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs index 7b6828c6e18..afc60d33647 100644 --- a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs @@ -105,7 +105,7 @@ impl<'mir, 'tcx: 'mir> interpret::Machine<'mir, 'tcx> for DummyMachine { _destination: &interpret::MPlaceTy<'tcx, Self::Provenance>, _target: Option<BasicBlock>, _unwind: UnwindAction, - ) -> interpret::InterpResult<'tcx> { + ) -> interpret::InterpResult<'tcx, Option<ty::Instance<'tcx>>> { unimplemented!() } diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index dd835279df3..e9cf5a3d769 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -459,16 +459,26 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, dest: &MPlaceTy<'tcx, Self::Provenance>, target: Option<mir::BasicBlock>, _unwind: mir::UnwindAction, - ) -> InterpResult<'tcx> { + ) -> InterpResult<'tcx, Option<ty::Instance<'tcx>>> { // Shared intrinsics. if ecx.emulate_intrinsic(instance, args, dest, target)? { - return Ok(()); + return Ok(None); } let intrinsic_name = ecx.tcx.item_name(instance.def_id()); // CTFE-specific intrinsics. let Some(ret) = target else { - throw_unsup_format!("intrinsic `{intrinsic_name}` is not supported at compile-time"); + // Handle diverging intrinsics. We can't handle any of them (that are not already + // handled above), but check if there is a fallback body. + if ecx.tcx.intrinsic(instance.def_id()).unwrap().must_be_overridden { + throw_unsup_format!( + "intrinsic `{intrinsic_name}` is not supported at compile-time" + ); + } + return Ok(Some(ty::Instance { + def: ty::InstanceDef::Item(instance.def_id()), + args: instance.args, + })); }; match intrinsic_name { sym::ptr_guaranteed_cmp => { @@ -536,14 +546,21 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, // not the optimization stage.) sym::is_val_statically_known => ecx.write_scalar(Scalar::from_bool(false), dest)?, _ => { - throw_unsup_format!( - "intrinsic `{intrinsic_name}` is not supported at compile-time" - ); + // We haven't handled the intrinsic, let's see if we can use a fallback body. + if ecx.tcx.intrinsic(instance.def_id()).unwrap().must_be_overridden { + throw_unsup_format!( + "intrinsic `{intrinsic_name}` is not supported at compile-time" + ); + } + return Ok(Some(ty::Instance { + def: ty::InstanceDef::Item(instance.def_id()), + args: instance.args, + })); } } ecx.go_to_block(ret); - Ok(()) + Ok(None) } fn assert_panic( diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 4d37c3c22cd..f73293856c7 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -414,7 +414,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } self.copy_op(&self.project_index(&input, index)?, dest)?; } - sym::likely | sym::unlikely | sym::black_box => { + sym::black_box => { // These just return their argument self.copy_op(&args[0], dest)?; } diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 8bc569bed54..8405d0746df 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -216,6 +216,9 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized { /// Directly process an intrinsic without pushing a stack frame. It is the hook's /// responsibility to advance the instruction pointer as appropriate. + /// + /// Returns `None` if the intrinsic was fully handled. + /// Otherwise, returns an `Instance` of the function that implements the intrinsic. fn call_intrinsic( ecx: &mut InterpCx<'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, @@ -223,7 +226,7 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized { destination: &MPlaceTy<'tcx, Self::Provenance>, target: Option<mir::BasicBlock>, unwind: mir::UnwindAction, - ) -> InterpResult<'tcx>; + ) -> InterpResult<'tcx, Option<ty::Instance<'tcx>>>; /// Called to evaluate `Assert` MIR terminators that trigger a panic. fn assert_panic( diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index 9c31532a9ce..07425f9a686 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -539,14 +539,28 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ty::InstanceDef::Intrinsic(def_id) => { assert!(self.tcx.intrinsic(def_id).is_some()); // FIXME: Should `InPlace` arguments be reset to uninit? - M::call_intrinsic( + if let Some(fallback) = M::call_intrinsic( self, instance, &self.copy_fn_args(args), destination, target, unwind, - ) + )? { + assert!(!self.tcx.intrinsic(fallback.def_id()).unwrap().must_be_overridden); + assert!(matches!(fallback.def, ty::InstanceDef::Item(_))); + return self.eval_fn_call( + FnVal::Instance(fallback), + (caller_abi, caller_fn_abi), + args, + with_caller_location, + destination, + target, + unwind, + ); + } else { + Ok(()) + } } ty::InstanceDef::VTableShim(..) | ty::InstanceDef::ReifyShim(..) |
