diff options
| author | Ralf Jung <post@ralfj.de> | 2024-09-29 11:53:23 +0200 |
|---|---|---|
| committer | Ralf Jung <post@ralfj.de> | 2024-10-01 21:45:35 +0200 |
| commit | c4ce8c114b06840c3521a189ee44958b713fb33a (patch) | |
| tree | 8c7b85df780bfb8751c75ad3e7240bc805a40dfc /compiler/rustc_const_eval | |
| parent | 4b8a5bd511814ed97640c46ab2232acc0e0ade41 (diff) | |
| download | rust-c4ce8c114b06840c3521a189ee44958b713fb33a.tar.gz rust-c4ce8c114b06840c3521a189ee44958b713fb33a.zip | |
make InterpResult a dedicated type to avoid accidentally discarding the error
Diffstat (limited to 'compiler/rustc_const_eval')
24 files changed, 501 insertions, 494 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 ed1c912e6cb..743924faa21 100644 --- a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs @@ -6,7 +6,8 @@ use rustc_middle::{bug, span_bug, ty}; use rustc_span::def_id::DefId; use crate::interpret::{ - self, HasStaticRootDefId, ImmTy, Immediate, InterpCx, PointerArithmetic, throw_machine_stop, + self, HasStaticRootDefId, ImmTy, Immediate, InterpCx, PointerArithmetic, interp_ok, + throw_machine_stop, }; /// Macro for machine-specific `InterpError` without allocation. @@ -79,7 +80,7 @@ impl<'tcx> interpret::Machine<'tcx> for DummyMachine { throw_machine_stop_str!("can't access mutable globals in ConstProp"); } - Ok(()) + interp_ok(()) } fn find_mir_or_eval_fn( @@ -127,7 +128,7 @@ impl<'tcx> interpret::Machine<'tcx> for DummyMachine { right: &interpret::ImmTy<'tcx, Self::Provenance>, ) -> interpret::InterpResult<'tcx, ImmTy<'tcx, Self::Provenance>> { use rustc_middle::mir::BinOp::*; - Ok(match bin_op { + interp_ok(match bin_op { Eq | Ne | Lt | Le | Gt | Ge => { // Types can differ, e.g. fn ptrs with different `for`. assert_eq!(left.layout.abi, right.layout.abi); diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index a241edbd77a..672353e629d 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -20,7 +20,7 @@ use crate::const_eval::CheckAlignment; use crate::interpret::{ CtfeValidationMode, GlobalId, Immediate, InternKind, InternResult, InterpCx, InterpError, InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking, StackPopCleanup, create_static_alloc, - eval_nullary_intrinsic, intern_const_alloc_recursive, throw_exhaust, + eval_nullary_intrinsic, intern_const_alloc_recursive, interp_ok, throw_exhaust, }; use crate::{CTRL_C_RECEIVED, errors}; @@ -98,19 +98,19 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>( return Err(ecx .tcx .dcx() - .emit_err(errors::DanglingPtrInFinal { span: ecx.tcx.span, kind: intern_kind }) - .into()); + .emit_err(errors::DanglingPtrInFinal { span: ecx.tcx.span, kind: intern_kind })) + .into(); } Err(InternResult::FoundBadMutablePointer) => { return Err(ecx .tcx .dcx() - .emit_err(errors::MutablePtrInFinal { span: ecx.tcx.span, kind: intern_kind }) - .into()); + .emit_err(errors::MutablePtrInFinal { span: ecx.tcx.span, kind: intern_kind })) + .into(); } } - Ok(R::make_result(ret, ecx)) + interp_ok(R::make_result(ret, ecx)) } /// The `InterpCx` is only meant to be used to do field and index projections into constants for @@ -147,7 +147,8 @@ pub fn mk_eval_cx_for_const_val<'tcx>( ty: Ty<'tcx>, ) -> Option<(CompileTimeInterpCx<'tcx>, OpTy<'tcx>)> { let ecx = mk_eval_cx_to_read_const_val(tcx.tcx, tcx.span, param_env, CanAccessMutGlobal::No); - let op = ecx.const_val_to_op(val, ty, None).ok()?; + // FIXME: is it a problem to discard the error here? + let op = ecx.const_val_to_op(val, ty, None).discard_err()?; Some((ecx, op)) } @@ -185,12 +186,16 @@ pub(super) fn op_to_const<'tcx>( _ => false, }; let immediate = if force_as_immediate { - match ecx.read_immediate(op) { + match ecx.read_immediate(op).report_err() { Ok(imm) => Right(imm), - Err(err) if !for_diagnostics => { - panic!("normalization works on validated constants: {err:?}") + Err(err) => { + if for_diagnostics { + // This discard the error, but for diagnostics that's okay. + op.as_mplace_or_imm() + } else { + panic!("normalization works on validated constants: {err:?}") + } } - _ => op.as_mplace_or_imm(), } } else { op.as_mplace_or_imm() @@ -283,17 +288,19 @@ pub fn eval_to_const_value_raw_provider<'tcx>( let ty::FnDef(_, args) = ty.kind() else { bug!("intrinsic with type {:?}", ty); }; - return eval_nullary_intrinsic(tcx, key.param_env, def_id, args).map_err(|error| { - let span = tcx.def_span(def_id); - - super::report( - tcx, - error.into_kind(), - span, - || (span, vec![]), - |span, _| errors::NullaryIntrinsicError { span }, - ) - }); + return eval_nullary_intrinsic(tcx, key.param_env, def_id, args).report_err().map_err( + |error| { + let span = tcx.def_span(def_id); + + super::report( + tcx, + error.into_kind(), + span, + || (span, vec![]), + |span, _| errors::NullaryIntrinsicError { span }, + ) + }, + ); } tcx.eval_to_allocation_raw(key).map(|val| turn_into_const_value(tcx, val, key)) @@ -376,6 +383,7 @@ fn eval_in_interpreter<'tcx, R: InterpretationResult<'tcx>>( ); let res = ecx.load_mir(cid.instance.def, cid.promoted); res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, body)) + .report_err() .map_err(|error| report_eval_error(&ecx, cid, error)) } @@ -400,6 +408,7 @@ fn const_validate_mplace<'tcx>( } }; ecx.const_validate_operand(&mplace.into(), path, &mut ref_tracking, mode) + .report_err() // Instead of just reporting the `InterpError` via the usual machinery, we give a more targeted // error about the validation failure. .map_err(|error| report_validation_error(&ecx, cid, error, alloc_id))?; diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 6d74998b7d8..4aec74595bc 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -24,8 +24,8 @@ use crate::fluent_generated as fluent; use crate::interpret::{ self, AllocId, AllocRange, ConstAllocation, CtfeProvenance, FnArg, Frame, GlobalAlloc, ImmTy, InterpCx, InterpResult, MPlaceTy, OpTy, Pointer, PointerArithmetic, RangeSet, Scalar, - StackPopCleanup, compile_time_machine, err_ub, throw_exhaust, throw_inval, throw_ub_custom, - throw_unsup, throw_unsup_format, + StackPopCleanup, compile_time_machine, interp_ok, throw_exhaust, throw_inval, throw_ub, + throw_ub_custom, throw_unsup, throw_unsup_format, }; /// When hitting this many interpreted terminators we emit a deny by default lint @@ -247,7 +247,7 @@ impl<'tcx> CompileTimeInterpCx<'tcx> { let msg = Symbol::intern(self.read_str(&msg_place)?); let span = self.find_closest_untracked_caller_location(); let (file, line, col) = self.location_triple_for_span(span); - return Err(ConstEvalErrKind::Panic { msg, file, line, col }.into()); + return Err(ConstEvalErrKind::Panic { msg, file, line, col }).into(); } else if self.tcx.is_lang_item(def_id, LangItem::PanicFmt) { // For panic_fmt, call const_panic_fmt instead. let const_def_id = self.tcx.require_lang_item(LangItem::ConstPanicFmt, None); @@ -259,16 +259,16 @@ impl<'tcx> CompileTimeInterpCx<'tcx> { self.cur_span(), ); - return Ok(Some(new_instance)); + return interp_ok(Some(new_instance)); } else if self.tcx.is_lang_item(def_id, LangItem::AlignOffset) { let args = self.copy_fn_args(args); // For align_offset, we replace the function call if the pointer has no address. match self.align_offset(instance, &args, dest, ret)? { - ControlFlow::Continue(()) => return Ok(Some(instance)), - ControlFlow::Break(()) => return Ok(None), + ControlFlow::Continue(()) => return interp_ok(Some(instance)), + ControlFlow::Break(()) => return interp_ok(None), } } - Ok(Some(instance)) + interp_ok(Some(instance)) } /// `align_offset(ptr, target_align)` needs special handling in const eval, because the pointer @@ -323,25 +323,25 @@ impl<'tcx> CompileTimeInterpCx<'tcx> { dest, StackPopCleanup::Goto { ret, unwind: mir::UnwindAction::Unreachable }, )?; - Ok(ControlFlow::Break(())) + interp_ok(ControlFlow::Break(())) } else { // Not alignable in const, return `usize::MAX`. let usize_max = Scalar::from_target_usize(self.target_usize_max(), self); self.write_scalar(usize_max, dest)?; self.return_to_block(ret)?; - Ok(ControlFlow::Break(())) + interp_ok(ControlFlow::Break(())) } } Err(_addr) => { // The pointer has an address, continue with function call. - Ok(ControlFlow::Continue(())) + interp_ok(ControlFlow::Continue(())) } } } /// See documentation on the `ptr_guaranteed_cmp` intrinsic. fn guaranteed_cmp(&mut self, a: Scalar, b: Scalar) -> InterpResult<'tcx, u8> { - Ok(match (a, b) { + interp_ok(match (a, b) { // Comparisons between integers are always known. (Scalar::Int { .. }, Scalar::Int { .. }) => { if a == b { @@ -403,8 +403,8 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { instance: ty::InstanceKind<'tcx>, ) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> { match instance { - ty::InstanceKind::Item(def) => Ok(ecx.tcx.mir_for_ctfe(def)), - _ => Ok(ecx.tcx.instance_mir(instance)), + ty::InstanceKind::Item(def) => interp_ok(ecx.tcx.mir_for_ctfe(def)), + _ => interp_ok(ecx.tcx.instance_mir(instance)), } } @@ -422,7 +422,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { // 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); + return interp_ok(None); }; // Only check non-glue functions @@ -444,14 +444,14 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { // This is a const fn. Call it. // 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))) + interp_ok(Some((ecx.load_mir(instance.def, None)?, orig_instance))) } fn panic_nounwind(ecx: &mut InterpCx<'tcx, Self>, msg: &str) -> InterpResult<'tcx> { let msg = Symbol::intern(msg); let span = ecx.find_closest_untracked_caller_location(); let (file, line, col) = ecx.location_triple_for_span(span); - Err(ConstEvalErrKind::Panic { msg, file, line, col }.into()) + Err(ConstEvalErrKind::Panic { msg, file, line, col }).into() } fn call_intrinsic( @@ -464,7 +464,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { ) -> InterpResult<'tcx, Option<ty::Instance<'tcx>>> { // Shared intrinsics. if ecx.eval_intrinsic(instance, args, dest, target)? { - return Ok(None); + return interp_ok(None); } let intrinsic_name = ecx.tcx.item_name(instance.def_id()); @@ -541,7 +541,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { "intrinsic `{intrinsic_name}` is not supported at compile-time" ); } - return Ok(Some(ty::Instance { + return interp_ok(Some(ty::Instance { def: ty::InstanceKind::Item(instance.def_id()), args: instance.args, })); @@ -550,7 +550,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { // Intrinsic is done, jump to next block. ecx.return_to_block(target)?; - Ok(None) + interp_ok(None) } fn assert_panic( @@ -581,7 +581,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { } } }; - Err(ConstEvalErrKind::AssertFailure(err).into()) + Err(ConstEvalErrKind::AssertFailure(err)).into() } fn binary_ptr_op( @@ -652,7 +652,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { } } - Ok(()) + interp_ok(()) } #[inline(always)] @@ -670,7 +670,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { if !ecx.recursion_limit.value_within_limit(ecx.stack().len() + 1) { throw_exhaust!(StackFrameLimitReached) } else { - Ok(frame) + interp_ok(frame) } } @@ -700,22 +700,22 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { if is_write { // Write access. These are never allowed, but we give a targeted error message. match alloc.mutability { - Mutability::Not => Err(err_ub!(WriteToReadOnly(alloc_id)).into()), - Mutability::Mut => Err(ConstEvalErrKind::ModifiedGlobal.into()), + Mutability::Not => throw_ub!(WriteToReadOnly(alloc_id)), + Mutability::Mut => Err(ConstEvalErrKind::ModifiedGlobal).into(), } } else { // Read access. These are usually allowed, with some exceptions. if machine.can_access_mut_global == CanAccessMutGlobal::Yes { // Machine configuration allows us read from anything (e.g., `static` initializer). - Ok(()) + interp_ok(()) } else if alloc.mutability == Mutability::Mut { // Machine configuration does not allow us to read statics (e.g., `const` // initializer). - Err(ConstEvalErrKind::ConstAccessesMutGlobal.into()) + Err(ConstEvalErrKind::ConstAccessesMutGlobal).into() } else { // Immutable global, this read is fine. assert_eq!(alloc.mutability, Mutability::Not); - Ok(()) + interp_ok(()) } } } @@ -748,9 +748,9 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { // even when there is interior mutability.) place.map_provenance(CtfeProvenance::as_shared_ref) }; - Ok(ImmTy::from_immediate(new_place.to_ref(ecx), val.layout)) + interp_ok(ImmTy::from_immediate(new_place.to_ref(ecx), val.layout)) } else { - Ok(val.clone()) + interp_ok(val.clone()) } } @@ -763,20 +763,20 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { ) -> InterpResult<'tcx> { if range.size == Size::ZERO { // Nothing to check. - return Ok(()); + return interp_ok(()); } // Reject writes through immutable pointers. if immutable { - return Err(ConstEvalErrKind::WriteThroughImmutablePointer.into()); + return Err(ConstEvalErrKind::WriteThroughImmutablePointer).into(); } // Everything else is fine. - Ok(()) + interp_ok(()) } fn before_alloc_read(ecx: &InterpCx<'tcx, Self>, alloc_id: AllocId) -> InterpResult<'tcx> { // Check if this is the currently evaluated static. if Some(alloc_id) == ecx.machine.static_root_ids.map(|(id, _)| id) { - return Err(ConstEvalErrKind::RecursiveStatic.into()); + return Err(ConstEvalErrKind::RecursiveStatic).into(); } // If this is another static, make sure we fire off the query to detect cycles. // But only do that when checks for static recursion are enabled. @@ -788,7 +788,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { ecx.ctfe_query(|tcx| tcx.eval_static_initializer(def_id))?; } } - Ok(()) + interp_ok(()) } fn cached_union_data_range<'e>( diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs index 48aeee2e6f0..ba19f642795 100644 --- a/compiler/rustc_const_eval/src/const_eval/mod.rs +++ b/compiler/rustc_const_eval/src/const_eval/mod.rs @@ -1,13 +1,12 @@ // Not in interpret to make sure we do not use private implementation details -use rustc_middle::mir::interpret::InterpErrorInfo; use rustc_middle::query::{Key, TyCtxtAt}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::{bug, mir}; use rustc_target::abi::VariantIdx; use tracing::instrument; -use crate::interpret::{InterpCx, format_interp_error}; +use crate::interpret::InterpCx; mod dummy_machine; mod error; @@ -33,17 +32,6 @@ pub(crate) enum ValTreeCreationError<'tcx> { } pub(crate) type ValTreeCreationResult<'tcx> = Result<ty::ValTree<'tcx>, ValTreeCreationError<'tcx>>; -impl<'tcx> From<InterpErrorInfo<'tcx>> for ValTreeCreationError<'tcx> { - fn from(err: InterpErrorInfo<'tcx>) -> Self { - ty::tls::with(|tcx| { - bug!( - "Unexpected Undefined Behavior error during valtree construction: {}", - format_interp_error(tcx.dcx(), err), - ) - }) - } -} - #[instrument(skip(tcx), level = "debug")] pub(crate) fn try_destructure_mir_constant_for_user_output<'tcx>( tcx: TyCtxtAt<'tcx>, @@ -60,8 +48,8 @@ pub(crate) fn try_destructure_mir_constant_for_user_output<'tcx>( return None; } ty::Adt(def, _) => { - let variant = ecx.read_discriminant(&op).ok()?; - let down = ecx.project_downcast(&op, variant).ok()?; + let variant = ecx.read_discriminant(&op).discard_err()?; + let down = ecx.project_downcast(&op, variant).discard_err()?; (def.variants()[variant].fields.len(), Some(variant), down) } ty::Tuple(args) => (args.len(), None, op), @@ -70,7 +58,7 @@ pub(crate) fn try_destructure_mir_constant_for_user_output<'tcx>( let fields_iter = (0..field_count) .map(|i| { - let field_op = ecx.project_field(&down, i).ok()?; + let field_op = ecx.project_field(&down, i).discard_err()?; let val = op_to_const(&ecx, &field_op, /* for diagnostics */ true); Some((val, field_op.layout.ty)) }) diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index a11d491bdd2..9e80e666ba9 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -92,7 +92,7 @@ fn const_to_valtree_inner<'tcx>( Ok(ty::ValTree::zst()) } ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => { - let val = ecx.read_immediate(place)?; + let val = ecx.read_immediate(place).unwrap(); let val = val.to_scalar_int().unwrap(); *num_nodes += 1; @@ -114,7 +114,7 @@ fn const_to_valtree_inner<'tcx>( // equality at compile-time (see `ptr_guaranteed_cmp`). // However we allow those that are just integers in disguise. // First, get the pointer. Remember it might be wide! - let val = ecx.read_immediate(place)?; + let val = ecx.read_immediate(place).unwrap(); // We could allow wide raw pointers where both sides are integers in the future, // but for now we reject them. if matches!(val.layout.abi, Abi::ScalarPair(..)) { @@ -135,7 +135,7 @@ fn const_to_valtree_inner<'tcx>( ty::FnPtr(..) => Err(ValTreeCreationError::NonSupportedType(ty)), ty::Ref(_, _, _) => { - let derefd_place = ecx.deref_pointer(place)?; + let derefd_place = ecx.deref_pointer(place).unwrap(); const_to_valtree_inner(ecx, &derefd_place, num_nodes) } @@ -159,7 +159,7 @@ fn const_to_valtree_inner<'tcx>( bug!("uninhabited types should have errored and never gotten converted to valtree") } - let variant = ecx.read_discriminant(place)?; + let variant = ecx.read_discriminant(place).unwrap(); branches(ecx, place, def.variant(variant).fields.len(), def.is_enum().then_some(variant), num_nodes) } diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index 19aa76bf1ea..4945563f4a4 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -15,8 +15,8 @@ use tracing::{info, instrument, trace}; use super::{ CtfeProvenance, FnVal, ImmTy, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, PlaceTy, - Projectable, Provenance, ReturnAction, Scalar, StackPopCleanup, StackPopInfo, throw_ub, - throw_ub_custom, throw_unsup_format, + Projectable, Provenance, ReturnAction, Scalar, StackPopCleanup, StackPopInfo, interp_ok, + throw_ub, throw_ub_custom, throw_unsup_format, }; use crate::fluent_generated as fluent; @@ -64,7 +64,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { arg: &FnArg<'tcx, M::Provenance>, field: usize, ) -> InterpResult<'tcx, FnArg<'tcx, M::Provenance>> { - Ok(match arg { + interp_ok(match arg { FnArg::Copy(op) => FnArg::Copy(self.project_field(op, field)?), FnArg::InPlace(mplace) => FnArg::InPlace(self.project_field(mplace, field)?), }) @@ -97,7 +97,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // another type. let ty::Adt(def, args) = layout.ty.kind() else { // Not an ADT, so definitely no NPO. - return Ok(layout); + return interp_ok(layout); }; let inner = if self.tcx.is_diagnostic_item(sym::Option, def.did()) { // The wrapped type is the only arg. @@ -111,10 +111,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } else if rhs.is_1zst() { lhs } else { - return Ok(layout); // no NPO + return interp_ok(layout); // no NPO } } else { - return Ok(layout); // no NPO + return interp_ok(layout); // no NPO }; // Check if the inner type is one of the NPO-guaranteed ones. @@ -126,7 +126,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Stop at NPO types so that we don't miss that attribute in the check below! def.is_struct() && !is_npo(def) }); - Ok(match inner.ty.kind() { + interp_ok(match inner.ty.kind() { ty::Ref(..) | ty::FnPtr(..) => { // Option<&T> behaves like &T, and same for fn() inner @@ -153,11 +153,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ) -> InterpResult<'tcx, bool> { // Fast path: equal types are definitely compatible. if caller.ty == callee.ty { - return Ok(true); + return interp_ok(true); } // 1-ZST are compatible with all 1-ZST (and with nothing else). if caller.is_1zst() || callee.is_1zst() { - return Ok(caller.is_1zst() && callee.is_1zst()); + return interp_ok(caller.is_1zst() && callee.is_1zst()); } // Unfold newtypes and NPO optimizations. let unfold = |layout: TyAndLayout<'tcx>| { @@ -180,17 +180,17 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { _ => None, }; if let (Some(caller), Some(callee)) = (thin_pointer(caller), thin_pointer(callee)) { - return Ok(caller == callee); + return interp_ok(caller == callee); } // For wide pointers we have to get the pointee type. let pointee_ty = |ty: Ty<'tcx>| -> InterpResult<'tcx, Option<Ty<'tcx>>> { // We cannot use `builtin_deref` here since we need to reject `Box<T, MyAlloc>`. - Ok(Some(match ty.kind() { + interp_ok(Some(match ty.kind() { ty::Ref(_, ty, _) => *ty, ty::RawPtr(ty, _) => *ty, // We only accept `Box` with the default allocator. _ if ty.is_box_global(*self.tcx) => ty.expect_boxed_ty(), - _ => return Ok(None), + _ => return interp_ok(None), })) }; if let (Some(caller), Some(callee)) = (pointee_ty(caller.ty)?, pointee_ty(callee.ty)?) { @@ -202,7 +202,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let normalize = |ty| self.tcx.normalize_erasing_regions(self.param_env, ty); ty.ptr_metadata_ty(*self.tcx, normalize) }; - return Ok(meta_ty(caller) == meta_ty(callee)); + return interp_ok(meta_ty(caller) == meta_ty(callee)); } // Compatible integer types (in particular, usize vs ptr-sized-u32/u64). @@ -217,11 +217,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { }; if let (Some(caller), Some(callee)) = (int_ty(caller.ty), int_ty(callee.ty)) { // This is okay if they are the same integer type. - return Ok(caller == callee); + return interp_ok(caller == callee); } // Fall back to exact equality. - Ok(caller == callee) + interp_ok(caller == callee) } fn check_argument_compat( @@ -235,13 +235,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Ensure that our checks imply actual ABI compatibility for this concrete call. // (This can fail e.g. if `#[rustc_nonnull_optimization_guaranteed]` is used incorrectly.) assert!(caller_abi.eq_abi(callee_abi)); - Ok(true) + interp_ok(true) } else { trace!( "check_argument_compat: incompatible ABIs:\ncaller: {:?}\ncallee: {:?}", caller_abi, callee_abi ); - Ok(false) + interp_ok(false) } } @@ -266,7 +266,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if !already_live { self.storage_live(callee_arg.as_local().unwrap())?; } - return Ok(()); + return interp_ok(()); } // Find next caller arg. let Some((caller_arg, caller_abi)) = caller_args.next() else { @@ -308,7 +308,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if let FnArg::InPlace(mplace) = caller_arg { M::protect_in_place_function_argument(self, mplace)?; } - Ok(()) + interp_ok(()) } /// The main entry point for creating a new stack frame: performs ABI checks and initializes @@ -536,7 +536,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { unwind, ); } else { - Ok(()) + interp_ok(()) } } ty::InstanceKind::VTableShim(..) @@ -561,7 +561,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { unwind, )? else { - return Ok(()); + return interp_ok(()); }; // Special handling for the closure ABI: untuple the last argument. @@ -572,7 +572,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { trace!("init_fn_call: Will pass last argument by untupling"); Cow::from( args.iter() - .map(|a| Ok(a.clone())) + .map(|a| interp_ok(a.clone())) .chain( (0..untuple_arg.layout().fields.count()) .map(|i| self.fn_arg_field(untuple_arg, i)), @@ -886,27 +886,25 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // this transmute. res } else { - Ok(()) + interp_ok(()) }; // All right, now it is time to actually pop the frame. - let stack_pop_info = self.pop_stack_frame_raw(unwinding)?; - - // Report error from return value copy, if any. - copy_ret_result?; + // An error here takes precedence over the copy error. + let (stack_pop_info, ()) = self.pop_stack_frame_raw(unwinding).and(copy_ret_result)?; match stack_pop_info.return_action { ReturnAction::Normal => {} ReturnAction::NoJump => { // The hook already did everything. - return Ok(()); + return interp_ok(()); } ReturnAction::NoCleanup => { // If we are not doing cleanup, also skip everything else. assert!(self.stack().is_empty(), "only the topmost frame should ever be leaked"); assert!(!unwinding, "tried to skip cleanup during unwinding"); // Skip machine hook. - return Ok(()); + return interp_ok(()); } } @@ -931,7 +929,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.stack().is_empty(), "only the bottommost frame can have StackPopCleanup::Root" ); - Ok(()) + interp_ok(()) } } } diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 85e7d91c2ad..565a7d16242 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -14,7 +14,8 @@ use tracing::trace; use super::util::ensure_monomorphic_enough; use super::{ - FnVal, ImmTy, Immediate, InterpCx, Machine, OpTy, PlaceTy, err_inval, throw_ub, throw_ub_custom, + FnVal, ImmTy, Immediate, InterpCx, Machine, OpTy, PlaceTy, err_inval, interp_ok, throw_ub, + throw_ub_custom, }; use crate::fluent_generated as fluent; @@ -157,7 +158,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.copy_op_allow_transmute(src, dest)?; } } - Ok(()) + interp_ok(()) } /// Handles 'IntToInt' and 'IntToFloat' casts. @@ -169,7 +170,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { assert!(src.layout.ty.is_integral() || src.layout.ty.is_char() || src.layout.ty.is_bool()); assert!(cast_to.ty.is_floating_point() || cast_to.ty.is_integral() || cast_to.ty.is_char()); - Ok(ImmTy::from_scalar( + interp_ok(ImmTy::from_scalar( self.cast_from_int_like(src.to_scalar(), src.layout, cast_to.ty)?, cast_to, )) @@ -192,7 +193,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { FloatTy::F64 => self.cast_from_float(src.to_scalar().to_f64()?, cast_to.ty), FloatTy::F128 => self.cast_from_float(src.to_scalar().to_f128()?, cast_to.ty), }; - Ok(ImmTy::from_scalar(val, cast_to)) + interp_ok(ImmTy::from_scalar(val, cast_to)) } /// Handles 'FnPtrToPtr' and 'PtrToPtr' casts. @@ -206,14 +207,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Handle casting any ptr to raw ptr (might be a fat ptr). if cast_to.size == src.layout.size { // Thin or fat pointer that just has the ptr kind of target type changed. - return Ok(ImmTy::from_immediate(**src, cast_to)); + return interp_ok(ImmTy::from_immediate(**src, cast_to)); } else { // Casting the metadata away from a fat ptr. assert_eq!(src.layout.size, 2 * self.pointer_size()); assert_eq!(cast_to.size, self.pointer_size()); assert!(src.layout.ty.is_unsafe_ptr()); return match **src { - Immediate::ScalarPair(data, _) => Ok(ImmTy::from_scalar(data, cast_to)), + Immediate::ScalarPair(data, _) => interp_ok(ImmTy::from_scalar(data, cast_to)), Immediate::Scalar(..) => span_bug!( self.cur_span(), "{:?} input to a fat-to-thin cast ({} -> {})", @@ -240,7 +241,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Ok(ptr) => M::expose_ptr(self, ptr)?, Err(_) => {} // Do nothing, exposing an invalid pointer (`None` provenance) is a NOP. }; - Ok(ImmTy::from_scalar(self.cast_from_int_like(scalar, src.layout, cast_to.ty)?, cast_to)) + interp_ok(ImmTy::from_scalar( + self.cast_from_int_like(scalar, src.layout, cast_to.ty)?, + cast_to, + )) } pub fn pointer_with_exposed_provenance_cast( @@ -258,7 +262,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Then turn address into pointer. let ptr = M::ptr_from_addr_cast(self, addr)?; - Ok(ImmTy::from_scalar(Scalar::from_maybe_pointer(ptr, self), cast_to)) + interp_ok(ImmTy::from_scalar(Scalar::from_maybe_pointer(ptr, self), cast_to)) } /// Low-level cast helper function. This works directly on scalars and can take 'int-like' input @@ -280,7 +284,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { _ => span_bug!(self.cur_span(), "invalid int-like cast from {}", src_layout.ty), }; - Ok(match *cast_ty.kind() { + interp_ok(match *cast_ty.kind() { // int -> int Int(_) | Uint(_) => { let size = match *cast_ty.kind() { @@ -505,7 +509,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.unsize_into(&src_field, cast_ty_field, &dst_field)?; } } - Ok(()) + interp_ok(()) } _ => { // Do not ICE if we are not monomorphic enough. diff --git a/compiler/rustc_const_eval/src/interpret/discriminant.rs b/compiler/rustc_const_eval/src/interpret/discriminant.rs index 3bab2b3261e..81e0b1e12ca 100644 --- a/compiler/rustc_const_eval/src/interpret/discriminant.rs +++ b/compiler/rustc_const_eval/src/interpret/discriminant.rs @@ -7,7 +7,8 @@ use rustc_target::abi::{self, TagEncoding, VariantIdx, Variants}; use tracing::{instrument, trace}; use super::{ - ImmTy, InterpCx, InterpResult, Machine, Projectable, Scalar, Writeable, err_ub, throw_ub, + ImmTy, InterpCx, InterpResult, Machine, Projectable, Scalar, Writeable, err_ub, interp_ok, + throw_ub, }; impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { @@ -48,7 +49,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if actual_variant != variant_index { throw_ub!(InvalidNichedEnumVariantWritten { enum_ty: dest.layout().ty }); } - Ok(()) + interp_ok(()) } } } @@ -89,7 +90,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { throw_ub!(UninhabitedEnumVariantRead(index)) } } - return Ok(index); + return interp_ok(index); } Variants::Multiple { tag, ref tag_encoding, tag_field, .. } => { (tag, tag_encoding, tag_field) @@ -205,7 +206,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if op.layout().for_variant(self, index).abi.is_uninhabited() { throw_ub!(UninhabitedEnumVariantRead(index)) } - Ok(index) + interp_ok(index) } pub fn discriminant_for_variant( @@ -226,7 +227,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Scalar::from_uint(variant.as_u32(), discr_layout.size) } }; - Ok(ImmTy::from_scalar(discr_value, discr_layout)) + interp_ok(ImmTy::from_scalar(discr_value, discr_layout)) } /// Computes how to write the tag of a given variant of enum `ty`: @@ -247,7 +248,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // discriminant is encoded implicitly, so any attempt to write // the wrong discriminant for a `Single` enum will reliably // result in UB. - Ok(None) + interp_ok(None) } abi::Variants::Multiple { @@ -265,7 +266,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let tag_size = tag_layout.size(self); let tag_val = tag_size.truncate(discr_val); let tag = ScalarInt::try_from_uint(tag_val, tag_size).unwrap(); - Ok(Some((tag, tag_field))) + interp_ok(Some((tag, tag_field))) } abi::Variants::Multiple { @@ -274,7 +275,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } if untagged_variant == variant_index => { // The untagged variant is implicitly encoded simply by having a // value that is outside the niche variants. - Ok(None) + interp_ok(None) } abi::Variants::Multiple { @@ -299,7 +300,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let tag = self .binary_op(mir::BinOp::Add, &variant_index_relative_val, &niche_start_val)? .to_scalar_int()?; - Ok(Some((tag, tag_field))) + interp_ok(Some((tag, tag_field))) } } } diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index f4c4a6fb0bf..5165f95afd5 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -19,9 +19,9 @@ use rustc_trait_selection::traits::ObligationCtxt; use tracing::{debug, instrument, trace}; use super::{ - Frame, FrameInfo, GlobalId, InterpErrorInfo, InterpResult, MPlaceTy, Machine, MemPlaceMeta, - Memory, OpTy, Place, PlaceTy, PointerArithmetic, Projectable, Provenance, err_inval, - throw_inval, throw_ub, throw_ub_custom, + Frame, FrameInfo, GlobalId, InterpError, InterpErrorInfo, InterpResult, MPlaceTy, Machine, + MemPlaceMeta, Memory, OpTy, Place, PlaceTy, PointerArithmetic, Projectable, Provenance, + err_inval, interp_ok, throw_inval, throw_ub, throw_ub_custom, }; use crate::{ReportErrorExt, fluent_generated as fluent, util}; @@ -73,7 +73,7 @@ where } impl<'tcx, M: Machine<'tcx>> LayoutOfHelpers<'tcx> for InterpCx<'tcx, M> { - type LayoutOfResult = InterpResult<'tcx, TyAndLayout<'tcx>>; + type LayoutOfResult = Result<TyAndLayout<'tcx>, InterpError<'tcx>>; #[inline] fn layout_tcx_at_span(&self) -> Span { @@ -82,29 +82,24 @@ impl<'tcx, M: Machine<'tcx>> LayoutOfHelpers<'tcx> for InterpCx<'tcx, M> { } #[inline] - fn handle_layout_err( - &self, - err: LayoutError<'tcx>, - _: Span, - _: Ty<'tcx>, - ) -> InterpErrorInfo<'tcx> { - err_inval!(Layout(err)).into() + fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> InterpError<'tcx> { + err_inval!(Layout(err)) } } impl<'tcx, M: Machine<'tcx>> FnAbiOfHelpers<'tcx> for InterpCx<'tcx, M> { - type FnAbiOfResult = InterpResult<'tcx, &'tcx FnAbi<'tcx, Ty<'tcx>>>; + type FnAbiOfResult = Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, InterpError<'tcx>>; fn handle_fn_abi_err( &self, err: FnAbiError<'tcx>, _span: Span, _fn_abi_request: FnAbiRequest<'tcx>, - ) -> InterpErrorInfo<'tcx> { + ) -> InterpError<'tcx> { match err { - FnAbiError::Layout(err) => err_inval!(Layout(err)).into(), + FnAbiError::Layout(err) => err_inval!(Layout(err)), FnAbiError::AdjustForForeignAbi(err) => { - err_inval!(FnAbiAdjustForForeignAbi(err)).into() + err_inval!(FnAbiAdjustForForeignAbi(err)) } } } @@ -160,7 +155,7 @@ pub(super) fn from_known_layout<'tcx>( ); } } - Ok(known_layout) + interp_ok(known_layout) } } } @@ -262,7 +257,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if let Some(err) = body.tainted_by_errors { throw_inval!(AlreadyReported(ReportedErrorInfo::tainted_by_errors(err))); } - Ok(body) + interp_ok(body) } /// Call this on things you got out of the MIR (so it is as generic as the current @@ -305,7 +300,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { trace!("param_env: {:#?}", self.param_env); trace!("args: {:#?}", args); match ty::Instance::try_resolve(*self.tcx, self.param_env, def, args) { - Ok(Some(instance)) => Ok(instance), + Ok(Some(instance)) => interp_ok(instance), Ok(None) => throw_inval!(TooGeneric), // FIXME(eddyb) this could be a bit more specific than `AlreadyReported`. @@ -401,7 +396,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { layout: &TyAndLayout<'tcx>, ) -> InterpResult<'tcx, Option<(Size, Align)>> { if layout.is_sized() { - return Ok(Some((layout.size, layout.align.abi))); + return interp_ok(Some((layout.size, layout.align.abi))); } match layout.ty.kind() { ty::Adt(..) | ty::Tuple(..) => { @@ -425,7 +420,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { else { // A field with an extern type. We don't know the actual dynamic size // or the alignment. - return Ok(None); + return interp_ok(None); }; // # First compute the dynamic alignment @@ -456,12 +451,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if full_size > self.max_size_of_val() { throw_ub!(InvalidMeta(InvalidMetaKind::TooBig)); } - Ok(Some((full_size, full_align))) + interp_ok(Some((full_size, full_align))) } ty::Dynamic(expected_trait, _, ty::Dyn) => { let vtable = metadata.unwrap_meta().to_pointer(self)?; // Read size and align from vtable (already checks size). - Ok(Some(self.get_vtable_size_and_align(vtable, Some(expected_trait))?)) + interp_ok(Some(self.get_vtable_size_and_align(vtable, Some(expected_trait))?)) } ty::Slice(_) | ty::Str => { @@ -474,10 +469,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if size > self.max_size_of_val() { throw_ub!(InvalidMeta(InvalidMetaKind::SliceTooBig)); } - Ok(Some((size, elem.align.abi))) + interp_ok(Some((size, elem.align.abi))) } - ty::Foreign(_) => Ok(None), + ty::Foreign(_) => interp_ok(None), _ => span_bug!(self.cur_span(), "size_and_align_of::<{}> not supported", layout.ty), } @@ -503,7 +498,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { pub fn return_to_block(&mut self, target: Option<mir::BasicBlock>) -> InterpResult<'tcx> { if let Some(target) = target { self.go_to_block(target); - Ok(()) + interp_ok(()) } else { throw_ub!(Unreachable) } @@ -530,10 +525,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { M::unwind_terminate(self, reason)?; // This might have pushed a new stack frame, or it terminated execution. // Either way, `loc` will not be updated. - return Ok(()); + return interp_ok(()); } }; - Ok(()) + interp_ok(()) } /// Call a query that can return `ErrorHandled`. Should be used for statics and other globals. diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index 81659df7c53..7a1b92601a4 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -26,7 +26,9 @@ use rustc_span::def_id::LocalDefId; use rustc_span::sym; use tracing::{instrument, trace}; -use super::{AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, PlaceTy, err_ub}; +use super::{ + AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, PlaceTy, err_ub, interp_ok, +}; use crate::const_eval; use crate::errors::NestedStaticInThreadLocal; @@ -307,7 +309,7 @@ pub fn intern_const_alloc_for_constprop<'tcx, T, M: CompileTimeMachine<'tcx, T>> ) -> InterpResult<'tcx, ()> { if ecx.tcx.try_get_global_alloc(alloc_id).is_some() { // The constant is already in global memory. Do nothing. - return Ok(()); + return interp_ok(()); } // Move allocation to `tcx`. if let Some(_) = @@ -318,7 +320,7 @@ pub fn intern_const_alloc_for_constprop<'tcx, T, M: CompileTimeMachine<'tcx, T>> // proper recursive interning loop -- or just call `intern_const_alloc_recursive`. panic!("`intern_const_alloc_for_constprop` called on allocation with nested provenance") } - Ok(()) + interp_ok(()) } impl<'tcx, M: super::intern::CompileTimeMachine<'tcx, !>> InterpCx<'tcx, M> { @@ -342,6 +344,6 @@ impl<'tcx, M: super::intern::CompileTimeMachine<'tcx, !>> InterpCx<'tcx, M> { panic!("`intern_with_temp_alloc` with nested allocations"); } } - Ok(alloc_id) + interp_ok(alloc_id) } } diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 4c34ffc5d4e..52780cc6a3a 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -18,7 +18,7 @@ use super::util::ensure_monomorphic_enough; use super::{ Allocation, CheckInAllocMsg, ConstAllocation, GlobalId, ImmTy, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, Pointer, PointerArithmetic, Provenance, Scalar, err_inval, - err_ub_custom, err_unsup_format, throw_inval, throw_ub_custom, throw_ub_format, + err_ub_custom, err_unsup_format, interp_ok, throw_inval, throw_ub_custom, throw_ub_format, }; use crate::fluent_generated as fluent; @@ -39,7 +39,7 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>( ) -> InterpResult<'tcx, ConstValue<'tcx>> { let tp_ty = args.type_at(0); let name = tcx.item_name(def_id); - Ok(match name { + interp_ok(match name { sym::type_name => { ensure_monomorphic_enough(tcx, tp_ty)?; let alloc = alloc_type_name(tcx, tp_ty); @@ -329,6 +329,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { fluent::const_eval_offset_from_different_allocations, name = intrinsic_name, ) + .into() })?; // Perform division by size to compute return value. @@ -378,7 +379,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { M::panic_nounwind(self, &msg)?; // Skip the `return_to_block` at the end (we panicked, we do not return). - return Ok(true); + return interp_ok(true); } } sym::simd_insert => { @@ -438,12 +439,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } // Unsupported intrinsic: skip the return_to_block below. - _ => return Ok(false), + _ => return interp_ok(false), } trace!("{:?}", self.dump_place(&dest.clone().into())); self.return_to_block(ret)?; - Ok(true) + interp_ok(true) } pub(super) fn eval_nondiverging_intrinsic( @@ -457,7 +458,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if !cond { throw_ub_custom!(fluent::const_eval_assume_false); } - Ok(()) + interp_ok(()) } NonDivergingIntrinsic::CopyNonOverlapping(mir::CopyNonOverlapping { count, @@ -499,7 +500,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } _ => bug!("not a numeric intrinsic: {}", name), }; - Ok(Scalar::from_uint(bits_out, ret_layout.size)) + interp_ok(Scalar::from_uint(bits_out, ret_layout.size)) } pub fn exact_div( @@ -540,7 +541,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let (val, overflowed) = self.binary_op(mir_op.wrapping_to_overflowing().unwrap(), l, r)?.to_scalar_pair(); - Ok(if overflowed.to_bool()? { + interp_ok(if overflowed.to_bool()? { let size = l.layout.size; if l.layout.abi.is_signed() { // For signed ints the saturated value depends on the sign of the first @@ -582,7 +583,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // The offset must be in bounds starting from `ptr`. self.check_ptr_access_signed(ptr, offset_bytes, CheckInAllocMsg::PointerArithmeticTest)?; // This also implies that there is no overflow, so we are done. - Ok(ptr.wrapping_signed_offset(offset_bytes, self)) + interp_ok(ptr.wrapping_signed_offset(offset_bytes, self)) } /// Copy `count*size_of::<T>()` many bytes from `*src` to `*dst`. @@ -628,7 +629,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.copy_op(&right, &left)?; self.copy_op(&temp, &right)?; self.deallocate_ptr(temp.ptr(), None, kind)?; - Ok(()) + interp_ok(()) } pub fn write_bytes_intrinsic( @@ -669,7 +670,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // `Ordering`'s discriminants are -1/0/+1, so casting does the right thing. let result = Ord::cmp(left_bytes, right_bytes) as i32; - Ok(Scalar::from_i32(result)) + interp_ok(Scalar::from_i32(result)) } pub(crate) fn raw_eq_intrinsic( @@ -687,13 +688,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { this.check_ptr_align(ptr, layout.align.abi)?; let Some(alloc_ref) = self.get_ptr_alloc(ptr, layout.size)? else { // zero-sized access - return Ok(&[]); + return interp_ok(&[]); }; alloc_ref.get_bytes_strip_provenance() }; let lhs_bytes = get_bytes(self, lhs)?; let rhs_bytes = get_bytes(self, rhs)?; - Ok(Scalar::from_bool(lhs_bytes == rhs_bytes)) + interp_ok(Scalar::from_bool(lhs_bytes == rhs_bytes)) } } diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index a809f74e8eb..0f796c31222 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -20,7 +20,8 @@ use rustc_target::spec::abi::Abi as CallAbi; use super::{ AllocBytes, AllocId, AllocKind, AllocRange, Allocation, CTFE_ALLOC_SALT, ConstAllocation, CtfeProvenance, FnArg, Frame, ImmTy, InterpCx, InterpResult, MPlaceTy, MemoryKind, - Misalignment, OpTy, PlaceTy, Pointer, Provenance, RangeSet, throw_unsup, throw_unsup_format, + Misalignment, OpTy, PlaceTy, Pointer, Provenance, RangeSet, interp_ok, throw_unsup, + throw_unsup_format, }; /// Data returned by [`Machine::after_stack_pop`], and consumed by @@ -185,7 +186,7 @@ pub trait Machine<'tcx>: Sized { ecx: &InterpCx<'tcx, Self>, instance: ty::InstanceKind<'tcx>, ) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> { - Ok(ecx.tcx.instance_mir(instance)) + interp_ok(ecx.tcx.instance_mir(instance)) } /// Entry point to all function calls. @@ -280,7 +281,7 @@ pub trait Machine<'tcx>: Sized { /// Called before a basic block terminator is executed. #[inline] fn before_terminator(_ecx: &mut InterpCx<'tcx, Self>) -> InterpResult<'tcx> { - Ok(()) + interp_ok(()) } /// Determines the result of a `NullaryOp::UbChecks` invocation. @@ -290,7 +291,7 @@ pub trait Machine<'tcx>: Sized { /// You can use this to detect long or endlessly running programs. #[inline] fn increment_const_eval_counter(_ecx: &mut InterpCx<'tcx, Self>) -> InterpResult<'tcx> { - Ok(()) + interp_ok(()) } /// Called before a global allocation is accessed. @@ -304,7 +305,7 @@ pub trait Machine<'tcx>: Sized { _static_def_id: Option<DefId>, _is_write: bool, ) -> InterpResult<'tcx> { - Ok(()) + interp_ok(()) } /// Return the `AllocId` for the given thread-local static in the current thread. @@ -422,7 +423,7 @@ pub trait Machine<'tcx>: Sized { _prov: (AllocId, Self::ProvenanceExtra), _range: AllocRange, ) -> InterpResult<'tcx> { - Ok(()) + interp_ok(()) } /// Hook for performing extra checks on any memory read access, @@ -433,7 +434,7 @@ pub trait Machine<'tcx>: Sized { /// Used to prevent statics from self-initializing by reading from their own memory /// as it is being initialized. fn before_alloc_read(_ecx: &InterpCx<'tcx, Self>, _alloc_id: AllocId) -> InterpResult<'tcx> { - Ok(()) + interp_ok(()) } /// Hook for performing extra checks on a memory write access. @@ -446,7 +447,7 @@ pub trait Machine<'tcx>: Sized { _prov: (AllocId, Self::ProvenanceExtra), _range: AllocRange, ) -> InterpResult<'tcx> { - Ok(()) + interp_ok(()) } /// Hook for performing extra operations on a memory deallocation. @@ -460,7 +461,7 @@ pub trait Machine<'tcx>: Sized { _align: Align, _kind: MemoryKind<Self::MemoryKind>, ) -> InterpResult<'tcx> { - Ok(()) + interp_ok(()) } /// Executes a retagging operation for a single pointer. @@ -471,7 +472,7 @@ pub trait Machine<'tcx>: Sized { _kind: mir::RetagKind, val: &ImmTy<'tcx, Self::Provenance>, ) -> InterpResult<'tcx, ImmTy<'tcx, Self::Provenance>> { - Ok(val.clone()) + interp_ok(val.clone()) } /// Executes a retagging operation on a compound value. @@ -482,7 +483,7 @@ pub trait Machine<'tcx>: Sized { _kind: mir::RetagKind, _place: &PlaceTy<'tcx, Self::Provenance>, ) -> InterpResult<'tcx> { - Ok(()) + interp_ok(()) } /// Called on places used for in-place function argument and return value handling. @@ -516,7 +517,7 @@ pub trait Machine<'tcx>: Sized { /// Called immediately after a stack frame got pushed and its locals got initialized. fn after_stack_push(_ecx: &mut InterpCx<'tcx, Self>) -> InterpResult<'tcx> { - Ok(()) + interp_ok(()) } /// Called just before the return value is copied to the caller-provided return place. @@ -524,7 +525,7 @@ pub trait Machine<'tcx>: Sized { _ecx: &InterpCx<'tcx, Self>, _frame: &Frame<'tcx, Self::Provenance, Self::FrameExtra>, ) -> InterpResult<'tcx> { - Ok(()) + interp_ok(()) } /// Called immediately after a stack frame got popped, but before jumping back to the caller. @@ -537,14 +538,14 @@ pub trait Machine<'tcx>: Sized { ) -> InterpResult<'tcx, ReturnAction> { // By default, we do not support unwinding from panics assert!(!unwinding); - Ok(ReturnAction::Normal) + interp_ok(ReturnAction::Normal) } /// Called immediately after an "immediate" local variable is read /// (i.e., this is called for reads that do not end up accessing addressable memory). #[inline(always)] fn after_local_read(_ecx: &InterpCx<'tcx, Self>, _local: mir::Local) -> InterpResult<'tcx> { - Ok(()) + interp_ok(()) } /// Called immediately after an "immediate" local variable is assigned a new value @@ -556,7 +557,7 @@ pub trait Machine<'tcx>: Sized { _local: mir::Local, _storage_live: bool, ) -> InterpResult<'tcx> { - Ok(()) + interp_ok(()) } /// Called immediately after actual memory was allocated for a local @@ -567,7 +568,7 @@ pub trait Machine<'tcx>: Sized { _local: mir::Local, _mplace: &MPlaceTy<'tcx, Self::Provenance>, ) -> InterpResult<'tcx> { - Ok(()) + interp_ok(()) } /// Evaluate the given constant. The `eval` function will do all the required evaluation, @@ -645,7 +646,7 @@ pub macro compile_time_machine(<$tcx: lifetime>) { ) -> InterpResult<$tcx> { // For now we don't do any checking here. We can't use `tcx.sess` because that can differ // between crates, and we need to ensure that const-eval always behaves the same. - Ok(()) + interp_ok(()) } #[inline(always)] @@ -665,7 +666,7 @@ pub macro compile_time_machine(<$tcx: lifetime>) { fn ub_checks(_ecx: &InterpCx<$tcx, Self>) -> InterpResult<$tcx, bool> { // We can't look at `tcx.sess` here as that can differ across crates, which can lead to // unsound differences in evaluating the same constant at different instantiation sites. - Ok(true) + interp_ok(true) } #[inline(always)] @@ -675,7 +676,7 @@ pub macro compile_time_machine(<$tcx: lifetime>) { alloc: &'b Allocation, ) -> InterpResult<$tcx, Cow<'b, Allocation<Self::Provenance>>> { // Overwrite default implementation: no need to adjust anything. - Ok(Cow::Borrowed(alloc)) + interp_ok(Cow::Borrowed(alloc)) } fn init_alloc_extra( @@ -685,7 +686,7 @@ pub macro compile_time_machine(<$tcx: lifetime>) { _size: Size, _align: Align, ) -> InterpResult<$tcx, Self::AllocExtra> { - Ok(()) + interp_ok(()) } fn extern_static_pointer( @@ -693,7 +694,7 @@ pub macro compile_time_machine(<$tcx: lifetime>) { def_id: DefId, ) -> InterpResult<$tcx, Pointer> { // Use the `AllocId` associated with the `DefId`. Any actual *access* will fail. - Ok(Pointer::new(ecx.tcx.reserve_and_set_static_alloc(def_id).into(), Size::ZERO)) + interp_ok(Pointer::new(ecx.tcx.reserve_and_set_static_alloc(def_id).into(), Size::ZERO)) } #[inline(always)] @@ -702,7 +703,7 @@ pub macro compile_time_machine(<$tcx: lifetime>) { ptr: Pointer<CtfeProvenance>, _kind: Option<MemoryKind<Self::MemoryKind>>, ) -> InterpResult<$tcx, Pointer<CtfeProvenance>> { - Ok(ptr) + interp_ok(ptr) } #[inline(always)] @@ -713,7 +714,7 @@ pub macro compile_time_machine(<$tcx: lifetime>) { // Allow these casts, but make the pointer not dereferenceable. // (I.e., they behave like transmutation.) // This is correct because no pointers can ever be exposed in compile-time evaluation. - Ok(Pointer::from_addr_invalid(addr)) + interp_ok(Pointer::from_addr_invalid(addr)) } #[inline(always)] diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index c3b506d848c..e6ab8ca12a8 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -23,7 +23,7 @@ use tracing::{debug, instrument, trace}; use super::{ AllocBytes, AllocId, AllocMap, AllocRange, Allocation, CheckAlignMsg, CheckInAllocMsg, CtfeProvenance, GlobalAlloc, InterpCx, InterpResult, Machine, MayLeak, Misalignment, Pointer, - PointerArithmetic, Provenance, Scalar, alloc_range, err_ub, err_ub_custom, throw_ub, + PointerArithmetic, Provenance, Scalar, alloc_range, err_ub, err_ub_custom, interp_ok, throw_ub, throw_ub_custom, throw_unsup, throw_unsup_format, }; use crate::fluent_generated as fluent; @@ -82,7 +82,7 @@ pub enum FnVal<'tcx, Other> { impl<'tcx, Other> FnVal<'tcx, Other> { pub fn as_instance(self) -> InterpResult<'tcx, Instance<'tcx>> { match self { - FnVal::Instance(instance) => Ok(instance), + FnVal::Instance(instance) => interp_ok(instance), FnVal::Other(_) => { throw_unsup_format!("'foreign' function pointers are not supported in this context") } @@ -284,7 +284,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.mem_copy(ptr, new_ptr.into(), old_size.min(new_size), /*nonoverlapping*/ true)?; self.deallocate_ptr(ptr, old_size_and_align, kind)?; - Ok(new_ptr) + interp_ok(new_ptr) } #[instrument(skip(self), level = "debug")] @@ -330,8 +330,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ) } None => err_ub!(PointerUseAfterFree(alloc_id, CheckInAllocMsg::MemoryAccessTest)), - } - .into()); + }) + .into(); }; if alloc.mutability.is_not() { @@ -376,7 +376,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { bug!("Nothing can be deallocated twice"); } - Ok(()) + interp_ok(()) } /// Internal helper function to determine the allocation and offset of a pointer (if any). @@ -395,7 +395,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { |this, alloc_id, offset, prov| { let (size, align) = this .get_live_alloc_size_and_align(alloc_id, CheckInAllocMsg::MemoryAccessTest)?; - Ok((size, align, (alloc_id, offset, prov))) + interp_ok((size, align, (alloc_id, offset, prov))) }, ) } @@ -412,9 +412,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let size = i64::try_from(size.bytes()).unwrap(); // it would be an error to even ask for more than isize::MAX bytes Self::check_and_deref_ptr(self, ptr, size, msg, |this, alloc_id, _, _| { let (size, align) = this.get_live_alloc_size_and_align(alloc_id, msg)?; - Ok((size, align, ())) + interp_ok((size, align, ())) })?; - Ok(()) + interp_ok(()) } /// Check whether the given pointer points to live memory for a signed amount of bytes. @@ -428,9 +428,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ) -> InterpResult<'tcx> { Self::check_and_deref_ptr(self, ptr, size, msg, |this, alloc_id, _, _| { let (size, align) = this.get_live_alloc_size_and_align(alloc_id, msg)?; - Ok((size, align, ())) + interp_ok((size, align, ())) })?; - Ok(()) + interp_ok(()) } /// Low-level helper function to check if a ptr is in-bounds and potentially return a reference @@ -455,10 +455,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ) -> InterpResult<'tcx, Option<T>> { // Everything is okay with size 0. if size == 0 { - return Ok(None); + return interp_ok(None); } - Ok(match this.borrow().ptr_try_get_alloc_id(ptr, size) { + interp_ok(match this.borrow().ptr_try_get_alloc_id(ptr, size) { Err(addr) => { // We couldn't get a proper allocation. throw_ub!(DanglingIntPointer { addr, inbounds_size: size, msg }); @@ -498,7 +498,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if let Some(misaligned) = misaligned { throw_ub!(AlignmentCheckFailed(misaligned, msg)) } - Ok(()) + interp_ok(()) } pub(super) fn is_ptr_misaligned( @@ -634,7 +634,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // `get_global_alloc` that we can actually use directly without inserting anything anywhere. // So the error type is `InterpResult<'tcx, &Allocation<M::Provenance>>`. let a = self.memory.alloc_map.get_or(id, || { - let alloc = self.get_global_alloc(id, /*is_write*/ false).map_err(Err)?; + // We have to funnel the `InterpErrorInfo` through a `Result` to match the `get_or` API, + // so we use `report_err` for that. + let alloc = self.get_global_alloc(id, /*is_write*/ false).report_err().map_err(Err)?; match alloc { Cow::Borrowed(alloc) => { // We got a ref, cheaply return that as an "error" so that the @@ -653,8 +655,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { }); // Now unpack that funny error type match a { - Ok(a) => Ok(&a.1), - Err(a) => a, + Ok(a) => interp_ok(&a.1), + Err(a) => a.into(), } } @@ -662,7 +664,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// The caller is responsible for calling the access hooks! pub fn get_alloc_bytes_unchecked_raw(&self, id: AllocId) -> InterpResult<'tcx, *const u8> { let alloc = self.get_alloc_raw(id)?; - Ok(alloc.get_bytes_unchecked_raw()) + interp_ok(alloc.get_bytes_unchecked_raw()) } /// Bounds-checked *but not align-checked* allocation access. @@ -680,7 +682,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { CheckInAllocMsg::MemoryAccessTest, |this, alloc_id, offset, prov| { let alloc = this.get_alloc_raw(alloc_id)?; - Ok((alloc.size(), alloc.align, (alloc_id, offset, prov, alloc))) + interp_ok((alloc.size(), alloc.align, (alloc_id, offset, prov, alloc))) }, )?; // We want to call the hook on *all* accesses that involve an AllocId, including zero-sized @@ -703,20 +705,20 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { range, )?; } - Ok(Some(AllocRef { alloc, range, tcx: *self.tcx, alloc_id })) + interp_ok(Some(AllocRef { alloc, range, tcx: *self.tcx, alloc_id })) } else { - Ok(None) + interp_ok(None) } } /// Return the `extra` field of the given allocation. pub fn get_alloc_extra<'a>(&'a self, id: AllocId) -> InterpResult<'tcx, &'a M::AllocExtra> { - Ok(&self.get_alloc_raw(id)?.extra) + interp_ok(&self.get_alloc_raw(id)?.extra) } /// Return the `mutability` field of the given allocation. pub fn get_alloc_mutability<'a>(&'a self, id: AllocId) -> InterpResult<'tcx, Mutability> { - Ok(self.get_alloc_raw(id)?.mutability) + interp_ok(self.get_alloc_raw(id)?.mutability) } /// Gives raw mutable access to the `Allocation`, without bounds or alignment checks. @@ -750,7 +752,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if alloc.mutability.is_not() { throw_ub!(WriteToReadOnly(id)) } - Ok((alloc, &mut self.machine)) + interp_ok((alloc, &mut self.machine)) } /// Gives raw, mutable access to the `Allocation` address, without bounds or alignment checks. @@ -760,7 +762,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { id: AllocId, ) -> InterpResult<'tcx, *mut u8> { let alloc = self.get_alloc_raw_mut(id)?.0; - Ok(alloc.get_bytes_unchecked_raw_mut()) + interp_ok(alloc.get_bytes_unchecked_raw_mut()) } /// Bounds-checked *but not align-checked* allocation access. @@ -781,7 +783,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { CheckInAllocMsg::MemoryAccessTest, |this, alloc_id, offset, prov| { let (alloc, machine) = this.get_alloc_raw_mut(alloc_id)?; - Ok((alloc.size(), alloc.align, (alloc_id, offset, prov, alloc, machine))) + interp_ok((alloc.size(), alloc.align, (alloc_id, offset, prov, alloc, machine))) }, )?; @@ -790,9 +792,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if !validation_in_progress { M::before_memory_write(tcx, machine, &mut alloc.extra, (alloc_id, prov), range)?; } - Ok(Some(AllocRefMut { alloc, range, tcx: *tcx, alloc_id })) + interp_ok(Some(AllocRefMut { alloc, range, tcx: *tcx, alloc_id })) } else { - Ok(None) + interp_ok(None) } } @@ -802,7 +804,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { id: AllocId, ) -> InterpResult<'tcx, (&'a mut M::AllocExtra, &'a mut M)> { let (alloc, machine) = self.get_alloc_raw_mut(id)?; - Ok((&mut alloc.extra, machine)) + interp_ok((&mut alloc.extra, machine)) } /// Check whether an allocation is live. This is faster than calling @@ -904,7 +906,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if matches!(kind, AllocKind::Dead) { throw_ub!(PointerUseAfterFree(id, msg)) } - Ok((size, align)) + interp_ok((size, align)) } fn get_fn_alloc(&self, id: AllocId) -> Option<FnVal<'tcx, M::ExtraFnVal>> { @@ -928,7 +930,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { throw_ub!(InvalidFunctionPointer(Pointer::new(alloc_id, offset))) } self.get_fn_alloc(alloc_id) - .ok_or_else(|| err_ub!(InvalidFunctionPointer(Pointer::new(alloc_id, offset))).into()) + .ok_or_else(|| err_ub!(InvalidFunctionPointer(Pointer::new(alloc_id, offset)))) + .into() } /// Get the dynamic type of the given vtable pointer. @@ -951,12 +954,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if let Some(expected_dyn_type) = expected_trait { self.check_vtable_for_type(vtable_dyn_type, expected_dyn_type)?; } - Ok(ty) + interp_ok(ty) } pub fn alloc_mark_immutable(&mut self, id: AllocId) -> InterpResult<'tcx> { self.get_alloc_raw_mut(id)?.0.mutability = Mutability::Not; - Ok(()) + interp_ok(()) } /// Create a lazy debug printer that prints the given allocation and all allocations it points @@ -1144,10 +1147,11 @@ impl<'a, 'tcx, Prov: Provenance, Extra, Bytes: AllocBytes> pub fn write_scalar(&mut self, range: AllocRange, val: Scalar<Prov>) -> InterpResult<'tcx> { let range = self.range.subrange(range); debug!("write_scalar at {:?}{range:?}: {val:?}", self.alloc_id); - Ok(self - .alloc + + self.alloc .write_scalar(&self.tcx, range, val) - .map_err(|e| e.to_interp_error(self.alloc_id))?) + .map_err(|e| e.to_interp_error(self.alloc_id)) + .into() } /// `offset` is relative to this allocation reference, not the base of the allocation. @@ -1158,26 +1162,27 @@ impl<'a, 'tcx, Prov: Provenance, Extra, Bytes: AllocBytes> /// Mark the given sub-range (relative to this allocation reference) as uninitialized. pub fn write_uninit(&mut self, range: AllocRange) -> InterpResult<'tcx> { let range = self.range.subrange(range); - Ok(self - .alloc + + self.alloc .write_uninit(&self.tcx, range) - .map_err(|e| e.to_interp_error(self.alloc_id))?) + .map_err(|e| e.to_interp_error(self.alloc_id)) + .into() } /// Mark the entire referenced range as uninitialized pub fn write_uninit_full(&mut self) -> InterpResult<'tcx> { - Ok(self - .alloc + self.alloc .write_uninit(&self.tcx, self.range) - .map_err(|e| e.to_interp_error(self.alloc_id))?) + .map_err(|e| e.to_interp_error(self.alloc_id)) + .into() } /// Remove all provenance in the reference range. pub fn clear_provenance(&mut self) -> InterpResult<'tcx> { - Ok(self - .alloc + self.alloc .clear_provenance(&self.tcx, self.range) - .map_err(|e| e.to_interp_error(self.alloc_id))?) + .map_err(|e| e.to_interp_error(self.alloc_id)) + .into() } } @@ -1189,12 +1194,10 @@ impl<'a, 'tcx, Prov: Provenance, Extra, Bytes: AllocBytes> AllocRef<'a, 'tcx, Pr read_provenance: bool, ) -> InterpResult<'tcx, Scalar<Prov>> { let range = self.range.subrange(range); - let res = self - .alloc + self.alloc .read_scalar(&self.tcx, range, read_provenance) - .map_err(|e| e.to_interp_error(self.alloc_id))?; - debug!("read_scalar at {:?}{range:?}: {res:?}", self.alloc_id); - Ok(res) + .map_err(|e| e.to_interp_error(self.alloc_id)) + .into() } /// `range` is relative to this allocation reference, not the base of the allocation. @@ -1212,10 +1215,10 @@ impl<'a, 'tcx, Prov: Provenance, Extra, Bytes: AllocBytes> AllocRef<'a, 'tcx, Pr /// `range` is relative to this allocation reference, not the base of the allocation. pub fn get_bytes_strip_provenance<'b>(&'b self) -> InterpResult<'tcx, &'a [u8]> { - Ok(self - .alloc + self.alloc .get_bytes_strip_provenance(&self.tcx, self.range) - .map_err(|e| e.to_interp_error(self.alloc_id))?) + .map_err(|e| e.to_interp_error(self.alloc_id)) + .into() } /// Returns whether the allocation has provenance anywhere in the range of the `AllocRef`. @@ -1236,14 +1239,16 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ) -> InterpResult<'tcx, &[u8]> { let Some(alloc_ref) = self.get_ptr_alloc(ptr, size)? else { // zero-sized access - return Ok(&[]); + return interp_ok(&[]); }; // Side-step AllocRef and directly access the underlying bytes more efficiently. // (We are staying inside the bounds here so all is good.) - Ok(alloc_ref - .alloc - .get_bytes_strip_provenance(&alloc_ref.tcx, alloc_ref.range) - .map_err(|e| e.to_interp_error(alloc_ref.alloc_id))?) + interp_ok( + alloc_ref + .alloc + .get_bytes_strip_provenance(&alloc_ref.tcx, alloc_ref.range) + .map_err(|e| e.to_interp_error(alloc_ref.alloc_id))?, + ) } /// Writes the given stream of bytes into memory. @@ -1263,7 +1268,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let Some(alloc_ref) = self.get_ptr_alloc_mut(ptr, size)? else { // zero-sized access assert_matches!(src.next(), None, "iterator said it was empty but returned an element"); - return Ok(()); + return interp_ok(()); }; // Side-step AllocRef and directly access the underlying bytes more efficiently. @@ -1279,7 +1284,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { *dest = src.next().expect("iterator was shorter than it said it would be"); } assert_matches!(src.next(), None, "iterator was longer than it said it would be"); - Ok(()) + interp_ok(()) } pub fn mem_copy( @@ -1316,7 +1321,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Source alloc preparations and access hooks. let Some((src_alloc_id, src_offset, src_prov)) = src_parts else { // Zero-sized *source*, that means dest is also zero-sized and we have nothing to do. - return Ok(()); + return interp_ok(()); }; let src_alloc = self.get_alloc_raw(src_alloc_id)?; let src_range = alloc_range(src_offset, size); @@ -1332,7 +1337,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // We already did the source checks and called the hooks so we are good to return early. let Some((dest_alloc_id, dest_offset, dest_prov)) = dest_parts else { // Zero-sized *destination*. - return Ok(()); + return interp_ok(()); }; // Prepare getting source provenance. @@ -1375,7 +1380,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { .write_uninit(&tcx, dest_range) .map_err(|e| e.to_interp_error(dest_alloc_id))?; // We can forget about the provenance, this is all not initialized anyway. - return Ok(()); + return interp_ok(()); } // SAFE: The above indexing would have panicked if there weren't at least `size` bytes @@ -1432,7 +1437,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // copy the provenance to the destination dest_alloc.provenance_apply_copy(provenance); - Ok(()) + interp_ok(()) } } @@ -1441,7 +1446,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// Test if this value might be null. /// If the machine does not support ptr-to-int casts, this is conservative. pub fn scalar_may_be_null(&self, scalar: Scalar<M::Provenance>) -> InterpResult<'tcx, bool> { - Ok(match scalar.try_to_scalar_int() { + interp_ok(match scalar.try_to_scalar_int() { Ok(int) => int.is_null(), Err(_) => { // Can only happen during CTFE. @@ -1508,13 +1513,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ptr: Pointer<Option<M::Provenance>>, size: i64, ) -> InterpResult<'tcx, (AllocId, Size, M::ProvenanceExtra)> { - self.ptr_try_get_alloc_id(ptr, size).map_err(|offset| { - err_ub!(DanglingIntPointer { - addr: offset, - inbounds_size: size, - msg: CheckInAllocMsg::InboundsTest + self.ptr_try_get_alloc_id(ptr, size) + .map_err(|offset| { + err_ub!(DanglingIntPointer { + addr: offset, + inbounds_size: size, + msg: CheckInAllocMsg::InboundsTest + }) }) .into() - }) } } diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 31ee3e6519a..7e6600060b4 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -16,7 +16,7 @@ use tracing::trace; use super::{ CtfeProvenance, InterpCx, InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta, OffsetMode, PlaceTy, Pointer, Projectable, Provenance, Scalar, alloc_range, err_ub, from_known_layout, - mir_assign_valid_types, throw_ub, + interp_ok, mir_assign_valid_types, throw_ub, }; /// An `Immediate` represents a single immediate self-contained Rust value. @@ -149,7 +149,7 @@ impl<Prov: Provenance> Immediate<Prov> { } Immediate::Uninit => {} } - Ok(()) + interp_ok(()) } } @@ -307,7 +307,7 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { data_size: s.size().bytes(), })); } - Ok(s) + interp_ok(s) } #[inline] @@ -430,7 +430,7 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for ImmTy<'tcx, Prov> { ecx: &InterpCx<'tcx, M>, ) -> InterpResult<'tcx, Self> { assert_matches!(meta, MemPlaceMeta::None); // we can't store this anywhere anyway - Ok(self.offset_(offset, layout, ecx)) + interp_ok(self.offset_(offset, layout, ecx)) } #[inline(always)] @@ -438,7 +438,7 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for ImmTy<'tcx, Prov> { &self, _ecx: &InterpCx<'tcx, M>, ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { - Ok(self.clone().into()) + interp_ok(self.clone().into()) } } @@ -514,11 +514,13 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for OpTy<'tcx, Prov> { ecx: &InterpCx<'tcx, M>, ) -> InterpResult<'tcx, Self> { match self.as_mplace_or_imm() { - Left(mplace) => Ok(mplace.offset_with_meta(offset, mode, meta, layout, ecx)?.into()), + Left(mplace) => { + interp_ok(mplace.offset_with_meta(offset, mode, meta, layout, ecx)?.into()) + } Right(imm) => { assert_matches!(meta, MemPlaceMeta::None); // no place to store metadata here // Every part of an uninit is uninit. - Ok(imm.offset_(offset, layout, ecx).into()) + interp_ok(imm.offset_(offset, layout, ecx).into()) } } } @@ -528,7 +530,7 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for OpTy<'tcx, Prov> { &self, _ecx: &InterpCx<'tcx, M>, ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { - Ok(self.clone()) + interp_ok(self.clone()) } } @@ -543,12 +545,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ) -> InterpResult<'tcx, Option<ImmTy<'tcx, M::Provenance>>> { if mplace.layout.is_unsized() { // Don't touch unsized - return Ok(None); + return interp_ok(None); } let Some(alloc) = self.get_place_alloc(mplace)? else { // zero-sized type can be left uninit - return Ok(Some(ImmTy::uninit(mplace.layout))); + return interp_ok(Some(ImmTy::uninit(mplace.layout))); }; // It may seem like all types with `Scalar` or `ScalarPair` ABI are fair game at this point. @@ -557,7 +559,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // case where some of the bytes are initialized and others are not. So, we need an extra // check that walks over the type of `mplace` to make sure it is truly correct to treat this // like a `Scalar` (or `ScalarPair`). - Ok(match mplace.layout.abi { + interp_ok(match mplace.layout.abi { Abi::Scalar(abi::Scalar::Initialized { value: s, .. }) => { let size = s.size(self); assert_eq!(size, mplace.layout.size, "abi::Scalar size does not match layout size"); @@ -606,7 +608,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { &self, src: &impl Projectable<'tcx, M::Provenance>, ) -> InterpResult<'tcx, Either<MPlaceTy<'tcx, M::Provenance>, ImmTy<'tcx, M::Provenance>>> { - Ok(match src.to_op(self)?.as_mplace_or_imm() { + interp_ok(match src.to_op(self)?.as_mplace_or_imm() { Left(ref mplace) => { if let Some(val) = self.read_immediate_from_mplace_raw(mplace)? { Right(val) @@ -637,7 +639,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if matches!(*imm, Immediate::Uninit) { throw_ub!(InvalidUninitBytes(None)); } - Ok(imm) + interp_ok(imm) } /// Read a scalar from a place @@ -645,7 +647,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { &self, op: &impl Projectable<'tcx, M::Provenance>, ) -> InterpResult<'tcx, Scalar<M::Provenance>> { - Ok(self.read_immediate(op)?.to_scalar()) + interp_ok(self.read_immediate(op)?.to_scalar()) } // Pointer-sized reads are fairly common and need target layout access, so we wrap them in @@ -678,7 +680,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let len = mplace.len(self)?; let bytes = self.read_bytes_ptr_strip_provenance(mplace.ptr(), Size::from_bytes(len))?; let str = std::str::from_utf8(bytes).map_err(|err| err_ub!(InvalidStr(err)))?; - Ok(str) + interp_ok(str) } /// Read from a local of the current frame. @@ -698,7 +700,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { assert!(!layout.is_unsized()); } M::after_local_read(self, local)?; - Ok(OpTy { op, layout }) + interp_ok(OpTy { op, layout }) } /// Every place can be read from, so we can turn them into an operand. @@ -709,12 +711,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { place: &PlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { match place.as_mplace_or_local() { - Left(mplace) => Ok(mplace.into()), + Left(mplace) => interp_ok(mplace.into()), Right((local, offset, locals_addr, _)) => { debug_assert!(place.layout.is_sized()); // only sized locals can ever be `Place::Local`. debug_assert_eq!(locals_addr, self.frame().locals_addr()); let base = self.local_to_op(local, None)?; - Ok(match offset { + interp_ok(match offset { Some(offset) => base.offset(offset, place.layout, self)?, None => { // In the common case this hasn't been projected. @@ -764,7 +766,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ) } } - Ok(op) + interp_ok(op) } /// Evaluate the operand, returning a place where you can then find the data. @@ -794,7 +796,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } }; trace!("{:?}: {:?}", mir_op, op); - Ok(op) + interp_ok(op) } pub(crate) fn const_val_to_op( @@ -805,12 +807,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { // Other cases need layout. let adjust_scalar = |scalar| -> InterpResult<'tcx, _> { - Ok(match scalar { + interp_ok(match scalar { Scalar::Ptr(ptr, size) => Scalar::Ptr(self.global_root_pointer(ptr)?, size), Scalar::Int(int) => Scalar::Int(int), }) }; - let layout = from_known_layout(self.tcx, self.param_env, layout, || self.layout_of(ty))?; + let layout = + from_known_layout(self.tcx, self.param_env, layout, || self.layout_of(ty).into())?; let imm = match val_val { mir::ConstValue::Indirect { alloc_id, offset } => { // This is const data, no mutation allowed. @@ -818,7 +821,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { CtfeProvenance::from(alloc_id).as_immutable(), offset, ))?; - return Ok(self.ptr_to_mplace(ptr.into(), layout).into()); + return interp_ok(self.ptr_to_mplace(ptr.into(), layout).into()); } mir::ConstValue::Scalar(x) => adjust_scalar(x)?.into(), mir::ConstValue::ZeroSized => Immediate::Uninit, @@ -829,7 +832,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Immediate::new_slice(self.global_root_pointer(ptr)?.into(), meta, self) } }; - Ok(OpTy { op: Operand::Immediate(imm), layout }) + interp_ok(OpTy { op: Operand::Immediate(imm), layout }) } } diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index 863b330a74c..52cd9b898bb 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -9,7 +9,7 @@ use rustc_span::symbol::sym; use rustc_target::abi::Size; use tracing::trace; -use super::{ImmTy, InterpCx, Machine, MemPlaceMeta, throw_ub}; +use super::{ImmTy, InterpCx, Machine, MemPlaceMeta, interp_ok, throw_ub}; impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { fn three_way_compare<T: Ord>(&self, lhs: T, rhs: T) -> ImmTy<'tcx, M::Provenance> { @@ -156,7 +156,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { }); } - return Ok(ImmTy::from_scalar_int(result, left.layout)); + return interp_ok(ImmTy::from_scalar_int(result, left.layout)); } // For the remaining ops, the types must be the same on both sides @@ -181,10 +181,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { _ => None, }; if let Some(op) = op { - return Ok(ImmTy::from_bool(op(&l_signed(), &r_signed()), *self.tcx)); + return interp_ok(ImmTy::from_bool(op(&l_signed(), &r_signed()), *self.tcx)); } if bin_op == Cmp { - return Ok(self.three_way_compare(l_signed(), r_signed())); + return interp_ok(self.three_way_compare(l_signed(), r_signed())); } let op: Option<fn(i128, i128) -> (i128, bool)> = match bin_op { Div if r.is_null() => throw_ub!(DivisionByZero), @@ -221,7 +221,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { throw_ub!(ArithOverflow { intrinsic }); } let res = ImmTy::from_scalar_int(result, left.layout); - return Ok(if with_overflow { + return interp_ok(if with_overflow { let overflow = ImmTy::from_bool(overflow, *self.tcx); ImmTy::from_pair(res, overflow, *self.tcx) } else { @@ -234,10 +234,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let r = r_unsigned(); if bin_op == Cmp { - return Ok(self.three_way_compare(l, r)); + return interp_ok(self.three_way_compare(l, r)); } - Ok(match bin_op { + interp_ok(match bin_op { Eq => ImmTy::from_bool(l == r, *self.tcx), Ne => ImmTy::from_bool(l != r, *self.tcx), @@ -339,7 +339,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { throw_ub!(PointerArithOverflow) } let offset_ptr = self.ptr_offset_inbounds(ptr, offset_bytes)?; - Ok(ImmTy::from_scalar(Scalar::from_maybe_pointer(offset_ptr, self), left.layout)) + interp_ok(ImmTy::from_scalar( + Scalar::from_maybe_pointer(offset_ptr, self), + left.layout, + )) } // Fall back to machine hook so Miri can support more pointer ops. @@ -366,20 +369,20 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { assert_eq!(left.layout.ty, right.layout.ty); let left = left.to_scalar(); let right = right.to_scalar(); - Ok(self.binary_char_op(bin_op, left.to_char()?, right.to_char()?)) + interp_ok(self.binary_char_op(bin_op, left.to_char()?, right.to_char()?)) } ty::Bool => { assert_eq!(left.layout.ty, right.layout.ty); let left = left.to_scalar(); let right = right.to_scalar(); - Ok(self.binary_bool_op(bin_op, left.to_bool()?, right.to_bool()?)) + interp_ok(self.binary_bool_op(bin_op, left.to_bool()?, right.to_bool()?)) } ty::Float(fty) => { assert_eq!(left.layout.ty, right.layout.ty); let layout = left.layout; let left = left.to_scalar(); let right = right.to_scalar(); - Ok(match fty { + interp_ok(match fty { FloatTy::F16 => { self.binary_float_op(bin_op, layout, left.to_f16()?, right.to_f16()?) } @@ -447,7 +450,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Not => !val, _ => span_bug!(self.cur_span(), "Invalid bool op {:?}", un_op), }; - Ok(ImmTy::from_bool(res, *self.tcx)) + interp_ok(ImmTy::from_bool(res, *self.tcx)) } ty::Float(fty) => { let val = val.to_scalar(); @@ -462,7 +465,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { FloatTy::F64 => Scalar::from_f64(-val.to_f64()?), FloatTy::F128 => Scalar::from_f128(-val.to_f128()?), }; - Ok(ImmTy::from_scalar(res, layout)) + interp_ok(ImmTy::from_scalar(res, layout)) } ty::Int(..) => { let val = val.to_scalar().to_int(layout.size)?; @@ -472,7 +475,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { _ => span_bug!(self.cur_span(), "Invalid integer op {:?}", un_op), }; let res = ScalarInt::truncate_from_int(res, layout.size).0; - Ok(ImmTy::from_scalar(res.into(), layout)) + interp_ok(ImmTy::from_scalar(res.into(), layout)) } ty::Uint(..) => { let val = val.to_scalar().to_uint(layout.size)?; @@ -481,12 +484,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { _ => span_bug!(self.cur_span(), "Invalid unsigned integer op {:?}", un_op), }; let res = ScalarInt::truncate_from_uint(res, layout.size).0; - Ok(ImmTy::from_scalar(res.into(), layout)) + interp_ok(ImmTy::from_scalar(res.into(), layout)) } ty::RawPtr(..) | ty::Ref(..) => { assert_eq!(un_op, PtrMetadata); let (_, meta) = val.to_scalar_and_meta(); - Ok(match meta { + interp_ok(match meta { MemPlaceMeta::Meta(scalar) => { let ty = un_op.ty(*self.tcx, val.layout.ty); let layout = self.layout_of(ty)?; @@ -514,7 +517,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let layout = self.layout_of(arg_ty)?; let usize_layout = || self.layout_of(self.tcx.types.usize).unwrap(); - Ok(match null_op { + interp_ok(match null_op { SizeOf => { if !layout.abi.is_sized() { span_bug!(self.cur_span(), "unsized type for `NullaryOp::SizeOf`"); diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 05264d32c6b..449d4c6bd7d 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -13,9 +13,9 @@ use rustc_target::abi::{Abi, Align, HasDataLayout, Size}; use tracing::{instrument, trace}; use super::{ - AllocRef, AllocRefMut, CheckAlignMsg, CtfeProvenance, DiscardInterpError, ImmTy, Immediate, - InterpCx, InterpResult, Machine, MemoryKind, Misalignment, OffsetMode, OpTy, Operand, Pointer, - Projectable, Provenance, Scalar, alloc_range, mir_assign_valid_types, + AllocRef, AllocRefMut, CheckAlignMsg, CtfeProvenance, ImmTy, Immediate, InterpCx, InterpResult, + Machine, MemoryKind, Misalignment, OffsetMode, OpTy, Operand, Pointer, Projectable, Provenance, + Scalar, alloc_range, interp_ok, mir_assign_valid_types, }; #[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)] @@ -90,7 +90,7 @@ impl<Prov: Provenance> MemPlace<Prov> { } OffsetMode::Wrapping => self.ptr.wrapping_offset(offset, ecx), }; - Ok(MemPlace { ptr, meta, misaligned: self.misaligned }) + interp_ok(MemPlace { ptr, meta, misaligned: self.misaligned }) } } @@ -163,7 +163,10 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for MPlaceTy<'tcx, Prov> { layout: TyAndLayout<'tcx>, ecx: &InterpCx<'tcx, M>, ) -> InterpResult<'tcx, Self> { - Ok(MPlaceTy { mplace: self.mplace.offset_with_meta_(offset, mode, meta, ecx)?, layout }) + interp_ok(MPlaceTy { + mplace: self.mplace.offset_with_meta_(offset, mode, meta, ecx)?, + layout, + }) } #[inline(always)] @@ -171,7 +174,7 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for MPlaceTy<'tcx, Prov> { &self, _ecx: &InterpCx<'tcx, M>, ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { - Ok(self.clone().into()) + interp_ok(self.clone().into()) } } @@ -279,7 +282,7 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for PlaceTy<'tcx, Prov> { layout: TyAndLayout<'tcx>, ecx: &InterpCx<'tcx, M>, ) -> InterpResult<'tcx, Self> { - Ok(match self.as_mplace_or_local() { + interp_ok(match self.as_mplace_or_local() { Left(mplace) => mplace.offset_with_meta(offset, mode, meta, layout, ecx)?.into(), Right((local, old_offset, locals_addr, _)) => { debug_assert!(layout.is_sized(), "unsized locals should live in memory"); @@ -367,7 +370,7 @@ impl<'tcx, Prov: Provenance> Writeable<'tcx, Prov> for MPlaceTy<'tcx, Prov> { &self, _ecx: &mut InterpCx<'tcx, M>, ) -> InterpResult<'tcx, MPlaceTy<'tcx, Prov>> { - Ok(self.clone()) + interp_ok(self.clone()) } } @@ -425,7 +428,7 @@ where // `ref_to_mplace` is called on raw pointers even if they don't actually get dereferenced; // we hence can't call `size_and_align_of` since that asserts more validity than we want. let ptr = ptr.to_pointer(self)?; - Ok(self.ptr_with_meta_to_mplace(ptr, meta, layout, /*unaligned*/ false)) + interp_ok(self.ptr_with_meta_to_mplace(ptr, meta, layout, /*unaligned*/ false)) } /// Turn a mplace into a (thin or wide) mutable raw pointer, pointing to the same space. @@ -437,7 +440,7 @@ where ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { let imm = mplace.mplace.to_ref(self); let layout = self.layout_of(Ty::new_mut_ptr(self.tcx.tcx, mplace.layout.ty))?; - Ok(ImmTy::from_immediate(imm, layout)) + interp_ok(ImmTy::from_immediate(imm, layout)) } /// Take an operand, representing a pointer, and dereference it to a place. @@ -458,7 +461,7 @@ where trace!("deref to {} on {:?}", val.layout.ty, *val); let mplace = self.ref_to_mplace(&val)?; - Ok(mplace) + interp_ok(mplace) } #[inline] @@ -474,7 +477,7 @@ where // If an access is both OOB and misaligned, we want to see the bounds error. let a = self.get_ptr_alloc(mplace.ptr(), size)?; self.check_misalign(mplace.mplace.misaligned, CheckAlignMsg::BasedOn)?; - Ok(a) + interp_ok(a) } #[inline] @@ -489,17 +492,10 @@ where // We check alignment separately, and raise that error *after* checking everything else. // If an access is both OOB and misaligned, we want to see the bounds error. // However we have to call `check_misalign` first to make the borrow checker happy. - let misalign_err = self.check_misalign(mplace.mplace.misaligned, CheckAlignMsg::BasedOn); - match self.get_ptr_alloc_mut(mplace.ptr(), size) { - Ok(a) => { - misalign_err?; - Ok(a) - } - Err(e) => { - misalign_err.discard_interp_err(); - Err(e) - } - } + let misalign_res = self.check_misalign(mplace.mplace.misaligned, CheckAlignMsg::BasedOn); + // An error from get_ptr_alloc_mut takes precedence. + let (a, ()) = self.get_ptr_alloc_mut(mplace.ptr(), size).and(misalign_res)?; + interp_ok(a) } /// Turn a local in the current frame into a place. @@ -519,7 +515,7 @@ where Operand::Indirect(mplace) => Place::Ptr(*mplace), } }; - Ok(PlaceTy { place, layout }) + interp_ok(PlaceTy { place, layout }) } /// Computes a place. You should only use this if you intend to write into this @@ -556,7 +552,7 @@ where ) } } - Ok(place) + interp_ok(place) } /// Given a place, returns either the underlying mplace or a reference to where the value of @@ -572,7 +568,7 @@ where (&mut Immediate<M::Provenance>, TyAndLayout<'tcx>, mir::Local), >, > { - Ok(match place.to_place().as_mplace_or_local() { + interp_ok(match place.to_place().as_mplace_or_local() { Left(mplace) => Left(mplace), Right((local, offset, locals_addr, layout)) => { if offset.is_some() { @@ -617,7 +613,7 @@ where )?; } - Ok(()) + interp_ok(()) } /// Write a scalar to a place @@ -667,7 +663,7 @@ where self.write_immediate_to_mplace_no_validate(src, mplace.layout, mplace.mplace)?; } } - Ok(()) + interp_ok(()) } /// Write an immediate to memory. @@ -690,7 +686,7 @@ where let tcx = *self.tcx; let Some(mut alloc) = self.get_place_alloc_mut(&MPlaceTy { mplace: dest, layout })? else { // zero-sized access - return Ok(()); + return interp_ok(()); }; match value { @@ -715,7 +711,7 @@ where alloc.write_scalar(alloc_range(Size::ZERO, a_val.size()), a_val)?; alloc.write_scalar(alloc_range(b_offset, b_val.size()), b_val)?; // We don't have to reset padding here, `write_immediate` will anyway do a validation run. - Ok(()) + interp_ok(()) } Immediate::Uninit => alloc.write_uninit_full(), } @@ -736,12 +732,12 @@ where Left(mplace) => { let Some(mut alloc) = self.get_place_alloc_mut(&mplace)? else { // Zero-sized access - return Ok(()); + return interp_ok(()); }; alloc.write_uninit_full()?; } } - Ok(()) + interp_ok(()) } /// Remove all provenance in the given place. @@ -760,12 +756,12 @@ where Left(mplace) => { let Some(mut alloc) = self.get_place_alloc_mut(&mplace)? else { // Zero-sized access - return Ok(()); + return interp_ok(()); }; alloc.clear_provenance()?; } } - Ok(()) + interp_ok(()) } /// Copies the data from an operand to a place. @@ -848,7 +844,7 @@ where )?; } - Ok(()) + interp_ok(()) } /// Copies the data from an operand to a place. @@ -925,7 +921,7 @@ where self.mem_copy(src.ptr(), dest.ptr(), dest_size, /*nonoverlapping*/ true)?; self.check_misalign(src.mplace.misaligned, CheckAlignMsg::BasedOn)?; self.check_misalign(dest.mplace.misaligned, CheckAlignMsg::BasedOn)?; - Ok(()) + interp_ok(()) } /// Ensures that a place is in memory, and returns where it is. @@ -987,7 +983,7 @@ where Place::Ptr(mplace) => mplace, }; // Return with the original layout and align, so that the caller can go on - Ok(MPlaceTy { mplace, layout: place.layout }) + interp_ok(MPlaceTy { mplace, layout: place.layout }) } pub fn allocate_dyn( @@ -1000,7 +996,7 @@ where span_bug!(self.cur_span(), "cannot allocate space for `extern` type, size is not known") }; let ptr = self.allocate_ptr(size, align, kind)?; - Ok(self.ptr_with_meta_to_mplace(ptr.into(), meta, layout, /*unaligned*/ false)) + interp_ok(self.ptr_with_meta_to_mplace(ptr.into(), meta, layout, /*unaligned*/ false)) } pub fn allocate( @@ -1035,7 +1031,7 @@ where }; let meta = Scalar::from_target_usize(u64::try_from(str.len()).unwrap(), self); let layout = self.layout_of(self.tcx.types.str_).unwrap(); - Ok(self.ptr_with_meta_to_mplace( + interp_ok(self.ptr_with_meta_to_mplace( ptr.into(), MemPlaceMeta::Meta(meta), layout, @@ -1051,7 +1047,7 @@ where let _ = self.tcx.global_alloc(raw.alloc_id); let ptr = self.global_root_pointer(Pointer::from(raw.alloc_id))?; let layout = self.layout_of(raw.ty)?; - Ok(self.ptr_to_mplace(ptr.into(), layout)) + interp_ok(self.ptr_to_mplace(ptr.into(), layout)) } } diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs index 621afdb1050..cc49d7cebf4 100644 --- a/compiler/rustc_const_eval/src/interpret/projection.rs +++ b/compiler/rustc_const_eval/src/interpret/projection.rs @@ -18,7 +18,7 @@ use tracing::{debug, instrument}; use super::{ InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy, Provenance, Scalar, err_ub, - throw_ub, throw_unsup, + interp_ok, throw_ub, throw_unsup, }; /// Describes the constraints placed on offset-projections. @@ -54,7 +54,7 @@ pub trait Projectable<'tcx, Prov: Provenance>: Sized + std::fmt::Debug { // Go through the layout. There are lots of types that support a length, // e.g., SIMD types. (But not all repr(simd) types even have FieldsShape::Array!) match layout.fields { - abi::FieldsShape::Array { count, .. } => Ok(count), + abi::FieldsShape::Array { count, .. } => interp_ok(count), _ => bug!("len not supported on sized type {:?}", layout.ty), } } @@ -115,9 +115,9 @@ impl<'a, 'tcx, Prov: Provenance, P: Projectable<'tcx, Prov>> ArrayIterator<'a, ' &mut self, ecx: &InterpCx<'tcx, M>, ) -> InterpResult<'tcx, Option<(u64, P)>> { - let Some(idx) = self.range.next() else { return Ok(None) }; + let Some(idx) = self.range.next() else { return interp_ok(None) }; // We use `Wrapping` here since the offset has already been checked when the iterator was created. - Ok(Some(( + interp_ok(Some(( idx, self.base.offset_with_meta( self.stride * idx, @@ -258,7 +258,7 @@ where // SIMD types must be newtypes around arrays, so all we have to do is project to their only field. let array = self.project_field(base, 0)?; let len = array.len(self)?; - Ok((array, len)) + interp_ok((array, len)) } fn project_constant_index<P: Projectable<'tcx, M::Provenance>>( @@ -300,7 +300,13 @@ where debug!("project_array_fields: {base:?} {len}"); base.offset(len * stride, self.layout_of(self.tcx.types.unit).unwrap(), self)?; // Create the iterator. - Ok(ArrayIterator { base, range: 0..len, stride, field_layout, _phantom: PhantomData }) + interp_ok(ArrayIterator { + base, + range: 0..len, + stride, + field_layout, + _phantom: PhantomData, + }) } /// Subslicing @@ -367,7 +373,7 @@ where P: Projectable<'tcx, M::Provenance> + From<MPlaceTy<'tcx, M::Provenance>> + std::fmt::Debug, { use rustc_middle::mir::ProjectionElem::*; - Ok(match proj_elem { + interp_ok(match proj_elem { OpaqueCast(ty) => { span_bug!(self.cur_span(), "OpaqueCast({ty}) encountered after borrowck") } diff --git a/compiler/rustc_const_eval/src/interpret/stack.rs b/compiler/rustc_const_eval/src/interpret/stack.rs index 15868f1b02d..3bc9f46aea0 100644 --- a/compiler/rustc_const_eval/src/interpret/stack.rs +++ b/compiler/rustc_const_eval/src/interpret/stack.rs @@ -17,7 +17,7 @@ use tracing::{info_span, instrument, trace}; use super::{ AllocId, CtfeProvenance, Immediate, InterpCx, InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta, MemoryKind, Operand, Pointer, Provenance, ReturnAction, Scalar, - from_known_layout, throw_ub, throw_unsup, + from_known_layout, interp_ok, throw_ub, throw_unsup, }; use crate::errors; @@ -189,7 +189,7 @@ impl<'tcx, Prov: Provenance> LocalState<'tcx, Prov> { pub(super) fn access(&self) -> InterpResult<'tcx, &Operand<Prov>> { match &self.value { LocalValue::Dead => throw_ub!(DeadLocal), // could even be "invalid program"? - LocalValue::Live(val) => Ok(val), + LocalValue::Live(val) => interp_ok(val), } } @@ -199,7 +199,7 @@ impl<'tcx, Prov: Provenance> LocalState<'tcx, Prov> { pub(super) fn access_mut(&mut self) -> InterpResult<'tcx, &mut Operand<Prov>> { match &mut self.value { LocalValue::Dead => throw_ub!(DeadLocal), // could even be "invalid program"? - LocalValue::Live(val) => Ok(val), + LocalValue::Live(val) => interp_ok(val), } } } @@ -391,7 +391,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let span = info_span!("frame", "{}", instance); self.frame_mut().tracing_span.enter(span); - Ok(()) + interp_ok(()) } /// Low-level helper that pops a stack frame from the stack and returns some information about @@ -426,7 +426,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { return_action = ReturnAction::NoCleanup; }; - Ok(StackPopInfo { return_action, return_to_block, return_place }) + interp_ok(StackPopInfo { return_action, return_to_block, return_place }) } /// A private helper for [`pop_stack_frame_raw`](InterpCx::pop_stack_frame_raw). @@ -449,7 +449,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } } - Ok(cleanup) + interp_ok(cleanup) } /// In the current stack frame, mark all locals as live that are not arguments and don't have @@ -464,7 +464,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.storage_live(local)?; } } - Ok(()) + interp_ok(()) } pub fn storage_live_dyn( @@ -550,7 +550,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // If the local is already live, deallocate its old memory. let old = mem::replace(&mut self.frame_mut().locals[local].value, local_val); self.deallocate_local(old)?; - Ok(()) + interp_ok(()) } /// Mark a storage as live, killing the previous content. @@ -566,7 +566,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // If the local is already dead, this is a NOP. let old = mem::replace(&mut self.frame_mut().locals[local].value, LocalValue::Dead); self.deallocate_local(old)?; - Ok(()) + interp_ok(()) } fn deallocate_local(&mut self, local: LocalValue<M::Provenance>) -> InterpResult<'tcx> { @@ -581,7 +581,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ); self.deallocate_ptr(ptr, None, MemoryKind::Stack)?; }; - Ok(()) + interp_ok(()) } #[inline(always)] @@ -593,19 +593,19 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ) -> InterpResult<'tcx, TyAndLayout<'tcx>> { let state = &frame.locals[local]; if let Some(layout) = state.layout.get() { - return Ok(layout); + return interp_ok(layout); } let layout = from_known_layout(self.tcx, self.param_env, layout, || { let local_ty = frame.body.local_decls[local].ty; let local_ty = self.instantiate_from_frame_and_normalize_erasing_regions(frame, local_ty)?; - self.layout_of(local_ty) + self.layout_of(local_ty).into() })?; // Layouts of locals are requested a lot, so we cache them. state.layout.set(Some(layout)); - Ok(layout) + interp_ok(layout) } } diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 8e2367e0d21..aa752955675 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -14,7 +14,7 @@ use tracing::{info, instrument, trace}; use super::{ FnArg, FnVal, ImmTy, Immediate, InterpCx, InterpResult, Machine, MemPlaceMeta, PlaceTy, - Projectable, Scalar, throw_ub, + Projectable, Scalar, interp_ok, throw_ub, }; use crate::util; @@ -36,7 +36,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { #[inline(always)] pub fn step(&mut self) -> InterpResult<'tcx, bool> { if self.stack().is_empty() { - return Ok(false); + return interp_ok(false); } let Either::Left(loc) = self.frame().loc else { @@ -44,7 +44,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Just go on unwinding. trace!("unwinding: skipping frame"); self.return_from_current_stack_frame(/* unwinding */ true)?; - return Ok(true); + return interp_ok(true); }; let basic_block = &self.body().basic_blocks[loc.block]; @@ -55,7 +55,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { assert_eq!(old_frames, self.frame_idx()); // Advance the program counter. self.frame_mut().loc.as_mut().left().unwrap().statement_index += 1; - return Ok(true); + return interp_ok(true); } M::before_terminator(self)?; @@ -67,7 +67,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { info!("// executing {:?}", loc.block); } } - Ok(true) + interp_ok(true) } /// Runs the interpretation logic for the given `mir::Statement` at the current frame and @@ -145,7 +145,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Nop => {} } - Ok(()) + interp_ok(()) } /// Evaluate an assignment statement. @@ -277,7 +277,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { trace!("{:?}", self.dump_place(&dest)); - Ok(()) + interp_ok(()) } /// Writes the aggregate to the destination. @@ -313,7 +313,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let ptr_imm = Immediate::new_pointer_with_meta(data, meta, self); let ptr = ImmTy::from_immediate(ptr_imm, dest.layout); self.copy_op(&ptr, dest)?; - return Ok(()); + return interp_ok(()); } _ => (FIRST_VARIANT, dest.clone(), None), }; @@ -365,7 +365,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { )?; } - Ok(()) + interp_ok(()) } /// Evaluate the arguments of a function call @@ -373,7 +373,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { &self, op: &mir::Operand<'tcx>, ) -> InterpResult<'tcx, FnArg<'tcx, M::Provenance>> { - Ok(match op { + interp_ok(match op { mir::Operand::Copy(_) | mir::Operand::Constant(_) => { // Make a regular copy. let op = self.eval_operand(op, None)?; @@ -442,7 +442,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } }; - Ok(EvaluatedCalleeAndArgs { callee, args, fn_sig, fn_abi, with_caller_location }) + interp_ok(EvaluatedCalleeAndArgs { callee, args, fn_sig, fn_abi, with_caller_location }) } fn eval_terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> InterpResult<'tcx> { @@ -537,7 +537,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // generic. In order to make sure that generic and non-generic code behaves // roughly the same (and in keeping with Mir semantics) we do nothing here. self.go_to_block(target); - return Ok(()); + return interp_ok(()); } trace!("TerminatorKind::drop: {:?}, type {}", place, place.layout.ty); self.init_drop_in_place_call(&place, instance, target, unwind)?; @@ -566,7 +566,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // By definition, a Resume terminator means // that we're unwinding self.return_from_current_stack_frame(/* unwinding */ true)?; - return Ok(()); + return interp_ok(()); } // It is UB to ever encounter this. @@ -584,6 +584,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } } - Ok(()) + interp_ok(()) } } diff --git a/compiler/rustc_const_eval/src/interpret/traits.rs b/compiler/rustc_const_eval/src/interpret/traits.rs index 8eead6018ac..da7d6853c0e 100644 --- a/compiler/rustc_const_eval/src/interpret/traits.rs +++ b/compiler/rustc_const_eval/src/interpret/traits.rs @@ -5,7 +5,9 @@ use rustc_target::abi::{Align, Size}; use tracing::trace; use super::util::ensure_monomorphic_enough; -use super::{InterpCx, MPlaceTy, Machine, MemPlaceMeta, OffsetMode, Projectable, throw_ub}; +use super::{ + InterpCx, MPlaceTy, Machine, MemPlaceMeta, OffsetMode, Projectable, interp_ok, throw_ub, +}; impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// Creates a dynamic vtable for the given type and vtable origin. This is used only for @@ -31,7 +33,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let salt = M::get_global_alloc_salt(self, None); let vtable_symbolic_allocation = self.tcx.reserve_and_set_vtable_alloc(ty, dyn_ty, salt); let vtable_ptr = self.global_root_pointer(Pointer::from(vtable_symbolic_allocation))?; - Ok(vtable_ptr.into()) + interp_ok(vtable_ptr.into()) } pub fn get_vtable_size_and_align( @@ -42,7 +44,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let ty = self.get_ptr_vtable_ty(vtable, expected_trait)?; let layout = self.layout_of(ty)?; assert!(layout.is_sized(), "there are no vtables for unsized types"); - Ok((layout.size, layout.align.abi)) + interp_ok((layout.size, layout.align.abi)) } pub(super) fn vtable_entries( @@ -102,7 +104,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } } - Ok(()) + interp_ok(()) } /// Turn a place with a `dyn Trait` type into a place with the actual dynamic type. @@ -127,7 +129,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { layout, self, )?; - Ok(mplace) + interp_ok(mplace) } /// Turn a `dyn* Trait` type into an value with the actual dynamic type. @@ -147,6 +149,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // `data` is already the right thing but has the wrong type. So we transmute it. let layout = self.layout_of(ty)?; let data = data.transmute(layout, self)?; - Ok(data) + interp_ok(data) } } diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index 2d53badf0f9..8bb5f173a56 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -9,7 +9,7 @@ use rustc_middle::ty::{ }; use tracing::debug; -use super::{InterpCx, MPlaceTy, MemoryKind, throw_inval}; +use super::{InterpCx, MPlaceTy, MemoryKind, interp_ok, throw_inval}; use crate::const_eval::{CompileTimeInterpCx, CompileTimeMachine, InterpretationResult}; /// Checks whether a type contains generic parameters which must be instantiated. @@ -23,7 +23,7 @@ where { debug!("ensure_monomorphic_enough: ty={:?}", ty); if !ty.has_param() { - return Ok(()); + return interp_ok(()); } struct FoundParam; @@ -78,7 +78,7 @@ where if matches!(ty.visit_with(&mut vis), ControlFlow::Break(FoundParam)) { throw_inval!(TooGeneric); } else { - Ok(()) + interp_ok(()) } } @@ -103,5 +103,5 @@ pub(crate) fn create_static_alloc<'tcx>( assert_eq!(ecx.machine.static_root_ids, None); ecx.machine.static_root_ids = Some((alloc_id, static_def_id)); assert!(ecx.memory.alloc_map.insert(alloc_id, (MemoryKind::Stack, alloc)).is_none()); - Ok(ecx.ptr_to_mplace(Pointer::from(alloc_id).into(), layout)) + interp_ok(ecx.ptr_to_mplace(Pointer::from(alloc_id).into(), layout)) } diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 3c9fdd73100..13641ef2bd3 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -18,7 +18,7 @@ use rustc_middle::bug; use rustc_middle::mir::interpret::ValidationErrorKind::{self, *}; use rustc_middle::mir::interpret::{ ExpectedKind, InterpError, InterpErrorInfo, InvalidMetaKind, Misalignment, PointerKind, - Provenance, UnsupportedOpInfo, ValidationErrorInfo, alloc_range, + Provenance, UnsupportedOpInfo, ValidationErrorInfo, alloc_range, interp_ok, }; use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, Ty}; @@ -32,7 +32,7 @@ use super::machine::AllocMap; use super::{ AllocId, AllocKind, CheckInAllocMsg, GlobalAlloc, ImmTy, Immediate, InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, PlaceTy, Pointer, Projectable, Scalar, ValueVisitor, err_ub, - format_interp_error, throw_ub, + format_interp_error, }; // for the validation errors @@ -42,7 +42,7 @@ use super::InterpError::Unsupported as Unsup; use super::UndefinedBehaviorInfo::*; use super::UnsupportedOpInfo::*; -macro_rules! throw_validation_failure { +macro_rules! err_validation_failure { ($where:expr, $kind: expr) => {{ let where_ = &$where; let path = if !where_.is_empty() { @@ -53,10 +53,16 @@ macro_rules! throw_validation_failure { None }; - throw_ub!(ValidationError(ValidationErrorInfo { path, kind: $kind })) + err_ub!(ValidationError(ValidationErrorInfo { path, kind: $kind })) }}; } +macro_rules! throw_validation_failure { + ($where:expr, $kind: expr) => { + do yeet err_validation_failure!($where, $kind) + }; +} + /// If $e throws an error matching the pattern, throw a validation failure. /// Other errors are passed back to the caller, unchanged -- and if they reach the root of /// the visitor, we make sure only validation errors and `InvalidProgram` errors are left. @@ -91,25 +97,22 @@ macro_rules! try_validation { ($e:expr, $where:expr, $( $( $p:pat_param )|+ => $kind: expr ),+ $(,)? ) => {{ - match $e { - Ok(x) => x, + $e.map_err(|e| { // We catch the error and turn it into a validation failure. We are okay with // allocation here as this can only slow down builds that fail anyway. - Err(e) => { - let (kind, backtrace) = e.into_parts(); - match kind { - $( - $($p)|+ => { - throw_validation_failure!( - $where, - $kind - ) - } - ),+, - _ => Err::<!, _>(InterpErrorInfo::from_parts(kind, backtrace))?, - } + let (kind, backtrace) = e.into_parts(); + match kind { + $( + $($p)|+ => { + err_validation_failure!( + $where, + $kind + ).into() + } + ),+, + _ => InterpErrorInfo::from_parts(kind, backtrace), } - } + })? }}; } @@ -381,7 +384,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { // Undo changes self.path.truncate(path_len); // Done - Ok(r) + interp_ok(r) } fn read_immediate( @@ -389,7 +392,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { val: &PlaceTy<'tcx, M::Provenance>, expected: ExpectedKind, ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { - Ok(try_validation!( + interp_ok(try_validation!( self.ecx.read_immediate(val), self.path, Ub(InvalidUninitBytes(None)) => @@ -407,7 +410,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { val: &PlaceTy<'tcx, M::Provenance>, expected: ExpectedKind, ) -> InterpResult<'tcx, Scalar<M::Provenance>> { - Ok(self.read_immediate(val, expected)?.to_scalar()) + interp_ok(self.read_immediate(val, expected)?.to_scalar()) } fn deref_pointer( @@ -472,7 +475,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { _ => bug!("Unexpected unsized type tail: {:?}", tail), } - Ok(()) + interp_ok(()) } /// Check a reference or `Box`. @@ -635,7 +638,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { } // Potentially skip recursive check. if skip_recursive_check { - return Ok(()); + return interp_ok(()); } } else { // This is not CTFE, so it's Miri with recursive checking. @@ -644,7 +647,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { // FIXME: should we also skip `UnsafeCell` behind shared references? Currently that is not // needed since validation reads bypass Stacked Borrows and data race checks. if matches!(ptr_kind, PointerKind::Box) { - return Ok(()); + return interp_ok(()); } } let path = &self.path; @@ -657,7 +660,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { new_path }); } - Ok(()) + interp_ok(()) } /// Check if this is a value of primitive type, and if yes check the validity of the value @@ -684,7 +687,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { self.ecx.clear_provenance(value)?; self.add_data_range_place(value); } - Ok(true) + interp_ok(true) } ty::Char => { let scalar = self.read_scalar(value, ExpectedKind::Char)?; @@ -699,7 +702,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { self.ecx.clear_provenance(value)?; self.add_data_range_place(value); } - Ok(true) + interp_ok(true) } ty::Float(_) | ty::Int(_) | ty::Uint(_) => { // NOTE: Keep this in sync with the array optimization for int/float @@ -716,18 +719,18 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { self.ecx.clear_provenance(value)?; self.add_data_range_place(value); } - Ok(true) + interp_ok(true) } ty::RawPtr(..) => { let place = self.deref_pointer(value, ExpectedKind::RawPtr)?; if place.layout.is_unsized() { self.check_wide_ptr_meta(place.meta(), place.layout)?; } - Ok(true) + interp_ok(true) } ty::Ref(_, _ty, mutbl) => { self.check_safe_pointer(value, PointerKind::Ref(*mutbl))?; - Ok(true) + interp_ok(true) } ty::FnPtr(..) => { let scalar = self.read_scalar(value, ExpectedKind::FnPtr)?; @@ -756,12 +759,12 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { } self.add_data_range_place(value); } - Ok(true) + interp_ok(true) } ty::Never => throw_validation_failure!(self.path, NeverVal), ty::Foreign(..) | ty::FnDef(..) => { // Nothing to check. - Ok(true) + interp_ok(true) } // The above should be all the primitive types. The rest is compound, we // check them by visiting their fields/variants. @@ -774,7 +777,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { | ty::Closure(..) | ty::Pat(..) | ty::CoroutineClosure(..) - | ty::Coroutine(..) => Ok(false), + | ty::Coroutine(..) => interp_ok(false), // Some types only occur during typechecking, they have no layout. // We should not see them here and we could not check them anyway. ty::Error(_) @@ -811,11 +814,11 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { max_value }) } else { - return Ok(()); + return interp_ok(()); } } else if scalar_layout.is_always_valid(self.ecx) { // Easy. (This is reachable if `enforce_number_validity` is set.) - return Ok(()); + return interp_ok(()); } else { // Conservatively, we reject, because the pointer *could* have a bad // value. @@ -828,7 +831,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { }; // Now compare. if valid_range.contains(bits) { - Ok(()) + interp_ok(()) } else { throw_validation_failure!(self.path, OutOfRange { value: format!("{bits}"), @@ -887,7 +890,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { } fn reset_padding(&mut self, place: &PlaceTy<'tcx, M::Provenance>) -> InterpResult<'tcx> { - let Some(data_bytes) = self.data_bytes.as_mut() else { return Ok(()) }; + let Some(data_bytes) = self.data_bytes.as_mut() else { return interp_ok(()) }; // Our value must be in memory, otherwise we would not have set up `data_bytes`. let mplace = self.ecx.force_allocation(place)?; // Determine starting offset and size. @@ -899,14 +902,14 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { // If there is no padding at all, we can skip the rest: check for // a single data range covering the entire value. if data_bytes.0 == &[(start_offset, size)] { - return Ok(()); + return interp_ok(()); } // Get a handle for the allocation. Do this only once, to avoid looking up the same // allocation over and over again. (Though to be fair, iterating the value already does // exactly that.) let Some(mut alloc) = self.ecx.get_ptr_alloc_mut(mplace.ptr(), size)? else { // A ZST, no padding to clear. - return Ok(()); + return interp_ok(()); }; // Add a "finalizer" data range at the end, so that the iteration below finds all gaps // between ranges. @@ -933,7 +936,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { padding_cleared_until = offset + size; } assert!(padding_cleared_until == start_offset + size); - Ok(()) + interp_ok(()) } /// Computes the data range of this union type: @@ -1073,7 +1076,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, val: &PlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx, VariantIdx> { self.with_elem(PathElem::EnumTag, move |this| { - Ok(try_validation!( + interp_ok(try_validation!( this.ecx.read_discriminant(val), this.path, Ub(InvalidTag(val)) => InvalidEnumTag { @@ -1137,7 +1140,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, data_bytes.add_range(base_offset + offset, size); } } - Ok(()) + interp_ok(()) } #[inline] @@ -1147,7 +1150,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, val: &PlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx> { self.check_safe_pointer(val, PointerKind::Box)?; - Ok(()) + interp_ok(()) } #[inline] @@ -1160,7 +1163,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, // We assume that the Scalar validity range does not restrict these values // any further than `try_visit_primitive` does! if self.try_visit_primitive(val)? { - return Ok(()); + return interp_ok(()); } // Special check preventing `UnsafeCell` in the inner part of constants @@ -1207,7 +1210,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, // If the size is 0, there is nothing to check. // (`size` can only be 0 if `len` is 0, and empty arrays are always valid.) if size == Size::ZERO { - return Ok(()); + return interp_ok(()); } // Now that we definitely have a non-ZST array, we know it lives in memory -- except it may // be an uninitialized local variable, those are also "immediate". @@ -1227,37 +1230,33 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, // No need for an alignment check here, this is not an actual memory access. let alloc = self.ecx.get_ptr_alloc(mplace.ptr(), size)?.expect("we already excluded size 0"); - match alloc.get_bytes_strip_provenance() { - // In the happy case, we needn't check anything else. - Ok(_) => {} + alloc.get_bytes_strip_provenance().map_err(|err| { // Some error happened, try to provide a more detailed description. - Err(err) => { - // For some errors we might be able to provide extra information. - // (This custom logic does not fit the `try_validation!` macro.) - let (kind, backtrace) = err.into_parts(); - match kind { - Ub(InvalidUninitBytes(Some((_alloc_id, access)))) | Unsup(ReadPointerAsInt(Some((_alloc_id, access)))) => { - // Some byte was uninitialized, determine which - // element that byte belongs to so we can - // provide an index. - let i = usize::try_from( - access.bad.start.bytes() / layout.size.bytes(), - ) - .unwrap(); - self.path.push(PathElem::ArrayElem(i)); - - if matches!(kind, Ub(InvalidUninitBytes(_))) { - throw_validation_failure!(self.path, Uninit { expected }) - } else { - throw_validation_failure!(self.path, PointerAsInt { expected }) - } - } + // For some errors we might be able to provide extra information. + // (This custom logic does not fit the `try_validation!` macro.) + let (kind, backtrace) = err.into_parts(); + match kind { + Ub(InvalidUninitBytes(Some((_alloc_id, access)))) | Unsup(ReadPointerAsInt(Some((_alloc_id, access)))) => { + // Some byte was uninitialized, determine which + // element that byte belongs to so we can + // provide an index. + let i = usize::try_from( + access.bad.start.bytes() / layout.size.bytes(), + ) + .unwrap(); + self.path.push(PathElem::ArrayElem(i)); - // Propagate upwards (that will also check for unexpected errors). - _ => return Err(InterpErrorInfo::from_parts(kind, backtrace)), + if matches!(kind, Ub(InvalidUninitBytes(_))) { + err_validation_failure!(self.path, Uninit { expected }).into() + } else { + err_validation_failure!(self.path, PointerAsInt { expected }).into() + } } + + // Propagate upwards (that will also check for unexpected errors). + _ => return InterpErrorInfo::from_parts(kind, backtrace), } - } + })?; // Don't forget that these are all non-pointer types, and thus do not preserve // provenance. @@ -1335,7 +1334,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, } } - Ok(()) + interp_ok(()) } } @@ -1351,7 +1350,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { trace!("validate_operand_internal: {:?}, {:?}", *val, val.layout.ty); // Run the visitor. - match self.run_for_validation(|ecx| { + self.run_for_validation(|ecx| { let reset_padding = reset_provenance_and_padding && { // Check if `val` is actually stored in memory. If not, padding is not even // represented and we need not reset it. @@ -1367,29 +1366,22 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { }; v.visit_value(val)?; v.reset_padding(val)?; - InterpResult::Ok(()) - }) { - Ok(()) => Ok(()), - // Pass through validation failures and "invalid program" issues. - Err(err) - if matches!( - err.kind(), - err_ub!(ValidationError { .. }) - | InterpError::InvalidProgram(_) - | InterpError::Unsupported(UnsupportedOpInfo::ExternTypeField) - ) => - { - Err(err) - } - // Complain about any other kind of error -- those are bad because we'd like to - // report them in a way that shows *where* in the value the issue lies. - Err(err) => { + interp_ok(()) + }) + .map_err(|err| { + if !matches!( + err.kind(), + err_ub!(ValidationError { .. }) + | InterpError::InvalidProgram(_) + | InterpError::Unsupported(UnsupportedOpInfo::ExternTypeField) + ) { bug!( "Unexpected error during validation: {}", format_interp_error(self.tcx.dcx(), err) ); } - } + err + }) } /// This function checks the data at `op` to be const-valid. @@ -1460,6 +1452,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /*reset_provenance_and_padding*/ false, )?; } - Ok(()) + interp_ok(()) } } diff --git a/compiler/rustc_const_eval/src/interpret/visitor.rs b/compiler/rustc_const_eval/src/interpret/visitor.rs index d004a3f0892..647917dbb67 100644 --- a/compiler/rustc_const_eval/src/interpret/visitor.rs +++ b/compiler/rustc_const_eval/src/interpret/visitor.rs @@ -10,7 +10,7 @@ use rustc_middle::ty::{self, Ty}; use rustc_target::abi::{FieldIdx, FieldsShape, VariantIdx, Variants}; use tracing::trace; -use super::{InterpCx, MPlaceTy, Machine, Projectable, throw_inval}; +use super::{InterpCx, MPlaceTy, Machine, Projectable, interp_ok, throw_inval}; /// How to traverse a value and what to do when we are at the leaves. pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized { @@ -46,14 +46,14 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized { /// Visits the given value as a union. No automatic recursion can happen here. #[inline(always)] fn visit_union(&mut self, _v: &Self::V, _fields: NonZero<usize>) -> InterpResult<'tcx> { - Ok(()) + interp_ok(()) } /// Visits the given value as the pointer of a `Box`. There is nothing to recurse into. /// The type of `v` will be a raw pointer to `T`, but this is a field of `Box<T>` and the /// pointee type is the actual `T`. `box_ty` provides the full type of the `Box` itself. #[inline(always)] fn visit_box(&mut self, _box_ty: Ty<'tcx>, _v: &Self::V) -> InterpResult<'tcx> { - Ok(()) + interp_ok(()) } /// Called each time we recurse down to a field of a "product-like" aggregate @@ -165,7 +165,7 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized { self.visit_field(v, 1, &alloc)?; // We visited all parts of this one. - return Ok(()); + return interp_ok(()); } // Non-normalized types should never show up here. @@ -222,6 +222,6 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized { Variants::Single { .. } => {} } - Ok(()) + interp_ok(()) } } diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs index 421648d9e7b..649179d5b1e 100644 --- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs +++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs @@ -1,5 +1,4 @@ use rustc_middle::bug; -use rustc_middle::mir::interpret::DiscardInterpError; use rustc_middle::ty::layout::{ HasTyCtxt, LayoutCx, LayoutError, LayoutOf, TyAndLayout, ValidityRequirement, }; @@ -76,7 +75,7 @@ fn check_validity_requirement_strict<'tcx>( /*recursive*/ false, /*reset_provenance_and_padding*/ false, ) - .discard_interp_err() + .discard_err() .is_some()) } |
