Rollup merge of #114992 - RalfJung:rustc_do_not_const_check, r=b-naber

const-eval: ensure we never const-execute a function marked rustc_do_not_const_check
This commit is contained in:
Matthias Krüger 2023-08-20 00:28:33 +02:00 committed by GitHub
commit bb3cf24d15
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -427,52 +427,41 @@ fn load_mir(
fn find_mir_or_eval_fn( fn find_mir_or_eval_fn(
ecx: &mut InterpCx<'mir, 'tcx, Self>, ecx: &mut InterpCx<'mir, 'tcx, Self>,
instance: ty::Instance<'tcx>, orig_instance: ty::Instance<'tcx>,
_abi: CallAbi, _abi: CallAbi,
args: &[FnArg<'tcx>], args: &[FnArg<'tcx>],
dest: &PlaceTy<'tcx>, dest: &PlaceTy<'tcx>,
ret: Option<mir::BasicBlock>, ret: Option<mir::BasicBlock>,
_unwind: mir::UnwindAction, // unwinding is not supported in consts _unwind: mir::UnwindAction, // unwinding is not supported in consts
) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> { ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> {
debug!("find_mir_or_eval_fn: {:?}", instance); debug!("find_mir_or_eval_fn: {:?}", orig_instance);
// Replace some functions.
let Some(instance) = ecx.hook_special_const_fn(orig_instance, args, dest, ret)? else {
// Call has already been handled.
return Ok(None);
};
// Only check non-glue functions // Only check non-glue functions
if let ty::InstanceDef::Item(def) = instance.def { if let ty::InstanceDef::Item(def) = instance.def {
// Execution might have wandered off into other crates, so we cannot do a stability- // Execution might have wandered off into other crates, so we cannot do a stability-
// sensitive check here. But we can at least rule out functions that are not const // sensitive check here. But we can at least rule out functions that are not const at
// at all. // all. That said, we have to allow calling functions inside a trait marked with
if !ecx.tcx.is_const_fn_raw(def) { // #[const_trait]. These *are* const-checked!
// allow calling functions inside a trait marked with #[const_trait]. // FIXME: why does `is_const_fn_raw` not classify them as const?
if !ecx.tcx.is_const_default_method(def) { if (!ecx.tcx.is_const_fn_raw(def) && !ecx.tcx.is_const_default_method(def))
// We certainly do *not* want to actually call the fn || ecx.tcx.has_attr(def, sym::rustc_do_not_const_check)
// though, so be sure we return here. {
throw_unsup_format!("calling non-const function `{}`", instance) // We certainly do *not* want to actually call the fn
} // though, so be sure we return here.
} throw_unsup_format!("calling non-const function `{}`", instance)
let Some(new_instance) = ecx.hook_special_const_fn(instance, args, dest, ret)? else {
return Ok(None);
};
if new_instance != instance {
// We call another const fn instead.
// However, we return the *original* instance to make backtraces work out
// (and we hope this does not confuse the FnAbi checks too much).
return Ok(Self::find_mir_or_eval_fn(
ecx,
new_instance,
_abi,
args,
dest,
ret,
_unwind,
)?
.map(|(body, _instance)| (body, instance)));
} }
} }
// This is a const fn. Call it. // This is a const fn. Call it.
Ok(Some((ecx.load_mir(instance.def, None)?, instance))) // In case of replacement, we return the *original* instance to make backtraces work out
// (and we hope this does not confuse the FnAbi checks too much).
Ok(Some((ecx.load_mir(instance.def, None)?, orig_instance)))
} }
fn call_intrinsic( fn call_intrinsic(