make InterpResult a dedicated type to avoid accidentally discarding the error

This commit is contained in:
Ralf Jung 2024-09-29 11:53:23 +02:00
parent 4b8a5bd511
commit c4ce8c114b
102 changed files with 1588 additions and 1466 deletions

View file

@ -4,7 +4,7 @@
use rustc_const_eval::const_eval::{DummyMachine, throw_machine_stop_str};
use rustc_const_eval::interpret::{
DiscardInterpError, ImmTy, Immediate, InterpCx, OpTy, PlaceTy, Projectable,
ImmTy, Immediate, InterpCx, OpTy, PlaceTy, Projectable, interp_ok,
};
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def::DefKind;
@ -238,6 +238,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
FlatSet::Elem(op) => self
.ecx
.int_to_int_or_float(&op, layout)
.discard_err()
.map_or(FlatSet::Top, |result| self.wrap_immediate(*result)),
FlatSet::Bottom => FlatSet::Bottom,
FlatSet::Top => FlatSet::Top,
@ -251,6 +252,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
FlatSet::Elem(op) => self
.ecx
.float_to_float_or_int(&op, layout)
.discard_err()
.map_or(FlatSet::Top, |result| self.wrap_immediate(*result)),
FlatSet::Bottom => FlatSet::Bottom,
FlatSet::Top => FlatSet::Top,
@ -273,6 +275,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
FlatSet::Elem(value) => self
.ecx
.unary_op(*op, &value)
.discard_err()
.map_or(FlatSet::Top, |val| self.wrap_immediate(*val)),
FlatSet::Bottom => FlatSet::Bottom,
FlatSet::Top => FlatSet::Top,
@ -366,10 +369,8 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
}
}
Operand::Constant(box constant) => {
if let Some(constant) = self
.ecx
.eval_mir_constant(&constant.const_, constant.span, None)
.discard_interp_err()
if let Some(constant) =
self.ecx.eval_mir_constant(&constant.const_, constant.span, None).discard_err()
{
self.assign_constant(state, place, constant, &[]);
}
@ -391,7 +392,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
for &(mut proj_elem) in projection {
if let PlaceElem::Index(index) = proj_elem {
if let FlatSet::Elem(index) = state.get(index.into(), &self.map)
&& let Some(offset) = index.to_target_usize(&self.tcx).discard_interp_err()
&& let Some(offset) = index.to_target_usize(&self.tcx).discard_err()
&& let Some(min_length) = offset.checked_add(1)
{
proj_elem = PlaceElem::ConstantIndex { offset, min_length, from_end: false };
@ -399,40 +400,35 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
return;
}
}
operand =
if let Some(operand) = self.ecx.project(&operand, proj_elem).discard_interp_err() {
operand
} else {
return;
}
operand = if let Some(operand) = self.ecx.project(&operand, proj_elem).discard_err() {
operand
} else {
return;
}
}
self.map.for_each_projection_value(
place,
operand,
&mut |elem, op| match elem {
TrackElem::Field(idx) => {
self.ecx.project_field(op, idx.as_usize()).discard_interp_err()
}
TrackElem::Variant(idx) => self.ecx.project_downcast(op, idx).discard_interp_err(),
TrackElem::Field(idx) => self.ecx.project_field(op, idx.as_usize()).discard_err(),
TrackElem::Variant(idx) => self.ecx.project_downcast(op, idx).discard_err(),
TrackElem::Discriminant => {
let variant = self.ecx.read_discriminant(op).discard_interp_err()?;
let discr_value = self
.ecx
.discriminant_for_variant(op.layout.ty, variant)
.discard_interp_err()?;
let variant = self.ecx.read_discriminant(op).discard_err()?;
let discr_value =
self.ecx.discriminant_for_variant(op.layout.ty, variant).discard_err()?;
Some(discr_value.into())
}
TrackElem::DerefLen => {
let op: OpTy<'_> = self.ecx.deref_pointer(op).discard_interp_err()?.into();
let len_usize = op.len(&self.ecx).discard_interp_err()?;
let op: OpTy<'_> = self.ecx.deref_pointer(op).discard_err()?.into();
let len_usize = op.len(&self.ecx).discard_err()?;
let layout =
self.tcx.layout_of(self.param_env.and(self.tcx.types.usize)).unwrap();
Some(ImmTy::from_uint(len_usize, layout).into())
}
},
&mut |place, op| {
if let Some(imm) = self.ecx.read_immediate_raw(op).discard_interp_err()
if let Some(imm) = self.ecx.read_immediate_raw(op).discard_err()
&& let Some(imm) = imm.right()
{
let elem = self.wrap_immediate(*imm);
@ -456,7 +452,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
(FlatSet::Bottom, _) | (_, FlatSet::Bottom) => (FlatSet::Bottom, FlatSet::Bottom),
// Both sides are known, do the actual computation.
(FlatSet::Elem(left), FlatSet::Elem(right)) => {
match self.ecx.binary_op(op, &left, &right).discard_interp_err() {
match self.ecx.binary_op(op, &left, &right).discard_err() {
// Ideally this would return an Immediate, since it's sometimes
// a pair and sometimes not. But as a hack we always return a pair
// and just make the 2nd component `Bottom` when it does not exist.
@ -479,7 +475,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
}
let arg_scalar = const_arg.to_scalar();
let Some(arg_value) = arg_scalar.to_bits(layout.size).discard_interp_err() else {
let Some(arg_value) = arg_scalar.to_bits(layout.size).discard_err() else {
return (FlatSet::Top, FlatSet::Top);
};
@ -527,10 +523,8 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
return None;
}
let enum_ty_layout = self.tcx.layout_of(self.param_env.and(enum_ty)).ok()?;
let discr_value = self
.ecx
.discriminant_for_variant(enum_ty_layout.ty, variant_index)
.discard_interp_err()?;
let discr_value =
self.ecx.discriminant_for_variant(enum_ty_layout.ty, variant_index).discard_err()?;
Some(discr_value.to_scalar())
}
@ -584,7 +578,7 @@ impl<'a, 'tcx> Collector<'a, 'tcx> {
map: &Map<'tcx>,
) -> Option<Const<'tcx>> {
let ty = place.ty(self.local_decls, self.patch.tcx).ty;
let layout = ecx.layout_of(ty).discard_interp_err()?;
let layout = ecx.layout_of(ty).ok()?;
if layout.is_zst() {
return Some(Const::zero_sized(ty));
@ -606,7 +600,7 @@ impl<'a, 'tcx> Collector<'a, 'tcx> {
.intern_with_temp_alloc(layout, |ecx, dest| {
try_write_constant(ecx, dest, place, ty, state, map)
})
.discard_interp_err()?;
.discard_err()?;
return Some(Const::Val(ConstValue::Indirect { alloc_id, offset: Size::ZERO }, ty));
}
@ -643,7 +637,7 @@ fn try_write_constant<'tcx>(
// Fast path for ZSTs.
if layout.is_zst() {
return Ok(());
return interp_ok(());
}
// Fast path for scalars.
@ -728,7 +722,7 @@ fn try_write_constant<'tcx>(
ty::Error(_) | ty::Infer(..) | ty::CoroutineWitness(..) => bug!(),
}
Ok(())
interp_ok(())
}
impl<'mir, 'tcx>
@ -841,7 +835,7 @@ impl<'tcx> MutVisitor<'tcx> for Patch<'tcx> {
if let PlaceElem::Index(local) = elem {
let offset = self.before_effect.get(&(location, local.into()))?;
let offset = offset.try_to_scalar()?;
let offset = offset.to_target_usize(&self.tcx).discard_interp_err()?;
let offset = offset.to_target_usize(&self.tcx).discard_err()?;
let min_length = offset.checked_add(1)?;
Some(PlaceElem::ConstantIndex { offset, min_length, from_end: false })
} else {

View file

@ -87,8 +87,8 @@ use std::borrow::Cow;
use either::Either;
use rustc_const_eval::const_eval::DummyMachine;
use rustc_const_eval::interpret::{
DiscardInterpError, ImmTy, Immediate, InterpCx, MemPlaceMeta, MemoryKind, OpTy, Projectable,
Scalar, intern_const_alloc_for_constprop,
ImmTy, Immediate, InterpCx, MemPlaceMeta, MemoryKind, OpTy, Projectable, Scalar,
intern_const_alloc_for_constprop,
};
use rustc_data_structures::fx::FxIndexSet;
use rustc_data_structures::graph::dominators::Dominators;
@ -393,7 +393,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
Repeat(..) => return None,
Constant { ref value, disambiguator: _ } => {
self.ecx.eval_mir_constant(value, DUMMY_SP, None).discard_interp_err()?
self.ecx.eval_mir_constant(value, DUMMY_SP, None).discard_err()?
}
Aggregate(kind, variant, ref fields) => {
let fields = fields
@ -414,39 +414,37 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
AggregateTy::RawPtr { output_pointer_ty, .. } => output_pointer_ty,
};
let variant = if ty.is_enum() { Some(variant) } else { None };
let ty = self.ecx.layout_of(ty).discard_interp_err()?;
let ty = self.ecx.layout_of(ty).ok()?;
if ty.is_zst() {
ImmTy::uninit(ty).into()
} else if matches!(kind, AggregateTy::RawPtr { .. }) {
// Pointers don't have fields, so don't `project_field` them.
let data = self.ecx.read_pointer(fields[0]).discard_interp_err()?;
let data = self.ecx.read_pointer(fields[0]).discard_err()?;
let meta = if fields[1].layout.is_zst() {
MemPlaceMeta::None
} else {
MemPlaceMeta::Meta(self.ecx.read_scalar(fields[1]).discard_interp_err()?)
MemPlaceMeta::Meta(self.ecx.read_scalar(fields[1]).discard_err()?)
};
let ptr_imm = Immediate::new_pointer_with_meta(data, meta, &self.ecx);
ImmTy::from_immediate(ptr_imm, ty).into()
} else if matches!(ty.abi, Abi::Scalar(..) | Abi::ScalarPair(..)) {
let dest = self.ecx.allocate(ty, MemoryKind::Stack).discard_interp_err()?;
let dest = self.ecx.allocate(ty, MemoryKind::Stack).discard_err()?;
let variant_dest = if let Some(variant) = variant {
self.ecx.project_downcast(&dest, variant).discard_interp_err()?
self.ecx.project_downcast(&dest, variant).discard_err()?
} else {
dest.clone()
};
for (field_index, op) in fields.into_iter().enumerate() {
let field_dest = self
.ecx
.project_field(&variant_dest, field_index)
.discard_interp_err()?;
self.ecx.copy_op(op, &field_dest).discard_interp_err()?;
let field_dest =
self.ecx.project_field(&variant_dest, field_index).discard_err()?;
self.ecx.copy_op(op, &field_dest).discard_err()?;
}
self.ecx
.write_discriminant(variant.unwrap_or(FIRST_VARIANT), &dest)
.discard_interp_err()?;
.discard_err()?;
self.ecx
.alloc_mark_immutable(dest.ptr().provenance.unwrap().alloc_id())
.discard_interp_err()?;
.discard_err()?;
dest.into()
} else {
return None;
@ -472,7 +470,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
// This should have been replaced by a `ConstantIndex` earlier.
ProjectionElem::Index(_) => return None,
};
self.ecx.project(value, elem).discard_interp_err()?
self.ecx.project(value, elem).discard_err()?
}
Address { place, kind, provenance: _ } => {
if !place.is_indirect_first_projection() {
@ -480,14 +478,14 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
}
let local = self.locals[place.local]?;
let pointer = self.evaluated[local].as_ref()?;
let mut mplace = self.ecx.deref_pointer(pointer).discard_interp_err()?;
let mut mplace = self.ecx.deref_pointer(pointer).discard_err()?;
for proj in place.projection.iter().skip(1) {
// We have no call stack to associate a local with a value, so we cannot
// interpret indexing.
if matches!(proj, ProjectionElem::Index(_)) {
return None;
}
mplace = self.ecx.project(&mplace, proj).discard_interp_err()?;
mplace = self.ecx.project(&mplace, proj).discard_err()?;
}
let pointer = mplace.to_ref(&self.ecx);
let ty = match kind {
@ -499,28 +497,26 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
),
AddressKind::Address(mutbl) => Ty::new_ptr(self.tcx, mplace.layout.ty, mutbl),
};
let layout = self.ecx.layout_of(ty).discard_interp_err()?;
let layout = self.ecx.layout_of(ty).ok()?;
ImmTy::from_immediate(pointer, layout).into()
}
Discriminant(base) => {
let base = self.evaluated[base].as_ref()?;
let variant = self.ecx.read_discriminant(base).discard_interp_err()?;
let discr_value = self
.ecx
.discriminant_for_variant(base.layout.ty, variant)
.discard_interp_err()?;
let variant = self.ecx.read_discriminant(base).discard_err()?;
let discr_value =
self.ecx.discriminant_for_variant(base.layout.ty, variant).discard_err()?;
discr_value.into()
}
Len(slice) => {
let slice = self.evaluated[slice].as_ref()?;
let usize_layout = self.ecx.layout_of(self.tcx.types.usize).unwrap();
let len = slice.len(&self.ecx).discard_interp_err()?;
let len = slice.len(&self.ecx).discard_err()?;
let imm = ImmTy::from_uint(len, usize_layout);
imm.into()
}
NullaryOp(null_op, ty) => {
let layout = self.ecx.layout_of(ty).discard_interp_err()?;
let layout = self.ecx.layout_of(ty).ok()?;
if let NullOp::SizeOf | NullOp::AlignOf = null_op
&& layout.is_unsized()
{
@ -542,36 +538,36 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
}
UnaryOp(un_op, operand) => {
let operand = self.evaluated[operand].as_ref()?;
let operand = self.ecx.read_immediate(operand).discard_interp_err()?;
let val = self.ecx.unary_op(un_op, &operand).discard_interp_err()?;
let operand = self.ecx.read_immediate(operand).discard_err()?;
let val = self.ecx.unary_op(un_op, &operand).discard_err()?;
val.into()
}
BinaryOp(bin_op, lhs, rhs) => {
let lhs = self.evaluated[lhs].as_ref()?;
let lhs = self.ecx.read_immediate(lhs).discard_interp_err()?;
let lhs = self.ecx.read_immediate(lhs).discard_err()?;
let rhs = self.evaluated[rhs].as_ref()?;
let rhs = self.ecx.read_immediate(rhs).discard_interp_err()?;
let val = self.ecx.binary_op(bin_op, &lhs, &rhs).discard_interp_err()?;
let rhs = self.ecx.read_immediate(rhs).discard_err()?;
let val = self.ecx.binary_op(bin_op, &lhs, &rhs).discard_err()?;
val.into()
}
Cast { kind, value, from: _, to } => match kind {
CastKind::IntToInt | CastKind::IntToFloat => {
let value = self.evaluated[value].as_ref()?;
let value = self.ecx.read_immediate(value).discard_interp_err()?;
let to = self.ecx.layout_of(to).discard_interp_err()?;
let res = self.ecx.int_to_int_or_float(&value, to).discard_interp_err()?;
let value = self.ecx.read_immediate(value).discard_err()?;
let to = self.ecx.layout_of(to).ok()?;
let res = self.ecx.int_to_int_or_float(&value, to).discard_err()?;
res.into()
}
CastKind::FloatToFloat | CastKind::FloatToInt => {
let value = self.evaluated[value].as_ref()?;
let value = self.ecx.read_immediate(value).discard_interp_err()?;
let to = self.ecx.layout_of(to).discard_interp_err()?;
let res = self.ecx.float_to_float_or_int(&value, to).discard_interp_err()?;
let value = self.ecx.read_immediate(value).discard_err()?;
let to = self.ecx.layout_of(to).ok()?;
let res = self.ecx.float_to_float_or_int(&value, to).discard_err()?;
res.into()
}
CastKind::Transmute => {
let value = self.evaluated[value].as_ref()?;
let to = self.ecx.layout_of(to).discard_interp_err()?;
let to = self.ecx.layout_of(to).ok()?;
// `offset` for immediates only supports scalar/scalar-pair ABIs,
// so bail out if the target is not one.
if value.as_mplace_or_imm().is_right() {
@ -581,29 +577,29 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
_ => return None,
}
}
value.offset(Size::ZERO, to, &self.ecx).discard_interp_err()?
value.offset(Size::ZERO, to, &self.ecx).discard_err()?
}
CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize, _) => {
let src = self.evaluated[value].as_ref()?;
let to = self.ecx.layout_of(to).discard_interp_err()?;
let dest = self.ecx.allocate(to, MemoryKind::Stack).discard_interp_err()?;
self.ecx.unsize_into(src, to, &dest.clone().into()).discard_interp_err()?;
let to = self.ecx.layout_of(to).ok()?;
let dest = self.ecx.allocate(to, MemoryKind::Stack).discard_err()?;
self.ecx.unsize_into(src, to, &dest.clone().into()).discard_err()?;
self.ecx
.alloc_mark_immutable(dest.ptr().provenance.unwrap().alloc_id())
.discard_interp_err()?;
.discard_err()?;
dest.into()
}
CastKind::FnPtrToPtr | CastKind::PtrToPtr => {
let src = self.evaluated[value].as_ref()?;
let src = self.ecx.read_immediate(src).discard_interp_err()?;
let to = self.ecx.layout_of(to).discard_interp_err()?;
let ret = self.ecx.ptr_to_ptr(&src, to).discard_interp_err()?;
let src = self.ecx.read_immediate(src).discard_err()?;
let to = self.ecx.layout_of(to).ok()?;
let ret = self.ecx.ptr_to_ptr(&src, to).discard_err()?;
ret.into()
}
CastKind::PointerCoercion(ty::adjustment::PointerCoercion::UnsafeFnPointer, _) => {
let src = self.evaluated[value].as_ref()?;
let src = self.ecx.read_immediate(src).discard_interp_err()?;
let to = self.ecx.layout_of(to).discard_interp_err()?;
let src = self.ecx.read_immediate(src).discard_err()?;
let to = self.ecx.layout_of(to).ok()?;
ImmTy::from_immediate(*src, to).into()
}
_ => return None,
@ -715,7 +711,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
&& let Some(idx) = self.locals[idx_local]
{
if let Some(offset) = self.evaluated[idx].as_ref()
&& let Some(offset) = self.ecx.read_target_usize(offset).discard_interp_err()
&& let Some(offset) = self.ecx.read_target_usize(offset).discard_err()
&& let Some(min_length) = offset.checked_add(1)
{
projection.to_mut()[i] =
@ -875,7 +871,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
&& let DefKind::Enum = self.tcx.def_kind(enum_did)
{
let enum_ty = self.tcx.type_of(enum_did).instantiate(self.tcx, enum_args);
let discr = self.ecx.discriminant_for_variant(enum_ty, variant).discard_interp_err()?;
let discr = self.ecx.discriminant_for_variant(enum_ty, variant).discard_err()?;
return Some(self.insert_scalar(discr.to_scalar(), discr.layout.ty));
}
@ -1225,13 +1221,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
return None;
}
let layout = self.ecx.layout_of(lhs_ty).discard_interp_err()?;
let layout = self.ecx.layout_of(lhs_ty).ok()?;
let as_bits = |value| {
let constant = self.evaluated[value].as_ref()?;
if layout.abi.is_scalar() {
let scalar = self.ecx.read_scalar(constant).discard_interp_err()?;
scalar.to_bits(constant.layout.size).discard_interp_err()
let scalar = self.ecx.read_scalar(constant).discard_err()?;
scalar.to_bits(constant.layout.size).discard_err()
} else {
// `constant` is a wide pointer. Do not evaluate to bits.
None
@ -1491,7 +1487,7 @@ fn op_to_prop_const<'tcx>(
// If this constant has scalar ABI, return it as a `ConstValue::Scalar`.
if let Abi::Scalar(abi::Scalar::Initialized { .. }) = op.layout.abi
&& let Some(scalar) = ecx.read_scalar(op).discard_interp_err()
&& let Some(scalar) = ecx.read_scalar(op).discard_err()
{
if !scalar.try_to_scalar_int().is_ok() {
// Check that we do not leak a pointer.
@ -1505,12 +1501,12 @@ fn op_to_prop_const<'tcx>(
// If this constant is already represented as an `Allocation`,
// try putting it into global memory to return it.
if let Either::Left(mplace) = op.as_mplace_or_imm() {
let (size, _align) = ecx.size_and_align_of_mplace(&mplace).discard_interp_err()??;
let (size, _align) = ecx.size_and_align_of_mplace(&mplace).discard_err()??;
// Do not try interning a value that contains provenance.
// Due to https://github.com/rust-lang/rust/issues/79738, doing so could lead to bugs.
// FIXME: remove this hack once that issue is fixed.
let alloc_ref = ecx.get_ptr_alloc(mplace.ptr(), size).discard_interp_err()??;
let alloc_ref = ecx.get_ptr_alloc(mplace.ptr(), size).discard_err()??;
if alloc_ref.has_provenance() {
return None;
}
@ -1518,7 +1514,7 @@ fn op_to_prop_const<'tcx>(
let pointer = mplace.ptr().into_pointer_or_addr().ok()?;
let (prov, offset) = pointer.into_parts();
let alloc_id = prov.alloc_id();
intern_const_alloc_for_constprop(ecx, alloc_id).discard_interp_err()?;
intern_const_alloc_for_constprop(ecx, alloc_id).discard_err()?;
// `alloc_id` may point to a static. Codegen will choke on an `Indirect` with anything
// by `GlobalAlloc::Memory`, so do fall through to copying if needed.
@ -1533,9 +1529,8 @@ fn op_to_prop_const<'tcx>(
}
// Everything failed: create a new allocation to hold the data.
let alloc_id = ecx
.intern_with_temp_alloc(op.layout, |ecx, dest| ecx.copy_op(op, dest))
.discard_interp_err()?;
let alloc_id =
ecx.intern_with_temp_alloc(op.layout, |ecx, dest| ecx.copy_op(op, dest)).discard_err()?;
let value = ConstValue::Indirect { alloc_id, offset: Size::ZERO };
// Check that we do not leak a pointer.

View file

@ -37,9 +37,7 @@
use rustc_arena::DroplessArena;
use rustc_const_eval::const_eval::DummyMachine;
use rustc_const_eval::interpret::{
DiscardInterpError, ImmTy, Immediate, InterpCx, OpTy, Projectable,
};
use rustc_const_eval::interpret::{ImmTy, Immediate, InterpCx, OpTy, Projectable};
use rustc_data_structures::fx::FxHashSet;
use rustc_index::IndexVec;
use rustc_index::bit_set::BitSet;
@ -202,7 +200,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
debug!(?discr, ?bb);
let discr_ty = discr.ty(self.body, self.tcx).ty;
let Some(discr_layout) = self.ecx.layout_of(discr_ty).discard_interp_err() else {
let Ok(discr_layout) = self.ecx.layout_of(discr_ty) else {
return;
};
@ -392,28 +390,24 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
lhs,
constant,
&mut |elem, op| match elem {
TrackElem::Field(idx) => {
self.ecx.project_field(op, idx.as_usize()).discard_interp_err()
}
TrackElem::Variant(idx) => self.ecx.project_downcast(op, idx).discard_interp_err(),
TrackElem::Field(idx) => self.ecx.project_field(op, idx.as_usize()).discard_err(),
TrackElem::Variant(idx) => self.ecx.project_downcast(op, idx).discard_err(),
TrackElem::Discriminant => {
let variant = self.ecx.read_discriminant(op).discard_interp_err()?;
let discr_value = self
.ecx
.discriminant_for_variant(op.layout.ty, variant)
.discard_interp_err()?;
let variant = self.ecx.read_discriminant(op).discard_err()?;
let discr_value =
self.ecx.discriminant_for_variant(op.layout.ty, variant).discard_err()?;
Some(discr_value.into())
}
TrackElem::DerefLen => {
let op: OpTy<'_> = self.ecx.deref_pointer(op).discard_interp_err()?.into();
let len_usize = op.len(&self.ecx).discard_interp_err()?;
let op: OpTy<'_> = self.ecx.deref_pointer(op).discard_err()?.into();
let len_usize = op.len(&self.ecx).discard_err()?;
let layout = self.ecx.layout_of(self.tcx.types.usize).unwrap();
Some(ImmTy::from_uint(len_usize, layout).into())
}
},
&mut |place, op| {
if let Some(conditions) = state.try_get_idx(place, &self.map)
&& let Some(imm) = self.ecx.read_immediate_raw(op).discard_interp_err()
&& let Some(imm) = self.ecx.read_immediate_raw(op).discard_err()
&& let Some(imm) = imm.right()
&& let Immediate::Scalar(Scalar::Int(int)) = *imm
{
@ -437,10 +431,8 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
match rhs {
// If we expect `lhs ?= A`, we have an opportunity if we assume `constant == A`.
Operand::Constant(constant) => {
let Some(constant) = self
.ecx
.eval_mir_constant(&constant.const_, constant.span, None)
.discard_interp_err()
let Some(constant) =
self.ecx.eval_mir_constant(&constant.const_, constant.span, None).discard_err()
else {
return;
};
@ -482,7 +474,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
&& let Some(discr_value) = self
.ecx
.discriminant_for_variant(agg_ty, *variant_index)
.discard_interp_err()
.discard_err()
{
self.process_immediate(bb, discr_target, discr_value, state);
}
@ -567,7 +559,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
// `SetDiscriminant` may be a no-op if the assigned variant is the untagged variant
// of a niche encoding. If we cannot ensure that we write to the discriminant, do
// nothing.
let Some(enum_layout) = self.ecx.layout_of(enum_ty).discard_interp_err() else {
let Ok(enum_layout) = self.ecx.layout_of(enum_ty) else {
return;
};
let writes_discriminant = match enum_layout.variants {
@ -582,10 +574,8 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
} => *variant_index != untagged_variant,
};
if writes_discriminant {
let Some(discr) = self
.ecx
.discriminant_for_variant(enum_ty, *variant_index)
.discard_interp_err()
let Some(discr) =
self.ecx.discriminant_for_variant(enum_ty, *variant_index).discard_err()
else {
return;
};
@ -662,7 +652,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
let Some(discr) = discr.place() else { return };
let discr_ty = discr.ty(self.body, self.tcx).ty;
let Some(discr_layout) = self.ecx.layout_of(discr_ty).discard_interp_err() else {
let Ok(discr_layout) = self.ecx.layout_of(discr_ty) else {
return;
};
let Some(conditions) = state.try_get(discr.as_ref(), &self.map) else { return };

View file

@ -6,7 +6,7 @@ use std::fmt::Debug;
use rustc_const_eval::const_eval::DummyMachine;
use rustc_const_eval::interpret::{
DiscardInterpError, ImmTy, InterpCx, InterpResult, Projectable, Scalar, format_interp_error,
ImmTy, InterpCx, InterpResult, Projectable, Scalar, format_interp_error, interp_ok,
};
use rustc_data_structures::fx::FxHashSet;
use rustc_hir::HirId;
@ -101,8 +101,7 @@ impl<'tcx> Value<'tcx> {
}
(PlaceElem::Index(idx), Value::Aggregate { fields, .. }) => {
let idx = prop.get_const(idx.into())?.immediate()?;
let idx =
prop.ecx.read_target_usize(idx).discard_interp_err()?.try_into().ok()?;
let idx = prop.ecx.read_target_usize(idx).discard_err()?.try_into().ok()?;
if idx <= FieldIdx::MAX_AS_U32 {
fields.get(FieldIdx::from_u32(idx)).unwrap_or(&Value::Uninit)
} else {
@ -232,22 +231,20 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
where
F: FnOnce(&mut Self) -> InterpResult<'tcx, T>,
{
match f(self) {
Ok(val) => Some(val),
Err(error) => {
trace!("InterpCx operation failed: {:?}", error);
f(self)
.map_err(|err| {
trace!("InterpCx operation failed: {:?}", err);
// Some errors shouldn't come up because creating them causes
// an allocation, which we should avoid. When that happens,
// dedicated error variants should be introduced instead.
assert!(
!error.kind().formatted_string(),
!err.kind().formatted_string(),
"known panics lint encountered formatting error: {}",
format_interp_error(self.ecx.tcx.dcx(), error),
format_interp_error(self.ecx.tcx.dcx(), err),
);
error.discard_interp_err();
None
}
}
err
})
.discard_err()
}
/// Returns the value, if any, of evaluating `c`.
@ -317,7 +314,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
.ecx
.binary_op(BinOp::SubWithOverflow, &ImmTy::from_int(0, arg.layout), &arg)?
.to_scalar_pair();
Ok((arg, overflow.to_bool()?))
interp_ok((arg, overflow.to_bool()?))
})?;
if overflow {
self.report_assert_as_lint(
@ -349,9 +346,9 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
// We need the type of the LHS. We cannot use `place_layout` as that is the type
// of the result, which for checked binops is not the same!
let left_ty = left.ty(self.local_decls(), self.tcx);
let left_size = self.ecx.layout_of(left_ty).discard_interp_err()?.size;
let left_size = self.ecx.layout_of(left_ty).ok()?.size;
let right_size = r.layout.size;
let r_bits = r.to_scalar().to_bits(right_size).discard_interp_err();
let r_bits = r.to_scalar().to_bits(right_size).discard_err();
if r_bits.is_some_and(|b| b >= left_size.bits() as u128) {
debug!("check_binary_op: reporting assert for {:?}", location);
let panic = AssertKind::Overflow(
@ -498,7 +495,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
// This can be `None` if the lhs wasn't const propagated and we just
// triggered the assert on the value of the rhs.
self.eval_operand(op)
.and_then(|op| self.ecx.read_immediate(&op).discard_interp_err())
.and_then(|op| self.ecx.read_immediate(&op).discard_err())
.map_or(DbgVal::Underscore, |op| DbgVal::Val(op.to_const_int()))
};
let msg = match msg {
@ -542,7 +539,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
return None;
}
use rustc_middle::mir::Rvalue::*;
let layout = self.ecx.layout_of(dest.ty(self.body, self.tcx).ty).discard_interp_err()?;
let layout = self.ecx.layout_of(dest.ty(self.body, self.tcx).ty).ok()?;
trace!(?layout);
let val: Value<'_> = match *rvalue {
@ -604,7 +601,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
Len(place) => {
let len = match self.get_const(place)? {
Value::Immediate(src) => src.len(&self.ecx).discard_interp_err()?,
Value::Immediate(src) => src.len(&self.ecx).discard_err()?,
Value::Aggregate { fields, .. } => fields.len() as u64,
Value::Uninit => match place.ty(self.local_decls(), self.tcx).ty.kind() {
ty::Array(_, n) => n.try_eval_target_usize(self.tcx, self.param_env)?,
@ -617,7 +614,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
Ref(..) | RawPtr(..) => return None,
NullaryOp(ref null_op, ty) => {
let op_layout = self.use_ecx(|this| this.ecx.layout_of(ty))?;
let op_layout = self.ecx.layout_of(ty).ok()?;
let val = match null_op {
NullOp::SizeOf => op_layout.size.bytes(),
NullOp::AlignOf => op_layout.align.abi.bytes(),
@ -635,21 +632,21 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
Cast(ref kind, ref value, to) => match kind {
CastKind::IntToInt | CastKind::IntToFloat => {
let value = self.eval_operand(value)?;
let value = self.ecx.read_immediate(&value).discard_interp_err()?;
let to = self.ecx.layout_of(to).discard_interp_err()?;
let res = self.ecx.int_to_int_or_float(&value, to).discard_interp_err()?;
let value = self.ecx.read_immediate(&value).discard_err()?;
let to = self.ecx.layout_of(to).ok()?;
let res = self.ecx.int_to_int_or_float(&value, to).discard_err()?;
res.into()
}
CastKind::FloatToFloat | CastKind::FloatToInt => {
let value = self.eval_operand(value)?;
let value = self.ecx.read_immediate(&value).discard_interp_err()?;
let to = self.ecx.layout_of(to).discard_interp_err()?;
let res = self.ecx.float_to_float_or_int(&value, to).discard_interp_err()?;
let value = self.ecx.read_immediate(&value).discard_err()?;
let to = self.ecx.layout_of(to).ok()?;
let res = self.ecx.float_to_float_or_int(&value, to).discard_err()?;
res.into()
}
CastKind::Transmute => {
let value = self.eval_operand(value)?;
let to = self.ecx.layout_of(to).discard_interp_err()?;
let to = self.ecx.layout_of(to).ok()?;
// `offset` for immediates only supports scalar/scalar-pair ABIs,
// so bail out if the target is not one.
match (value.layout.abi, to.abi) {
@ -658,7 +655,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
_ => return None,
}
value.offset(Size::ZERO, to, &self.ecx).discard_interp_err()?.into()
value.offset(Size::ZERO, to, &self.ecx).discard_err()?.into()
}
_ => return None,
},
@ -783,8 +780,7 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
TerminatorKind::SwitchInt { ref discr, ref targets } => {
if let Some(ref value) = self.eval_operand(discr)
&& let Some(value_const) = self.use_ecx(|this| this.ecx.read_scalar(value))
&& let Some(constant) =
value_const.to_bits(value_const.size()).discard_interp_err()
&& let Some(constant) = value_const.to_bits(value_const.size()).discard_err()
{
// We managed to evaluate the discriminant, so we know we only need to visit
// one target.