Revert "Auto merge of #134330 - scottmcm:no-more-rvalue-len, r=matthewjasper"
This reverts commite108481f74
, reversing changes made to303e8bd768
.
This commit is contained in:
parent
efc25761e5
commit
ca1c17c88d
37 changed files with 272 additions and 51 deletions
|
@ -829,6 +829,7 @@ use self::ReadOrWrite::{Activation, Read, Reservation, Write};
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||||
enum ArtificialField {
|
enum ArtificialField {
|
||||||
|
ArrayLength,
|
||||||
FakeBorrow,
|
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(
|
self.access_place(
|
||||||
location,
|
location,
|
||||||
(place, span),
|
(place, span),
|
||||||
(Shallow(None), Read(ReadKind::Copy)),
|
(Shallow(af), Read(ReadKind::Copy)),
|
||||||
LocalMutationIsAllowed::No,
|
LocalMutationIsAllowed::No,
|
||||||
state,
|
state,
|
||||||
);
|
);
|
||||||
|
|
|
@ -203,7 +203,8 @@ fn place_components_conflict<'tcx>(
|
||||||
let base_ty = base.ty(body, tcx).ty;
|
let base_ty = base.ty(body, tcx).ty;
|
||||||
|
|
||||||
match (elem, base_ty.kind(), access) {
|
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
|
// The array length is like additional fields on the
|
||||||
// type; it does not overlap any existing data there.
|
// type; it does not overlap any existing data there.
|
||||||
// Furthermore, if cannot actually be a prefix of any
|
// Furthermore, if cannot actually be a prefix of any
|
||||||
|
|
|
@ -300,11 +300,16 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> {
|
||||||
self.consume_operand(location, op);
|
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(
|
self.access_place(
|
||||||
location,
|
location,
|
||||||
place,
|
place,
|
||||||
(Shallow(None), Read(ReadKind::Copy)),
|
(Shallow(af), Read(ReadKind::Copy)),
|
||||||
LocalMutationIsAllowed::No,
|
LocalMutationIsAllowed::No,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2235,6 +2235,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
|
|
||||||
Rvalue::RawPtr(..)
|
Rvalue::RawPtr(..)
|
||||||
| Rvalue::ThreadLocalRef(..)
|
| Rvalue::ThreadLocalRef(..)
|
||||||
|
| Rvalue::Len(..)
|
||||||
| Rvalue::Discriminant(..)
|
| Rvalue::Discriminant(..)
|
||||||
| Rvalue::NullaryOp(NullOp::OffsetOf(..), _) => {}
|
| Rvalue::NullaryOp(NullOp::OffsetOf(..), _) => {}
|
||||||
}
|
}
|
||||||
|
@ -2250,6 +2251,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
| Rvalue::Repeat(..)
|
| Rvalue::Repeat(..)
|
||||||
| Rvalue::Ref(..)
|
| Rvalue::Ref(..)
|
||||||
| Rvalue::RawPtr(..)
|
| Rvalue::RawPtr(..)
|
||||||
|
| Rvalue::Len(..)
|
||||||
| Rvalue::Cast(..)
|
| Rvalue::Cast(..)
|
||||||
| Rvalue::ShallowInitBox(..)
|
| Rvalue::ShallowInitBox(..)
|
||||||
| Rvalue::BinaryOp(..)
|
| Rvalue::BinaryOp(..)
|
||||||
|
|
|
@ -828,6 +828,12 @@ fn codegen_stmt<'tcx>(
|
||||||
fx.bcx.ins().nop();
|
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) => {
|
Rvalue::ShallowInitBox(ref operand, content_ty) => {
|
||||||
let content_ty = fx.monomorphize(content_ty);
|
let content_ty = fx.monomorphize(content_ty);
|
||||||
let box_layout = fx.layout_of(Ty::new_box(fx.tcx, content_ty));
|
let box_layout = fx.layout_of(Ty::new_box(fx.tcx, content_ty));
|
||||||
|
|
|
@ -10,9 +10,9 @@ use rustc_session::config::OptLevel;
|
||||||
use rustc_span::{DUMMY_SP, Span};
|
use rustc_span::{DUMMY_SP, Span};
|
||||||
use tracing::{debug, instrument};
|
use tracing::{debug, instrument};
|
||||||
|
|
||||||
use super::FunctionCx;
|
|
||||||
use super::operand::{OperandRef, OperandValue};
|
use super::operand::{OperandRef, OperandValue};
|
||||||
use super::place::PlaceRef;
|
use super::place::PlaceRef;
|
||||||
|
use super::{FunctionCx, LocalRef};
|
||||||
use crate::common::IntPredicate;
|
use crate::common::IntPredicate;
|
||||||
use crate::traits::*;
|
use crate::traits::*;
|
||||||
use crate::{MemFlags, base};
|
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)
|
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))
|
mir::Rvalue::BinaryOp(op_with_overflow, box (ref lhs, ref rhs))
|
||||||
if let Some(op) = op_with_overflow.overflowing_to_wrapping() =>
|
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`
|
/// Codegen an `Rvalue::RawPtr` or `Rvalue::Ref`
|
||||||
fn codegen_place_to_pointer(
|
fn codegen_place_to_pointer(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -1077,6 +1103,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
mir::Rvalue::Ref(..) |
|
mir::Rvalue::Ref(..) |
|
||||||
mir::Rvalue::CopyForDeref(..) |
|
mir::Rvalue::CopyForDeref(..) |
|
||||||
mir::Rvalue::RawPtr(..) |
|
mir::Rvalue::RawPtr(..) |
|
||||||
|
mir::Rvalue::Len(..) |
|
||||||
mir::Rvalue::Cast(..) | // (*)
|
mir::Rvalue::Cast(..) | // (*)
|
||||||
mir::Rvalue::ShallowInitBox(..) | // (*)
|
mir::Rvalue::ShallowInitBox(..) | // (*)
|
||||||
mir::Rvalue::BinaryOp(..) |
|
mir::Rvalue::BinaryOp(..) |
|
||||||
|
|
|
@ -495,7 +495,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
||||||
Rvalue::Use(_)
|
Rvalue::Use(_)
|
||||||
| Rvalue::CopyForDeref(..)
|
| Rvalue::CopyForDeref(..)
|
||||||
| Rvalue::Repeat(..)
|
| Rvalue::Repeat(..)
|
||||||
| Rvalue::Discriminant(..) => {}
|
| Rvalue::Discriminant(..)
|
||||||
|
| Rvalue::Len(_) => {}
|
||||||
|
|
||||||
Rvalue::Aggregate(kind, ..) => {
|
Rvalue::Aggregate(kind, ..) => {
|
||||||
if let AggregateKind::Coroutine(def_id, ..) = kind.as_ref()
|
if let AggregateKind::Coroutine(def_id, ..) = kind.as_ref()
|
||||||
|
|
|
@ -230,7 +230,9 @@ where
|
||||||
Q::in_any_value_of_ty(cx, rvalue.ty(cx.body, cx.tcx))
|
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()),
|
Rvalue::CopyForDeref(place) => in_place::<Q, _>(cx, in_local, place.as_ref()),
|
||||||
|
|
||||||
|
|
|
@ -197,6 +197,7 @@ where
|
||||||
| mir::Rvalue::CopyForDeref(..)
|
| mir::Rvalue::CopyForDeref(..)
|
||||||
| mir::Rvalue::ThreadLocalRef(..)
|
| mir::Rvalue::ThreadLocalRef(..)
|
||||||
| mir::Rvalue::Repeat(..)
|
| mir::Rvalue::Repeat(..)
|
||||||
|
| mir::Rvalue::Len(..)
|
||||||
| mir::Rvalue::BinaryOp(..)
|
| mir::Rvalue::BinaryOp(..)
|
||||||
| mir::Rvalue::NullaryOp(..)
|
| mir::Rvalue::NullaryOp(..)
|
||||||
| mir::Rvalue::UnaryOp(..)
|
| mir::Rvalue::UnaryOp(..)
|
||||||
|
|
|
@ -15,7 +15,7 @@ use tracing::{info, instrument, trace};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
FnArg, FnVal, ImmTy, Immediate, InterpCx, InterpResult, Machine, MemPlaceMeta, PlaceTy,
|
FnArg, FnVal, ImmTy, Immediate, InterpCx, InterpResult, Machine, MemPlaceMeta, PlaceTy,
|
||||||
Projectable, interp_ok, throw_ub,
|
Projectable, Scalar, interp_ok, throw_ub,
|
||||||
};
|
};
|
||||||
use crate::util;
|
use crate::util;
|
||||||
|
|
||||||
|
@ -218,6 +218,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||||
self.write_repeat(operand, &dest)?;
|
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) => {
|
Ref(_, borrow_kind, place) => {
|
||||||
let src = self.eval_place(place)?;
|
let src = self.eval_place(place)?;
|
||||||
let place = self.force_allocation(&src)?;
|
let place = self.force_allocation(&src)?;
|
||||||
|
|
|
@ -1068,6 +1068,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
|
||||||
pretty_print_const(b, fmt, false)?;
|
pretty_print_const(b, fmt, false)?;
|
||||||
write!(fmt, "]")
|
write!(fmt, "]")
|
||||||
}
|
}
|
||||||
|
Len(ref a) => write!(fmt, "Len({a:?})"),
|
||||||
Cast(ref kind, ref place, ref ty) => {
|
Cast(ref kind, ref place, ref ty) => {
|
||||||
with_no_trimmed_paths!(write!(fmt, "{place:?} as {ty} ({kind:?})"))
|
with_no_trimmed_paths!(write!(fmt, "{place:?} as {ty} ({kind:?})"))
|
||||||
}
|
}
|
||||||
|
|
|
@ -424,6 +424,7 @@ impl<'tcx> Rvalue<'tcx> {
|
||||||
| Rvalue::Ref(_, _, _)
|
| Rvalue::Ref(_, _, _)
|
||||||
| Rvalue::ThreadLocalRef(_)
|
| Rvalue::ThreadLocalRef(_)
|
||||||
| Rvalue::RawPtr(_, _)
|
| Rvalue::RawPtr(_, _)
|
||||||
|
| Rvalue::Len(_)
|
||||||
| Rvalue::Cast(
|
| Rvalue::Cast(
|
||||||
CastKind::IntToInt
|
CastKind::IntToInt
|
||||||
| CastKind::FloatToInt
|
| CastKind::FloatToInt
|
||||||
|
|
|
@ -1351,6 +1351,16 @@ pub enum Rvalue<'tcx> {
|
||||||
/// model.
|
/// model.
|
||||||
RawPtr(Mutability, Place<'tcx>),
|
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`.
|
/// Performs essentially all of the casts that can be performed via `as`.
|
||||||
///
|
///
|
||||||
/// This allows for casts from/to a variety of types.
|
/// This allows for casts from/to a variety of types.
|
||||||
|
|
|
@ -210,6 +210,7 @@ impl<'tcx> Rvalue<'tcx> {
|
||||||
let place_ty = place.ty(local_decls, tcx).ty;
|
let place_ty = place.ty(local_decls, tcx).ty;
|
||||||
Ty::new_ptr(tcx, place_ty, mutability)
|
Ty::new_ptr(tcx, place_ty, mutability)
|
||||||
}
|
}
|
||||||
|
Rvalue::Len(..) => tcx.types.usize,
|
||||||
Rvalue::Cast(.., ty) => ty,
|
Rvalue::Cast(.., ty) => ty,
|
||||||
Rvalue::BinaryOp(op, box (ref lhs, ref rhs)) => {
|
Rvalue::BinaryOp(op, box (ref lhs, ref rhs)) => {
|
||||||
let lhs_ty = lhs.ty(local_decls, tcx);
|
let lhs_ty = lhs.ty(local_decls, tcx);
|
||||||
|
|
|
@ -695,6 +695,14 @@ macro_rules! make_mir_visitor {
|
||||||
self.visit_place(path, ctx, location);
|
self.visit_place(path, ctx, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Rvalue::Len(path) => {
|
||||||
|
self.visit_place(
|
||||||
|
path,
|
||||||
|
PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect),
|
||||||
|
location
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Rvalue::Cast(_cast_kind, operand, ty) => {
|
Rvalue::Cast(_cast_kind, operand, ty) => {
|
||||||
self.visit_operand(operand, location);
|
self.visit_operand(operand, location);
|
||||||
self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
|
self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
|
||||||
|
|
|
@ -246,6 +246,7 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> {
|
||||||
let offset = self.parse_operand(args[1])?;
|
let offset = self.parse_operand(args[1])?;
|
||||||
Ok(Rvalue::BinaryOp(BinOp::Offset, Box::new((ptr, offset))))
|
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_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])?)),
|
@call(mir_copy_for_deref, args) => Ok(Rvalue::CopyForDeref(self.parse_place(args[0])?)),
|
||||||
ExprKind::Borrow { borrow_kind, arg } => Ok(
|
ExprKind::Borrow { borrow_kind, arg } => Ok(
|
||||||
|
|
|
@ -635,7 +635,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
///
|
///
|
||||||
/// For arrays it'll be `Operand::Constant` with the actual length;
|
/// For arrays it'll be `Operand::Constant` with the actual length;
|
||||||
/// For slices it'll be `Operand::Move` of a local using `PtrMetadata`.
|
/// For slices it'll be `Operand::Move` of a local using `PtrMetadata`.
|
||||||
pub(in crate::builder) fn len_of_slice_or_array(
|
fn len_of_slice_or_array(
|
||||||
&mut self,
|
&mut self,
|
||||||
block: BasicBlock,
|
block: BasicBlock,
|
||||||
place: Place<'tcx>,
|
place: Place<'tcx>,
|
||||||
|
|
|
@ -243,8 +243,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
TestKind::Len { len, op } => {
|
TestKind::Len { len, op } => {
|
||||||
|
let usize_ty = self.tcx.types.usize;
|
||||||
|
let actual = self.temp(usize_ty, test.span);
|
||||||
|
|
||||||
// actual = len(place)
|
// 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>
|
// expected = <N>
|
||||||
let expected = self.push_usize(block, source_info, len);
|
let expected = self.push_usize(block, source_info, len);
|
||||||
|
@ -259,7 +262,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
fail_block,
|
fail_block,
|
||||||
source_info,
|
source_info,
|
||||||
op,
|
op,
|
||||||
actual,
|
Operand::Move(actual),
|
||||||
Operand::Move(expected),
|
Operand::Move(expected),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,6 +91,7 @@ where
|
||||||
| Rvalue::Use(..)
|
| Rvalue::Use(..)
|
||||||
| Rvalue::ThreadLocalRef(..)
|
| Rvalue::ThreadLocalRef(..)
|
||||||
| Rvalue::Repeat(..)
|
| Rvalue::Repeat(..)
|
||||||
|
| Rvalue::Len(..)
|
||||||
| Rvalue::BinaryOp(..)
|
| Rvalue::BinaryOp(..)
|
||||||
| Rvalue::NullaryOp(..)
|
| Rvalue::NullaryOp(..)
|
||||||
| Rvalue::UnaryOp(..)
|
| Rvalue::UnaryOp(..)
|
||||||
|
|
|
@ -413,6 +413,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
|
||||||
Rvalue::Ref(..)
|
Rvalue::Ref(..)
|
||||||
| Rvalue::RawPtr(..)
|
| Rvalue::RawPtr(..)
|
||||||
| Rvalue::Discriminant(..)
|
| Rvalue::Discriminant(..)
|
||||||
|
| Rvalue::Len(..)
|
||||||
| Rvalue::NullaryOp(
|
| Rvalue::NullaryOp(
|
||||||
NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..) | NullOp::UbChecks,
|
NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..) | NullOp::UbChecks,
|
||||||
_,
|
_,
|
||||||
|
|
|
@ -408,6 +408,18 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
|
||||||
state: &mut State<FlatSet<Scalar>>,
|
state: &mut State<FlatSet<Scalar>>,
|
||||||
) -> ValueOrPlace<FlatSet<Scalar>> {
|
) -> ValueOrPlace<FlatSet<Scalar>> {
|
||||||
let val = match rvalue {
|
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) => {
|
Rvalue::Cast(CastKind::IntToInt | CastKind::IntToFloat, operand, ty) => {
|
||||||
let Ok(layout) = self.tcx.layout_of(self.typing_env.as_query_input(*ty)) else {
|
let Ok(layout) = self.tcx.layout_of(self.typing_env.as_query_input(*ty)) else {
|
||||||
return ValueOrPlace::Value(FlatSet::Top);
|
return ValueOrPlace::Value(FlatSet::Top);
|
||||||
|
|
|
@ -575,6 +575,7 @@ impl WriteInfo {
|
||||||
| Rvalue::NullaryOp(_, _)
|
| Rvalue::NullaryOp(_, _)
|
||||||
| Rvalue::Ref(_, _, _)
|
| Rvalue::Ref(_, _, _)
|
||||||
| Rvalue::RawPtr(_, _)
|
| Rvalue::RawPtr(_, _)
|
||||||
|
| Rvalue::Len(_)
|
||||||
| Rvalue::Discriminant(_)
|
| Rvalue::Discriminant(_)
|
||||||
| Rvalue::CopyForDeref(_) => {}
|
| Rvalue::CopyForDeref(_) => {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -223,6 +223,8 @@ enum Value<'tcx> {
|
||||||
Projection(VnIndex, ProjectionElem<VnIndex, Ty<'tcx>>),
|
Projection(VnIndex, ProjectionElem<VnIndex, Ty<'tcx>>),
|
||||||
/// Discriminant of the given value.
|
/// Discriminant of the given value.
|
||||||
Discriminant(VnIndex),
|
Discriminant(VnIndex),
|
||||||
|
/// Length of an array or slice.
|
||||||
|
Len(VnIndex),
|
||||||
|
|
||||||
// Operations.
|
// Operations.
|
||||||
NullaryOp(NullOp<'tcx>, Ty<'tcx>),
|
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()?;
|
self.ecx.discriminant_for_variant(base.layout.ty, variant).discard_err()?;
|
||||||
discr_value.into()
|
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) => {
|
NullaryOp(null_op, ty) => {
|
||||||
let layout = self.ecx.layout_of(ty).ok()?;
|
let layout = self.ecx.layout_of(ty).ok()?;
|
||||||
if let NullOp::SizeOf | NullOp::AlignOf = null_op
|
if let NullOp::SizeOf | NullOp::AlignOf = null_op
|
||||||
|
@ -854,6 +863,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Operations.
|
// Operations.
|
||||||
|
Rvalue::Len(ref mut place) => return self.simplify_len(place, location),
|
||||||
Rvalue::Cast(ref mut kind, ref mut value, to) => {
|
Rvalue::Cast(ref mut kind, ref mut value, to) => {
|
||||||
return self.simplify_cast(kind, value, to, location);
|
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 }))
|
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 {
|
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 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);
|
let right_meta_ty = right_ptr_ty.pointee_metadata_ty_or_projection(self.tcx);
|
||||||
|
|
|
@ -440,6 +440,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
||||||
| Rvalue::Use(..)
|
| Rvalue::Use(..)
|
||||||
| Rvalue::CopyForDeref(..)
|
| Rvalue::CopyForDeref(..)
|
||||||
| Rvalue::Repeat(..)
|
| Rvalue::Repeat(..)
|
||||||
|
| Rvalue::Len(..)
|
||||||
| Rvalue::Cast(..)
|
| Rvalue::Cast(..)
|
||||||
| Rvalue::ShallowInitBox(..)
|
| Rvalue::ShallowInitBox(..)
|
||||||
| Rvalue::Discriminant(..)
|
| Rvalue::Discriminant(..)
|
||||||
|
@ -599,6 +600,20 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
||||||
return None;
|
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,
|
Ref(..) | RawPtr(..) => return None,
|
||||||
|
|
||||||
NullaryOp(ref null_op, ty) => {
|
NullaryOp(ref null_op, ty) => {
|
||||||
|
|
|
@ -430,7 +430,9 @@ impl<'tcx> Validator<'_, 'tcx> {
|
||||||
self.validate_operand(op)?
|
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),
|
Rvalue::ThreadLocalRef(_) => return Err(Unpromotable),
|
||||||
|
|
||||||
|
|
|
@ -1018,6 +1018,14 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Rvalue::Ref(..) => {}
|
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) => {
|
Rvalue::BinaryOp(op, vals) => {
|
||||||
use BinOp::*;
|
use BinOp::*;
|
||||||
let a = vals.0.ty(&self.body.local_decls, self.tcx);
|
let a = vals.0.ty(&self.body.local_decls, self.tcx);
|
||||||
|
|
|
@ -181,6 +181,7 @@ impl<'tcx> Stable<'tcx> for mir::Rvalue<'tcx> {
|
||||||
RawPtr(mutability, place) => {
|
RawPtr(mutability, place) => {
|
||||||
stable_mir::mir::Rvalue::AddressOf(mutability.stable(tables), place.stable(tables))
|
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(cast_kind, op, ty) => stable_mir::mir::Rvalue::Cast(
|
||||||
cast_kind.stable(tables),
|
cast_kind.stable(tables),
|
||||||
op.stable(tables),
|
op.stable(tables),
|
||||||
|
|
|
@ -1287,6 +1287,7 @@ symbols! {
|
||||||
mir_drop,
|
mir_drop,
|
||||||
mir_field,
|
mir_field,
|
||||||
mir_goto,
|
mir_goto,
|
||||||
|
mir_len,
|
||||||
mir_make_place,
|
mir_make_place,
|
||||||
mir_move,
|
mir_move,
|
||||||
mir_offset,
|
mir_offset,
|
||||||
|
|
|
@ -233,7 +233,7 @@
|
||||||
//!
|
//!
|
||||||
//! - Operands implicitly convert to `Use` rvalues.
|
//! - Operands implicitly convert to `Use` rvalues.
|
||||||
//! - `&`, `&mut`, `addr_of!`, and `addr_of_mut!` all work to create their associated rvalue.
|
//! - `&`, `&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.
|
//! - Unary and binary operations use their normal Rust syntax - `a * b`, `!c`, etc.
|
||||||
//! - The binary operation `Offset` can be created via [`Offset`].
|
//! - The binary operation `Offset` can be created via [`Offset`].
|
||||||
//! - Checked binary operations are represented by wrapping the associated binop in [`Checked`].
|
//! - 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_assume", fn Assume(operand: bool));
|
||||||
define!("mir_deinit", fn Deinit<T>(place: T));
|
define!("mir_deinit", fn Deinit<T>(place: T));
|
||||||
define!("mir_checked", fn Checked<T>(binop: T) -> (T, bool));
|
define!("mir_checked", fn Checked<T>(binop: T) -> (T, bool));
|
||||||
|
define!("mir_len", fn Len<T>(place: T) -> usize);
|
||||||
define!(
|
define!(
|
||||||
"mir_ptr_metadata",
|
"mir_ptr_metadata",
|
||||||
fn PtrMetadata<P: ?Sized>(place: *const P) -> <P as ::core::ptr::Pointee>::Metadata
|
fn PtrMetadata<P: ?Sized>(place: *const P) -> <P as ::core::ptr::Pointee>::Metadata
|
||||||
|
|
|
@ -109,7 +109,7 @@ fn check_rvalue<'tcx>(
|
||||||
) -> McfResult {
|
) -> McfResult {
|
||||||
match rvalue {
|
match rvalue {
|
||||||
Rvalue::ThreadLocalRef(_) => Err((span, "cannot access thread local storage in const fn".into())),
|
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)
|
check_place(tcx, *place, span, body, msrv)
|
||||||
},
|
},
|
||||||
Rvalue::CopyForDeref(place) => check_place(tcx, *place, span, body, msrv),
|
Rvalue::CopyForDeref(place) => check_place(tcx, *place, span, body, msrv),
|
||||||
|
|
14
tests/mir-opt/building/custom/arrays.arrays.built.after.mir
Normal file
14
tests/mir-opt/building/custom/arrays.arrays.built.after.mir
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
22
tests/mir-opt/building/custom/arrays.rs
Normal file
22
tests/mir-opt/building/custom/arrays.rs
Normal 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);
|
||||||
|
}
|
|
@ -22,14 +22,14 @@
|
||||||
|
|
||||||
bb1: {
|
bb1: {
|
||||||
StorageDead(_3);
|
StorageDead(_3);
|
||||||
_4 = PtrMetadata(copy _2);
|
_4 = Len((*_2));
|
||||||
_5 = const 4_usize;
|
_5 = const 4_usize;
|
||||||
_6 = Ge(move _4, move _5);
|
_6 = Ge(move _4, move _5);
|
||||||
switchInt(move _6) -> [0: bb2, otherwise: bb3];
|
switchInt(move _6) -> [0: bb2, otherwise: bb3];
|
||||||
}
|
}
|
||||||
|
|
||||||
bb2: {
|
bb2: {
|
||||||
_7 = PtrMetadata(copy _2);
|
_7 = Len((*_2));
|
||||||
_8 = const 3_usize;
|
_8 = const 3_usize;
|
||||||
_9 = Ge(move _7, move _8);
|
_9 = Ge(move _7, move _8);
|
||||||
- switchInt(move _9) -> [0: bb7, otherwise: bb8];
|
- switchInt(move _9) -> [0: bb7, otherwise: bb8];
|
||||||
|
|
|
@ -22,14 +22,14 @@
|
||||||
|
|
||||||
bb1: {
|
bb1: {
|
||||||
StorageDead(_3);
|
StorageDead(_3);
|
||||||
_4 = PtrMetadata(copy _2);
|
_4 = Len((*_2));
|
||||||
_5 = const 4_usize;
|
_5 = const 4_usize;
|
||||||
_6 = Ge(move _4, move _5);
|
_6 = Ge(move _4, move _5);
|
||||||
switchInt(move _6) -> [0: bb2, otherwise: bb3];
|
switchInt(move _6) -> [0: bb2, otherwise: bb3];
|
||||||
}
|
}
|
||||||
|
|
||||||
bb2: {
|
bb2: {
|
||||||
_7 = PtrMetadata(copy _2);
|
_7 = Len((*_2));
|
||||||
_8 = const 3_usize;
|
_8 = const 3_usize;
|
||||||
_9 = Ge(move _7, move _8);
|
_9 = Ge(move _7, move _8);
|
||||||
- switchInt(move _9) -> [0: bb7, otherwise: bb8];
|
- switchInt(move _9) -> [0: bb7, otherwise: bb8];
|
||||||
|
|
|
@ -7,16 +7,18 @@
|
||||||
let _2: &[T];
|
let _2: &[T];
|
||||||
let _3: &[T; 3];
|
let _3: &[T; 3];
|
||||||
let _4: [T; 3];
|
let _4: [T; 3];
|
||||||
let mut _8: !;
|
let mut _5: usize;
|
||||||
|
let mut _6: bool;
|
||||||
|
let mut _10: !;
|
||||||
scope 1 {
|
scope 1 {
|
||||||
debug v => _2;
|
debug v => _2;
|
||||||
let _5: &T;
|
|
||||||
let _6: &T;
|
|
||||||
let _7: &T;
|
let _7: &T;
|
||||||
|
let _8: &T;
|
||||||
|
let _9: &T;
|
||||||
scope 2 {
|
scope 2 {
|
||||||
debug v1 => _5;
|
debug v1 => _7;
|
||||||
debug v2 => _6;
|
debug v2 => _8;
|
||||||
debug v3 => _7;
|
debug v3 => _9;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,23 +27,25 @@
|
||||||
_4 = [copy _1, copy _1, copy _1];
|
_4 = [copy _1, copy _1, copy _1];
|
||||||
_3 = &_4;
|
_3 = &_4;
|
||||||
_2 = copy _3 as &[T] (PointerCoercion(Unsize, Implicit));
|
_2 = copy _3 as &[T] (PointerCoercion(Unsize, Implicit));
|
||||||
|
nop;
|
||||||
|
nop;
|
||||||
goto -> bb2;
|
goto -> bb2;
|
||||||
}
|
}
|
||||||
|
|
||||||
bb1: {
|
bb1: {
|
||||||
_8 = core::panicking::panic(const "internal error: entered unreachable code") -> unwind unreachable;
|
_10 = core::panicking::panic(const "internal error: entered unreachable code") -> unwind unreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
bb2: {
|
bb2: {
|
||||||
StorageLive(_5);
|
|
||||||
_5 = &(*_2)[0 of 3];
|
|
||||||
StorageLive(_6);
|
|
||||||
_6 = &(*_2)[1 of 3];
|
|
||||||
StorageLive(_7);
|
StorageLive(_7);
|
||||||
_7 = &(*_2)[2 of 3];
|
_7 = &(*_2)[0 of 3];
|
||||||
|
StorageLive(_8);
|
||||||
|
_8 = &(*_2)[1 of 3];
|
||||||
|
StorageLive(_9);
|
||||||
|
_9 = &(*_2)[2 of 3];
|
||||||
|
StorageDead(_9);
|
||||||
|
StorageDead(_8);
|
||||||
StorageDead(_7);
|
StorageDead(_7);
|
||||||
StorageDead(_6);
|
|
||||||
StorageDead(_5);
|
|
||||||
StorageDead(_4);
|
StorageDead(_4);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,16 +7,18 @@
|
||||||
let _2: &[T];
|
let _2: &[T];
|
||||||
let _3: &[T; 3];
|
let _3: &[T; 3];
|
||||||
let _4: [T; 3];
|
let _4: [T; 3];
|
||||||
let mut _8: !;
|
let mut _5: usize;
|
||||||
|
let mut _6: bool;
|
||||||
|
let mut _10: !;
|
||||||
scope 1 {
|
scope 1 {
|
||||||
debug v => _2;
|
debug v => _2;
|
||||||
let _5: &T;
|
|
||||||
let _6: &T;
|
|
||||||
let _7: &T;
|
let _7: &T;
|
||||||
|
let _8: &T;
|
||||||
|
let _9: &T;
|
||||||
scope 2 {
|
scope 2 {
|
||||||
debug v1 => _5;
|
debug v1 => _7;
|
||||||
debug v2 => _6;
|
debug v2 => _8;
|
||||||
debug v3 => _7;
|
debug v3 => _9;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,23 +27,25 @@
|
||||||
_4 = [copy _1, copy _1, copy _1];
|
_4 = [copy _1, copy _1, copy _1];
|
||||||
_3 = &_4;
|
_3 = &_4;
|
||||||
_2 = copy _3 as &[T] (PointerCoercion(Unsize, Implicit));
|
_2 = copy _3 as &[T] (PointerCoercion(Unsize, Implicit));
|
||||||
|
nop;
|
||||||
|
nop;
|
||||||
goto -> bb2;
|
goto -> bb2;
|
||||||
}
|
}
|
||||||
|
|
||||||
bb1: {
|
bb1: {
|
||||||
_8 = core::panicking::panic(const "internal error: entered unreachable code") -> unwind continue;
|
_10 = core::panicking::panic(const "internal error: entered unreachable code") -> unwind continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
bb2: {
|
bb2: {
|
||||||
StorageLive(_5);
|
|
||||||
_5 = &(*_2)[0 of 3];
|
|
||||||
StorageLive(_6);
|
|
||||||
_6 = &(*_2)[1 of 3];
|
|
||||||
StorageLive(_7);
|
StorageLive(_7);
|
||||||
_7 = &(*_2)[2 of 3];
|
_7 = &(*_2)[0 of 3];
|
||||||
|
StorageLive(_8);
|
||||||
|
_8 = &(*_2)[1 of 3];
|
||||||
|
StorageLive(_9);
|
||||||
|
_9 = &(*_2)[2 of 3];
|
||||||
|
StorageDead(_9);
|
||||||
|
StorageDead(_8);
|
||||||
StorageDead(_7);
|
StorageDead(_7);
|
||||||
StorageDead(_6);
|
|
||||||
StorageDead(_5);
|
|
||||||
StorageDead(_4);
|
StorageDead(_4);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,7 +92,7 @@
|
||||||
StorageDead(_7);
|
StorageDead(_7);
|
||||||
- StorageDead(_6);
|
- StorageDead(_6);
|
||||||
- StorageLive(_10);
|
- StorageLive(_10);
|
||||||
StorageLive(_11);
|
- StorageLive(_11);
|
||||||
- StorageLive(_12);
|
- StorageLive(_12);
|
||||||
StorageLive(_13);
|
StorageLive(_13);
|
||||||
_26 = const debuginfo::promoted[0];
|
_26 = const debuginfo::promoted[0];
|
||||||
|
@ -105,8 +105,9 @@
|
||||||
bb5: {
|
bb5: {
|
||||||
StorageDead(_15);
|
StorageDead(_15);
|
||||||
StorageDead(_13);
|
StorageDead(_13);
|
||||||
_11 = &(*_12);
|
- _11 = &(*_12);
|
||||||
_16 = PtrMetadata(copy _11);
|
- _16 = Len((*_11));
|
||||||
|
+ _16 = Len((*_12));
|
||||||
_17 = const 3_usize;
|
_17 = const 3_usize;
|
||||||
_18 = Ge(move _16, move _17);
|
_18 = Ge(move _16, move _17);
|
||||||
switchInt(move _18) -> [0: bb7, otherwise: bb6];
|
switchInt(move _18) -> [0: bb7, otherwise: bb6];
|
||||||
|
@ -136,7 +137,7 @@
|
||||||
|
|
||||||
bb8: {
|
bb8: {
|
||||||
- StorageDead(_12);
|
- StorageDead(_12);
|
||||||
StorageDead(_11);
|
- StorageDead(_11);
|
||||||
- StorageDead(_10);
|
- StorageDead(_10);
|
||||||
StorageLive(_22);
|
StorageLive(_22);
|
||||||
StorageLive(_23);
|
StorageLive(_23);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue