1
Fork 0

Auto merge of #135709 - lqd:bring-back-len, r=compiler-errors

Temporarily bring back `Rvalue::Len`

r? `@compiler-errors` as requested in https://github.com/rust-lang/rust/issues/135671#issuecomment-2599580364

> However, in the mean time, I'd rather we not crunch trying to find and more importantly validate the soundness of a solution 🤔

Agreed. To fix the IMO P-critical #135671 for which we somehow didn't have test coverage, this PR temporarily reverts:
- https://github.com/rust-lang/rust/pull/133734
- its bugfix https://github.com/rust-lang/rust/pull/134371
- https://github.com/rust-lang/rust/pull/134330

cc `@scottmcm`

I added the few samples from that issue as a test, but we can add more in the future, in particular it seems `@steffahn` [will work on that](https://github.com/rust-lang/rust/issues/135671#issuecomment-2599714354).

Fixes #135671. And if we want to land this, it should also be nominated for beta backport.
This commit is contained in:
bors 2025-01-19 06:09:51 +00:00
commit c62b732724
136 changed files with 1964 additions and 1542 deletions

View file

@ -829,6 +829,7 @@ use self::ReadOrWrite::{Activation, Read, Reservation, Write};
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
enum ArtificialField {
ArrayLength,
FakeBorrow,
}
@ -1338,11 +1339,16 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
);
}
&Rvalue::Discriminant(place) => {
&(Rvalue::Len(place) | Rvalue::Discriminant(place)) => {
let af = match *rvalue {
Rvalue::Len(..) => Some(ArtificialField::ArrayLength),
Rvalue::Discriminant(..) => None,
_ => unreachable!(),
};
self.access_place(
location,
(place, span),
(Shallow(None), Read(ReadKind::Copy)),
(Shallow(af), Read(ReadKind::Copy)),
LocalMutationIsAllowed::No,
state,
);

View file

@ -203,7 +203,8 @@ fn place_components_conflict<'tcx>(
let base_ty = base.ty(body, tcx).ty;
match (elem, base_ty.kind(), access) {
(_, _, Shallow(Some(ArtificialField::FakeBorrow))) => {
(_, _, Shallow(Some(ArtificialField::ArrayLength)))
| (_, _, Shallow(Some(ArtificialField::FakeBorrow))) => {
// The array length is like additional fields on the
// type; it does not overlap any existing data there.
// Furthermore, if cannot actually be a prefix of any

View file

@ -300,11 +300,16 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> {
self.consume_operand(location, op);
}
&Rvalue::Discriminant(place) => {
&(Rvalue::Len(place) | Rvalue::Discriminant(place)) => {
let af = match rvalue {
Rvalue::Len(..) => Some(ArtificialField::ArrayLength),
Rvalue::Discriminant(..) => None,
_ => unreachable!(),
};
self.access_place(
location,
place,
(Shallow(None), Read(ReadKind::Copy)),
(Shallow(af), Read(ReadKind::Copy)),
LocalMutationIsAllowed::No,
);
}

View file

@ -2235,6 +2235,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
Rvalue::RawPtr(..)
| Rvalue::ThreadLocalRef(..)
| Rvalue::Len(..)
| Rvalue::Discriminant(..)
| Rvalue::NullaryOp(NullOp::OffsetOf(..), _) => {}
}
@ -2250,6 +2251,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
| Rvalue::Repeat(..)
| Rvalue::Ref(..)
| Rvalue::RawPtr(..)
| Rvalue::Len(..)
| Rvalue::Cast(..)
| Rvalue::ShallowInitBox(..)
| Rvalue::BinaryOp(..)

View file

@ -828,6 +828,12 @@ fn codegen_stmt<'tcx>(
fx.bcx.ins().nop();
}
}
Rvalue::Len(place) => {
let place = codegen_place(fx, place);
let usize_layout = fx.layout_of(fx.tcx.types.usize);
let len = codegen_array_len(fx, place);
lval.write_cvalue(fx, CValue::by_val(len, usize_layout));
}
Rvalue::ShallowInitBox(ref operand, content_ty) => {
let content_ty = fx.monomorphize(content_ty);
let box_layout = fx.layout_of(Ty::new_box(fx.tcx, content_ty));

View file

@ -10,9 +10,9 @@ use rustc_session::config::OptLevel;
use rustc_span::{DUMMY_SP, Span};
use tracing::{debug, instrument};
use super::FunctionCx;
use super::operand::{OperandRef, OperandValue};
use super::place::PlaceRef;
use super::{FunctionCx, LocalRef};
use crate::common::IntPredicate;
use crate::traits::*;
use crate::{MemFlags, base};
@ -607,6 +607,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
self.codegen_place_to_pointer(bx, place, mk_ptr)
}
mir::Rvalue::Len(place) => {
let size = self.evaluate_array_len(bx, place);
OperandRef {
val: OperandValue::Immediate(size),
layout: bx.cx().layout_of(bx.tcx().types.usize),
}
}
mir::Rvalue::BinaryOp(op_with_overflow, box (ref lhs, ref rhs))
if let Some(op) = op_with_overflow.overflowing_to_wrapping() =>
{
@ -806,6 +814,24 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
}
fn evaluate_array_len(&mut self, bx: &mut Bx, place: mir::Place<'tcx>) -> Bx::Value {
// ZST are passed as operands and require special handling
// because codegen_place() panics if Local is operand.
if let Some(index) = place.as_local() {
if let LocalRef::Operand(op) = self.locals[index] {
if let ty::Array(_, n) = op.layout.ty.kind() {
let n = n
.try_to_target_usize(bx.tcx())
.expect("expected monomorphic const in codegen");
return bx.cx().const_usize(n);
}
}
}
// use common size calculation for non zero-sized types
let cg_value = self.codegen_place(bx, place.as_ref());
cg_value.len(bx.cx())
}
/// Codegen an `Rvalue::RawPtr` or `Rvalue::Ref`
fn codegen_place_to_pointer(
&mut self,
@ -1077,6 +1103,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
mir::Rvalue::Ref(..) |
mir::Rvalue::CopyForDeref(..) |
mir::Rvalue::RawPtr(..) |
mir::Rvalue::Len(..) |
mir::Rvalue::Cast(..) | // (*)
mir::Rvalue::ShallowInitBox(..) | // (*)
mir::Rvalue::BinaryOp(..) |

View file

@ -495,7 +495,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
Rvalue::Use(_)
| Rvalue::CopyForDeref(..)
| Rvalue::Repeat(..)
| Rvalue::Discriminant(..) => {}
| Rvalue::Discriminant(..)
| Rvalue::Len(_) => {}
Rvalue::Aggregate(kind, ..) => {
if let AggregateKind::Coroutine(def_id, ..) = kind.as_ref()
@ -579,27 +580,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
) => {}
Rvalue::ShallowInitBox(_, _) => {}
Rvalue::UnaryOp(op, operand) => {
Rvalue::UnaryOp(_, operand) => {
let ty = operand.ty(self.body, self.tcx);
match op {
UnOp::Not | UnOp::Neg => {
if is_int_bool_float_or_char(ty) {
// Int, bool, float, and char operations are fine.
} else {
span_bug!(
self.span,
"non-primitive type in `Rvalue::UnaryOp{op:?}`: {ty:?}",
);
}
}
UnOp::PtrMetadata => {
if !ty.is_ref() && !ty.is_unsafe_ptr() {
span_bug!(
self.span,
"non-pointer type in `Rvalue::UnaryOp({op:?})`: {ty:?}",
);
}
}
if is_int_bool_float_or_char(ty) {
// Int, bool, float, and char operations are fine.
} else {
span_bug!(self.span, "non-primitive type in `Rvalue::UnaryOp`: {:?}", ty);
}
}

View file

@ -230,7 +230,9 @@ where
Q::in_any_value_of_ty(cx, rvalue.ty(cx.body, cx.tcx))
}
Rvalue::Discriminant(place) => in_place::<Q, _>(cx, in_local, place.as_ref()),
Rvalue::Discriminant(place) | Rvalue::Len(place) => {
in_place::<Q, _>(cx, in_local, place.as_ref())
}
Rvalue::CopyForDeref(place) => in_place::<Q, _>(cx, in_local, place.as_ref()),

View file

@ -197,6 +197,7 @@ where
| mir::Rvalue::CopyForDeref(..)
| mir::Rvalue::ThreadLocalRef(..)
| mir::Rvalue::Repeat(..)
| mir::Rvalue::Len(..)
| mir::Rvalue::BinaryOp(..)
| mir::Rvalue::NullaryOp(..)
| mir::Rvalue::UnaryOp(..)

View file

@ -9,13 +9,12 @@ use rustc_middle::ty::layout::FnAbiOf;
use rustc_middle::ty::{self, Instance, Ty};
use rustc_middle::{bug, mir, span_bug};
use rustc_span::source_map::Spanned;
use rustc_span::{DesugaringKind, Span};
use rustc_target::callconv::FnAbi;
use tracing::{info, instrument, trace};
use super::{
FnArg, FnVal, ImmTy, Immediate, InterpCx, InterpResult, Machine, MemPlaceMeta, PlaceTy,
Projectable, interp_ok, throw_ub,
Projectable, Scalar, interp_ok, throw_ub,
};
use crate::util;
@ -81,9 +80,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
use rustc_middle::mir::StatementKind::*;
match &stmt.kind {
Assign(box (place, rvalue)) => {
self.eval_rvalue_into_place(rvalue, *place, stmt.source_info.span)?
}
Assign(box (place, rvalue)) => self.eval_rvalue_into_place(rvalue, *place)?,
SetDiscriminant { place, variant_index } => {
let dest = self.eval_place(**place)?;
@ -162,7 +159,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
&mut self,
rvalue: &mir::Rvalue<'tcx>,
place: mir::Place<'tcx>,
span: Span,
) -> InterpResult<'tcx> {
let dest = self.eval_place(place)?;
// FIXME: ensure some kind of non-aliasing between LHS and RHS?
@ -218,6 +214,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
self.write_repeat(operand, &dest)?;
}
Len(place) => {
let src = self.eval_place(place)?;
let len = src.len(self)?;
self.write_scalar(Scalar::from_target_usize(len, self), &dest)?;
}
Ref(_, borrow_kind, place) => {
let src = self.eval_place(place)?;
let place = self.force_allocation(&src)?;
@ -248,13 +250,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
let src = self.eval_place(place)?;
let place = self.force_allocation(&src)?;
let mut val = ImmTy::from_immediate(place.to_ref(self), dest.layout);
if !place_base_raw
&& span.desugaring_kind() != Some(DesugaringKind::IndexBoundsCheckReborrow)
{
if !place_base_raw {
// If this was not already raw, it needs retagging.
// As a special hack, we exclude the desugared `PtrMetadata(&raw const *_n)`
// from indexing. (Really we should not do any retag on `&raw` but that does not
// currently work with Stacked Borrows.)
val = M::retag_ptr_value(self, mir::RetagKind::Raw, &val)?;
}
self.write_immediate(*val, &dest)?;

View file

@ -467,9 +467,6 @@ impl<'tcx> Const<'tcx> {
let const_val = tcx.valtree_to_const_val((ty, valtree));
Self::Val(const_val, ty)
}
ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, args }) => {
Self::Unevaluated(UnevaluatedConst { def, args, promoted: None }, ty)
}
_ => Self::Ty(ty, c),
}
}

View file

@ -1068,6 +1068,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
pretty_print_const(b, fmt, false)?;
write!(fmt, "]")
}
Len(ref a) => write!(fmt, "Len({a:?})"),
Cast(ref kind, ref place, ref ty) => {
with_no_trimmed_paths!(write!(fmt, "{place:?} as {ty} ({kind:?})"))
}

View file

@ -424,6 +424,7 @@ impl<'tcx> Rvalue<'tcx> {
| Rvalue::Ref(_, _, _)
| Rvalue::ThreadLocalRef(_)
| Rvalue::RawPtr(_, _)
| Rvalue::Len(_)
| Rvalue::Cast(
CastKind::IntToInt
| CastKind::FloatToInt

View file

@ -1351,6 +1351,16 @@ pub enum Rvalue<'tcx> {
/// model.
RawPtr(Mutability, Place<'tcx>),
/// Yields the length of the place, as a `usize`.
///
/// If the type of the place is an array, this is the array length. For slices (`[T]`, not
/// `&[T]`) this accesses the place's metadata to determine the length. This rvalue is
/// ill-formed for places of other types.
///
/// This cannot be a `UnOp(PtrMetadata, _)` because that expects a value, and we only
/// have a place, and `UnOp(PtrMetadata, RawPtr(place))` is not a thing.
Len(Place<'tcx>),
/// Performs essentially all of the casts that can be performed via `as`.
///
/// This allows for casts from/to a variety of types.

View file

@ -210,6 +210,7 @@ impl<'tcx> Rvalue<'tcx> {
let place_ty = place.ty(local_decls, tcx).ty;
Ty::new_ptr(tcx, place_ty, mutability)
}
Rvalue::Len(..) => tcx.types.usize,
Rvalue::Cast(.., ty) => ty,
Rvalue::BinaryOp(op, box (ref lhs, ref rhs)) => {
let lhs_ty = lhs.ty(local_decls, tcx);

View file

@ -695,6 +695,14 @@ macro_rules! make_mir_visitor {
self.visit_place(path, ctx, location);
}
Rvalue::Len(path) => {
self.visit_place(
path,
PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect),
location
);
}
Rvalue::Cast(_cast_kind, operand, ty) => {
self.visit_operand(operand, location);
self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));

View file

@ -246,6 +246,7 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> {
let offset = self.parse_operand(args[1])?;
Ok(Rvalue::BinaryOp(BinOp::Offset, Box::new((ptr, offset))))
},
@call(mir_len, args) => Ok(Rvalue::Len(self.parse_place(args[0])?)),
@call(mir_ptr_metadata, args) => Ok(Rvalue::UnaryOp(UnOp::PtrMetadata, self.parse_operand(args[0])?)),
@call(mir_copy_for_deref, args) => Ok(Rvalue::CopyForDeref(self.parse_place(args[0])?)),
ExprKind::Borrow { borrow_kind, arg } => Ok(

View file

@ -11,7 +11,7 @@ use rustc_middle::mir::*;
use rustc_middle::thir::*;
use rustc_middle::ty::{self, AdtDef, CanonicalUserTypeAnnotation, Ty, Variance};
use rustc_middle::{bug, span_bug};
use rustc_span::{DesugaringKind, Span};
use rustc_span::Span;
use tracing::{debug, instrument, trace};
use crate::builder::ForGuard::{OutsideGuard, RefWithinGuard};
@ -630,98 +630,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
block.and(base_place.index(idx))
}
/// Given a place that's either an array or a slice, returns an operand
/// with the length of the array/slice.
///
/// For arrays it'll be `Operand::Constant` with the actual length;
/// For slices it'll be `Operand::Move` of a local using `PtrMetadata`.
pub(in crate::builder) fn len_of_slice_or_array(
&mut self,
block: BasicBlock,
place: Place<'tcx>,
span: Span,
source_info: SourceInfo,
) -> Operand<'tcx> {
let place_ty = place.ty(&self.local_decls, self.tcx).ty;
let usize_ty = self.tcx.types.usize;
match place_ty.kind() {
ty::Array(_elem_ty, len_const) => {
let ty_const = if let Some((_, len_ty)) = len_const.try_to_valtree()
&& len_ty != self.tcx.types.usize
{
// Bad const generics can give us a constant from the type that's
// not actually a `usize`, so in that case give an error instead.
// FIXME: It'd be nice if the type checker made sure this wasn't
// possible, instead.
let err = self.tcx.dcx().span_delayed_bug(
span,
format!(
"Array length should have already been a type error, as it's {len_ty:?}"
),
);
ty::Const::new_error(self.tcx, err)
} else {
// We know how long an array is, so just use that as a constant
// directly -- no locals needed. We do need one statement so
// that borrow- and initialization-checking consider it used,
// though. FIXME: Do we really *need* to count this as a use?
// Could partial array tracking work off something else instead?
self.cfg.push_fake_read(block, source_info, FakeReadCause::ForIndex, place);
*len_const
};
let const_ = Const::from_ty_const(ty_const, usize_ty, self.tcx);
Operand::Constant(Box::new(ConstOperand { span, user_ty: None, const_ }))
}
ty::Slice(_elem_ty) => {
let ptr_or_ref = if let [PlaceElem::Deref] = place.projection[..]
&& let local_ty = self.local_decls[place.local].ty
&& local_ty.is_trivially_pure_clone_copy()
{
// It's extremely common that we have something that can be
// directly passed to `PtrMetadata`, so avoid an unnecessary
// temporary and statement in those cases. Note that we can
// only do that for `Copy` types -- not `&mut [_]` -- because
// the MIR we're building here needs to pass NLL later.
Operand::Copy(Place::from(place.local))
} else {
let len_span = self.tcx.with_stable_hashing_context(|hcx| {
let span = source_info.span;
span.mark_with_reason(
None,
DesugaringKind::IndexBoundsCheckReborrow,
span.edition(),
hcx,
)
});
let ptr_ty = Ty::new_imm_ptr(self.tcx, place_ty);
let slice_ptr = self.temp(ptr_ty, span);
self.cfg.push_assign(
block,
SourceInfo { span: len_span, ..source_info },
slice_ptr,
Rvalue::RawPtr(Mutability::Not, place),
);
Operand::Move(slice_ptr)
};
let len = self.temp(usize_ty, span);
self.cfg.push_assign(
block,
source_info,
len,
Rvalue::UnaryOp(UnOp::PtrMetadata, ptr_or_ref),
);
Operand::Move(len)
}
_ => {
span_bug!(span, "len called on place of type {place_ty:?}")
}
}
}
fn bounds_check(
&mut self,
block: BasicBlock,
@ -730,25 +638,25 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
expr_span: Span,
source_info: SourceInfo,
) -> BasicBlock {
let slice = slice.to_place(self);
let usize_ty = self.tcx.types.usize;
let bool_ty = self.tcx.types.bool;
// bounds check:
let len = self.temp(usize_ty, expr_span);
let lt = self.temp(bool_ty, expr_span);
// len = len(slice)
let len = self.len_of_slice_or_array(block, slice, expr_span, source_info);
self.cfg.push_assign(block, source_info, len, Rvalue::Len(slice.to_place(self)));
// lt = idx < len
let bool_ty = self.tcx.types.bool;
let lt = self.temp(bool_ty, expr_span);
self.cfg.push_assign(
block,
source_info,
lt,
Rvalue::BinaryOp(
BinOp::Lt,
Box::new((Operand::Copy(Place::from(index)), len.to_copy())),
Box::new((Operand::Copy(Place::from(index)), Operand::Copy(len))),
),
);
let msg = BoundsCheck { len, index: Operand::Copy(Place::from(index)) };
let msg = BoundsCheck { len: Operand::Move(len), index: Operand::Copy(Place::from(index)) };
// assert!(lt, "...")
self.assert(block, Operand::Move(lt), true, msg, expr_span)
}

View file

@ -243,8 +243,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
TestKind::Len { len, op } => {
let usize_ty = self.tcx.types.usize;
let actual = self.temp(usize_ty, test.span);
// actual = len(place)
let actual = self.len_of_slice_or_array(block, place, test.span, source_info);
self.cfg.push_assign(block, source_info, actual, Rvalue::Len(place));
// expected = <N>
let expected = self.push_usize(block, source_info, len);
@ -259,7 +262,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
fail_block,
source_info,
op,
actual,
Operand::Move(actual),
Operand::Move(expected),
);
}

View file

@ -91,6 +91,7 @@ where
| Rvalue::Use(..)
| Rvalue::ThreadLocalRef(..)
| Rvalue::Repeat(..)
| Rvalue::Len(..)
| Rvalue::BinaryOp(..)
| Rvalue::NullaryOp(..)
| Rvalue::UnaryOp(..)

View file

@ -413,6 +413,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
Rvalue::Ref(..)
| Rvalue::RawPtr(..)
| Rvalue::Discriminant(..)
| Rvalue::Len(..)
| Rvalue::NullaryOp(
NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..) | NullOp::UbChecks,
_,

View file

@ -408,6 +408,18 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
state: &mut State<FlatSet<Scalar>>,
) -> ValueOrPlace<FlatSet<Scalar>> {
let val = match rvalue {
Rvalue::Len(place) => {
let place_ty = place.ty(self.local_decls, self.tcx);
if let ty::Array(_, len) = place_ty.ty.kind() {
Const::Ty(self.tcx.types.usize, *len)
.try_eval_scalar(self.tcx, self.typing_env)
.map_or(FlatSet::Top, FlatSet::Elem)
} else if let [ProjectionElem::Deref] = place.projection[..] {
state.get_len(place.local.into(), &self.map)
} else {
FlatSet::Top
}
}
Rvalue::Cast(CastKind::IntToInt | CastKind::IntToFloat, operand, ty) => {
let Ok(layout) = self.tcx.layout_of(self.typing_env.as_query_input(*ty)) else {
return ValueOrPlace::Value(FlatSet::Top);

View file

@ -575,6 +575,7 @@ impl WriteInfo {
| Rvalue::NullaryOp(_, _)
| Rvalue::Ref(_, _, _)
| Rvalue::RawPtr(_, _)
| Rvalue::Len(_)
| Rvalue::Discriminant(_)
| Rvalue::CopyForDeref(_) => {}
}

View file

@ -223,6 +223,8 @@ enum Value<'tcx> {
Projection(VnIndex, ProjectionElem<VnIndex, Ty<'tcx>>),
/// Discriminant of the given value.
Discriminant(VnIndex),
/// Length of an array or slice.
Len(VnIndex),
// Operations.
NullaryOp(NullOp<'tcx>, Ty<'tcx>),
@ -511,6 +513,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
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_err()?;
let imm = ImmTy::from_uint(len, usize_layout);
imm.into()
}
NullaryOp(null_op, ty) => {
let layout = self.ecx.layout_of(ty).ok()?;
if let NullOp::SizeOf | NullOp::AlignOf = null_op
@ -854,6 +863,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
}
// Operations.
Rvalue::Len(ref mut place) => return self.simplify_len(place, location),
Rvalue::Cast(ref mut kind, ref mut value, to) => {
return self.simplify_cast(kind, value, to, location);
}
@ -1474,6 +1484,47 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
Some(self.insert(Value::Cast { kind: *kind, value, from, to }))
}
fn simplify_len(&mut self, place: &mut Place<'tcx>, location: Location) -> Option<VnIndex> {
// Trivial case: we are fetching a statically known length.
let place_ty = place.ty(self.local_decls, self.tcx).ty;
if let ty::Array(_, len) = place_ty.kind() {
return self.insert_constant(Const::from_ty_const(
*len,
self.tcx.types.usize,
self.tcx,
));
}
let mut inner = self.simplify_place_value(place, location)?;
// The length information is stored in the wide pointer.
// Reborrowing copies length information from one pointer to the other.
while let Value::Address { place: borrowed, .. } = self.get(inner)
&& let [PlaceElem::Deref] = borrowed.projection[..]
&& let Some(borrowed) = self.locals[borrowed.local]
{
inner = borrowed;
}
// We have an unsizing cast, which assigns the length to wide pointer metadata.
if let Value::Cast { kind, from, to, .. } = self.get(inner)
&& let CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize, _) = kind
&& let Some(from) = from.builtin_deref(true)
&& let ty::Array(_, len) = from.kind()
&& let Some(to) = to.builtin_deref(true)
&& let ty::Slice(..) = to.kind()
{
return self.insert_constant(Const::from_ty_const(
*len,
self.tcx.types.usize,
self.tcx,
));
}
// Fallback: a symbolic `Len`.
Some(self.insert(Value::Len(inner)))
}
fn pointers_have_same_metadata(&self, left_ptr_ty: Ty<'tcx>, right_ptr_ty: Ty<'tcx>) -> bool {
let left_meta_ty = left_ptr_ty.pointee_metadata_ty_or_projection(self.tcx);
let right_meta_ty = right_ptr_ty.pointee_metadata_ty_or_projection(self.tcx);

View file

@ -46,6 +46,7 @@ impl<'tcx> crate::MirPass<'tcx> for InstSimplify {
}
ctx.simplify_bool_cmp(rvalue);
ctx.simplify_ref_deref(rvalue);
ctx.simplify_len(rvalue);
ctx.simplify_ptr_aggregate(rvalue);
ctx.simplify_cast(rvalue);
ctx.simplify_repeated_aggregate(rvalue);
@ -161,6 +162,18 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> {
}
}
/// Transform `Len([_; N])` ==> `N`.
fn simplify_len(&self, rvalue: &mut Rvalue<'tcx>) {
if let Rvalue::Len(ref place) = *rvalue {
let place_ty = place.ty(self.local_decls, self.tcx).ty;
if let ty::Array(_, len) = *place_ty.kind() {
let const_ = Const::from_ty_const(len, self.tcx.types.usize, self.tcx);
let constant = ConstOperand { span: DUMMY_SP, const_, user_ty: None };
*rvalue = Rvalue::Use(Operand::Constant(Box::new(constant)));
}
}
}
/// Transform `Aggregate(RawPtr, [p, ()])` ==> `Cast(PtrToPtr, p)`.
fn simplify_ptr_aggregate(&self, rvalue: &mut Rvalue<'tcx>) {
if let Rvalue::Aggregate(box AggregateKind::RawPtr(pointee_ty, mutability), fields) = rvalue

View file

@ -440,6 +440,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
| Rvalue::Use(..)
| Rvalue::CopyForDeref(..)
| Rvalue::Repeat(..)
| Rvalue::Len(..)
| Rvalue::Cast(..)
| Rvalue::ShallowInitBox(..)
| Rvalue::Discriminant(..)
@ -599,6 +600,20 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
return None;
}
Len(place) => {
let len = if let ty::Array(_, n) = place.ty(self.local_decls(), self.tcx).ty.kind()
{
n.try_to_target_usize(self.tcx)?
} else {
match self.get_const(place)? {
Value::Immediate(src) => src.len(&self.ecx).discard_err()?,
Value::Aggregate { fields, .. } => fields.len() as u64,
Value::Uninit => return None,
}
};
ImmTy::from_scalar(Scalar::from_target_usize(len, self), layout).into()
}
Ref(..) | RawPtr(..) => return None,
NullaryOp(ref null_op, ty) => {

View file

@ -430,7 +430,9 @@ impl<'tcx> Validator<'_, 'tcx> {
self.validate_operand(op)?
}
Rvalue::Discriminant(place) => self.validate_place(place.as_ref())?,
Rvalue::Discriminant(place) | Rvalue::Len(place) => {
self.validate_place(place.as_ref())?
}
Rvalue::ThreadLocalRef(_) => return Err(Unpromotable),

View file

@ -1018,6 +1018,14 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
}
}
Rvalue::Ref(..) => {}
Rvalue::Len(p) => {
let pty = p.ty(&self.body.local_decls, self.tcx).ty;
check_kinds!(
pty,
"Cannot compute length of non-array type {:?}",
ty::Array(..) | ty::Slice(..)
);
}
Rvalue::BinaryOp(op, vals) => {
use BinOp::*;
let a = vals.0.ty(&self.body.local_decls, self.tcx);
@ -1116,6 +1124,14 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
);
}
UnOp::PtrMetadata => {
if !matches!(self.body.phase, MirPhase::Runtime(_)) {
// It would probably be fine to support this in earlier phases, but at
// the time of writing it's only ever introduced from intrinsic
// lowering or other runtime-phase optimization passes, so earlier
// things can just `bug!` on it.
self.fail(location, "PtrMetadata should be in runtime MIR only");
}
check_kinds!(
a,
"Cannot PtrMetadata non-pointer non-reference type {:?}",

View file

@ -181,6 +181,7 @@ impl<'tcx> Stable<'tcx> for mir::Rvalue<'tcx> {
RawPtr(mutability, place) => {
stable_mir::mir::Rvalue::AddressOf(mutability.stable(tables), place.stable(tables))
}
Len(place) => stable_mir::mir::Rvalue::Len(place.stable(tables)),
Cast(cast_kind, op, ty) => stable_mir::mir::Rvalue::Cast(
cast_kind.stable(tables),
op.stable(tables),

View file

@ -1163,9 +1163,6 @@ pub enum DesugaringKind {
WhileLoop,
/// `async Fn()` bound modifier
BoundModifier,
/// Marks a `&raw const *_1` needed as part of getting the length of a mutable
/// slice for the bounds check, so that MIRI's retag handling can recognize it.
IndexBoundsCheckReborrow,
}
impl DesugaringKind {
@ -1182,7 +1179,6 @@ impl DesugaringKind {
DesugaringKind::ForLoop => "`for` loop",
DesugaringKind::WhileLoop => "`while` loop",
DesugaringKind::BoundModifier => "trait bound modifier",
DesugaringKind::IndexBoundsCheckReborrow => "slice indexing",
}
}
}

View file

@ -1287,6 +1287,7 @@ symbols! {
mir_drop,
mir_field,
mir_goto,
mir_len,
mir_make_place,
mir_move,
mir_offset,

View file

@ -233,7 +233,7 @@
//!
//! - Operands implicitly convert to `Use` rvalues.
//! - `&`, `&mut`, `addr_of!`, and `addr_of_mut!` all work to create their associated rvalue.
//! - [`Discriminant`] and [`CopyForDeref`] have associated functions.
//! - [`Discriminant`], [`Len`], and [`CopyForDeref`] have associated functions.
//! - Unary and binary operations use their normal Rust syntax - `a * b`, `!c`, etc.
//! - The binary operation `Offset` can be created via [`Offset`].
//! - Checked binary operations are represented by wrapping the associated binop in [`Checked`].
@ -401,6 +401,7 @@ define!("mir_storage_dead", fn StorageDead<T>(local: T));
define!("mir_assume", fn Assume(operand: bool));
define!("mir_deinit", fn Deinit<T>(place: T));
define!("mir_checked", fn Checked<T>(binop: T) -> (T, bool));
define!("mir_len", fn Len<T>(place: T) -> usize);
define!(
"mir_ptr_metadata",
fn PtrMetadata<P: ?Sized>(place: *const P) -> <P as ::core::ptr::Pointee>::Metadata

View file

@ -109,7 +109,7 @@ fn check_rvalue<'tcx>(
) -> McfResult {
match rvalue {
Rvalue::ThreadLocalRef(_) => Err((span, "cannot access thread local storage in const fn".into())),
Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) | Rvalue::RawPtr(_, place) => {
Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) | Rvalue::RawPtr(_, place) => {
check_place(tcx, *place, span, body, msrv)
},
Rvalue::CopyForDeref(place) => check_place(tcx, *place, span, body, msrv),

View file

@ -7,7 +7,8 @@ fn main() -> () {
let mut _5: u32;
let mut _6: *mut usize;
let _7: usize;
let mut _8: bool;
let mut _8: usize;
let mut _9: bool;
scope 1 {
debug x => _1;
let mut _2: usize;
@ -40,8 +41,9 @@ fn main() -> () {
StorageDead(_6);
StorageLive(_7);
_7 = copy _2;
_8 = Lt(copy _7, const 3_usize);
assert(move _8, "index out of bounds: the length is {} but the index is {}", const 3_usize, copy _7) -> [success: bb2, unwind unreachable];
_8 = Len(_1);
_9 = Lt(copy _7, copy _8);
assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, copy _7) -> [success: bb2, unwind unreachable];
}
bb2: {

View file

@ -7,7 +7,8 @@ fn main() -> () {
let mut _5: u32;
let mut _6: *mut usize;
let _7: usize;
let mut _8: bool;
let mut _8: usize;
let mut _9: bool;
scope 1 {
debug x => _1;
let mut _2: usize;
@ -40,8 +41,9 @@ fn main() -> () {
StorageDead(_6);
StorageLive(_7);
_7 = copy _2;
_8 = Lt(copy _7, const 3_usize);
assert(move _8, "index out of bounds: the length is {} but the index is {}", const 3_usize, copy _7) -> [success: bb2, unwind continue];
_8 = Len(_1);
_9 = Lt(copy _7, copy _8);
assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, copy _7) -> [success: bb2, unwind continue];
}
bb2: {

View file

@ -0,0 +1,14 @@
// MIR for `arrays` after built
fn arrays() -> usize {
let mut _0: usize;
let mut _1: [i32; C];
let mut _2: usize;
bb0: {
_1 = [const 5_i32; C];
_2 = Len(_1);
_0 = copy _2;
return;
}
}

View file

@ -0,0 +1,22 @@
// skip-filecheck
#![feature(custom_mir, core_intrinsics)]
extern crate core;
use core::intrinsics::mir::*;
// EMIT_MIR arrays.arrays.built.after.mir
#[custom_mir(dialect = "built")]
fn arrays<const C: usize>() -> usize {
mir! {
{
let x = [5_i32; C];
let c = Len(x);
RET = c;
Return()
}
}
}
fn main() {
assert_eq!(arrays::<20>(), 20);
}

View file

@ -1,31 +0,0 @@
// MIR for `index_array` after built
fn index_array(_1: &[i32; 7], _2: usize) -> &i32 {
debug array => _1;
debug index => _2;
let mut _0: &i32;
let _3: &i32;
let _4: usize;
let mut _5: bool;
bb0: {
StorageLive(_3);
StorageLive(_4);
_4 = copy _2;
FakeRead(ForIndex, (*_1));
_5 = Lt(copy _4, const 7_usize);
assert(move _5, "index out of bounds: the length is {} but the index is {}", const 7_usize, copy _4) -> [success: bb1, unwind: bb2];
}
bb1: {
_3 = &(*_1)[_4];
_0 = &(*_3);
StorageDead(_4);
StorageDead(_3);
return;
}
bb2 (cleanup): {
resume;
}
}

View file

@ -1,31 +0,0 @@
// MIR for `index_const_generic_array` after built
fn index_const_generic_array(_1: &[i32; N], _2: usize) -> &i32 {
debug array => _1;
debug index => _2;
let mut _0: &i32;
let _3: &i32;
let _4: usize;
let mut _5: bool;
bb0: {
StorageLive(_3);
StorageLive(_4);
_4 = copy _2;
FakeRead(ForIndex, (*_1));
_5 = Lt(copy _4, const N);
assert(move _5, "index out of bounds: the length is {} but the index is {}", const N, copy _4) -> [success: bb1, unwind: bb2];
}
bb1: {
_3 = &(*_1)[_4];
_0 = &(*_3);
StorageDead(_4);
StorageDead(_3);
return;
}
bb2 (cleanup): {
resume;
}
}

View file

@ -1,34 +0,0 @@
// MIR for `index_custom` after built
fn index_custom(_1: &WithSliceTail, _2: usize) -> &i32 {
debug custom => _1;
debug index => _2;
let mut _0: &i32;
let _3: &i32;
let _4: usize;
let mut _5: *const [i32];
let mut _6: usize;
let mut _7: bool;
bb0: {
StorageLive(_3);
StorageLive(_4);
_4 = copy _2;
_5 = &raw const ((*_1).1: [i32]);
_6 = PtrMetadata(move _5);
_7 = Lt(copy _4, copy _6);
assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, copy _4) -> [success: bb1, unwind: bb2];
}
bb1: {
_3 = &((*_1).1: [i32])[_4];
_0 = &(*_3);
StorageDead(_4);
StorageDead(_3);
return;
}
bb2 (cleanup): {
resume;
}
}

View file

@ -1,34 +0,0 @@
// MIR for `index_mut_slice` after built
fn index_mut_slice(_1: &mut [i32], _2: usize) -> &i32 {
debug slice => _1;
debug index => _2;
let mut _0: &i32;
let _3: &i32;
let _4: usize;
let mut _5: *const [i32];
let mut _6: usize;
let mut _7: bool;
bb0: {
StorageLive(_3);
StorageLive(_4);
_4 = copy _2;
_5 = &raw const (*_1);
_6 = PtrMetadata(move _5);
_7 = Lt(copy _4, copy _6);
assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, copy _4) -> [success: bb1, unwind: bb2];
}
bb1: {
_3 = &(*_1)[_4];
_0 = &(*_3);
StorageDead(_4);
StorageDead(_3);
return;
}
bb2 (cleanup): {
resume;
}
}

View file

@ -1,32 +0,0 @@
// MIR for `index_slice` after built
fn index_slice(_1: &[i32], _2: usize) -> &i32 {
debug slice => _1;
debug index => _2;
let mut _0: &i32;
let _3: &i32;
let _4: usize;
let mut _5: usize;
let mut _6: bool;
bb0: {
StorageLive(_3);
StorageLive(_4);
_4 = copy _2;
_5 = PtrMetadata(copy _1);
_6 = Lt(copy _4, copy _5);
assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, copy _4) -> [success: bb1, unwind: bb2];
}
bb1: {
_3 = &(*_1)[_4];
_0 = &(*_3);
StorageDead(_4);
StorageDead(_3);
return;
}
bb2 (cleanup): {
resume;
}
}

View file

@ -1,71 +0,0 @@
//@ compile-flags: -C opt-level=0
// EMIT_MIR index_array_and_slice.index_array.built.after.mir
fn index_array(array: &[i32; 7], index: usize) -> &i32 {
// CHECK: bb0:
// CHECK: [[LT:_.+]] = Lt(copy _2, const 7_usize);
// CHECK: assert(move [[LT]], "index out of bounds{{.+}}", const 7_usize, copy _2) -> [success: bb1, unwind
// CHECK: bb1:
// CHECK: _0 = &(*_1)[_2];
&array[index]
}
// EMIT_MIR index_array_and_slice.index_const_generic_array.built.after.mir
fn index_const_generic_array<const N: usize>(array: &[i32; N], index: usize) -> &i32 {
// CHECK: bb0:
// CHECK: [[LT:_.+]] = Lt(copy _2, const N);
// CHECK: assert(move [[LT]], "index out of bounds{{.+}}", const N, copy _2) -> [success: bb1, unwind
// CHECK: bb1:
// CHECK: _0 = &(*_1)[_2];
&array[index]
}
// EMIT_MIR index_array_and_slice.index_slice.built.after.mir
fn index_slice(slice: &[i32], index: usize) -> &i32 {
// CHECK: bb0:
// CHECK: [[LEN:_.+]] = PtrMetadata(copy _1);
// CHECK: [[LT:_.+]] = Lt(copy _2, copy [[LEN]]);
// CHECK: assert(move [[LT]], "index out of bounds{{.+}}", move [[LEN]], copy _2) -> [success: bb1,
// CHECK: bb1:
// CHECK: _0 = &(*_1)[_2];
&slice[index]
}
// EMIT_MIR index_array_and_slice.index_mut_slice.built.after.mir
fn index_mut_slice(slice: &mut [i32], index: usize) -> &i32 {
// While the filecheck here is identical to the above test, the emitted MIR is different.
// This cannot `copy _1` in the *built* MIR, only in the *runtime* MIR.
// CHECK: bb0:
// CHECK: [[LEN:_.+]] = PtrMetadata(copy _1);
// CHECK: [[LT:_.+]] = Lt(copy _2, copy [[LEN]]);
// CHECK: assert(move [[LT]], "index out of bounds{{.+}}", move [[LEN]], copy _2) -> [success: bb1,
// CHECK: bb1:
// CHECK: _0 = &(*_1)[_2];
&slice[index]
}
struct WithSliceTail(f64, [i32]);
// EMIT_MIR index_array_and_slice.index_custom.built.after.mir
fn index_custom(custom: &WithSliceTail, index: usize) -> &i32 {
// CHECK: bb0:
// CHECK: [[PTR:_.+]] = &raw const ((*_1).1: [i32]);
// CHECK: [[LEN:_.+]] = PtrMetadata(move [[PTR]]);
// CHECK: [[LT:_.+]] = Lt(copy _2, copy [[LEN]]);
// CHECK: assert(move [[LT]], "index out of bounds{{.+}}", move [[LEN]], copy _2) -> [success: bb1,
// CHECK: bb1:
// CHECK: _0 = &((*_1).1: [i32])[_2];
&custom.1[index]
}
fn main() {
index_array(&[1, 2, 3, 4, 5, 6, 7], 3);
index_slice(&[1, 2, 3, 4, 5, 6, 7][..], 3);
_ = index_custom;
}

View file

@ -6,7 +6,8 @@
let _1: u32;
let mut _2: [u32; 4];
let _3: usize;
let mut _4: bool;
let mut _4: usize;
let mut _5: bool;
scope 1 {
debug x => _1;
}
@ -17,9 +18,11 @@
_2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32];
StorageLive(_3);
_3 = const 2_usize;
- _4 = Lt(copy _3, const 4_usize);
- assert(move _4, "index out of bounds: the length is {} but the index is {}", const 4_usize, copy _3) -> [success: bb1, unwind unreachable];
+ _4 = const true;
- _4 = Len(_2);
- _5 = Lt(copy _3, copy _4);
- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind unreachable];
+ _4 = const 4_usize;
+ _5 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind unreachable];
}

View file

@ -6,7 +6,8 @@
let _1: u32;
let mut _2: [u32; 4];
let _3: usize;
let mut _4: bool;
let mut _4: usize;
let mut _5: bool;
scope 1 {
debug x => _1;
}
@ -17,9 +18,11 @@
_2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32];
StorageLive(_3);
_3 = const 2_usize;
- _4 = Lt(copy _3, const 4_usize);
- assert(move _4, "index out of bounds: the length is {} but the index is {}", const 4_usize, copy _3) -> [success: bb1, unwind continue];
+ _4 = const true;
- _4 = Len(_2);
- _5 = Lt(copy _3, copy _4);
- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind continue];
+ _4 = const 4_usize;
+ _5 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind continue];
}

View file

@ -6,7 +6,8 @@
let _1: u32;
let mut _2: [u32; 4];
let _3: usize;
let mut _4: bool;
let mut _4: usize;
let mut _5: bool;
scope 1 {
debug x => _1;
}
@ -17,9 +18,11 @@
_2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32];
StorageLive(_3);
_3 = const 2_usize;
- _4 = Lt(copy _3, const 4_usize);
- assert(move _4, "index out of bounds: the length is {} but the index is {}", const 4_usize, copy _3) -> [success: bb1, unwind unreachable];
+ _4 = const true;
- _4 = Len(_2);
- _5 = Lt(copy _3, copy _4);
- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind unreachable];
+ _4 = const 4_usize;
+ _5 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind unreachable];
}

View file

@ -6,7 +6,8 @@
let _1: u32;
let mut _2: [u32; 4];
let _3: usize;
let mut _4: bool;
let mut _4: usize;
let mut _5: bool;
scope 1 {
debug x => _1;
}
@ -17,9 +18,11 @@
_2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32];
StorageLive(_3);
_3 = const 2_usize;
- _4 = Lt(copy _3, const 4_usize);
- assert(move _4, "index out of bounds: the length is {} but the index is {}", const 4_usize, copy _3) -> [success: bb1, unwind continue];
+ _4 = const true;
- _4 = Len(_2);
- _5 = Lt(copy _3, copy _4);
- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind continue];
+ _4 = const 4_usize;
+ _5 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind continue];
}

View file

@ -30,22 +30,19 @@
StorageDead(_2);
StorageDead(_3);
StorageLive(_5);
- StorageLive(_6);
+ nop;
StorageLive(_6);
_6 = const 3_usize;
- _7 = PtrMetadata(copy _1);
_7 = Len((*_1));
- _8 = Lt(copy _6, copy _7);
- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind unreachable];
+ _7 = const 3_usize;
+ _8 = const false;
+ assert(const false, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 3_usize) -> [success: bb1, unwind unreachable];
+ _8 = Lt(const 3_usize, copy _7);
+ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 3_usize) -> [success: bb1, unwind unreachable];
}
bb1: {
- _5 = copy (*_1)[_6];
- StorageDead(_6);
+ _5 = copy (*_1)[3 of 4];
+ nop;
StorageDead(_6);
_0 = const ();
StorageDead(_5);
StorageDead(_1);

View file

@ -30,22 +30,19 @@
StorageDead(_2);
StorageDead(_3);
StorageLive(_5);
- StorageLive(_6);
+ nop;
StorageLive(_6);
_6 = const 3_usize;
- _7 = PtrMetadata(copy _1);
_7 = Len((*_1));
- _8 = Lt(copy _6, copy _7);
- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind continue];
+ _7 = const 3_usize;
+ _8 = const false;
+ assert(const false, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 3_usize) -> [success: bb1, unwind continue];
+ _8 = Lt(const 3_usize, copy _7);
+ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 3_usize) -> [success: bb1, unwind continue];
}
bb1: {
- _5 = copy (*_1)[_6];
- StorageDead(_6);
+ _5 = copy (*_1)[3 of 4];
+ nop;
StorageDead(_6);
_0 = const ();
StorageDead(_5);
StorageDead(_1);

View file

@ -30,22 +30,19 @@
StorageDead(_2);
StorageDead(_3);
StorageLive(_5);
- StorageLive(_6);
+ nop;
StorageLive(_6);
_6 = const 3_usize;
- _7 = PtrMetadata(copy _1);
_7 = Len((*_1));
- _8 = Lt(copy _6, copy _7);
- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind unreachable];
+ _7 = const 3_usize;
+ _8 = const false;
+ assert(const false, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 3_usize) -> [success: bb1, unwind unreachable];
+ _8 = Lt(const 3_usize, copy _7);
+ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 3_usize) -> [success: bb1, unwind unreachable];
}
bb1: {
- _5 = copy (*_1)[_6];
- StorageDead(_6);
+ _5 = copy (*_1)[3 of 4];
+ nop;
StorageDead(_6);
_0 = const ();
StorageDead(_5);
StorageDead(_1);

View file

@ -30,22 +30,19 @@
StorageDead(_2);
StorageDead(_3);
StorageLive(_5);
- StorageLive(_6);
+ nop;
StorageLive(_6);
_6 = const 3_usize;
- _7 = PtrMetadata(copy _1);
_7 = Len((*_1));
- _8 = Lt(copy _6, copy _7);
- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind continue];
+ _7 = const 3_usize;
+ _8 = const false;
+ assert(const false, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 3_usize) -> [success: bb1, unwind continue];
+ _8 = Lt(const 3_usize, copy _7);
+ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 3_usize) -> [success: bb1, unwind continue];
}
bb1: {
- _5 = copy (*_1)[_6];
- StorageDead(_6);
+ _5 = copy (*_1)[3 of 4];
+ nop;
StorageDead(_6);
_0 = const ();
StorageDead(_5);
StorageDead(_1);

View file

@ -6,7 +6,8 @@
let _1: u8;
let mut _2: [u8; 5000];
let _3: usize;
let mut _4: bool;
let mut _4: usize;
let mut _5: bool;
scope 1 {
debug x => _1;
}
@ -17,9 +18,11 @@
_2 = [const 0_u8; 5000];
StorageLive(_3);
_3 = const 2_usize;
- _4 = Lt(copy _3, const 5000_usize);
- assert(move _4, "index out of bounds: the length is {} but the index is {}", const 5000_usize, copy _3) -> [success: bb1, unwind unreachable];
+ _4 = const true;
- _4 = Len(_2);
- _5 = Lt(copy _3, copy _4);
- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind unreachable];
+ _4 = const 5000_usize;
+ _5 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind unreachable];
}

View file

@ -6,7 +6,8 @@
let _1: u8;
let mut _2: [u8; 5000];
let _3: usize;
let mut _4: bool;
let mut _4: usize;
let mut _5: bool;
scope 1 {
debug x => _1;
}
@ -17,9 +18,11 @@
_2 = [const 0_u8; 5000];
StorageLive(_3);
_3 = const 2_usize;
- _4 = Lt(copy _3, const 5000_usize);
- assert(move _4, "index out of bounds: the length is {} but the index is {}", const 5000_usize, copy _3) -> [success: bb1, unwind continue];
+ _4 = const true;
- _4 = Len(_2);
- _5 = Lt(copy _3, copy _4);
- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind continue];
+ _4 = const 5000_usize;
+ _5 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind continue];
}

View file

@ -6,7 +6,8 @@
let _1: u8;
let mut _2: [u8; 5000];
let _3: usize;
let mut _4: bool;
let mut _4: usize;
let mut _5: bool;
scope 1 {
debug x => _1;
}
@ -17,9 +18,11 @@
_2 = [const 0_u8; 5000];
StorageLive(_3);
_3 = const 2_usize;
- _4 = Lt(copy _3, const 5000_usize);
- assert(move _4, "index out of bounds: the length is {} but the index is {}", const 5000_usize, copy _3) -> [success: bb1, unwind unreachable];
+ _4 = const true;
- _4 = Len(_2);
- _5 = Lt(copy _3, copy _4);
- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind unreachable];
+ _4 = const 5000_usize;
+ _5 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind unreachable];
}

View file

@ -6,7 +6,8 @@
let _1: u8;
let mut _2: [u8; 5000];
let _3: usize;
let mut _4: bool;
let mut _4: usize;
let mut _5: bool;
scope 1 {
debug x => _1;
}
@ -17,9 +18,11 @@
_2 = [const 0_u8; 5000];
StorageLive(_3);
_3 = const 2_usize;
- _4 = Lt(copy _3, const 5000_usize);
- assert(move _4, "index out of bounds: the length is {} but the index is {}", const 5000_usize, copy _3) -> [success: bb1, unwind continue];
+ _4 = const true;
- _4 = Len(_2);
- _5 = Lt(copy _3, copy _4);
- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind continue];
+ _4 = const 5000_usize;
+ _5 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind continue];
}

View file

@ -7,7 +7,8 @@
let mut _2: u32;
let mut _3: [u32; 8];
let _4: usize;
let mut _5: bool;
let mut _5: usize;
let mut _6: bool;
scope 1 {
debug x => _1;
}
@ -19,9 +20,11 @@
_3 = [const 42_u32; 8];
StorageLive(_4);
_4 = const 2_usize;
- _5 = Lt(copy _4, const 8_usize);
- assert(move _5, "index out of bounds: the length is {} but the index is {}", const 8_usize, copy _4) -> [success: bb1, unwind unreachable];
+ _5 = const true;
- _5 = Len(_3);
- _6 = Lt(copy _4, copy _5);
- assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, copy _4) -> [success: bb1, unwind unreachable];
+ _5 = const 8_usize;
+ _6 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind unreachable];
}

View file

@ -7,7 +7,8 @@
let mut _2: u32;
let mut _3: [u32; 8];
let _4: usize;
let mut _5: bool;
let mut _5: usize;
let mut _6: bool;
scope 1 {
debug x => _1;
}
@ -19,9 +20,11 @@
_3 = [const 42_u32; 8];
StorageLive(_4);
_4 = const 2_usize;
- _5 = Lt(copy _4, const 8_usize);
- assert(move _5, "index out of bounds: the length is {} but the index is {}", const 8_usize, copy _4) -> [success: bb1, unwind continue];
+ _5 = const true;
- _5 = Len(_3);
- _6 = Lt(copy _4, copy _5);
- assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, copy _4) -> [success: bb1, unwind continue];
+ _5 = const 8_usize;
+ _6 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind continue];
}

View file

@ -7,7 +7,8 @@
let mut _2: u32;
let mut _3: [u32; 8];
let _4: usize;
let mut _5: bool;
let mut _5: usize;
let mut _6: bool;
scope 1 {
debug x => _1;
}
@ -19,9 +20,11 @@
_3 = [const 42_u32; 8];
StorageLive(_4);
_4 = const 2_usize;
- _5 = Lt(copy _4, const 8_usize);
- assert(move _5, "index out of bounds: the length is {} but the index is {}", const 8_usize, copy _4) -> [success: bb1, unwind unreachable];
+ _5 = const true;
- _5 = Len(_3);
- _6 = Lt(copy _4, copy _5);
- assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, copy _4) -> [success: bb1, unwind unreachable];
+ _5 = const 8_usize;
+ _6 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind unreachable];
}

View file

@ -7,7 +7,8 @@
let mut _2: u32;
let mut _3: [u32; 8];
let _4: usize;
let mut _5: bool;
let mut _5: usize;
let mut _6: bool;
scope 1 {
debug x => _1;
}
@ -19,9 +20,11 @@
_3 = [const 42_u32; 8];
StorageLive(_4);
_4 = const 2_usize;
- _5 = Lt(copy _4, const 8_usize);
- assert(move _5, "index out of bounds: the length is {} but the index is {}", const 8_usize, copy _4) -> [success: bb1, unwind continue];
+ _5 = const true;
- _5 = Len(_3);
- _6 = Lt(copy _4, copy _5);
- assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, copy _4) -> [success: bb1, unwind continue];
+ _5 = const 8_usize;
+ _6 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind continue];
}

View file

@ -30,12 +30,11 @@
StorageDead(_3);
StorageLive(_6);
_6 = const 1_usize;
- _7 = PtrMetadata(copy _2);
_7 = Len((*_2));
- _8 = Lt(copy _6, copy _7);
- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind unreachable];
+ _7 = const 3_usize;
+ _8 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind unreachable];
+ _8 = Lt(const 1_usize, copy _7);
+ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 1_usize) -> [success: bb1, unwind unreachable];
}
bb1: {

View file

@ -30,12 +30,11 @@
StorageDead(_3);
StorageLive(_6);
_6 = const 1_usize;
- _7 = PtrMetadata(copy _2);
_7 = Len((*_2));
- _8 = Lt(copy _6, copy _7);
- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind continue];
+ _7 = const 3_usize;
+ _8 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind continue];
+ _8 = Lt(const 1_usize, copy _7);
+ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 1_usize) -> [success: bb1, unwind continue];
}
bb1: {

View file

@ -30,12 +30,11 @@
StorageDead(_3);
StorageLive(_6);
_6 = const 1_usize;
- _7 = PtrMetadata(copy _2);
_7 = Len((*_2));
- _8 = Lt(copy _6, copy _7);
- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind unreachable];
+ _7 = const 3_usize;
+ _8 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind unreachable];
+ _8 = Lt(const 1_usize, copy _7);
+ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 1_usize) -> [success: bb1, unwind unreachable];
}
bb1: {

View file

@ -30,12 +30,11 @@
StorageDead(_3);
StorageLive(_6);
_6 = const 1_usize;
- _7 = PtrMetadata(copy _2);
_7 = Len((*_2));
- _8 = Lt(copy _6, copy _7);
- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind continue];
+ _7 = const 3_usize;
+ _8 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind continue];
+ _8 = Lt(const 1_usize, copy _7);
+ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 1_usize) -> [success: bb1, unwind continue];
}
bb1: {

View file

@ -18,7 +18,8 @@
let mut _15: !;
let mut _17: i32;
let _18: usize;
let mut _19: bool;
let mut _19: usize;
let mut _20: bool;
scope 1 {
debug sum => _1;
let _2: [i32; 4];
@ -91,10 +92,11 @@
StorageLive(_17);
- StorageLive(_18);
- _18 = copy _16;
- _19 = Lt(copy _18, const 4_usize);
- assert(move _19, "index out of bounds: the length is {} but the index is {}", const 4_usize, copy _18) -> [success: bb8, unwind unreachable];
+ _19 = Lt(copy _16, const 4_usize);
+ assert(move _19, "index out of bounds: the length is {} but the index is {}", const 4_usize, copy _16) -> [success: bb8, unwind unreachable];
_19 = Len(_2);
- _20 = Lt(copy _18, copy _19);
- assert(move _20, "index out of bounds: the length is {} but the index is {}", move _19, copy _18) -> [success: bb8, unwind unreachable];
+ _20 = Lt(copy _16, copy _19);
+ assert(move _20, "index out of bounds: the length is {} but the index is {}", move _19, copy _16) -> [success: bb8, unwind unreachable];
}
bb7: {

View file

@ -18,7 +18,8 @@
let mut _15: !;
let mut _17: i32;
let _18: usize;
let mut _19: bool;
let mut _19: usize;
let mut _20: bool;
scope 1 {
debug sum => _1;
let _2: [i32; 4];
@ -91,10 +92,11 @@
StorageLive(_17);
- StorageLive(_18);
- _18 = copy _16;
- _19 = Lt(copy _18, const 4_usize);
- assert(move _19, "index out of bounds: the length is {} but the index is {}", const 4_usize, copy _18) -> [success: bb8, unwind continue];
+ _19 = Lt(copy _16, const 4_usize);
+ assert(move _19, "index out of bounds: the length is {} but the index is {}", const 4_usize, copy _16) -> [success: bb8, unwind continue];
_19 = Len(_2);
- _20 = Lt(copy _18, copy _19);
- assert(move _20, "index out of bounds: the length is {} but the index is {}", move _19, copy _18) -> [success: bb8, unwind continue];
+ _20 = Lt(copy _16, copy _19);
+ assert(move _20, "index out of bounds: the length is {} but the index is {}", move _19, copy _16) -> [success: bb8, unwind continue];
}
bb7: {

View file

@ -6,7 +6,8 @@
let _1: u32;
let mut _2: [u32; 4];
let _3: usize;
let mut _4: bool;
let mut _4: usize;
let mut _5: bool;
scope 1 {
debug x => _1;
}
@ -17,9 +18,11 @@
_2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32];
StorageLive(_3);
_3 = const 2_usize;
- _4 = Lt(copy _3, const 4_usize);
- assert(move _4, "index out of bounds: the length is {} but the index is {}", const 4_usize, copy _3) -> [success: bb1, unwind unreachable];
+ _4 = const true;
- _4 = Len(_2);
- _5 = Lt(copy _3, copy _4);
- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind unreachable];
+ _4 = const 4_usize;
+ _5 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind unreachable];
}

View file

@ -6,7 +6,8 @@
let _1: u32;
let mut _2: [u32; 4];
let _3: usize;
let mut _4: bool;
let mut _4: usize;
let mut _5: bool;
scope 1 {
debug x => _1;
}
@ -17,9 +18,11 @@
_2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32];
StorageLive(_3);
_3 = const 2_usize;
- _4 = Lt(copy _3, const 4_usize);
- assert(move _4, "index out of bounds: the length is {} but the index is {}", const 4_usize, copy _3) -> [success: bb1, unwind continue];
+ _4 = const true;
- _4 = Len(_2);
- _5 = Lt(copy _3, copy _4);
- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind continue];
+ _4 = const 4_usize;
+ _5 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind continue];
}

View file

@ -6,7 +6,8 @@
let _1: u32;
let mut _2: [u32; 4];
let _3: usize;
let mut _4: bool;
let mut _4: usize;
let mut _5: bool;
scope 1 {
debug x => _1;
}
@ -17,9 +18,11 @@
_2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32];
StorageLive(_3);
_3 = const 2_usize;
- _4 = Lt(copy _3, const 4_usize);
- assert(move _4, "index out of bounds: the length is {} but the index is {}", const 4_usize, copy _3) -> [success: bb1, unwind unreachable];
+ _4 = const true;
- _4 = Len(_2);
- _5 = Lt(copy _3, copy _4);
- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind unreachable];
+ _4 = const 4_usize;
+ _5 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind unreachable];
}

View file

@ -6,7 +6,8 @@
let _1: u32;
let mut _2: [u32; 4];
let _3: usize;
let mut _4: bool;
let mut _4: usize;
let mut _5: bool;
scope 1 {
debug x => _1;
}
@ -17,9 +18,11 @@
_2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32];
StorageLive(_3);
_3 = const 2_usize;
- _4 = Lt(copy _3, const 4_usize);
- assert(move _4, "index out of bounds: the length is {} but the index is {}", const 4_usize, copy _3) -> [success: bb1, unwind continue];
+ _4 = const true;
- _4 = Len(_2);
- _5 = Lt(copy _3, copy _4);
- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind continue];
+ _4 = const 4_usize;
+ _5 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind continue];
}

View file

@ -11,10 +11,9 @@ fn main() {
// CHECK: [[array_lit]] = [const 0_u32, const 1_u32, const 2_u32, const 3_u32];
// CHECK-NOT: {{_.*}} = Len(
// CHECK-NOT: {{_.*}} = PtrMetadata(
// CHECK-NOT: {{_.*}} = Lt(
// CHECK-NOT: assert(move _
// CHECK: {{_.*}} = const 2_usize;
// CHECK: {{_.*}} = const 4_usize;
// CHECK: {{_.*}} = const true;
// CHECK: assert(const true
// CHECK: [[x]] = copy [[array_lit]][2 of 3];

View file

@ -6,7 +6,8 @@
let _1: u8;
let mut _2: [u8; 5000];
let _3: usize;
let mut _4: bool;
let mut _4: usize;
let mut _5: bool;
scope 1 {
debug x => _1;
}
@ -17,9 +18,11 @@
_2 = [const 0_u8; 5000];
StorageLive(_3);
_3 = const 2_usize;
- _4 = Lt(copy _3, const 5000_usize);
- assert(move _4, "index out of bounds: the length is {} but the index is {}", const 5000_usize, copy _3) -> [success: bb1, unwind unreachable];
+ _4 = const true;
- _4 = Len(_2);
- _5 = Lt(copy _3, copy _4);
- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind unreachable];
+ _4 = const 5000_usize;
+ _5 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind unreachable];
}

View file

@ -6,7 +6,8 @@
let _1: u8;
let mut _2: [u8; 5000];
let _3: usize;
let mut _4: bool;
let mut _4: usize;
let mut _5: bool;
scope 1 {
debug x => _1;
}
@ -17,9 +18,11 @@
_2 = [const 0_u8; 5000];
StorageLive(_3);
_3 = const 2_usize;
- _4 = Lt(copy _3, const 5000_usize);
- assert(move _4, "index out of bounds: the length is {} but the index is {}", const 5000_usize, copy _3) -> [success: bb1, unwind continue];
+ _4 = const true;
- _4 = Len(_2);
- _5 = Lt(copy _3, copy _4);
- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind continue];
+ _4 = const 5000_usize;
+ _5 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind continue];
}

View file

@ -6,7 +6,8 @@
let _1: u8;
let mut _2: [u8; 5000];
let _3: usize;
let mut _4: bool;
let mut _4: usize;
let mut _5: bool;
scope 1 {
debug x => _1;
}
@ -17,9 +18,11 @@
_2 = [const 0_u8; 5000];
StorageLive(_3);
_3 = const 2_usize;
- _4 = Lt(copy _3, const 5000_usize);
- assert(move _4, "index out of bounds: the length is {} but the index is {}", const 5000_usize, copy _3) -> [success: bb1, unwind unreachable];
+ _4 = const true;
- _4 = Len(_2);
- _5 = Lt(copy _3, copy _4);
- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind unreachable];
+ _4 = const 5000_usize;
+ _5 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind unreachable];
}

View file

@ -6,7 +6,8 @@
let _1: u8;
let mut _2: [u8; 5000];
let _3: usize;
let mut _4: bool;
let mut _4: usize;
let mut _5: bool;
scope 1 {
debug x => _1;
}
@ -17,9 +18,11 @@
_2 = [const 0_u8; 5000];
StorageLive(_3);
_3 = const 2_usize;
- _4 = Lt(copy _3, const 5000_usize);
- assert(move _4, "index out of bounds: the length is {} but the index is {}", const 5000_usize, copy _3) -> [success: bb1, unwind continue];
+ _4 = const true;
- _4 = Len(_2);
- _5 = Lt(copy _3, copy _4);
- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind continue];
+ _4 = const 5000_usize;
+ _5 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind continue];
}

View file

@ -10,7 +10,7 @@ fn main() {
// CHECK: debug x => [[x:_.*]];
// CHECK: [[array_lit:_.*]] = [const 0_u8; 5000];
// CHECK: {{_.*}} = const 2_usize;
// CHECK: {{_.*}} = const 5000_usize;
// CHECK: {{_.*}} = const true;
// CHECK: assert(const true
// CHECK: [[x]] = copy [[array_lit]][2 of 3];

View file

@ -7,7 +7,8 @@
let mut _2: u32;
let mut _3: [u32; 8];
let _4: usize;
let mut _5: bool;
let mut _5: usize;
let mut _6: bool;
scope 1 {
debug x => _1;
}
@ -19,9 +20,11 @@
_3 = [const 42_u32; 8];
StorageLive(_4);
_4 = const 2_usize;
- _5 = Lt(copy _4, const 8_usize);
- assert(move _5, "index out of bounds: the length is {} but the index is {}", const 8_usize, copy _4) -> [success: bb1, unwind unreachable];
+ _5 = const true;
- _5 = Len(_3);
- _6 = Lt(copy _4, copy _5);
- assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, copy _4) -> [success: bb1, unwind unreachable];
+ _5 = const 8_usize;
+ _6 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind unreachable];
}

View file

@ -7,7 +7,8 @@
let mut _2: u32;
let mut _3: [u32; 8];
let _4: usize;
let mut _5: bool;
let mut _5: usize;
let mut _6: bool;
scope 1 {
debug x => _1;
}
@ -19,9 +20,11 @@
_3 = [const 42_u32; 8];
StorageLive(_4);
_4 = const 2_usize;
- _5 = Lt(copy _4, const 8_usize);
- assert(move _5, "index out of bounds: the length is {} but the index is {}", const 8_usize, copy _4) -> [success: bb1, unwind continue];
+ _5 = const true;
- _5 = Len(_3);
- _6 = Lt(copy _4, copy _5);
- assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, copy _4) -> [success: bb1, unwind continue];
+ _5 = const 8_usize;
+ _6 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind continue];
}

View file

@ -7,7 +7,8 @@
let mut _2: u32;
let mut _3: [u32; 8];
let _4: usize;
let mut _5: bool;
let mut _5: usize;
let mut _6: bool;
scope 1 {
debug x => _1;
}
@ -19,9 +20,11 @@
_3 = [const 42_u32; 8];
StorageLive(_4);
_4 = const 2_usize;
- _5 = Lt(copy _4, const 8_usize);
- assert(move _5, "index out of bounds: the length is {} but the index is {}", const 8_usize, copy _4) -> [success: bb1, unwind unreachable];
+ _5 = const true;
- _5 = Len(_3);
- _6 = Lt(copy _4, copy _5);
- assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, copy _4) -> [success: bb1, unwind unreachable];
+ _5 = const 8_usize;
+ _6 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind unreachable];
}

View file

@ -7,7 +7,8 @@
let mut _2: u32;
let mut _3: [u32; 8];
let _4: usize;
let mut _5: bool;
let mut _5: usize;
let mut _6: bool;
scope 1 {
debug x => _1;
}
@ -19,9 +20,11 @@
_3 = [const 42_u32; 8];
StorageLive(_4);
_4 = const 2_usize;
- _5 = Lt(copy _4, const 8_usize);
- assert(move _5, "index out of bounds: the length is {} but the index is {}", const 8_usize, copy _4) -> [success: bb1, unwind continue];
+ _5 = const true;
- _5 = Len(_3);
- _6 = Lt(copy _4, copy _5);
- assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, copy _4) -> [success: bb1, unwind continue];
+ _5 = const 8_usize;
+ _6 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind continue];
}

View file

@ -9,9 +9,8 @@ fn main() {
// CHECK: [[array_lit:_.*]] = [const 42_u32; 8];
// CHECK-NOT: {{_.*}} = Len(
// CHECK-NOT: {{_.*}} = PtrMetadata(
// CHECK-NOT: {{_.*}} = Lt(
// CHECK: {{_.*}} = const 2_usize;
// CHECK: {{_.*}} = const 8_usize;
// CHECK: {{_.*}} = const true;
// CHECK: assert(const true

View file

@ -0,0 +1,77 @@
- // MIR for `main` before DataflowConstProp
+ // MIR for `main` after DataflowConstProp
fn main() -> () {
let mut _0: ();
let _1: u32;
let mut _2: &[u32];
let mut _3: &[u32; 3];
let _4: &[u32; 3];
let _5: [u32; 3];
let _6: usize;
let mut _7: usize;
let mut _8: bool;
let mut _10: &[u32];
let _11: usize;
let mut _12: usize;
let mut _13: bool;
let mut _14: &[u32; 3];
scope 1 {
debug local => _1;
let _9: u32;
scope 2 {
debug constant => _9;
}
}
bb0: {
StorageLive(_1);
StorageLive(_2);
StorageLive(_3);
StorageLive(_4);
_14 = const main::promoted[0];
_4 = copy _14;
_3 = copy _4;
_2 = move _3 as &[u32] (PointerCoercion(Unsize, AsCast));
StorageDead(_3);
StorageLive(_6);
_6 = const 1_usize;
- _7 = Len((*_2));
- _8 = Lt(copy _6, copy _7);
- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind unreachable];
+ _7 = const 3_usize;
+ _8 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind unreachable];
}
bb1: {
- _1 = copy (*_2)[_6];
+ _1 = copy (*_2)[1 of 2];
StorageDead(_6);
StorageDead(_4);
StorageDead(_2);
StorageLive(_9);
StorageLive(_10);
_10 = const main::SLICE;
StorageLive(_11);
_11 = const 1_usize;
- _12 = Len((*_10));
- _13 = Lt(copy _11, copy _12);
- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, copy _11) -> [success: bb2, unwind unreachable];
+ _12 = const 3_usize;
+ _13 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb2, unwind unreachable];
}
bb2: {
- _9 = copy (*_10)[_11];
+ _9 = copy (*_10)[1 of 2];
StorageDead(_11);
StorageDead(_10);
_0 = const ();
StorageDead(_9);
StorageDead(_1);
return;
}
}

View file

@ -0,0 +1,77 @@
- // MIR for `main` before DataflowConstProp
+ // MIR for `main` after DataflowConstProp
fn main() -> () {
let mut _0: ();
let _1: u32;
let mut _2: &[u32];
let mut _3: &[u32; 3];
let _4: &[u32; 3];
let _5: [u32; 3];
let _6: usize;
let mut _7: usize;
let mut _8: bool;
let mut _10: &[u32];
let _11: usize;
let mut _12: usize;
let mut _13: bool;
let mut _14: &[u32; 3];
scope 1 {
debug local => _1;
let _9: u32;
scope 2 {
debug constant => _9;
}
}
bb0: {
StorageLive(_1);
StorageLive(_2);
StorageLive(_3);
StorageLive(_4);
_14 = const main::promoted[0];
_4 = copy _14;
_3 = copy _4;
_2 = move _3 as &[u32] (PointerCoercion(Unsize, AsCast));
StorageDead(_3);
StorageLive(_6);
_6 = const 1_usize;
- _7 = Len((*_2));
- _8 = Lt(copy _6, copy _7);
- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind continue];
+ _7 = const 3_usize;
+ _8 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind continue];
}
bb1: {
- _1 = copy (*_2)[_6];
+ _1 = copy (*_2)[1 of 2];
StorageDead(_6);
StorageDead(_4);
StorageDead(_2);
StorageLive(_9);
StorageLive(_10);
_10 = const main::SLICE;
StorageLive(_11);
_11 = const 1_usize;
- _12 = Len((*_10));
- _13 = Lt(copy _11, copy _12);
- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, copy _11) -> [success: bb2, unwind continue];
+ _12 = const 3_usize;
+ _13 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb2, unwind continue];
}
bb2: {
- _9 = copy (*_10)[_11];
+ _9 = copy (*_10)[1 of 2];
StorageDead(_11);
StorageDead(_10);
_0 = const ();
StorageDead(_9);
StorageDead(_1);
return;
}
}

View file

@ -0,0 +1,77 @@
- // MIR for `main` before DataflowConstProp
+ // MIR for `main` after DataflowConstProp
fn main() -> () {
let mut _0: ();
let _1: u32;
let mut _2: &[u32];
let mut _3: &[u32; 3];
let _4: &[u32; 3];
let _5: [u32; 3];
let _6: usize;
let mut _7: usize;
let mut _8: bool;
let mut _10: &[u32];
let _11: usize;
let mut _12: usize;
let mut _13: bool;
let mut _14: &[u32; 3];
scope 1 {
debug local => _1;
let _9: u32;
scope 2 {
debug constant => _9;
}
}
bb0: {
StorageLive(_1);
StorageLive(_2);
StorageLive(_3);
StorageLive(_4);
_14 = const main::promoted[0];
_4 = copy _14;
_3 = copy _4;
_2 = move _3 as &[u32] (PointerCoercion(Unsize, AsCast));
StorageDead(_3);
StorageLive(_6);
_6 = const 1_usize;
- _7 = Len((*_2));
- _8 = Lt(copy _6, copy _7);
- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind unreachable];
+ _7 = const 3_usize;
+ _8 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind unreachable];
}
bb1: {
- _1 = copy (*_2)[_6];
+ _1 = copy (*_2)[1 of 2];
StorageDead(_6);
StorageDead(_4);
StorageDead(_2);
StorageLive(_9);
StorageLive(_10);
_10 = const main::SLICE;
StorageLive(_11);
_11 = const 1_usize;
- _12 = Len((*_10));
- _13 = Lt(copy _11, copy _12);
- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, copy _11) -> [success: bb2, unwind unreachable];
+ _12 = const 3_usize;
+ _13 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb2, unwind unreachable];
}
bb2: {
- _9 = copy (*_10)[_11];
+ _9 = copy (*_10)[1 of 2];
StorageDead(_11);
StorageDead(_10);
_0 = const ();
StorageDead(_9);
StorageDead(_1);
return;
}
}

View file

@ -0,0 +1,77 @@
- // MIR for `main` before DataflowConstProp
+ // MIR for `main` after DataflowConstProp
fn main() -> () {
let mut _0: ();
let _1: u32;
let mut _2: &[u32];
let mut _3: &[u32; 3];
let _4: &[u32; 3];
let _5: [u32; 3];
let _6: usize;
let mut _7: usize;
let mut _8: bool;
let mut _10: &[u32];
let _11: usize;
let mut _12: usize;
let mut _13: bool;
let mut _14: &[u32; 3];
scope 1 {
debug local => _1;
let _9: u32;
scope 2 {
debug constant => _9;
}
}
bb0: {
StorageLive(_1);
StorageLive(_2);
StorageLive(_3);
StorageLive(_4);
_14 = const main::promoted[0];
_4 = copy _14;
_3 = copy _4;
_2 = move _3 as &[u32] (PointerCoercion(Unsize, AsCast));
StorageDead(_3);
StorageLive(_6);
_6 = const 1_usize;
- _7 = Len((*_2));
- _8 = Lt(copy _6, copy _7);
- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind continue];
+ _7 = const 3_usize;
+ _8 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind continue];
}
bb1: {
- _1 = copy (*_2)[_6];
+ _1 = copy (*_2)[1 of 2];
StorageDead(_6);
StorageDead(_4);
StorageDead(_2);
StorageLive(_9);
StorageLive(_10);
_10 = const main::SLICE;
StorageLive(_11);
_11 = const 1_usize;
- _12 = Len((*_10));
- _13 = Lt(copy _11, copy _12);
- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, copy _11) -> [success: bb2, unwind continue];
+ _12 = const 3_usize;
+ _13 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb2, unwind continue];
}
bb2: {
- _9 = copy (*_10)[_11];
+ _9 = copy (*_10)[1 of 2];
StorageDead(_11);
StorageDead(_10);
_0 = const ();
StorageDead(_9);
StorageDead(_1);
return;
}
}

View file

@ -0,0 +1,34 @@
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
//@ test-mir-pass: DataflowConstProp
//@ compile-flags: -Zmir-enable-passes=+InstSimplify-after-simplifycfg
// EMIT_MIR_FOR_EACH_BIT_WIDTH
// EMIT_MIR slice_len.main.DataflowConstProp.diff
// CHECK-LABEL: fn main(
fn main() {
// CHECK: debug local => [[local:_.*]];
// CHECK: debug constant => [[constant:_.*]];
// CHECK-NOT: {{_.*}} = Len(
// CHECK-NOT: {{_.*}} = Lt(
// CHECK-NOT: assert(move _
// CHECK: {{_.*}} = const 3_usize;
// CHECK: {{_.*}} = const true;
// CHECK: assert(const true,
// CHECK: [[local]] = copy (*{{_.*}})[1 of 2];
let local = (&[1u32, 2, 3] as &[u32])[1];
// CHECK-NOT: {{_.*}} = Len(
// CHECK-NOT: {{_.*}} = Lt(
// CHECK-NOT: assert(move _
const SLICE: &[u32] = &[1, 2, 3];
// CHECK: {{_.*}} = const 3_usize;
// CHECK: {{_.*}} = const true;
// CHECK: assert(const true,
// CHECK-NOT: [[constant]] = {{copy|move}} (*{{_.*}})[_
// CHECK: [[constant]] = copy (*{{_.*}})[1 of 2];
let constant = SLICE[1];
}

View file

@ -22,14 +22,14 @@
bb1: {
StorageDead(_3);
_4 = PtrMetadata(copy _2);
_4 = Len((*_2));
_5 = const 4_usize;
_6 = Ge(move _4, move _5);
switchInt(move _6) -> [0: bb2, otherwise: bb3];
}
bb2: {
_7 = PtrMetadata(copy _2);
_7 = Len((*_2));
_8 = const 3_usize;
_9 = Ge(move _7, move _8);
- switchInt(move _9) -> [0: bb7, otherwise: bb8];

View file

@ -22,14 +22,14 @@
bb1: {
StorageDead(_3);
_4 = PtrMetadata(copy _2);
_4 = Len((*_2));
_5 = const 4_usize;
_6 = Ge(move _4, move _5);
switchInt(move _6) -> [0: bb2, otherwise: bb3];
}
bb2: {
_7 = PtrMetadata(copy _2);
_7 = Len((*_2));
_8 = const 3_usize;
_9 = Ge(move _7, move _8);
- switchInt(move _9) -> [0: bb7, otherwise: bb8];

View file

@ -53,7 +53,7 @@
StorageLive(_8);
- _8 = copy _2;
+ _8 = const usize::MAX;
_9 = PtrMetadata(copy _1);
_9 = Len((*_1));
- _10 = Lt(copy _8, copy _9);
- assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, copy _8) -> [success: bb3, unwind unreachable];
+ _10 = Lt(const usize::MAX, copy _9);
@ -72,7 +72,7 @@
StorageDead(_5);
StorageLive(_11);
_11 = const 0_usize;
_12 = PtrMetadata(copy _1);
_12 = Len((*_1));
- _13 = Lt(copy _11, copy _12);
- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, copy _11) -> [success: bb5, unwind unreachable];
+ _13 = Lt(const 0_usize, copy _12);

View file

@ -53,7 +53,7 @@
StorageLive(_8);
- _8 = copy _2;
+ _8 = const usize::MAX;
_9 = PtrMetadata(copy _1);
_9 = Len((*_1));
- _10 = Lt(copy _8, copy _9);
- assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, copy _8) -> [success: bb3, unwind continue];
+ _10 = Lt(const usize::MAX, copy _9);
@ -72,7 +72,7 @@
StorageDead(_5);
StorageLive(_11);
_11 = const 0_usize;
_12 = PtrMetadata(copy _1);
_12 = Len((*_1));
- _13 = Lt(copy _11, copy _12);
- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, copy _11) -> [success: bb5, unwind continue];
+ _13 = Lt(const 0_usize, copy _12);

View file

@ -1,72 +0,0 @@
- // MIR for `dedup_multiple_bounds_checks_lengths` before GVN
+ // MIR for `dedup_multiple_bounds_checks_lengths` after GVN
fn dedup_multiple_bounds_checks_lengths(_1: &[i32]) -> [i32; 3] {
debug x => _1;
let mut _0: [i32; 3];
let mut _2: i32;
let _3: usize;
let mut _4: usize;
let mut _5: bool;
let mut _6: i32;
let _7: usize;
let mut _8: usize;
let mut _9: bool;
let mut _10: i32;
let _11: usize;
let mut _12: usize;
let mut _13: bool;
bb0: {
StorageLive(_2);
StorageLive(_3);
_3 = const 42_usize;
_4 = PtrMetadata(copy _1);
- _5 = Lt(copy _3, copy _4);
- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind unreachable];
+ _5 = Lt(const 42_usize, copy _4);
+ assert(move _5, "index out of bounds: the length is {} but the index is {}", copy _4, const 42_usize) -> [success: bb1, unwind unreachable];
}
bb1: {
- _2 = copy (*_1)[_3];
+ _2 = copy (*_1)[42 of 43];
StorageLive(_6);
StorageLive(_7);
_7 = const 13_usize;
- _8 = PtrMetadata(copy _1);
- _9 = Lt(copy _7, copy _8);
- assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, copy _7) -> [success: bb2, unwind unreachable];
+ _8 = copy _4;
+ _9 = Lt(const 13_usize, copy _4);
+ assert(move _9, "index out of bounds: the length is {} but the index is {}", copy _4, const 13_usize) -> [success: bb2, unwind unreachable];
}
bb2: {
- _6 = copy (*_1)[_7];
+ _6 = copy (*_1)[13 of 14];
StorageLive(_10);
StorageLive(_11);
_11 = const 7_usize;
- _12 = PtrMetadata(copy _1);
- _13 = Lt(copy _11, copy _12);
- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, copy _11) -> [success: bb3, unwind unreachable];
+ _12 = copy _4;
+ _13 = Lt(const 7_usize, copy _4);
+ assert(move _13, "index out of bounds: the length is {} but the index is {}", copy _4, const 7_usize) -> [success: bb3, unwind unreachable];
}
bb3: {
- _10 = copy (*_1)[_11];
+ _10 = copy (*_1)[7 of 8];
_0 = [move _2, move _6, move _10];
StorageDead(_10);
StorageDead(_6);
StorageDead(_2);
StorageDead(_11);
StorageDead(_7);
StorageDead(_3);
return;
}
}

View file

@ -1,72 +0,0 @@
- // MIR for `dedup_multiple_bounds_checks_lengths` before GVN
+ // MIR for `dedup_multiple_bounds_checks_lengths` after GVN
fn dedup_multiple_bounds_checks_lengths(_1: &[i32]) -> [i32; 3] {
debug x => _1;
let mut _0: [i32; 3];
let mut _2: i32;
let _3: usize;
let mut _4: usize;
let mut _5: bool;
let mut _6: i32;
let _7: usize;
let mut _8: usize;
let mut _9: bool;
let mut _10: i32;
let _11: usize;
let mut _12: usize;
let mut _13: bool;
bb0: {
StorageLive(_2);
StorageLive(_3);
_3 = const 42_usize;
_4 = PtrMetadata(copy _1);
- _5 = Lt(copy _3, copy _4);
- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind continue];
+ _5 = Lt(const 42_usize, copy _4);
+ assert(move _5, "index out of bounds: the length is {} but the index is {}", copy _4, const 42_usize) -> [success: bb1, unwind continue];
}
bb1: {
- _2 = copy (*_1)[_3];
+ _2 = copy (*_1)[42 of 43];
StorageLive(_6);
StorageLive(_7);
_7 = const 13_usize;
- _8 = PtrMetadata(copy _1);
- _9 = Lt(copy _7, copy _8);
- assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, copy _7) -> [success: bb2, unwind continue];
+ _8 = copy _4;
+ _9 = Lt(const 13_usize, copy _4);
+ assert(move _9, "index out of bounds: the length is {} but the index is {}", copy _4, const 13_usize) -> [success: bb2, unwind continue];
}
bb2: {
- _6 = copy (*_1)[_7];
+ _6 = copy (*_1)[13 of 14];
StorageLive(_10);
StorageLive(_11);
_11 = const 7_usize;
- _12 = PtrMetadata(copy _1);
- _13 = Lt(copy _11, copy _12);
- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, copy _11) -> [success: bb3, unwind continue];
+ _12 = copy _4;
+ _13 = Lt(const 7_usize, copy _4);
+ assert(move _13, "index out of bounds: the length is {} but the index is {}", copy _4, const 7_usize) -> [success: bb3, unwind continue];
}
bb3: {
- _10 = copy (*_1)[_11];
+ _10 = copy (*_1)[7 of 8];
_0 = [move _2, move _6, move _10];
StorageDead(_10);
StorageDead(_6);
StorageDead(_2);
StorageDead(_11);
StorageDead(_7);
StorageDead(_3);
return;
}
}

View file

@ -10,11 +10,13 @@
let _5: ();
let mut _6: T;
let _7: usize;
let mut _8: bool;
let _9: ();
let mut _10: T;
let _11: usize;
let mut _12: bool;
let mut _8: usize;
let mut _9: bool;
let _10: ();
let mut _11: T;
let _12: usize;
let mut _13: usize;
let mut _14: bool;
scope 1 {
debug a => _3;
}
@ -30,10 +32,12 @@
StorageLive(_6);
StorageLive(_7);
_7 = const 0_usize;
- _8 = Lt(copy _7, const N);
- assert(move _8, "index out of bounds: the length is {} but the index is {}", const N, copy _7) -> [success: bb1, unwind unreachable];
+ _8 = Lt(const 0_usize, const N);
+ assert(move _8, "index out of bounds: the length is {} but the index is {}", const N, const 0_usize) -> [success: bb1, unwind unreachable];
- _8 = Len(_3);
- _9 = Lt(copy _7, copy _8);
- assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, copy _7) -> [success: bb1, unwind unreachable];
+ _8 = const N;
+ _9 = Lt(const 0_usize, const N);
+ assert(move _9, "index out of bounds: the length is {} but the index is {}", const N, const 0_usize) -> [success: bb1, unwind unreachable];
}
bb1: {
@ -47,27 +51,29 @@
StorageDead(_6);
StorageDead(_7);
StorageDead(_5);
StorageLive(_9);
StorageLive(_10);
StorageLive(_11);
_11 = copy _2;
- _12 = Lt(copy _11, const N);
- assert(move _12, "index out of bounds: the length is {} but the index is {}", const N, copy _11) -> [success: bb3, unwind unreachable];
+ _12 = Lt(copy _2, const N);
+ assert(move _12, "index out of bounds: the length is {} but the index is {}", const N, copy _2) -> [success: bb3, unwind unreachable];
StorageLive(_12);
_12 = copy _2;
- _13 = Len(_3);
- _14 = Lt(copy _12, copy _13);
- assert(move _14, "index out of bounds: the length is {} but the index is {}", move _13, copy _12) -> [success: bb3, unwind unreachable];
+ _13 = const N;
+ _14 = Lt(copy _2, const N);
+ assert(move _14, "index out of bounds: the length is {} but the index is {}", const N, copy _2) -> [success: bb3, unwind unreachable];
}
bb3: {
- _10 = copy _3[_11];
- _9 = opaque::<T>(move _10) -> [return: bb4, unwind unreachable];
+ _10 = copy _1;
+ _9 = opaque::<T>(copy _1) -> [return: bb4, unwind unreachable];
- _11 = copy _3[_12];
- _10 = opaque::<T>(move _11) -> [return: bb4, unwind unreachable];
+ _11 = copy _1;
+ _10 = opaque::<T>(copy _1) -> [return: bb4, unwind unreachable];
}
bb4: {
StorageDead(_10);
StorageDead(_11);
StorageDead(_9);
StorageDead(_12);
StorageDead(_10);
_0 = const ();
StorageDead(_3);
return;

View file

@ -10,11 +10,13 @@
let _5: ();
let mut _6: T;
let _7: usize;
let mut _8: bool;
let _9: ();
let mut _10: T;
let _11: usize;
let mut _12: bool;
let mut _8: usize;
let mut _9: bool;
let _10: ();
let mut _11: T;
let _12: usize;
let mut _13: usize;
let mut _14: bool;
scope 1 {
debug a => _3;
}
@ -30,10 +32,12 @@
StorageLive(_6);
StorageLive(_7);
_7 = const 0_usize;
- _8 = Lt(copy _7, const N);
- assert(move _8, "index out of bounds: the length is {} but the index is {}", const N, copy _7) -> [success: bb1, unwind continue];
+ _8 = Lt(const 0_usize, const N);
+ assert(move _8, "index out of bounds: the length is {} but the index is {}", const N, const 0_usize) -> [success: bb1, unwind continue];
- _8 = Len(_3);
- _9 = Lt(copy _7, copy _8);
- assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, copy _7) -> [success: bb1, unwind continue];
+ _8 = const N;
+ _9 = Lt(const 0_usize, const N);
+ assert(move _9, "index out of bounds: the length is {} but the index is {}", const N, const 0_usize) -> [success: bb1, unwind continue];
}
bb1: {
@ -47,27 +51,29 @@
StorageDead(_6);
StorageDead(_7);
StorageDead(_5);
StorageLive(_9);
StorageLive(_10);
StorageLive(_11);
_11 = copy _2;
- _12 = Lt(copy _11, const N);
- assert(move _12, "index out of bounds: the length is {} but the index is {}", const N, copy _11) -> [success: bb3, unwind continue];
+ _12 = Lt(copy _2, const N);
+ assert(move _12, "index out of bounds: the length is {} but the index is {}", const N, copy _2) -> [success: bb3, unwind continue];
StorageLive(_12);
_12 = copy _2;
- _13 = Len(_3);
- _14 = Lt(copy _12, copy _13);
- assert(move _14, "index out of bounds: the length is {} but the index is {}", move _13, copy _12) -> [success: bb3, unwind continue];
+ _13 = const N;
+ _14 = Lt(copy _2, const N);
+ assert(move _14, "index out of bounds: the length is {} but the index is {}", const N, copy _2) -> [success: bb3, unwind continue];
}
bb3: {
- _10 = copy _3[_11];
- _9 = opaque::<T>(move _10) -> [return: bb4, unwind continue];
+ _10 = copy _1;
+ _9 = opaque::<T>(copy _1) -> [return: bb4, unwind continue];
- _11 = copy _3[_12];
- _10 = opaque::<T>(move _11) -> [return: bb4, unwind continue];
+ _11 = copy _1;
+ _10 = opaque::<T>(copy _1) -> [return: bb4, unwind continue];
}
bb4: {
StorageDead(_10);
StorageDead(_11);
StorageDead(_9);
StorageDead(_12);
StorageDead(_10);
_0 = const ();
StorageDead(_3);
return;

View file

@ -835,25 +835,6 @@ fn array_len(x: &mut [i32; 42]) -> usize {
std::intrinsics::ptr_metadata(x)
}
// Check that we only load the length once, rather than all 3 times.
fn dedup_multiple_bounds_checks_lengths(x: &[i32]) -> [i32; 3] {
// CHECK-LABEL: fn dedup_multiple_bounds_checks_lengths
// CHECK: [[LEN:_.+]] = PtrMetadata(copy _1);
// CHECK: Lt(const 42_usize, copy [[LEN]]);
// CHECK: assert{{.+}}copy [[LEN]]
// CHECK: [[A:_.+]] = copy (*_1)[42 of 43];
// CHECK-NOT: PtrMetadata
// CHECK: Lt(const 13_usize, copy [[LEN]]);
// CHECK: assert{{.+}}copy [[LEN]]
// CHECK: [[B:_.+]] = copy (*_1)[13 of 14];
// CHECK-NOT: PtrMetadata
// CHECK: Lt(const 7_usize, copy [[LEN]]);
// CHECK: assert{{.+}}copy [[LEN]]
// CHECK: [[C:_.+]] = copy (*_1)[7 of 8];
// CHECK: _0 = [move [[A]], move [[B]], move [[C]]]
[x[42], x[13], x[7]]
}
#[custom_mir(dialect = "runtime")]
fn generic_cast_metadata<T, A: ?Sized, B: ?Sized>(ps: *const [T], pa: *const A, pb: *const B) {
// CHECK-LABEL: fn generic_cast_metadata
@ -1128,7 +1109,6 @@ enum Never {}
// EMIT_MIR gvn.casts_before_aggregate_raw_ptr.GVN.diff
// EMIT_MIR gvn.manual_slice_mut_len.GVN.diff
// EMIT_MIR gvn.array_len.GVN.diff
// EMIT_MIR gvn.dedup_multiple_bounds_checks_lengths.GVN.diff
// EMIT_MIR gvn.generic_cast_metadata.GVN.diff
// EMIT_MIR gvn.cast_pointer_eq.GVN.diff
// EMIT_MIR gvn.aggregate_struct_then_transmute.GVN.diff

View file

@ -10,60 +10,62 @@
let mut _6: &i32;
let _7: &i32;
let _8: usize;
let mut _9: bool;
let mut _11: *const dyn std::marker::Send;
let _12: &dyn std::marker::Send;
let mut _13: &i32;
let _14: &i32;
let _15: usize;
let mut _16: bool;
let _17: ();
let mut _9: usize;
let mut _10: bool;
let mut _12: *const dyn std::marker::Send;
let _13: &dyn std::marker::Send;
let mut _14: &i32;
let _15: &i32;
let _16: usize;
let mut _17: usize;
let mut _18: bool;
let mut _19: *const dyn std::marker::Send;
let mut _20: *const dyn std::marker::Send;
let _19: ();
let mut _20: bool;
let mut _21: *const dyn std::marker::Send;
let _22: ();
let mut _23: bool;
let mut _24: *const dyn std::marker::Send;
let mut _25: *const dyn std::marker::Send;
let mut _22: *const dyn std::marker::Send;
let mut _23: *const dyn std::marker::Send;
let _24: ();
let mut _25: bool;
let mut _26: *const dyn std::marker::Send;
let _27: ();
let mut _28: bool;
let mut _29: *const dyn std::marker::Send;
let mut _30: *const dyn std::marker::Send;
let mut _27: *const dyn std::marker::Send;
let mut _28: *const dyn std::marker::Send;
let _29: ();
let mut _30: bool;
let mut _31: *const dyn std::marker::Send;
let _32: ();
let mut _33: bool;
let mut _34: *const dyn std::marker::Send;
let mut _35: *const dyn std::marker::Send;
let mut _32: *const dyn std::marker::Send;
let mut _33: *const dyn std::marker::Send;
let _34: ();
let mut _35: bool;
let mut _36: *const dyn std::marker::Send;
let _37: ();
let mut _38: bool;
let mut _39: *const dyn std::marker::Send;
let mut _40: *const dyn std::marker::Send;
let mut _37: *const dyn std::marker::Send;
let mut _38: *const dyn std::marker::Send;
let _39: ();
let mut _40: bool;
let mut _41: *const dyn std::marker::Send;
let _42: ();
let mut _43: bool;
let mut _44: *const dyn std::marker::Send;
let mut _45: *const dyn std::marker::Send;
let mut _42: *const dyn std::marker::Send;
let mut _43: *const dyn std::marker::Send;
let _44: ();
let mut _45: bool;
let mut _46: *const dyn std::marker::Send;
let mut _47: &[i32; 2];
let mut _47: *const dyn std::marker::Send;
let mut _48: *const dyn std::marker::Send;
let mut _49: &[i32; 2];
scope 1 {
debug slice => _1;
let _3: *const dyn std::marker::Send;
scope 2 {
debug a => _3;
let _10: *const dyn std::marker::Send;
let _11: *const dyn std::marker::Send;
scope 3 {
debug b => _10;
debug b => _11;
}
}
}
bb0: {
StorageLive(_1);
_47 = const wide_ptr_same_provenance::promoted[0];
_1 = &(*_47);
_49 = const wide_ptr_same_provenance::promoted[0];
_1 = &(*_49);
StorageLive(_3);
- StorageLive(_4);
+ nop;
@ -72,9 +74,11 @@
StorageLive(_7);
StorageLive(_8);
_8 = const 0_usize;
- _9 = Lt(copy _8, const 2_usize);
- assert(move _9, "index out of bounds: the length is {} but the index is {}", const 2_usize, copy _8) -> [success: bb1, unwind unreachable];
+ _9 = const true;
- _9 = Len((*_1));
- _10 = Lt(copy _8, copy _9);
- assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, copy _8) -> [success: bb1, unwind unreachable];
+ _9 = const 2_usize;
+ _10 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 2_usize, const 0_usize) -> [success: bb1, unwind unreachable];
}
@ -91,168 +95,170 @@
+ nop;
StorageDead(_7);
StorageDead(_5);
StorageLive(_10);
- StorageLive(_11);
StorageLive(_11);
- StorageLive(_12);
+ nop;
StorageLive(_12);
StorageLive(_13);
StorageLive(_14);
StorageLive(_15);
_15 = const 1_usize;
- _16 = Lt(copy _15, const 2_usize);
- assert(move _16, "index out of bounds: the length is {} but the index is {}", const 2_usize, copy _15) -> [success: bb2, unwind unreachable];
+ _16 = const true;
StorageLive(_16);
_16 = const 1_usize;
- _17 = Len((*_1));
- _18 = Lt(copy _16, copy _17);
- assert(move _18, "index out of bounds: the length is {} but the index is {}", move _17, copy _16) -> [success: bb2, unwind unreachable];
+ _17 = const 2_usize;
+ _18 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 2_usize, const 1_usize) -> [success: bb2, unwind unreachable];
}
bb2: {
- _14 = &(*_1)[_15];
+ _14 = &(*_1)[1 of 2];
_13 = &(*_14);
_12 = move _13 as &dyn std::marker::Send (PointerCoercion(Unsize, AsCast));
StorageDead(_13);
_11 = &raw const (*_12);
- _10 = move _11 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
- StorageDead(_11);
+ _10 = copy _11;
+ nop;
- _15 = &(*_1)[_16];
+ _15 = &(*_1)[1 of 2];
_14 = &(*_15);
_13 = move _14 as &dyn std::marker::Send (PointerCoercion(Unsize, AsCast));
StorageDead(_14);
StorageDead(_12);
StorageLive(_17);
StorageLive(_18);
_12 = &raw const (*_13);
- _11 = move _12 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
- StorageDead(_12);
+ _11 = copy _12;
+ nop;
StorageDead(_15);
StorageDead(_13);
StorageLive(_19);
- _19 = copy _3;
+ _19 = copy _4;
StorageLive(_20);
StorageLive(_21);
- _21 = copy _10;
- _20 = move _21 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
+ _21 = copy _11;
+ _20 = copy _11;
- _21 = copy _3;
+ _21 = copy _4;
StorageLive(_22);
StorageLive(_23);
- _23 = copy _11;
- _22 = move _23 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
+ _23 = copy _12;
+ _22 = copy _12;
StorageDead(_23);
- _20 = Eq(move _21, move _22);
+ _20 = Eq(copy _4, copy _12);
StorageDead(_22);
StorageDead(_21);
- _18 = Eq(move _19, move _20);
+ _18 = Eq(copy _4, copy _11);
StorageDead(_20);
StorageDead(_19);
_17 = opaque::<bool>(move _18) -> [return: bb3, unwind unreachable];
_19 = opaque::<bool>(move _20) -> [return: bb3, unwind unreachable];
}
bb3: {
StorageDead(_18);
StorageDead(_17);
StorageLive(_22);
StorageLive(_23);
StorageDead(_20);
StorageDead(_19);
StorageLive(_24);
- _24 = copy _3;
+ _24 = copy _4;
StorageLive(_25);
StorageLive(_26);
- _26 = copy _10;
- _25 = move _26 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
+ _26 = copy _11;
+ _25 = copy _11;
- _26 = copy _3;
+ _26 = copy _4;
StorageLive(_27);
StorageLive(_28);
- _28 = copy _11;
- _27 = move _28 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
+ _28 = copy _12;
+ _27 = copy _12;
StorageDead(_28);
- _25 = Ne(move _26, move _27);
+ _25 = Ne(copy _4, copy _12);
StorageDead(_27);
StorageDead(_26);
- _23 = Ne(move _24, move _25);
+ _23 = Ne(copy _4, copy _11);
StorageDead(_25);
StorageDead(_24);
_22 = opaque::<bool>(move _23) -> [return: bb4, unwind unreachable];
_24 = opaque::<bool>(move _25) -> [return: bb4, unwind unreachable];
}
bb4: {
StorageDead(_23);
StorageDead(_22);
StorageLive(_27);
StorageLive(_28);
StorageDead(_25);
StorageDead(_24);
StorageLive(_29);
- _29 = copy _3;
+ _29 = copy _4;
StorageLive(_30);
StorageLive(_31);
- _31 = copy _10;
- _30 = move _31 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
+ _31 = copy _11;
+ _30 = copy _11;
- _31 = copy _3;
+ _31 = copy _4;
StorageLive(_32);
StorageLive(_33);
- _33 = copy _11;
- _32 = move _33 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
+ _33 = copy _12;
+ _32 = copy _12;
StorageDead(_33);
- _30 = Lt(move _31, move _32);
+ _30 = Lt(copy _4, copy _12);
StorageDead(_32);
StorageDead(_31);
- _28 = Lt(move _29, move _30);
+ _28 = Lt(copy _4, copy _11);
StorageDead(_30);
StorageDead(_29);
_27 = opaque::<bool>(move _28) -> [return: bb5, unwind unreachable];
_29 = opaque::<bool>(move _30) -> [return: bb5, unwind unreachable];
}
bb5: {
StorageDead(_28);
StorageDead(_27);
StorageLive(_32);
StorageLive(_33);
StorageDead(_30);
StorageDead(_29);
StorageLive(_34);
- _34 = copy _3;
+ _34 = copy _4;
StorageLive(_35);
StorageLive(_36);
- _36 = copy _10;
- _35 = move _36 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
+ _36 = copy _11;
+ _35 = copy _11;
- _36 = copy _3;
+ _36 = copy _4;
StorageLive(_37);
StorageLive(_38);
- _38 = copy _11;
- _37 = move _38 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
+ _38 = copy _12;
+ _37 = copy _12;
StorageDead(_38);
- _35 = Le(move _36, move _37);
+ _35 = Le(copy _4, copy _12);
StorageDead(_37);
StorageDead(_36);
- _33 = Le(move _34, move _35);
+ _33 = Le(copy _4, copy _11);
StorageDead(_35);
StorageDead(_34);
_32 = opaque::<bool>(move _33) -> [return: bb6, unwind unreachable];
_34 = opaque::<bool>(move _35) -> [return: bb6, unwind unreachable];
}
bb6: {
StorageDead(_33);
StorageDead(_32);
StorageLive(_37);
StorageLive(_38);
StorageDead(_35);
StorageDead(_34);
StorageLive(_39);
- _39 = copy _3;
+ _39 = copy _4;
StorageLive(_40);
StorageLive(_41);
- _41 = copy _10;
- _40 = move _41 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
+ _41 = copy _11;
+ _40 = copy _11;
- _41 = copy _3;
+ _41 = copy _4;
StorageLive(_42);
StorageLive(_43);
- _43 = copy _11;
- _42 = move _43 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
+ _43 = copy _12;
+ _42 = copy _12;
StorageDead(_43);
- _40 = Gt(move _41, move _42);
+ _40 = Gt(copy _4, copy _12);
StorageDead(_42);
StorageDead(_41);
- _38 = Gt(move _39, move _40);
+ _38 = Gt(copy _4, copy _11);
StorageDead(_40);
StorageDead(_39);
_37 = opaque::<bool>(move _38) -> [return: bb7, unwind unreachable];
_39 = opaque::<bool>(move _40) -> [return: bb7, unwind unreachable];
}
bb7: {
StorageDead(_38);
StorageDead(_37);
StorageLive(_42);
StorageLive(_43);
StorageDead(_40);
StorageDead(_39);
StorageLive(_44);
- _44 = copy _3;
+ _44 = copy _4;
StorageLive(_45);
StorageLive(_46);
- _46 = copy _10;
- _45 = move _46 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
+ _46 = copy _11;
+ _45 = copy _11;
- _46 = copy _3;
+ _46 = copy _4;
StorageLive(_47);
StorageLive(_48);
- _48 = copy _11;
- _47 = move _48 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
+ _48 = copy _12;
+ _47 = copy _12;
StorageDead(_48);
- _45 = Ge(move _46, move _47);
+ _45 = Ge(copy _4, copy _12);
StorageDead(_47);
StorageDead(_46);
- _43 = Ge(move _44, move _45);
+ _43 = Ge(copy _4, copy _11);
StorageDead(_45);
StorageDead(_44);
_42 = opaque::<bool>(move _43) -> [return: bb8, unwind unreachable];
_44 = opaque::<bool>(move _45) -> [return: bb8, unwind unreachable];
}
bb8: {
StorageDead(_43);
StorageDead(_42);
StorageDead(_45);
StorageDead(_44);
_0 = const ();
StorageDead(_15);
StorageDead(_10);
StorageDead(_16);
StorageDead(_11);
StorageDead(_8);
StorageDead(_3);
StorageDead(_1);

View file

@ -10,60 +10,62 @@
let mut _6: &i32;
let _7: &i32;
let _8: usize;
let mut _9: bool;
let mut _11: *const dyn std::marker::Send;
let _12: &dyn std::marker::Send;
let mut _13: &i32;
let _14: &i32;
let _15: usize;
let mut _16: bool;
let _17: ();
let mut _9: usize;
let mut _10: bool;
let mut _12: *const dyn std::marker::Send;
let _13: &dyn std::marker::Send;
let mut _14: &i32;
let _15: &i32;
let _16: usize;
let mut _17: usize;
let mut _18: bool;
let mut _19: *const dyn std::marker::Send;
let mut _20: *const dyn std::marker::Send;
let _19: ();
let mut _20: bool;
let mut _21: *const dyn std::marker::Send;
let _22: ();
let mut _23: bool;
let mut _24: *const dyn std::marker::Send;
let mut _25: *const dyn std::marker::Send;
let mut _22: *const dyn std::marker::Send;
let mut _23: *const dyn std::marker::Send;
let _24: ();
let mut _25: bool;
let mut _26: *const dyn std::marker::Send;
let _27: ();
let mut _28: bool;
let mut _29: *const dyn std::marker::Send;
let mut _30: *const dyn std::marker::Send;
let mut _27: *const dyn std::marker::Send;
let mut _28: *const dyn std::marker::Send;
let _29: ();
let mut _30: bool;
let mut _31: *const dyn std::marker::Send;
let _32: ();
let mut _33: bool;
let mut _34: *const dyn std::marker::Send;
let mut _35: *const dyn std::marker::Send;
let mut _32: *const dyn std::marker::Send;
let mut _33: *const dyn std::marker::Send;
let _34: ();
let mut _35: bool;
let mut _36: *const dyn std::marker::Send;
let _37: ();
let mut _38: bool;
let mut _39: *const dyn std::marker::Send;
let mut _40: *const dyn std::marker::Send;
let mut _37: *const dyn std::marker::Send;
let mut _38: *const dyn std::marker::Send;
let _39: ();
let mut _40: bool;
let mut _41: *const dyn std::marker::Send;
let _42: ();
let mut _43: bool;
let mut _44: *const dyn std::marker::Send;
let mut _45: *const dyn std::marker::Send;
let mut _42: *const dyn std::marker::Send;
let mut _43: *const dyn std::marker::Send;
let _44: ();
let mut _45: bool;
let mut _46: *const dyn std::marker::Send;
let mut _47: &[i32; 2];
let mut _47: *const dyn std::marker::Send;
let mut _48: *const dyn std::marker::Send;
let mut _49: &[i32; 2];
scope 1 {
debug slice => _1;
let _3: *const dyn std::marker::Send;
scope 2 {
debug a => _3;
let _10: *const dyn std::marker::Send;
let _11: *const dyn std::marker::Send;
scope 3 {
debug b => _10;
debug b => _11;
}
}
}
bb0: {
StorageLive(_1);
_47 = const wide_ptr_same_provenance::promoted[0];
_1 = &(*_47);
_49 = const wide_ptr_same_provenance::promoted[0];
_1 = &(*_49);
StorageLive(_3);
- StorageLive(_4);
+ nop;
@ -72,9 +74,11 @@
StorageLive(_7);
StorageLive(_8);
_8 = const 0_usize;
- _9 = Lt(copy _8, const 2_usize);
- assert(move _9, "index out of bounds: the length is {} but the index is {}", const 2_usize, copy _8) -> [success: bb1, unwind continue];
+ _9 = const true;
- _9 = Len((*_1));
- _10 = Lt(copy _8, copy _9);
- assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, copy _8) -> [success: bb1, unwind continue];
+ _9 = const 2_usize;
+ _10 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 2_usize, const 0_usize) -> [success: bb1, unwind continue];
}
@ -91,168 +95,170 @@
+ nop;
StorageDead(_7);
StorageDead(_5);
StorageLive(_10);
- StorageLive(_11);
StorageLive(_11);
- StorageLive(_12);
+ nop;
StorageLive(_12);
StorageLive(_13);
StorageLive(_14);
StorageLive(_15);
_15 = const 1_usize;
- _16 = Lt(copy _15, const 2_usize);
- assert(move _16, "index out of bounds: the length is {} but the index is {}", const 2_usize, copy _15) -> [success: bb2, unwind continue];
+ _16 = const true;
StorageLive(_16);
_16 = const 1_usize;
- _17 = Len((*_1));
- _18 = Lt(copy _16, copy _17);
- assert(move _18, "index out of bounds: the length is {} but the index is {}", move _17, copy _16) -> [success: bb2, unwind continue];
+ _17 = const 2_usize;
+ _18 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 2_usize, const 1_usize) -> [success: bb2, unwind continue];
}
bb2: {
- _14 = &(*_1)[_15];
+ _14 = &(*_1)[1 of 2];
_13 = &(*_14);
_12 = move _13 as &dyn std::marker::Send (PointerCoercion(Unsize, AsCast));
StorageDead(_13);
_11 = &raw const (*_12);
- _10 = move _11 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
- StorageDead(_11);
+ _10 = copy _11;
+ nop;
- _15 = &(*_1)[_16];
+ _15 = &(*_1)[1 of 2];
_14 = &(*_15);
_13 = move _14 as &dyn std::marker::Send (PointerCoercion(Unsize, AsCast));
StorageDead(_14);
StorageDead(_12);
StorageLive(_17);
StorageLive(_18);
_12 = &raw const (*_13);
- _11 = move _12 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
- StorageDead(_12);
+ _11 = copy _12;
+ nop;
StorageDead(_15);
StorageDead(_13);
StorageLive(_19);
- _19 = copy _3;
+ _19 = copy _4;
StorageLive(_20);
StorageLive(_21);
- _21 = copy _10;
- _20 = move _21 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
+ _21 = copy _11;
+ _20 = copy _11;
- _21 = copy _3;
+ _21 = copy _4;
StorageLive(_22);
StorageLive(_23);
- _23 = copy _11;
- _22 = move _23 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
+ _23 = copy _12;
+ _22 = copy _12;
StorageDead(_23);
- _20 = Eq(move _21, move _22);
+ _20 = Eq(copy _4, copy _12);
StorageDead(_22);
StorageDead(_21);
- _18 = Eq(move _19, move _20);
+ _18 = Eq(copy _4, copy _11);
StorageDead(_20);
StorageDead(_19);
_17 = opaque::<bool>(move _18) -> [return: bb3, unwind continue];
_19 = opaque::<bool>(move _20) -> [return: bb3, unwind continue];
}
bb3: {
StorageDead(_18);
StorageDead(_17);
StorageLive(_22);
StorageLive(_23);
StorageDead(_20);
StorageDead(_19);
StorageLive(_24);
- _24 = copy _3;
+ _24 = copy _4;
StorageLive(_25);
StorageLive(_26);
- _26 = copy _10;
- _25 = move _26 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
+ _26 = copy _11;
+ _25 = copy _11;
- _26 = copy _3;
+ _26 = copy _4;
StorageLive(_27);
StorageLive(_28);
- _28 = copy _11;
- _27 = move _28 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
+ _28 = copy _12;
+ _27 = copy _12;
StorageDead(_28);
- _25 = Ne(move _26, move _27);
+ _25 = Ne(copy _4, copy _12);
StorageDead(_27);
StorageDead(_26);
- _23 = Ne(move _24, move _25);
+ _23 = Ne(copy _4, copy _11);
StorageDead(_25);
StorageDead(_24);
_22 = opaque::<bool>(move _23) -> [return: bb4, unwind continue];
_24 = opaque::<bool>(move _25) -> [return: bb4, unwind continue];
}
bb4: {
StorageDead(_23);
StorageDead(_22);
StorageLive(_27);
StorageLive(_28);
StorageDead(_25);
StorageDead(_24);
StorageLive(_29);
- _29 = copy _3;
+ _29 = copy _4;
StorageLive(_30);
StorageLive(_31);
- _31 = copy _10;
- _30 = move _31 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
+ _31 = copy _11;
+ _30 = copy _11;
- _31 = copy _3;
+ _31 = copy _4;
StorageLive(_32);
StorageLive(_33);
- _33 = copy _11;
- _32 = move _33 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
+ _33 = copy _12;
+ _32 = copy _12;
StorageDead(_33);
- _30 = Lt(move _31, move _32);
+ _30 = Lt(copy _4, copy _12);
StorageDead(_32);
StorageDead(_31);
- _28 = Lt(move _29, move _30);
+ _28 = Lt(copy _4, copy _11);
StorageDead(_30);
StorageDead(_29);
_27 = opaque::<bool>(move _28) -> [return: bb5, unwind continue];
_29 = opaque::<bool>(move _30) -> [return: bb5, unwind continue];
}
bb5: {
StorageDead(_28);
StorageDead(_27);
StorageLive(_32);
StorageLive(_33);
StorageDead(_30);
StorageDead(_29);
StorageLive(_34);
- _34 = copy _3;
+ _34 = copy _4;
StorageLive(_35);
StorageLive(_36);
- _36 = copy _10;
- _35 = move _36 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
+ _36 = copy _11;
+ _35 = copy _11;
- _36 = copy _3;
+ _36 = copy _4;
StorageLive(_37);
StorageLive(_38);
- _38 = copy _11;
- _37 = move _38 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
+ _38 = copy _12;
+ _37 = copy _12;
StorageDead(_38);
- _35 = Le(move _36, move _37);
+ _35 = Le(copy _4, copy _12);
StorageDead(_37);
StorageDead(_36);
- _33 = Le(move _34, move _35);
+ _33 = Le(copy _4, copy _11);
StorageDead(_35);
StorageDead(_34);
_32 = opaque::<bool>(move _33) -> [return: bb6, unwind continue];
_34 = opaque::<bool>(move _35) -> [return: bb6, unwind continue];
}
bb6: {
StorageDead(_33);
StorageDead(_32);
StorageLive(_37);
StorageLive(_38);
StorageDead(_35);
StorageDead(_34);
StorageLive(_39);
- _39 = copy _3;
+ _39 = copy _4;
StorageLive(_40);
StorageLive(_41);
- _41 = copy _10;
- _40 = move _41 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
+ _41 = copy _11;
+ _40 = copy _11;
- _41 = copy _3;
+ _41 = copy _4;
StorageLive(_42);
StorageLive(_43);
- _43 = copy _11;
- _42 = move _43 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
+ _43 = copy _12;
+ _42 = copy _12;
StorageDead(_43);
- _40 = Gt(move _41, move _42);
+ _40 = Gt(copy _4, copy _12);
StorageDead(_42);
StorageDead(_41);
- _38 = Gt(move _39, move _40);
+ _38 = Gt(copy _4, copy _11);
StorageDead(_40);
StorageDead(_39);
_37 = opaque::<bool>(move _38) -> [return: bb7, unwind continue];
_39 = opaque::<bool>(move _40) -> [return: bb7, unwind continue];
}
bb7: {
StorageDead(_38);
StorageDead(_37);
StorageLive(_42);
StorageLive(_43);
StorageDead(_40);
StorageDead(_39);
StorageLive(_44);
- _44 = copy _3;
+ _44 = copy _4;
StorageLive(_45);
StorageLive(_46);
- _46 = copy _10;
- _45 = move _46 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
+ _46 = copy _11;
+ _45 = copy _11;
- _46 = copy _3;
+ _46 = copy _4;
StorageLive(_47);
StorageLive(_48);
- _48 = copy _11;
- _47 = move _48 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit));
+ _48 = copy _12;
+ _47 = copy _12;
StorageDead(_48);
- _45 = Ge(move _46, move _47);
+ _45 = Ge(copy _4, copy _12);
StorageDead(_47);
StorageDead(_46);
- _43 = Ge(move _44, move _45);
+ _43 = Ge(copy _4, copy _11);
StorageDead(_45);
StorageDead(_44);
_42 = opaque::<bool>(move _43) -> [return: bb8, unwind continue];
_44 = opaque::<bool>(move _45) -> [return: bb8, unwind continue];
}
bb8: {
StorageDead(_43);
StorageDead(_42);
StorageDead(_45);
StorageDead(_44);
_0 = const ();
StorageDead(_15);
StorageDead(_10);
StorageDead(_16);
StorageDead(_11);
StorageDead(_8);
StorageDead(_3);
StorageDead(_1);

View file

@ -0,0 +1,77 @@
- // MIR for `norm2` before InstSimplify-after-simplifycfg
+ // MIR for `norm2` after InstSimplify-after-simplifycfg
fn norm2(_1: [f32; 2]) -> f32 {
debug x => _1;
let mut _0: f32;
let _2: f32;
let _3: usize;
let mut _4: usize;
let mut _5: bool;
let _7: usize;
let mut _8: usize;
let mut _9: bool;
let mut _10: f32;
let mut _11: f32;
let mut _12: f32;
let mut _13: f32;
let mut _14: f32;
let mut _15: f32;
scope 1 {
debug a => _2;
let _6: f32;
scope 2 {
debug b => _6;
}
}
bb0: {
StorageLive(_2);
StorageLive(_3);
_3 = const 0_usize;
- _4 = Len(_1);
+ _4 = const 2_usize;
_5 = Lt(copy _3, copy _4);
assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind unreachable];
}
bb1: {
_2 = copy _1[_3];
StorageDead(_3);
StorageLive(_6);
StorageLive(_7);
_7 = const 1_usize;
- _8 = Len(_1);
+ _8 = const 2_usize;
_9 = Lt(copy _7, copy _8);
assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, copy _7) -> [success: bb2, unwind unreachable];
}
bb2: {
_6 = copy _1[_7];
StorageDead(_7);
StorageLive(_10);
StorageLive(_11);
_11 = copy _2;
StorageLive(_12);
_12 = copy _2;
_10 = Mul(move _11, move _12);
StorageDead(_12);
StorageDead(_11);
StorageLive(_13);
StorageLive(_14);
_14 = copy _6;
StorageLive(_15);
_15 = copy _6;
_13 = Mul(move _14, move _15);
StorageDead(_15);
StorageDead(_14);
_0 = Add(move _10, move _13);
StorageDead(_13);
StorageDead(_10);
StorageDead(_6);
StorageDead(_2);
return;
}
}

View file

@ -0,0 +1,77 @@
- // MIR for `norm2` before InstSimplify-after-simplifycfg
+ // MIR for `norm2` after InstSimplify-after-simplifycfg
fn norm2(_1: [f32; 2]) -> f32 {
debug x => _1;
let mut _0: f32;
let _2: f32;
let _3: usize;
let mut _4: usize;
let mut _5: bool;
let _7: usize;
let mut _8: usize;
let mut _9: bool;
let mut _10: f32;
let mut _11: f32;
let mut _12: f32;
let mut _13: f32;
let mut _14: f32;
let mut _15: f32;
scope 1 {
debug a => _2;
let _6: f32;
scope 2 {
debug b => _6;
}
}
bb0: {
StorageLive(_2);
StorageLive(_3);
_3 = const 0_usize;
- _4 = Len(_1);
+ _4 = const 2_usize;
_5 = Lt(copy _3, copy _4);
assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind continue];
}
bb1: {
_2 = copy _1[_3];
StorageDead(_3);
StorageLive(_6);
StorageLive(_7);
_7 = const 1_usize;
- _8 = Len(_1);
+ _8 = const 2_usize;
_9 = Lt(copy _7, copy _8);
assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, copy _7) -> [success: bb2, unwind continue];
}
bb2: {
_6 = copy _1[_7];
StorageDead(_7);
StorageLive(_10);
StorageLive(_11);
_11 = copy _2;
StorageLive(_12);
_12 = copy _2;
_10 = Mul(move _11, move _12);
StorageDead(_12);
StorageDead(_11);
StorageLive(_13);
StorageLive(_14);
_14 = copy _6;
StorageLive(_15);
_15 = copy _6;
_13 = Mul(move _14, move _15);
StorageDead(_15);
StorageDead(_14);
_0 = Add(move _10, move _13);
StorageDead(_13);
StorageDead(_10);
StorageDead(_6);
StorageDead(_2);
return;
}
}

View file

@ -0,0 +1,15 @@
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
//@ test-mir-pass: InstSimplify-after-simplifycfg
// EMIT_MIR combine_array_len.norm2.InstSimplify-after-simplifycfg.diff
fn norm2(x: [f32; 2]) -> f32 {
// CHECK-LABEL: fn norm2(
// CHECK-NOT: Len(
let a = x[0];
let b = x[1];
a * a + b * b
}
fn main() {
assert_eq!(norm2([3.0, 4.0]), 5.0 * 5.0);
}

View file

@ -4,14 +4,15 @@ fn foo(_1: [(Never, u32); 1]) -> u32 {
debug xs => _1;
let mut _0: u32;
let _2: usize;
let mut _3: bool;
let mut _3: usize;
let mut _4: bool;
bb0: {
StorageLive(_2);
_2 = const 0_usize;
FakeRead(ForIndex, _1);
_3 = Lt(copy _2, const 1_usize);
assert(move _3, "index out of bounds: the length is {} but the index is {}", const 1_usize, copy _2) -> [success: bb1, unwind: bb2];
_3 = Len(_1);
_4 = Lt(copy _2, copy _3);
assert(move _4, "index out of bounds: the length is {} but the index is {}", move _3, copy _2) -> [success: bb1, unwind: bb2];
}
bb1: {

Some files were not shown because too many files have changed in this diff Show more