Auto merge of #66650 - matthewjasper:nonuniform-array-move, r=pnkfelix
Remove uniform array move MIR passes This PR fixes a number of bugs caused by limitations of this pass * Projections from constant indexes weren't being canonicalized * Constant indexes from the start weren't being canonicalized (they could have different min_lengths) * It didn't apply to non-moves This PR makes the following changes to support removing this pass: * ConstantIndex of arrays are now generated in a canonical form (from the start, min_length is the actual length). * Subslices are now split when generating move paths and when checking subslices have been moved. Additionally * The parent move path of a projection from an array element is now calculated correctly closes #66502
This commit is contained in:
commit
de0abf7599
32 changed files with 1141 additions and 641 deletions
|
|
@ -1714,18 +1714,25 @@ pub enum ProjectionElem<V, T> {
|
|||
ConstantIndex {
|
||||
/// index or -index (in Python terms), depending on from_end
|
||||
offset: u32,
|
||||
/// thing being indexed must be at least this long
|
||||
/// The thing being indexed must be at least this long. For arrays this
|
||||
/// is always the exact length.
|
||||
min_length: u32,
|
||||
/// counting backwards from end?
|
||||
/// Counting backwards from end? This is always false when indexing an
|
||||
/// array.
|
||||
from_end: bool,
|
||||
},
|
||||
|
||||
/// These indices are generated by slice patterns.
|
||||
///
|
||||
/// slice[from:-to] in Python terms.
|
||||
/// If `from_end` is true `slice[from..slice.len() - to]`.
|
||||
/// Otherwise `array[from..to]`.
|
||||
Subslice {
|
||||
from: u32,
|
||||
to: u32,
|
||||
/// Whether `to` counts from the start or end of the array/slice.
|
||||
/// For `PlaceElem`s this is `true` if and only if the base is a slice.
|
||||
/// For `ProjectionKind`, this can also be `true` for arrays.
|
||||
from_end: bool,
|
||||
},
|
||||
|
||||
/// "Downcast" to a variant of an ADT. Currently, we only introduce
|
||||
|
|
@ -1914,15 +1921,18 @@ impl Debug for Place<'_> {
|
|||
ProjectionElem::ConstantIndex { offset, min_length, from_end: true } => {
|
||||
write!(fmt, "[-{:?} of {:?}]", offset, min_length)?;
|
||||
}
|
||||
ProjectionElem::Subslice { from, to } if *to == 0 => {
|
||||
ProjectionElem::Subslice { from, to, from_end: true } if *to == 0 => {
|
||||
write!(fmt, "[{:?}:]", from)?;
|
||||
}
|
||||
ProjectionElem::Subslice { from, to } if *from == 0 => {
|
||||
ProjectionElem::Subslice { from, to, from_end: true } if *from == 0 => {
|
||||
write!(fmt, "[:-{:?}]", to)?;
|
||||
}
|
||||
ProjectionElem::Subslice { from, to } => {
|
||||
ProjectionElem::Subslice { from, to, from_end: true } => {
|
||||
write!(fmt, "[{:?}:-{:?}]", from, to)?;
|
||||
}
|
||||
ProjectionElem::Subslice { from, to, from_end: false } => {
|
||||
write!(fmt, "[{:?}..{:?}]", from, to)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2456,7 +2466,7 @@ impl UserTypeProjection {
|
|||
}
|
||||
|
||||
pub(crate) fn subslice(mut self, from: u32, to: u32) -> Self {
|
||||
self.projs.push(ProjectionElem::Subslice { from, to });
|
||||
self.projs.push(ProjectionElem::Subslice { from, to, from_end: true });
|
||||
self
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -88,14 +88,17 @@ impl<'tcx> PlaceTy<'tcx> {
|
|||
}
|
||||
ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } =>
|
||||
PlaceTy::from_ty(self.ty.builtin_index().unwrap()),
|
||||
ProjectionElem::Subslice { from, to } => {
|
||||
ProjectionElem::Subslice { from, to, from_end } => {
|
||||
PlaceTy::from_ty(match self.ty.kind {
|
||||
ty::Array(inner, size) => {
|
||||
ty::Slice(..) => self.ty,
|
||||
ty::Array(inner, _) if !from_end => {
|
||||
tcx.mk_array(inner, (to - from) as u64)
|
||||
}
|
||||
ty::Array(inner, size) if from_end => {
|
||||
let size = size.eval_usize(tcx, param_env);
|
||||
let len = size - (from as u64) - (to as u64);
|
||||
tcx.mk_array(inner, len)
|
||||
}
|
||||
ty::Slice(..) => self.ty,
|
||||
_ => {
|
||||
bug!("cannot subslice non-array type: `{:?}`", self)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -954,7 +954,7 @@ macro_rules! visit_place_fns {
|
|||
);
|
||||
}
|
||||
ProjectionElem::Deref |
|
||||
ProjectionElem::Subslice { from: _, to: _ } |
|
||||
ProjectionElem::Subslice { from: _, to: _, from_end: _ } |
|
||||
ProjectionElem::ConstantIndex { offset: _,
|
||||
min_length: _,
|
||||
from_end: _ } |
|
||||
|
|
|
|||
|
|
@ -565,7 +565,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
let llindex = bx.sub(lllen, lloffset);
|
||||
cg_base.project_index(bx, llindex)
|
||||
}
|
||||
mir::ProjectionElem::Subslice { from, to } => {
|
||||
mir::ProjectionElem::Subslice { from, to, from_end } => {
|
||||
let mut subslice = cg_base.project_index(bx,
|
||||
bx.cx().const_usize(*from as u64));
|
||||
let projected_ty = PlaceTy::from_ty(cg_base.layout.ty)
|
||||
|
|
@ -573,6 +573,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
subslice.layout = bx.cx().layout_of(self.monomorphize(&projected_ty));
|
||||
|
||||
if subslice.layout.is_unsized() {
|
||||
assert!(from_end, "slice subslices should be `from_end`");
|
||||
subslice.llextra = Some(bx.sub(cg_base.llextra.unwrap(),
|
||||
bx.cx().const_usize((*from as u64) + (*to as u64))));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,10 +78,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
.collect();
|
||||
|
||||
if move_out_indices.is_empty() {
|
||||
let root_place = self
|
||||
.prefixes(used_place, PrefixSet::All)
|
||||
.last()
|
||||
.unwrap();
|
||||
let root_place = PlaceRef { projection: &[], ..used_place };
|
||||
|
||||
if !self.uninitialized_error_reported.insert(root_place) {
|
||||
debug!(
|
||||
|
|
|
|||
|
|
@ -174,7 +174,7 @@ fn do_mir_borrowck<'a, 'tcx>(
|
|||
|
||||
let mut errors_buffer = Vec::new();
|
||||
let (move_data, move_errors): (MoveData<'tcx>, Option<Vec<(Place<'tcx>, MoveError<'tcx>)>>) =
|
||||
match MoveData::gather_moves(&body, tcx) {
|
||||
match MoveData::gather_moves(&body, tcx, param_env) {
|
||||
Ok(move_data) => (move_data, None),
|
||||
Err((move_data, move_errors)) => (move_data, Some(move_errors)),
|
||||
};
|
||||
|
|
@ -1600,7 +1600,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
(prefix, place_span.0, place_span.1),
|
||||
mpi,
|
||||
);
|
||||
return; // don't bother finding other problems.
|
||||
}
|
||||
}
|
||||
Err(NoMovePathFound::ReachedStatic) => {
|
||||
|
|
@ -1614,6 +1613,46 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Subslices correspond to multiple move paths, so we iterate through the
|
||||
/// elements of the base array. For each element we check
|
||||
///
|
||||
/// * Does this element overlap with our slice.
|
||||
/// * Is any part of it uninitialized.
|
||||
fn check_if_subslice_element_is_moved(
|
||||
&mut self,
|
||||
location: Location,
|
||||
desired_action: InitializationRequiringAction,
|
||||
place_span: (PlaceRef<'cx, 'tcx>, Span),
|
||||
maybe_uninits: &FlowAtLocation<'tcx, MaybeUninitializedPlaces<'cx, 'tcx>>,
|
||||
from: u32,
|
||||
to: u32,
|
||||
) {
|
||||
if let Some(mpi) = self.move_path_for_place(place_span.0) {
|
||||
let mut child = self.move_data.move_paths[mpi].first_child;
|
||||
while let Some(child_mpi) = child {
|
||||
let child_move_place = &self.move_data.move_paths[child_mpi];
|
||||
let child_place = &child_move_place.place;
|
||||
let last_proj = child_place.projection.last().unwrap();
|
||||
if let ProjectionElem::ConstantIndex { offset, from_end, .. } = last_proj {
|
||||
debug_assert!(!from_end, "Array constant indexing shouldn't be `from_end`.");
|
||||
|
||||
if (from..to).contains(offset) {
|
||||
if let Some(uninit_child) = maybe_uninits.has_any_child_of(child_mpi) {
|
||||
self.report_use_of_moved_or_uninitialized(
|
||||
location,
|
||||
desired_action,
|
||||
(place_span.0, place_span.0, place_span.1),
|
||||
uninit_child,
|
||||
);
|
||||
return; // don't bother finding other problems.
|
||||
}
|
||||
}
|
||||
}
|
||||
child = child_move_place.next_sibling;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_if_path_or_subpath_is_moved(
|
||||
&mut self,
|
||||
location: Location,
|
||||
|
|
@ -1640,6 +1679,30 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
|
||||
self.check_if_full_path_is_moved(location, desired_action, place_span, flow_state);
|
||||
|
||||
if let [
|
||||
base_proj @ ..,
|
||||
ProjectionElem::Subslice { from, to, from_end: false },
|
||||
] = place_span.0.projection {
|
||||
let place_ty = Place::ty_from(
|
||||
place_span.0.base,
|
||||
base_proj,
|
||||
self.body(),
|
||||
self.infcx.tcx,
|
||||
);
|
||||
if let ty::Array(..) = place_ty.ty.kind {
|
||||
let array_place = PlaceRef { base: place_span.0.base, projection: base_proj };
|
||||
self.check_if_subslice_element_is_moved(
|
||||
location,
|
||||
desired_action,
|
||||
(array_place, place_span.1),
|
||||
maybe_uninits,
|
||||
*from,
|
||||
*to,
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// A move of any shallow suffix of `place` also interferes
|
||||
// with an attempt to use `place`. This is scenario 3 above.
|
||||
//
|
||||
|
|
@ -1675,25 +1738,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
/// static variable, as we do not track those in the MoveData.
|
||||
fn move_path_closest_to(
|
||||
&mut self,
|
||||
place: PlaceRef<'cx, 'tcx>,
|
||||
place: PlaceRef<'_, 'tcx>,
|
||||
) -> Result<(PlaceRef<'cx, 'tcx>, MovePathIndex), NoMovePathFound> {
|
||||
let mut last_prefix = place.base;
|
||||
|
||||
for prefix in self.prefixes(place, PrefixSet::All) {
|
||||
if let Some(mpi) = self.move_path_for_place(prefix) {
|
||||
return Ok((prefix, mpi));
|
||||
}
|
||||
|
||||
last_prefix = prefix.base;
|
||||
}
|
||||
|
||||
match last_prefix {
|
||||
PlaceBase::Local(_) => panic!("should have move path for every Local"),
|
||||
PlaceBase::Static(_) => Err(NoMovePathFound::ReachedStatic),
|
||||
match self.move_data.rev_lookup.find(place) {
|
||||
LookupResult::Parent(Some(mpi))
|
||||
| LookupResult::Exact(mpi) => Ok((self.move_data.move_paths[mpi].place.as_ref(), mpi)),
|
||||
LookupResult::Parent(None) => Err(NoMovePathFound::ReachedStatic),
|
||||
}
|
||||
}
|
||||
|
||||
fn move_path_for_place(&mut self, place: PlaceRef<'cx, 'tcx>) -> Option<MovePathIndex> {
|
||||
fn move_path_for_place(&mut self, place: PlaceRef<'_, 'tcx>) -> Option<MovePathIndex> {
|
||||
// If returns None, then there is no move path corresponding
|
||||
// to a direct owner of `place` (which means there is nothing
|
||||
// that borrowck tracks for its analysis).
|
||||
|
|
|
|||
|
|
@ -675,23 +675,16 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
|||
}),
|
||||
)
|
||||
}
|
||||
ProjectionElem::Subslice { from, to } => PlaceTy::from_ty(
|
||||
ProjectionElem::Subslice { from, to, from_end } => PlaceTy::from_ty(
|
||||
match base_ty.kind {
|
||||
ty::Array(inner, size) => {
|
||||
let size = size.eval_usize(tcx, self.cx.param_env);
|
||||
let min_size = (from as u64) + (to as u64);
|
||||
if let Some(rest_size) = size.checked_sub(min_size) {
|
||||
tcx.mk_array(inner, rest_size)
|
||||
} else {
|
||||
span_mirbug_and_err!(
|
||||
self,
|
||||
place,
|
||||
"taking too-small slice of {:?}",
|
||||
base_ty
|
||||
)
|
||||
}
|
||||
ty::Array(inner, _) => {
|
||||
assert!(!from_end, "array subslices should not use from_end");
|
||||
tcx.mk_array(inner, (to - from) as u64)
|
||||
}
|
||||
ty::Slice(..) => base_ty,
|
||||
ty::Slice(..) => {
|
||||
assert!(from_end, "slice subslices should use from_end");
|
||||
base_ty
|
||||
},
|
||||
_ => span_mirbug_and_err!(self, place, "slice of non-array {:?}", base_ty),
|
||||
},
|
||||
),
|
||||
|
|
|
|||
|
|
@ -503,34 +503,62 @@ fn place_projection_conflict<'tcx>(
|
|||
Overlap::Disjoint
|
||||
}
|
||||
}
|
||||
(ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false },
|
||||
ProjectionElem::Subslice {from, .. })
|
||||
| (ProjectionElem::Subslice {from, .. },
|
||||
ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false }) => {
|
||||
if offset >= from {
|
||||
debug!(
|
||||
"place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-SUBSLICE");
|
||||
(
|
||||
ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false },
|
||||
ProjectionElem::Subslice { from, to, from_end: false }
|
||||
)
|
||||
| (
|
||||
ProjectionElem::Subslice { from, to, from_end: false },
|
||||
ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false }
|
||||
) => {
|
||||
if (from..to).contains(&offset) {
|
||||
debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-SUBSLICE");
|
||||
Overlap::EqualOrDisjoint
|
||||
} else {
|
||||
debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-SUBSLICE");
|
||||
Overlap::Disjoint
|
||||
}
|
||||
}
|
||||
(ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true },
|
||||
ProjectionElem::Subslice {from: _, to })
|
||||
| (ProjectionElem::Subslice {from: _, to },
|
||||
ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true }) => {
|
||||
if offset > to {
|
||||
debug!("place_element_conflict: \
|
||||
DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-SUBSLICE-FE");
|
||||
(ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false },
|
||||
ProjectionElem::Subslice {from, .. })
|
||||
| (ProjectionElem::Subslice {from, .. },
|
||||
ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false }) => {
|
||||
if offset >= from {
|
||||
debug!(
|
||||
"place_element_conflict: DISJOINT-OR-EQ-SLICE-CONSTANT-INDEX-SUBSLICE");
|
||||
Overlap::EqualOrDisjoint
|
||||
} else {
|
||||
debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-SUBSLICE-FE");
|
||||
debug!("place_element_conflict: DISJOINT-SLICE-CONSTANT-INDEX-SUBSLICE");
|
||||
Overlap::Disjoint
|
||||
}
|
||||
}
|
||||
(ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true },
|
||||
ProjectionElem::Subslice { to, from_end: true, .. })
|
||||
| (ProjectionElem::Subslice { to, from_end: true, .. },
|
||||
ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true }) => {
|
||||
if offset > to {
|
||||
debug!("place_element_conflict: \
|
||||
DISJOINT-OR-EQ-SLICE-CONSTANT-INDEX-SUBSLICE-FE");
|
||||
Overlap::EqualOrDisjoint
|
||||
} else {
|
||||
debug!("place_element_conflict: DISJOINT-SLICE-CONSTANT-INDEX-SUBSLICE-FE");
|
||||
Overlap::Disjoint
|
||||
}
|
||||
}
|
||||
(
|
||||
ProjectionElem::Subslice { from: f1, to: t1, from_end: false },
|
||||
ProjectionElem::Subslice { from: f2, to: t2, from_end: false }
|
||||
) => {
|
||||
if f2 >= t1 || f1 >= t2 {
|
||||
debug!("place_element_conflict: DISJOINT-ARRAY-SUBSLICES");
|
||||
Overlap::Disjoint
|
||||
} else {
|
||||
debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-SUBSLICES");
|
||||
Overlap::EqualOrDisjoint
|
||||
}
|
||||
}
|
||||
(ProjectionElem::Subslice { .. }, ProjectionElem::Subslice { .. }) => {
|
||||
debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-SUBSLICES");
|
||||
debug!("place_element_conflict: DISJOINT-OR-EQ-SLICE-SUBSLICES");
|
||||
Overlap::EqualOrDisjoint
|
||||
}
|
||||
(ProjectionElem::Deref, _)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ use crate::build::Builder;
|
|||
use crate::build::matches::MatchPair;
|
||||
use crate::hair::*;
|
||||
use rustc::mir::*;
|
||||
use rustc::ty;
|
||||
use smallvec::SmallVec;
|
||||
use std::u32;
|
||||
use std::convert::TryInto;
|
||||
|
|
@ -31,9 +32,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
prefix: &'pat [Pat<'tcx>],
|
||||
opt_slice: Option<&'pat Pat<'tcx>>,
|
||||
suffix: &'pat [Pat<'tcx>]) {
|
||||
let min_length = prefix.len() + suffix.len();
|
||||
let min_length = min_length.try_into().unwrap();
|
||||
let tcx = self.hir.tcx();
|
||||
let (min_length, exact_size) = match place.ty(&self.local_decls, tcx).ty.kind {
|
||||
ty::Array(_, length) => (
|
||||
length.eval_usize(tcx, self.hir.param_env).try_into().unwrap(),
|
||||
true
|
||||
),
|
||||
_ => (
|
||||
(prefix.len() + suffix.len()).try_into().unwrap(),
|
||||
false,
|
||||
),
|
||||
};
|
||||
|
||||
match_pairs.extend(
|
||||
prefix.iter()
|
||||
|
|
@ -50,10 +59,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
);
|
||||
|
||||
if let Some(subslice_pat) = opt_slice {
|
||||
let subslice = tcx.mk_place_elem(place.clone(),ProjectionElem::Subslice {
|
||||
from: prefix.len() as u32,
|
||||
to: suffix.len() as u32
|
||||
});
|
||||
let suffix_len = suffix.len() as u32;
|
||||
let subslice = tcx.mk_place_elem(
|
||||
place.clone(),
|
||||
ProjectionElem::Subslice {
|
||||
from: prefix.len() as u32,
|
||||
to: if exact_size { min_length - suffix_len } else { suffix_len },
|
||||
from_end: !exact_size,
|
||||
},
|
||||
);
|
||||
match_pairs.push(MatchPair::new(subslice, subslice_pat));
|
||||
}
|
||||
|
||||
|
|
@ -62,10 +76,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
.rev()
|
||||
.enumerate()
|
||||
.map(|(idx, subpattern)| {
|
||||
let end_offset = (idx + 1) as u32;
|
||||
let elem = ProjectionElem::ConstantIndex {
|
||||
offset: (idx+1) as u32,
|
||||
offset: if exact_size { min_length - end_offset } else { end_offset },
|
||||
min_length,
|
||||
from_end: true,
|
||||
from_end: !exact_size,
|
||||
};
|
||||
let place = tcx.mk_place_elem(place.clone(), elem);
|
||||
MatchPair::new(place, subpattern)
|
||||
|
|
|
|||
|
|
@ -49,8 +49,8 @@ impl<'tcx> Lift for PlaceElem<'tcx> {
|
|||
ProjectionElem::Deref => ProjectionElem::Deref,
|
||||
ProjectionElem::Field(ref f, ty) => ProjectionElem::Field(f.clone(), ty.lift()),
|
||||
ProjectionElem::Index(ref i) => ProjectionElem::Index(i.lift()),
|
||||
ProjectionElem::Subslice { from, to } => {
|
||||
ProjectionElem::Subslice { from: from, to: to }
|
||||
ProjectionElem::Subslice { from, to, from_end } => {
|
||||
ProjectionElem::Subslice { from, to, from_end }
|
||||
}
|
||||
ProjectionElem::ConstantIndex { offset, min_length, from_end } => {
|
||||
ProjectionElem::ConstantIndex { offset, min_length, from_end }
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use rustc::ty::{self, TyCtxt};
|
|||
use rustc_index::vec::IndexVec;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::convert::TryInto;
|
||||
use std::mem;
|
||||
|
||||
use super::abs_domain::Lift;
|
||||
|
|
@ -17,12 +17,13 @@ use super::{
|
|||
struct MoveDataBuilder<'a, 'tcx> {
|
||||
body: &'a Body<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
data: MoveData<'tcx>,
|
||||
errors: Vec<(Place<'tcx>, MoveError<'tcx>)>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
|
||||
fn new(body: &'a Body<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
|
||||
fn new(body: &'a Body<'tcx>, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
|
||||
let mut move_paths = IndexVec::new();
|
||||
let mut path_map = IndexVec::new();
|
||||
let mut init_path_map = IndexVec::new();
|
||||
|
|
@ -30,6 +31,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
|
|||
MoveDataBuilder {
|
||||
body,
|
||||
tcx,
|
||||
param_env,
|
||||
errors: Vec::new(),
|
||||
data: MoveData {
|
||||
moves: IndexVec::new(),
|
||||
|
|
@ -148,42 +150,47 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
|||
InteriorOfSliceOrArray { ty: place_ty, is_index: true },
|
||||
));
|
||||
}
|
||||
_ => {
|
||||
// FIXME: still badly broken
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
_ => {}
|
||||
};
|
||||
|
||||
let proj = &place.projection[..i+1];
|
||||
base = match self
|
||||
.builder
|
||||
.data
|
||||
.rev_lookup
|
||||
.projections
|
||||
.entry((base, elem.lift()))
|
||||
{
|
||||
Entry::Occupied(ent) => *ent.get(),
|
||||
Entry::Vacant(ent) => {
|
||||
let path = MoveDataBuilder::new_move_path(
|
||||
&mut self.builder.data.move_paths,
|
||||
&mut self.builder.data.path_map,
|
||||
&mut self.builder.data.init_path_map,
|
||||
Some(base),
|
||||
Place {
|
||||
base: place.base.clone(),
|
||||
projection: tcx.intern_place_elems(proj),
|
||||
},
|
||||
);
|
||||
ent.insert(path);
|
||||
path
|
||||
}
|
||||
};
|
||||
base = self.add_move_path(base, elem, |tcx| {
|
||||
Place {
|
||||
base: place.base.clone(),
|
||||
projection: tcx.intern_place_elems(&place.projection[..i+1]),
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Ok(base)
|
||||
}
|
||||
|
||||
fn add_move_path(
|
||||
&mut self,
|
||||
base: MovePathIndex,
|
||||
elem: &PlaceElem<'tcx>,
|
||||
mk_place: impl FnOnce(TyCtxt<'tcx>) -> Place<'tcx>,
|
||||
) -> MovePathIndex {
|
||||
let MoveDataBuilder {
|
||||
data: MoveData { rev_lookup, move_paths, path_map, init_path_map, .. },
|
||||
tcx,
|
||||
..
|
||||
} = self.builder;
|
||||
*rev_lookup.projections
|
||||
.entry((base, elem.lift()))
|
||||
.or_insert_with(move || {
|
||||
let path = MoveDataBuilder::new_move_path(
|
||||
move_paths,
|
||||
path_map,
|
||||
init_path_map,
|
||||
Some(base),
|
||||
mk_place(*tcx),
|
||||
);
|
||||
path
|
||||
})
|
||||
}
|
||||
|
||||
fn create_move_path(&mut self, place: &Place<'tcx>) {
|
||||
// This is an non-moving access (such as an overwrite or
|
||||
// drop), so this not being a valid move path is OK.
|
||||
|
|
@ -214,8 +221,9 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
|
|||
pub(super) fn gather_moves<'tcx>(
|
||||
body: &Body<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
) -> Result<MoveData<'tcx>, (MoveData<'tcx>, Vec<(Place<'tcx>, MoveError<'tcx>)>)> {
|
||||
let mut builder = MoveDataBuilder::new(body, tcx);
|
||||
let mut builder = MoveDataBuilder::new(body, tcx, param_env);
|
||||
|
||||
builder.gather_args();
|
||||
|
||||
|
|
@ -411,20 +419,67 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
|||
fn gather_move(&mut self, place: &Place<'tcx>) {
|
||||
debug!("gather_move({:?}, {:?})", self.loc, place);
|
||||
|
||||
let path = match self.move_path_for(place) {
|
||||
Ok(path) | Err(MoveError::UnionMove { path }) => path,
|
||||
Err(error @ MoveError::IllegalMove { .. }) => {
|
||||
self.builder.errors.push((place.clone(), error));
|
||||
return;
|
||||
if let [
|
||||
ref base @ ..,
|
||||
ProjectionElem::Subslice { from, to, from_end: false },
|
||||
] = **place.projection {
|
||||
// Split `Subslice` patterns into the corresponding list of
|
||||
// `ConstIndex` patterns. This is done to ensure that all move paths
|
||||
// are disjoint, which is expected by drop elaboration.
|
||||
let base_place = Place {
|
||||
base: place.base.clone(),
|
||||
projection: self.builder.tcx.intern_place_elems(base),
|
||||
};
|
||||
let base_path = match self.move_path_for(&base_place) {
|
||||
Ok(path) => path,
|
||||
Err(MoveError::UnionMove { path }) => {
|
||||
self.record_move(place, path);
|
||||
return;
|
||||
}
|
||||
Err(error @ MoveError::IllegalMove { .. }) => {
|
||||
self.builder.errors.push((base_place, error));
|
||||
return;
|
||||
}
|
||||
};
|
||||
let base_ty = base_place.ty(self.builder.body, self.builder.tcx).ty;
|
||||
let len: u32 = match base_ty.kind {
|
||||
ty::Array(_, size) => {
|
||||
let length = size.eval_usize(self.builder.tcx, self.builder.param_env);
|
||||
length.try_into().expect(
|
||||
"slice pattern of array with more than u32::MAX elements"
|
||||
)
|
||||
}
|
||||
_ => bug!("from_end: false slice pattern of non-array type"),
|
||||
};
|
||||
for offset in from..to {
|
||||
let elem = ProjectionElem::ConstantIndex {
|
||||
offset,
|
||||
min_length: len,
|
||||
from_end: false,
|
||||
};
|
||||
let path = self.add_move_path(
|
||||
base_path,
|
||||
&elem,
|
||||
|tcx| tcx.mk_place_elem(base_place.clone(), elem),
|
||||
);
|
||||
self.record_move(place, path);
|
||||
}
|
||||
};
|
||||
let move_out = self.builder.data.moves.push(MoveOut { path: path, source: self.loc });
|
||||
} else {
|
||||
match self.move_path_for(place) {
|
||||
Ok(path) | Err(MoveError::UnionMove { path }) => self.record_move(place, path),
|
||||
Err(error @ MoveError::IllegalMove { .. }) => {
|
||||
self.builder.errors.push((place.clone(), error));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn record_move(&mut self, place: &Place<'tcx>, path: MovePathIndex) {
|
||||
let move_out = self.builder.data.moves.push(MoveOut { path: path, source: self.loc });
|
||||
debug!(
|
||||
"gather_move({:?}, {:?}): adding move {:?} of {:?}",
|
||||
self.loc, place, move_out, path
|
||||
);
|
||||
|
||||
self.builder.data.path_map[path].push(move_out);
|
||||
self.builder.data.loc_map[self.loc].push(move_out);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use core::slice::Iter;
|
||||
use rustc::mir::*;
|
||||
use rustc::ty::{Ty, TyCtxt};
|
||||
use rustc::ty::{Ty, TyCtxt, ParamEnv};
|
||||
use rustc::util::nodemap::FxHashMap;
|
||||
use rustc_index::vec::{Enumerated, Idx, IndexVec};
|
||||
use smallvec::SmallVec;
|
||||
|
|
@ -318,8 +318,9 @@ impl<'tcx> MoveData<'tcx> {
|
|||
pub fn gather_moves(
|
||||
body: &Body<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ParamEnv<'tcx>,
|
||||
) -> Result<Self, (Self, Vec<(Place<'tcx>, MoveError<'tcx>)>)> {
|
||||
builder::gather_moves(body, tcx)
|
||||
builder::gather_moves(body, tcx, param_env)
|
||||
}
|
||||
|
||||
/// For the move path `mpi`, returns the root local variable (if any) that starts the path.
|
||||
|
|
|
|||
|
|
@ -451,9 +451,15 @@ where
|
|||
base: MPlaceTy<'tcx, M::PointerTag>,
|
||||
from: u64,
|
||||
to: u64,
|
||||
from_end: bool,
|
||||
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
|
||||
let len = base.len(self)?; // also asserts that we have a type where this makes sense
|
||||
assert!(from <= len - to);
|
||||
let actual_to = if from_end {
|
||||
assert!(from <= len - to);
|
||||
len - to
|
||||
} else {
|
||||
to
|
||||
};
|
||||
|
||||
// Not using layout method because that works with usize, and does not work with slices
|
||||
// (that have count 0 in their layout).
|
||||
|
|
@ -464,7 +470,7 @@ where
|
|||
};
|
||||
|
||||
// Compute meta and new layout
|
||||
let inner_len = len - to - from;
|
||||
let inner_len = actual_to - from;
|
||||
let (meta, ty) = match base.layout.ty.kind {
|
||||
// It is not nice to match on the type, but that seems to be the only way to
|
||||
// implement this.
|
||||
|
|
@ -528,8 +534,8 @@ where
|
|||
self.mplace_field(base, index)?
|
||||
}
|
||||
|
||||
Subslice { from, to } =>
|
||||
self.mplace_subslice(base, u64::from(from), u64::from(to))?,
|
||||
Subslice { from, to, from_end } =>
|
||||
self.mplace_subslice(base, u64::from(from), u64::from(to), from_end)?,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops {
|
|||
|
||||
let def_id = src.def_id();
|
||||
let param_env = tcx.param_env(src.def_id()).with_reveal_all();
|
||||
let move_data = match MoveData::gather_moves(body, tcx) {
|
||||
let move_data = match MoveData::gather_moves(body, tcx, param_env) {
|
||||
Ok(move_data) => move_data,
|
||||
Err(_) => bug!("No `move_errors` should be allowed in MIR borrowck"),
|
||||
};
|
||||
|
|
@ -234,12 +234,11 @@ impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> {
|
|||
|
||||
fn array_subpath(&self, path: Self::Path, index: u32, size: u32) -> Option<Self::Path> {
|
||||
dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e {
|
||||
ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false } => {
|
||||
ProjectionElem::ConstantIndex { offset, min_length, from_end } => {
|
||||
debug_assert!(size == *min_length, "min_length should be exact for arrays");
|
||||
assert!(!from_end, "from_end should not be used for array element ConstantIndex");
|
||||
*offset == index
|
||||
}
|
||||
ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true } => {
|
||||
size - offset == index
|
||||
}
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@ pub mod copy_prop;
|
|||
pub mod const_prop;
|
||||
pub mod generator;
|
||||
pub mod inline;
|
||||
pub mod uniform_array_move_out;
|
||||
pub mod uninhabited_enum_branching;
|
||||
|
||||
pub(crate) fn provide(providers: &mut Providers<'_>) {
|
||||
|
|
@ -229,7 +228,6 @@ fn mir_const(tcx: TyCtxt<'_>, def_id: DefId) -> &Steal<BodyAndCache<'_>> {
|
|||
// What we need to do constant evaluation.
|
||||
&simplify::SimplifyCfg::new("initial"),
|
||||
&rustc_peek::SanityCheck,
|
||||
&uniform_array_move_out::UniformArrayMoveOut,
|
||||
]);
|
||||
body.ensure_predecessors();
|
||||
tcx.alloc_steal_mir(body)
|
||||
|
|
@ -294,7 +292,6 @@ fn run_optimization_passes<'tcx>(
|
|||
// Optimizations begin.
|
||||
&uninhabited_enum_branching::UninhabitedEnumBranching,
|
||||
&simplify::SimplifyCfg::new("after-uninhabited-enum-branching"),
|
||||
&uniform_array_move_out::RestoreSubsliceArrayMoveOut::new(tcx),
|
||||
&inline::Inline,
|
||||
|
||||
// Lowering generator control-flow and variables
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ impl<'tcx> MirPass<'tcx> for SanityCheck {
|
|||
|
||||
let attributes = tcx.get_attrs(def_id);
|
||||
let param_env = tcx.param_env(def_id);
|
||||
let move_data = MoveData::gather_moves(body, tcx).unwrap();
|
||||
let move_data = MoveData::gather_moves(body, tcx, param_env).unwrap();
|
||||
let mdpe = MoveDataParamEnv { move_data: move_data, param_env: param_env };
|
||||
let dead_unwinds = BitSet::new_empty(body.basic_blocks().len());
|
||||
let flow_inits =
|
||||
|
|
|
|||
|
|
@ -1,381 +0,0 @@
|
|||
// This pass converts move out from array by Subslice and
|
||||
// ConstIndex{.., from_end: true} to ConstIndex move out(s) from begin
|
||||
// of array. It allows detect error by mir borrowck and elaborate
|
||||
// drops for array without additional work.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// let a = [ box 1,box 2, box 3];
|
||||
// if b {
|
||||
// let [_a.., _] = a;
|
||||
// } else {
|
||||
// let [.., _b] = a;
|
||||
// }
|
||||
//
|
||||
// mir statement _10 = move _2[:-1]; replaced by:
|
||||
// StorageLive(_12);
|
||||
// _12 = move _2[0 of 3];
|
||||
// StorageLive(_13);
|
||||
// _13 = move _2[1 of 3];
|
||||
// _10 = [move _12, move _13]
|
||||
// StorageDead(_12);
|
||||
// StorageDead(_13);
|
||||
//
|
||||
// and mir statement _11 = move _2[-1 of 1]; replaced by:
|
||||
// _11 = move _2[2 of 3];
|
||||
//
|
||||
// FIXME: integrate this transformation to the mir build
|
||||
|
||||
use rustc::ty;
|
||||
use rustc::ty::TyCtxt;
|
||||
use rustc::mir::*;
|
||||
use rustc::mir::visit::{Visitor, PlaceContext, NonUseContext};
|
||||
use rustc_index::vec::{IndexVec};
|
||||
use crate::transform::{MirPass, MirSource};
|
||||
use crate::util::patch::MirPatch;
|
||||
|
||||
pub struct UniformArrayMoveOut;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for UniformArrayMoveOut {
|
||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) {
|
||||
let mut patch = MirPatch::new(body);
|
||||
let param_env = tcx.param_env(src.def_id());
|
||||
{
|
||||
let read_only_cache = read_only!(body);
|
||||
let mut visitor
|
||||
= UniformArrayMoveOutVisitor{ body, patch: &mut patch, tcx, param_env};
|
||||
visitor.visit_body(read_only_cache);
|
||||
}
|
||||
patch.apply(body);
|
||||
}
|
||||
}
|
||||
|
||||
struct UniformArrayMoveOutVisitor<'a, 'tcx> {
|
||||
body: &'a Body<'tcx>,
|
||||
patch: &'a mut MirPatch<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for UniformArrayMoveOutVisitor<'a, 'tcx> {
|
||||
fn visit_assign(&mut self,
|
||||
dst_place: &Place<'tcx>,
|
||||
rvalue: &Rvalue<'tcx>,
|
||||
location: Location) {
|
||||
if let Rvalue::Use(Operand::Move(ref src_place)) = rvalue {
|
||||
if let &[ref proj_base @ .., elem] = src_place.projection.as_ref() {
|
||||
if let ProjectionElem::ConstantIndex{offset: _,
|
||||
min_length: _,
|
||||
from_end: false} = elem {
|
||||
// no need to transformation
|
||||
} else {
|
||||
let place_ty =
|
||||
Place::ty_from(&src_place.base, proj_base, self.body, self.tcx).ty;
|
||||
if let ty::Array(item_ty, const_size) = place_ty.kind {
|
||||
if let Some(size) = const_size.try_eval_usize(self.tcx, self.param_env) {
|
||||
assert!(size <= u32::max_value() as u64,
|
||||
"uniform array move out doesn't supported
|
||||
for array bigger then u32");
|
||||
self.uniform(
|
||||
location,
|
||||
dst_place,
|
||||
&src_place.base,
|
||||
&src_place.projection,
|
||||
item_ty,
|
||||
size as u32,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
self.super_assign(dst_place, rvalue, location)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> {
|
||||
fn uniform(&mut self,
|
||||
location: Location,
|
||||
dst_place: &Place<'tcx>,
|
||||
base: &PlaceBase<'tcx>,
|
||||
proj: &[PlaceElem<'tcx>],
|
||||
item_ty: &'tcx ty::TyS<'tcx>,
|
||||
size: u32) {
|
||||
if let [proj_base @ .., elem] = proj {
|
||||
match elem {
|
||||
// uniforms statements like_10 = move _2[:-1];
|
||||
ProjectionElem::Subslice{from, to} => {
|
||||
self.patch.make_nop(location);
|
||||
let temps : Vec<_> = (*from..(size-*to)).map(|i| {
|
||||
let temp =
|
||||
self.patch.new_temp(item_ty, self.body.source_info(location).span);
|
||||
self.patch.add_statement(location, StatementKind::StorageLive(temp));
|
||||
|
||||
let mut projection = proj_base.to_vec();
|
||||
projection.push(ProjectionElem::ConstantIndex {
|
||||
offset: i,
|
||||
min_length: size,
|
||||
from_end: false,
|
||||
});
|
||||
self.patch.add_assign(
|
||||
location,
|
||||
Place::from(temp),
|
||||
Rvalue::Use(Operand::Move(Place {
|
||||
base: base.clone(),
|
||||
projection: self.tcx.intern_place_elems(&projection),
|
||||
})),
|
||||
);
|
||||
temp
|
||||
}).collect();
|
||||
self.patch.add_assign(
|
||||
location,
|
||||
dst_place.clone(),
|
||||
Rvalue::Aggregate(
|
||||
box AggregateKind::Array(item_ty),
|
||||
temps.iter().map(
|
||||
|x| Operand::Move(Place::from(*x))
|
||||
).collect()
|
||||
)
|
||||
);
|
||||
for temp in temps {
|
||||
self.patch.add_statement(location, StatementKind::StorageDead(temp));
|
||||
}
|
||||
}
|
||||
// uniforms statements like _11 = move _2[-1 of 1];
|
||||
ProjectionElem::ConstantIndex{offset, min_length: _, from_end: true} => {
|
||||
self.patch.make_nop(location);
|
||||
|
||||
let mut projection = proj_base.to_vec();
|
||||
projection.push(ProjectionElem::ConstantIndex {
|
||||
offset: size - offset,
|
||||
min_length: size,
|
||||
from_end: false,
|
||||
});
|
||||
self.patch.add_assign(
|
||||
location,
|
||||
dst_place.clone(),
|
||||
Rvalue::Use(Operand::Move(Place {
|
||||
base: base.clone(),
|
||||
projection: self.tcx.intern_place_elems(&projection),
|
||||
})),
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Restore Subslice move out after analysis
|
||||
// Example:
|
||||
//
|
||||
// next statements:
|
||||
// StorageLive(_12);
|
||||
// _12 = move _2[0 of 3];
|
||||
// StorageLive(_13);
|
||||
// _13 = move _2[1 of 3];
|
||||
// _10 = [move _12, move _13]
|
||||
// StorageDead(_12);
|
||||
// StorageDead(_13);
|
||||
//
|
||||
// replaced by _10 = move _2[:-1];
|
||||
|
||||
pub struct RestoreSubsliceArrayMoveOut<'tcx> {
|
||||
tcx: TyCtxt<'tcx>
|
||||
}
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for RestoreSubsliceArrayMoveOut<'tcx> {
|
||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) {
|
||||
let mut patch = MirPatch::new(body);
|
||||
let param_env = tcx.param_env(src.def_id());
|
||||
{
|
||||
let read_only_cache = read_only!(body);
|
||||
let mut visitor = RestoreDataCollector {
|
||||
locals_use: IndexVec::from_elem(LocalUse::new(), &body.local_decls),
|
||||
candidates: vec![],
|
||||
};
|
||||
visitor.visit_body(read_only_cache);
|
||||
|
||||
for candidate in &visitor.candidates {
|
||||
let statement = &body[candidate.block].statements[candidate.statement_index];
|
||||
if let StatementKind::Assign(box(ref dst_place, ref rval)) = statement.kind {
|
||||
if let Rvalue::Aggregate(box AggregateKind::Array(_), ref items) = *rval {
|
||||
let items : Vec<_> = items.iter().map(|item| {
|
||||
if let Operand::Move(place) = item {
|
||||
if let Some(local) = place.as_local() {
|
||||
let local_use = &visitor.locals_use[local];
|
||||
let opt_index_and_place =
|
||||
Self::try_get_item_source(local_use, body);
|
||||
// each local should be used twice:
|
||||
// in assign and in aggregate statements
|
||||
if local_use.use_count == 2 && opt_index_and_place.is_some() {
|
||||
let (index, src_place) = opt_index_and_place.unwrap();
|
||||
return Some((local_use, index, src_place));
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}).collect();
|
||||
|
||||
let opt_src_place = items.first().and_then(|x| *x).map(|x| x.2);
|
||||
let opt_size = opt_src_place.and_then(|src_place| {
|
||||
let src_ty = Place::ty_from(
|
||||
src_place.base,
|
||||
src_place.projection,
|
||||
&**body,
|
||||
tcx
|
||||
).ty;
|
||||
if let ty::Array(_, ref size_o) = src_ty.kind {
|
||||
size_o.try_eval_usize(tcx, param_env)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
let restore_subslice = RestoreSubsliceArrayMoveOut { tcx };
|
||||
restore_subslice
|
||||
.check_and_patch(*candidate, &items, opt_size, &mut patch, dst_place);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
patch.apply(body);
|
||||
}
|
||||
}
|
||||
|
||||
impl RestoreSubsliceArrayMoveOut<'tcx> {
|
||||
pub fn new(tcx: TyCtxt<'tcx>) -> Self {
|
||||
RestoreSubsliceArrayMoveOut { tcx }
|
||||
}
|
||||
|
||||
// Checks that source has size, all locals are inited from same source place and
|
||||
// indices is an integer interval. If all checks pass do the replacent.
|
||||
// items are Vec<Option<LocalUse, index in source array, source place for init local>>
|
||||
fn check_and_patch(&self,
|
||||
candidate: Location,
|
||||
items: &[Option<(&LocalUse, u32, PlaceRef<'_, 'tcx>)>],
|
||||
opt_size: Option<u64>,
|
||||
patch: &mut MirPatch<'tcx>,
|
||||
dst_place: &Place<'tcx>) {
|
||||
let opt_src_place = items.first().and_then(|x| *x).map(|x| x.2);
|
||||
|
||||
if opt_size.is_some() && items.iter().all(
|
||||
|l| l.is_some() && l.unwrap().2 == opt_src_place.unwrap()) {
|
||||
let src_place = opt_src_place.unwrap();
|
||||
|
||||
let indices: Vec<_> = items.iter().map(|x| x.unwrap().1).collect();
|
||||
for i in 1..indices.len() {
|
||||
if indices[i - 1] + 1 != indices[i] {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let min = *indices.first().unwrap();
|
||||
let max = *indices.last().unwrap();
|
||||
|
||||
for item in items {
|
||||
let locals_use = item.unwrap().0;
|
||||
patch.make_nop(locals_use.alive.unwrap());
|
||||
patch.make_nop(locals_use.dead.unwrap());
|
||||
patch.make_nop(locals_use.first_use.unwrap());
|
||||
}
|
||||
patch.make_nop(candidate);
|
||||
let size = opt_size.unwrap() as u32;
|
||||
|
||||
let mut projection = src_place.projection.to_vec();
|
||||
projection.push(ProjectionElem::Subslice { from: min, to: size - max - 1 });
|
||||
patch.add_assign(
|
||||
candidate,
|
||||
dst_place.clone(),
|
||||
Rvalue::Use(Operand::Move(Place {
|
||||
base: src_place.base.clone(),
|
||||
projection: self.tcx.intern_place_elems(&projection),
|
||||
})),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn try_get_item_source<'a>(local_use: &LocalUse,
|
||||
body: &'a Body<'tcx>) -> Option<(u32, PlaceRef<'a, 'tcx>)> {
|
||||
if let Some(location) = local_use.first_use {
|
||||
let block = &body[location.block];
|
||||
if block.statements.len() > location.statement_index {
|
||||
let statement = &block.statements[location.statement_index];
|
||||
if let StatementKind::Assign(
|
||||
box(place, Rvalue::Use(Operand::Move(src_place)))
|
||||
) = &statement.kind {
|
||||
if let (Some(_), PlaceRef {
|
||||
base: _,
|
||||
projection: &[.., ProjectionElem::ConstantIndex {
|
||||
offset, min_length: _, from_end: false
|
||||
}],
|
||||
}) = (place.as_local(), src_place.as_ref()) {
|
||||
if let StatementKind::Assign(
|
||||
box(_, Rvalue::Use(Operand::Move(place)))
|
||||
) = &statement.kind {
|
||||
if let PlaceRef {
|
||||
base,
|
||||
projection: &[ref proj_base @ .., _],
|
||||
} = place.as_ref() {
|
||||
return Some((offset, PlaceRef {
|
||||
base,
|
||||
projection: proj_base,
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
struct LocalUse {
|
||||
alive: Option<Location>,
|
||||
dead: Option<Location>,
|
||||
use_count: u32,
|
||||
first_use: Option<Location>,
|
||||
}
|
||||
|
||||
impl LocalUse {
|
||||
pub fn new() -> Self {
|
||||
LocalUse{alive: None, dead: None, use_count: 0, first_use: None}
|
||||
}
|
||||
}
|
||||
|
||||
struct RestoreDataCollector {
|
||||
locals_use: IndexVec<Local, LocalUse>,
|
||||
candidates: Vec<Location>,
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for RestoreDataCollector {
|
||||
fn visit_assign(&mut self,
|
||||
place: &Place<'tcx>,
|
||||
rvalue: &Rvalue<'tcx>,
|
||||
location: Location) {
|
||||
if let Rvalue::Aggregate(box AggregateKind::Array(_), _) = *rvalue {
|
||||
self.candidates.push(location);
|
||||
}
|
||||
self.super_assign(place, rvalue, location)
|
||||
}
|
||||
|
||||
fn visit_local(&mut self,
|
||||
local: &Local,
|
||||
context: PlaceContext,
|
||||
location: Location) {
|
||||
let local_use = &mut self.locals_use[*local];
|
||||
match context {
|
||||
PlaceContext::NonUse(NonUseContext::StorageLive) => local_use.alive = Some(location),
|
||||
PlaceContext::NonUse(NonUseContext::StorageDead) => local_use.dead = Some(location),
|
||||
PlaceContext::NonUse(NonUseContext::VarDebugInfo) => {}
|
||||
_ => {
|
||||
local_use.use_count += 1;
|
||||
if local_use.first_use.is_none() {
|
||||
local_use.first_use = Some(location);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -21,9 +21,6 @@ fn main() {
|
|||
// _0 = move (_1.0: u32);
|
||||
// return;
|
||||
// }
|
||||
// bb2 (cleanup): {
|
||||
// resume;
|
||||
// }
|
||||
// }
|
||||
// END rustc.add.ConstProp.before.mir
|
||||
// START rustc.add.ConstProp.after.mir
|
||||
|
|
@ -38,9 +35,6 @@ fn main() {
|
|||
// _0 = const 4u32;
|
||||
// return;
|
||||
// }
|
||||
// bb2 (cleanup): {
|
||||
// resume;
|
||||
// }
|
||||
// }
|
||||
// END rustc.add.ConstProp.after.mir
|
||||
// START rustc.add.PreCodegen.before.mir
|
||||
|
|
|
|||
|
|
@ -18,58 +18,12 @@ fn main() {
|
|||
|
||||
// END RUST SOURCE
|
||||
|
||||
// START rustc.move_out_from_end.UniformArrayMoveOut.before.mir
|
||||
// StorageLive(_6);
|
||||
// _6 = move _1[-1 of 1];
|
||||
// _0 = ();
|
||||
// END rustc.move_out_from_end.UniformArrayMoveOut.before.mir
|
||||
|
||||
// START rustc.move_out_from_end.UniformArrayMoveOut.after.mir
|
||||
// StorageLive(_6);
|
||||
// START rustc.move_out_from_end.mir_map.0.mir
|
||||
// _6 = move _1[1 of 2];
|
||||
// nop;
|
||||
// _0 = ();
|
||||
// END rustc.move_out_from_end.UniformArrayMoveOut.after.mir
|
||||
// END rustc.move_out_from_end.mir_map.0.mir
|
||||
|
||||
// START rustc.move_out_by_subslice.UniformArrayMoveOut.before.mir
|
||||
// StorageLive(_6);
|
||||
// _6 = move _1[0:];
|
||||
// END rustc.move_out_by_subslice.UniformArrayMoveOut.before.mir
|
||||
|
||||
// START rustc.move_out_by_subslice.UniformArrayMoveOut.after.mir
|
||||
// StorageLive(_6);
|
||||
// StorageLive(_7);
|
||||
// _7 = move _1[0 of 2];
|
||||
// StorageLive(_8);
|
||||
// _8 = move _1[1 of 2];
|
||||
// _6 = [move _7, move _8];
|
||||
// StorageDead(_7);
|
||||
// StorageDead(_8);
|
||||
// nop;
|
||||
// START rustc.move_out_by_subslice.mir_map.0.mir
|
||||
// _6 = move _1[0..2];
|
||||
// _0 = ();
|
||||
// END rustc.move_out_by_subslice.UniformArrayMoveOut.after.mir
|
||||
|
||||
// START rustc.move_out_by_subslice.RestoreSubsliceArrayMoveOut.before.mir
|
||||
// StorageLive(_6);
|
||||
// StorageLive(_7);
|
||||
// _7 = move _1[0 of 2];
|
||||
// StorageLive(_8);
|
||||
// _8 = move _1[1 of 2];
|
||||
// _6 = [move _7, move _8];
|
||||
// StorageDead(_7);
|
||||
// StorageDead(_8);
|
||||
// _0 = ();
|
||||
// END rustc.move_out_by_subslice.RestoreSubsliceArrayMoveOut.before.mir
|
||||
|
||||
// START rustc.move_out_by_subslice.RestoreSubsliceArrayMoveOut.after.mir
|
||||
// StorageLive(_6);
|
||||
// nop;
|
||||
// nop;
|
||||
// nop;
|
||||
// nop;
|
||||
// _6 = move _1[0:];
|
||||
// nop;
|
||||
// nop;
|
||||
// nop;
|
||||
// _0 = ();
|
||||
// END rustc.move_out_by_subslice.RestoreSubsliceArrayMoveOut.after.mir
|
||||
// END rustc.move_out_by_subslice.mir_map.0.mir
|
||||
|
|
|
|||
|
|
@ -0,0 +1,69 @@
|
|||
// check-pass
|
||||
|
||||
#![feature(slice_patterns)]
|
||||
|
||||
fn array() -> [(String, String); 3] {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
// Const Index + Const Index
|
||||
|
||||
fn move_out_from_begin_and_one_from_end() {
|
||||
let a = array();
|
||||
let [_, _, _x] = a;
|
||||
let [.., _y, _] = a;
|
||||
}
|
||||
|
||||
fn move_out_from_begin_field_and_end_field() {
|
||||
let a = array();
|
||||
let [_, _, (_x, _)] = a;
|
||||
let [.., (_, _y)] = a;
|
||||
}
|
||||
|
||||
// Const Index + Slice
|
||||
|
||||
fn move_out_by_const_index_and_subslice() {
|
||||
let a = array();
|
||||
let [_x, _, _] = a;
|
||||
let [_, _y @ ..] = a;
|
||||
}
|
||||
|
||||
fn move_out_by_const_index_end_and_subslice() {
|
||||
let a = array();
|
||||
let [.., _x] = a;
|
||||
let [_y @ .., _] = a;
|
||||
}
|
||||
|
||||
fn move_out_by_const_index_field_and_subslice() {
|
||||
let a = array();
|
||||
let [(_x, _), _, _] = a;
|
||||
let [_, _y @ ..] = a;
|
||||
}
|
||||
|
||||
fn move_out_by_const_index_end_field_and_subslice() {
|
||||
let a = array();
|
||||
let [.., (_x, _)] = a;
|
||||
let [_y @ .., _] = a;
|
||||
}
|
||||
|
||||
fn move_out_by_const_subslice_and_index_field() {
|
||||
let a = array();
|
||||
let [_, _y @ ..] = a;
|
||||
let [(_x, _), _, _] = a;
|
||||
}
|
||||
|
||||
fn move_out_by_const_subslice_and_end_index_field() {
|
||||
let a = array();
|
||||
let [_y @ .., _] = a;
|
||||
let [.., (_x, _)] = a;
|
||||
}
|
||||
|
||||
// Slice + Slice
|
||||
|
||||
fn move_out_by_subslice_and_subslice() {
|
||||
let a = array();
|
||||
let [x @ .., _, _] = a;
|
||||
let [_, _y @ ..] = a;
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
// check-pass
|
||||
|
||||
#![feature(slice_patterns)]
|
||||
|
||||
fn array() -> [(String, String); 3] {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
// Const Index + Const Index
|
||||
|
||||
fn move_out_from_begin_and_one_from_end() {
|
||||
let a = array();
|
||||
let [_, _, _x] = a;
|
||||
let [.., ref _y, _] = a;
|
||||
}
|
||||
|
||||
fn move_out_from_begin_field_and_end_field() {
|
||||
let a = array();
|
||||
let [_, _, (_x, _)] = a;
|
||||
let [.., (_, ref _y)] = a;
|
||||
}
|
||||
|
||||
// Const Index + Slice
|
||||
|
||||
fn move_out_by_const_index_and_subslice() {
|
||||
let a = array();
|
||||
let [_x, _, _] = a;
|
||||
let [_, ref _y @ ..] = a;
|
||||
}
|
||||
|
||||
fn move_out_by_const_index_end_and_subslice() {
|
||||
let a = array();
|
||||
let [.., _x] = a;
|
||||
let [ref _y @ .., _] = a;
|
||||
}
|
||||
|
||||
fn move_out_by_const_index_field_and_subslice() {
|
||||
let a = array();
|
||||
let [(_x, _), _, _] = a;
|
||||
let [_, ref _y @ ..] = a;
|
||||
}
|
||||
|
||||
fn move_out_by_const_index_end_field_and_subslice() {
|
||||
let a = array();
|
||||
let [.., (_x, _)] = a;
|
||||
let [ref _y @ .., _] = a;
|
||||
}
|
||||
|
||||
fn move_out_by_const_subslice_and_index_field() {
|
||||
let a = array();
|
||||
let [_, _y @ ..] = a;
|
||||
let [(ref _x, _), _, _] = a;
|
||||
}
|
||||
|
||||
fn move_out_by_const_subslice_and_end_index_field() {
|
||||
let a = array();
|
||||
let [_y @ .., _] = a;
|
||||
let [.., (ref _x, _)] = a;
|
||||
}
|
||||
|
||||
// Slice + Slice
|
||||
|
||||
fn move_out_by_subslice_and_subslice() {
|
||||
let a = array();
|
||||
let [x @ .., _, _] = a;
|
||||
let [_, ref _y @ ..] = a;
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
99
src/test/ui/borrowck/borrowck-move-out-from-array-use.rs
Normal file
99
src/test/ui/borrowck/borrowck-move-out-from-array-use.rs
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
#![feature(slice_patterns)]
|
||||
|
||||
fn array() -> [(String, String); 3] {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
// Const Index + Const Index
|
||||
|
||||
fn move_out_from_begin_and_end() {
|
||||
let a = array();
|
||||
let [_, _, _x] = a;
|
||||
let [.., ref _y] = a; //~ ERROR [E0382]
|
||||
}
|
||||
|
||||
fn move_out_from_begin_field_and_end() {
|
||||
let a = array();
|
||||
let [_, _, (_x, _)] = a;
|
||||
let [.., ref _y] = a; //~ ERROR [E0382]
|
||||
}
|
||||
|
||||
fn move_out_from_begin_field_and_end_field() {
|
||||
let a = array();
|
||||
let [_, _, (_x, _)] = a;
|
||||
let [.., (ref _y, _)] = a; //~ ERROR [E0382]
|
||||
}
|
||||
|
||||
// Const Index + Slice
|
||||
|
||||
fn move_out_by_const_index_and_subslice() {
|
||||
let a = array();
|
||||
let [_x, _, _] = a;
|
||||
let [ref _y @ .., _, _] = a; //~ ERROR [E0382]
|
||||
}
|
||||
|
||||
fn move_out_by_const_index_end_and_subslice() {
|
||||
let a = array();
|
||||
let [.., _x] = a;
|
||||
let [_, _, ref _y @ ..] = a; //~ ERROR [E0382]
|
||||
}
|
||||
|
||||
fn move_out_by_const_index_field_and_subslice() {
|
||||
let a = array();
|
||||
let [(_x, _), _, _] = a;
|
||||
let [ref _y @ .., _, _] = a; //~ ERROR [E0382]
|
||||
}
|
||||
|
||||
fn move_out_by_const_index_end_field_and_subslice() {
|
||||
let a = array();
|
||||
let [.., (_x, _)] = a;
|
||||
let [_, _, ref _y @ ..] = a; //~ ERROR [E0382]
|
||||
}
|
||||
|
||||
fn move_out_by_subslice_and_const_index_field() {
|
||||
let a = array();
|
||||
let [_y @ .., _, _] = a;
|
||||
let [(ref _x, _), _, _] = a; //~ ERROR [E0382]
|
||||
}
|
||||
|
||||
fn move_out_by_subslice_and_const_index_end_field() {
|
||||
let a = array();
|
||||
let [_, _, _y @ ..] = a;
|
||||
let [.., (ref _x, _)] = a; //~ ERROR [E0382]
|
||||
}
|
||||
|
||||
// Slice + Slice
|
||||
|
||||
fn move_out_by_subslice_and_subslice() {
|
||||
let a = array();
|
||||
let [x @ .., _] = a;
|
||||
let [_, ref _y @ ..] = a; //~ ERROR [E0382]
|
||||
}
|
||||
|
||||
// Move + Assign
|
||||
|
||||
fn move_out_and_assign_end() {
|
||||
let mut a = array();
|
||||
let [_, _, _x] = a;
|
||||
a[2] = Default::default(); //~ ERROR [E0382]
|
||||
}
|
||||
|
||||
fn move_out_and_assign_end_field() {
|
||||
let mut a = array();
|
||||
let [_, _, (_x, _)] = a;
|
||||
a[2].1 = Default::default(); //~ ERROR [E0382]
|
||||
}
|
||||
|
||||
fn move_out_slice_and_assign_end() {
|
||||
let mut a = array();
|
||||
let [_, _, _x @ ..] = a;
|
||||
a[0] = Default::default(); //~ ERROR [E0382]
|
||||
}
|
||||
|
||||
fn move_out_slice_and_assign_end_field() {
|
||||
let mut a = array();
|
||||
let [_, _, _x @ ..] = a;
|
||||
a[0].1 = Default::default(); //~ ERROR [E0382]
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
143
src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr
Normal file
143
src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
error[E0382]: borrow of moved value: `a[..]`
|
||||
--> $DIR/borrowck-move-out-from-array-use.rs:12:14
|
||||
|
|
||||
LL | let [_, _, _x] = a;
|
||||
| -- value moved here
|
||||
LL | let [.., ref _y] = a;
|
||||
| ^^^^^^ value borrowed here after move
|
||||
|
|
||||
= note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: borrow of moved value: `a[..]`
|
||||
--> $DIR/borrowck-move-out-from-array-use.rs:18:14
|
||||
|
|
||||
LL | let [_, _, (_x, _)] = a;
|
||||
| -- value moved here
|
||||
LL | let [.., ref _y] = a;
|
||||
| ^^^^^^ value borrowed here after partial move
|
||||
|
|
||||
= note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: borrow of moved value: `a[..].0`
|
||||
--> $DIR/borrowck-move-out-from-array-use.rs:24:15
|
||||
|
|
||||
LL | let [_, _, (_x, _)] = a;
|
||||
| -- value moved here
|
||||
LL | let [.., (ref _y, _)] = a;
|
||||
| ^^^^^^ value borrowed here after move
|
||||
|
|
||||
= note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: borrow of moved value: `a`
|
||||
--> $DIR/borrowck-move-out-from-array-use.rs:32:10
|
||||
|
|
||||
LL | let [_x, _, _] = a;
|
||||
| -- value moved here
|
||||
LL | let [ref _y @ .., _, _] = a;
|
||||
| ^^^^^^^^^^^ value borrowed here after partial move
|
||||
|
|
||||
= note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: borrow of moved value: `a`
|
||||
--> $DIR/borrowck-move-out-from-array-use.rs:38:16
|
||||
|
|
||||
LL | let [.., _x] = a;
|
||||
| -- value moved here
|
||||
LL | let [_, _, ref _y @ ..] = a;
|
||||
| ^^^^^^^^^^^ value borrowed here after partial move
|
||||
|
|
||||
= note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: borrow of moved value: `a`
|
||||
--> $DIR/borrowck-move-out-from-array-use.rs:44:10
|
||||
|
|
||||
LL | let [(_x, _), _, _] = a;
|
||||
| -- value moved here
|
||||
LL | let [ref _y @ .., _, _] = a;
|
||||
| ^^^^^^^^^^^ value borrowed here after partial move
|
||||
|
|
||||
= note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: borrow of moved value: `a`
|
||||
--> $DIR/borrowck-move-out-from-array-use.rs:50:16
|
||||
|
|
||||
LL | let [.., (_x, _)] = a;
|
||||
| -- value moved here
|
||||
LL | let [_, _, ref _y @ ..] = a;
|
||||
| ^^^^^^^^^^^ value borrowed here after partial move
|
||||
|
|
||||
= note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: borrow of moved value: `a[..]`
|
||||
--> $DIR/borrowck-move-out-from-array-use.rs:56:11
|
||||
|
|
||||
LL | let [_y @ .., _, _] = a;
|
||||
| ------- value moved here
|
||||
LL | let [(ref _x, _), _, _] = a;
|
||||
| ^^^^^^ value borrowed here after move
|
||||
|
|
||||
= note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: borrow of moved value: `a[..]`
|
||||
--> $DIR/borrowck-move-out-from-array-use.rs:62:15
|
||||
|
|
||||
LL | let [_, _, _y @ ..] = a;
|
||||
| ------- value moved here
|
||||
LL | let [.., (ref _x, _)] = a;
|
||||
| ^^^^^^ value borrowed here after move
|
||||
|
|
||||
= note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: borrow of moved value: `a`
|
||||
--> $DIR/borrowck-move-out-from-array-use.rs:70:13
|
||||
|
|
||||
LL | let [x @ .., _] = a;
|
||||
| ------ value moved here
|
||||
LL | let [_, ref _y @ ..] = a;
|
||||
| ^^^^^^^^^^^ value borrowed here after partial move
|
||||
|
|
||||
= note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: use of moved value: `a`
|
||||
--> $DIR/borrowck-move-out-from-array-use.rs:78:5
|
||||
|
|
||||
LL | let [_, _, _x] = a;
|
||||
| -- value moved here
|
||||
LL | a[2] = Default::default();
|
||||
| ^^^^ value used here after partial move
|
||||
|
|
||||
= note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: use of moved value: `a`
|
||||
--> $DIR/borrowck-move-out-from-array-use.rs:84:5
|
||||
|
|
||||
LL | let [_, _, (_x, _)] = a;
|
||||
| -- value moved here
|
||||
LL | a[2].1 = Default::default();
|
||||
| ^^^^ value used here after partial move
|
||||
|
|
||||
= note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: use of moved value: `a`
|
||||
--> $DIR/borrowck-move-out-from-array-use.rs:90:5
|
||||
|
|
||||
LL | let [_, _, _x @ ..] = a;
|
||||
| ------- value moved here
|
||||
LL | a[0] = Default::default();
|
||||
| ^^^^ value used here after partial move
|
||||
|
|
||||
= note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: use of moved value: `a`
|
||||
--> $DIR/borrowck-move-out-from-array-use.rs:96:5
|
||||
|
|
||||
LL | let [_, _, _x @ ..] = a;
|
||||
| ------- value moved here
|
||||
LL | a[0].1 = Default::default();
|
||||
| ^^^^ value used here after partial move
|
||||
|
|
||||
= note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to 14 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0382`.
|
||||
|
|
@ -1,16 +1,73 @@
|
|||
#![feature(box_syntax)]
|
||||
#![feature(slice_patterns)]
|
||||
|
||||
fn array() -> [(String, String); 3] {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
// Const Index + Const Index
|
||||
|
||||
fn move_out_from_begin_and_end() {
|
||||
let a = [box 1, box 2];
|
||||
let [_, _x] = a;
|
||||
let a = array();
|
||||
let [_, _, _x] = a;
|
||||
let [.., _y] = a; //~ ERROR [E0382]
|
||||
}
|
||||
|
||||
fn move_out_from_begin_field_and_end() {
|
||||
let a = array();
|
||||
let [_, _, (_x, _)] = a;
|
||||
let [.., _y] = a; //~ ERROR [E0382]
|
||||
}
|
||||
|
||||
fn move_out_from_begin_field_and_end_field() {
|
||||
let a = array();
|
||||
let [_, _, (_x, _)] = a;
|
||||
let [.., (_y, _)] = a; //~ ERROR [E0382]
|
||||
}
|
||||
|
||||
// Const Index + Slice
|
||||
|
||||
fn move_out_by_const_index_and_subslice() {
|
||||
let a = [box 1, box 2];
|
||||
let [_x, _] = a;
|
||||
let [_y @ ..] = a; //~ ERROR [E0382]
|
||||
let a = array();
|
||||
let [_x, _, _] = a;
|
||||
let [_y @ .., _, _] = a; //~ ERROR [E0382]
|
||||
}
|
||||
|
||||
fn move_out_by_const_index_end_and_subslice() {
|
||||
let a = array();
|
||||
let [.., _x] = a;
|
||||
let [_, _, _y @ ..] = a; //~ ERROR [E0382]
|
||||
}
|
||||
|
||||
fn move_out_by_const_index_field_and_subslice() {
|
||||
let a = array();
|
||||
let [(_x, _), _, _] = a;
|
||||
let [_y @ .., _, _] = a; //~ ERROR [E0382]
|
||||
}
|
||||
|
||||
fn move_out_by_const_index_end_field_and_subslice() {
|
||||
let a = array();
|
||||
let [.., (_x, _)] = a;
|
||||
let [_, _, _y @ ..] = a; //~ ERROR [E0382]
|
||||
}
|
||||
|
||||
fn move_out_by_subslice_and_const_index_field() {
|
||||
let a = array();
|
||||
let [_y @ .., _, _] = a;
|
||||
let [(_x, _), _, _] = a; //~ ERROR [E0382]
|
||||
}
|
||||
|
||||
fn move_out_by_subslice_and_const_index_end_field() {
|
||||
let a = array();
|
||||
let [_, _, _y @ ..] = a;
|
||||
let [.., (_x, _)] = a; //~ ERROR [E0382]
|
||||
}
|
||||
|
||||
// Slice + Slice
|
||||
|
||||
fn move_out_by_subslice_and_subslice() {
|
||||
let a = array();
|
||||
let [x @ .., _] = a;
|
||||
let [_, _y @ ..] = a; //~ ERROR [E0382]
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -1,23 +1,103 @@
|
|||
error[E0382]: use of moved value: `a[..]`
|
||||
--> $DIR/borrowck-move-out-from-array.rs:7:14
|
||||
--> $DIR/borrowck-move-out-from-array.rs:12:14
|
||||
|
|
||||
LL | let [_, _x] = a;
|
||||
| -- value moved here
|
||||
LL | let [_, _, _x] = a;
|
||||
| -- value moved here
|
||||
LL | let [.., _y] = a;
|
||||
| ^^ value used here after move
|
||||
|
|
||||
= note: move occurs because `a[..]` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait
|
||||
= note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: use of moved value: `a[..]`
|
||||
--> $DIR/borrowck-move-out-from-array.rs:13:10
|
||||
--> $DIR/borrowck-move-out-from-array.rs:18:14
|
||||
|
|
||||
LL | let [_x, _] = a;
|
||||
| -- value moved here
|
||||
LL | let [_y @ ..] = a;
|
||||
| ^^^^^^^ value used here after move
|
||||
LL | let [_, _, (_x, _)] = a;
|
||||
| -- value moved here
|
||||
LL | let [.., _y] = a;
|
||||
| ^^ value used here after partial move
|
||||
|
|
||||
= note: move occurs because `a[..]` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait
|
||||
= note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error[E0382]: use of moved value: `a[..].0`
|
||||
--> $DIR/borrowck-move-out-from-array.rs:24:15
|
||||
|
|
||||
LL | let [_, _, (_x, _)] = a;
|
||||
| -- value moved here
|
||||
LL | let [.., (_y, _)] = a;
|
||||
| ^^ value used here after move
|
||||
|
|
||||
= note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: use of moved value: `a`
|
||||
--> $DIR/borrowck-move-out-from-array.rs:32:10
|
||||
|
|
||||
LL | let [_x, _, _] = a;
|
||||
| -- value moved here
|
||||
LL | let [_y @ .., _, _] = a;
|
||||
| ^^^^^^^ value used here after partial move
|
||||
|
|
||||
= note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: use of moved value: `a`
|
||||
--> $DIR/borrowck-move-out-from-array.rs:38:16
|
||||
|
|
||||
LL | let [.., _x] = a;
|
||||
| -- value moved here
|
||||
LL | let [_, _, _y @ ..] = a;
|
||||
| ^^^^^^^ value used here after partial move
|
||||
|
|
||||
= note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: use of moved value: `a`
|
||||
--> $DIR/borrowck-move-out-from-array.rs:44:10
|
||||
|
|
||||
LL | let [(_x, _), _, _] = a;
|
||||
| -- value moved here
|
||||
LL | let [_y @ .., _, _] = a;
|
||||
| ^^^^^^^ value used here after partial move
|
||||
|
|
||||
= note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: use of moved value: `a`
|
||||
--> $DIR/borrowck-move-out-from-array.rs:50:16
|
||||
|
|
||||
LL | let [.., (_x, _)] = a;
|
||||
| -- value moved here
|
||||
LL | let [_, _, _y @ ..] = a;
|
||||
| ^^^^^^^ value used here after partial move
|
||||
|
|
||||
= note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: use of moved value: `a[..].0`
|
||||
--> $DIR/borrowck-move-out-from-array.rs:56:11
|
||||
|
|
||||
LL | let [_y @ .., _, _] = a;
|
||||
| ------- value moved here
|
||||
LL | let [(_x, _), _, _] = a;
|
||||
| ^^ value used here after move
|
||||
|
|
||||
= note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: use of moved value: `a[..].0`
|
||||
--> $DIR/borrowck-move-out-from-array.rs:62:15
|
||||
|
|
||||
LL | let [_, _, _y @ ..] = a;
|
||||
| ------- value moved here
|
||||
LL | let [.., (_x, _)] = a;
|
||||
| ^^ value used here after move
|
||||
|
|
||||
= note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: use of moved value: `a`
|
||||
--> $DIR/borrowck-move-out-from-array.rs:70:13
|
||||
|
|
||||
LL | let [x @ .., _] = a;
|
||||
| ------ value moved here
|
||||
LL | let [_, _y @ ..] = a;
|
||||
| ^^^^^^^ value used here after partial move
|
||||
|
|
||||
= note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to 10 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0382`.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,66 @@
|
|||
// check-pass
|
||||
|
||||
#![feature(slice_patterns)]
|
||||
|
||||
fn nop(_s: &[& i32]) {}
|
||||
fn nop_subslice(_s: &[i32]) {}
|
||||
|
||||
fn const_index_ok(s: &mut [i32; 4]) {
|
||||
let [ref first, ref second, _, ref fourth, ..] = *s;
|
||||
let [_, _, ref mut third, ..] = *s;
|
||||
nop(&[first, second, third, fourth]);
|
||||
}
|
||||
|
||||
fn const_index_from_end_ok(s: &mut [i32; 4]) {
|
||||
let [.., ref fourth, ref third, _, ref first] = *s;
|
||||
let [.., ref mut second, _] = *s;
|
||||
nop(&[first, second, third, fourth]);
|
||||
}
|
||||
|
||||
fn const_index_mixed(s: &mut [i32; 6]) {
|
||||
let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s;
|
||||
|
||||
let [ref mut from_begin0, ..] = *s;
|
||||
nop(&[from_begin0, from_end1, from_end3, from_end4]);
|
||||
let [_, ref mut from_begin1, ..] = *s;
|
||||
nop(&[from_begin1, from_end1, from_end3, from_end4]);
|
||||
|
||||
let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s;
|
||||
|
||||
let [.., ref mut from_end1] = *s;
|
||||
nop(&[from_begin0, from_begin1, from_begin3, from_end1]);
|
||||
let [.., ref mut from_end2, _] = *s;
|
||||
nop(&[from_begin0, from_begin1, from_begin3, from_end2]);
|
||||
let [.., ref mut from_end4, _, _, _] = *s;
|
||||
nop(&[from_begin0, from_begin1, from_begin3, from_end4]);
|
||||
}
|
||||
|
||||
fn const_index_and_subslice_ok(s: &mut [i32; 4]) {
|
||||
let [ref first, ref second, ..] = *s;
|
||||
let [_, _, ref mut tail @ ..] = *s;
|
||||
nop(&[first, second]);
|
||||
nop_subslice(tail);
|
||||
}
|
||||
|
||||
fn const_index_and_subslice_from_end_ok(s: &mut [i32; 4]) {
|
||||
let [.., ref second, ref first] = *s;
|
||||
let [ref mut tail @ .., _, _] = *s;
|
||||
nop(&[first, second]);
|
||||
nop_subslice(tail);
|
||||
}
|
||||
|
||||
fn subslices(s: &mut [i32; 4]) {
|
||||
let [_, _, ref s1 @ ..] = *s;
|
||||
let [ref mut s2 @ .., _, _] = *s;
|
||||
nop_subslice(s1);
|
||||
nop_subslice(s2);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut v = [1,2,3,4];
|
||||
const_index_ok(&mut v);
|
||||
const_index_from_end_ok(&mut v);
|
||||
const_index_and_subslice_ok(&mut v);
|
||||
const_index_and_subslice_from_end_ok(&mut v);
|
||||
subslices(&mut v);
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
#![feature(slice_patterns)]
|
||||
|
||||
fn nop(_s: &[& i32]) {}
|
||||
fn nop_subslice(_s: &[i32]) {}
|
||||
|
||||
fn const_index_err(s: &mut [i32; 4]) {
|
||||
let [ref first, ref second, ..] = *s;
|
||||
let [_, ref mut second2, ref mut third, ..] = *s; //~ERROR
|
||||
nop(&[first, second, second2, third]);
|
||||
}
|
||||
|
||||
fn const_index_from_end_err(s: &mut [i32; 4]) {
|
||||
let [.., ref fourth, ref third, _, ref first] = *s;
|
||||
let [.., ref mut third2, _, _] = *s; //~ERROR
|
||||
nop(&[first, third, third2, fourth]);
|
||||
}
|
||||
|
||||
fn const_index_mixed(s: &mut [i32; 6]) {
|
||||
let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s;
|
||||
|
||||
let [_, _, ref mut from_begin2, ..] = *s; //~ERROR
|
||||
nop(&[from_begin2, from_end1, from_end3, from_end4]);
|
||||
let [_, _, _, ref mut from_begin3, ..] = *s; //~ERROR
|
||||
nop(&[from_begin3, from_end1, from_end3, from_end4]);
|
||||
|
||||
let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s;
|
||||
|
||||
let [.., ref mut from_end3, _, _] = *s; //~ERROR
|
||||
nop(&[from_begin0, from_begin1, from_begin3, from_end3]);
|
||||
}
|
||||
|
||||
fn const_index_and_subslice_err(s: &mut [i32; 4]) {
|
||||
let [ref first, ref second, ..] = *s;
|
||||
let [_, ref mut tail @ ..] = *s; //~ERROR
|
||||
nop(&[first, second]);
|
||||
nop_subslice(tail);
|
||||
}
|
||||
|
||||
fn const_index_and_subslice_from_end_err(s: &mut [i32; 4]) {
|
||||
let [.., ref second, ref first] = *s;
|
||||
let [ref mut tail @ .., _] = *s; //~ERROR
|
||||
nop(&[first, second]);
|
||||
nop_subslice(tail);
|
||||
}
|
||||
|
||||
fn subslices_overlap(s: &mut [i32; 4]) {
|
||||
let [_, ref s1 @ ..] = *s;
|
||||
let [ref mut s2 @ .., _, _] = *s; //~ERROR
|
||||
nop_subslice(s1);
|
||||
nop_subslice(s2);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut v = [1,2,3,4];
|
||||
const_index_err(&mut v);
|
||||
const_index_from_end_err(&mut v);
|
||||
const_index_and_subslice_err(&mut v);
|
||||
const_index_and_subslice_from_end_err(&mut v);
|
||||
subslices_overlap(&mut v);
|
||||
}
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
|
||||
--> $DIR/borrowck-slice-pattern-element-loan-array.rs:8:13
|
||||
|
|
||||
LL | let [ref first, ref second, ..] = *s;
|
||||
| ---------- immutable borrow occurs here
|
||||
LL | let [_, ref mut second2, ref mut third, ..] = *s;
|
||||
| ^^^^^^^^^^^^^^^^ mutable borrow occurs here
|
||||
LL | nop(&[first, second, second2, third]);
|
||||
| ------ immutable borrow later used here
|
||||
|
||||
error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
|
||||
--> $DIR/borrowck-slice-pattern-element-loan-array.rs:14:14
|
||||
|
|
||||
LL | let [.., ref fourth, ref third, _, ref first] = *s;
|
||||
| --------- immutable borrow occurs here
|
||||
LL | let [.., ref mut third2, _, _] = *s;
|
||||
| ^^^^^^^^^^^^^^ mutable borrow occurs here
|
||||
LL | nop(&[first, third, third2, fourth]);
|
||||
| ----- immutable borrow later used here
|
||||
|
||||
error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
|
||||
--> $DIR/borrowck-slice-pattern-element-loan-array.rs:21:16
|
||||
|
|
||||
LL | let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s;
|
||||
| ------------- immutable borrow occurs here
|
||||
LL |
|
||||
LL | let [_, _, ref mut from_begin2, ..] = *s;
|
||||
| ^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
|
||||
LL | nop(&[from_begin2, from_end1, from_end3, from_end4]);
|
||||
| --------- immutable borrow later used here
|
||||
|
||||
error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
|
||||
--> $DIR/borrowck-slice-pattern-element-loan-array.rs:23:19
|
||||
|
|
||||
LL | let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s;
|
||||
| ------------- immutable borrow occurs here
|
||||
...
|
||||
LL | let [_, _, _, ref mut from_begin3, ..] = *s;
|
||||
| ^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
|
||||
LL | nop(&[from_begin3, from_end1, from_end3, from_end4]);
|
||||
| --------- immutable borrow later used here
|
||||
|
||||
error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
|
||||
--> $DIR/borrowck-slice-pattern-element-loan-array.rs:28:14
|
||||
|
|
||||
LL | let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s;
|
||||
| --------------- immutable borrow occurs here
|
||||
LL |
|
||||
LL | let [.., ref mut from_end3, _, _] = *s;
|
||||
| ^^^^^^^^^^^^^^^^^ mutable borrow occurs here
|
||||
LL | nop(&[from_begin0, from_begin1, from_begin3, from_end3]);
|
||||
| ----------- immutable borrow later used here
|
||||
|
||||
error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
|
||||
--> $DIR/borrowck-slice-pattern-element-loan-array.rs:34:13
|
||||
|
|
||||
LL | let [ref first, ref second, ..] = *s;
|
||||
| ---------- immutable borrow occurs here
|
||||
LL | let [_, ref mut tail @ ..] = *s;
|
||||
| ^^^^^^^^^^^^^^^^^ mutable borrow occurs here
|
||||
LL | nop(&[first, second]);
|
||||
| ------ immutable borrow later used here
|
||||
|
||||
error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
|
||||
--> $DIR/borrowck-slice-pattern-element-loan-array.rs:41:10
|
||||
|
|
||||
LL | let [.., ref second, ref first] = *s;
|
||||
| ---------- immutable borrow occurs here
|
||||
LL | let [ref mut tail @ .., _] = *s;
|
||||
| ^^^^^^^^^^^^^^^^^ mutable borrow occurs here
|
||||
LL | nop(&[first, second]);
|
||||
| ------ immutable borrow later used here
|
||||
|
||||
error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
|
||||
--> $DIR/borrowck-slice-pattern-element-loan-array.rs:48:10
|
||||
|
|
||||
LL | let [_, ref s1 @ ..] = *s;
|
||||
| ----------- immutable borrow occurs here
|
||||
LL | let [ref mut s2 @ .., _, _] = *s;
|
||||
| ^^^^^^^^^^^^^^^ mutable borrow occurs here
|
||||
LL | nop_subslice(s1);
|
||||
| -- immutable borrow later used here
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0502`.
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
// check-pass
|
||||
|
||||
#![feature(slice_patterns)]
|
||||
|
||||
fn nop(_s: &[& i32]) {}
|
||||
fn nop_subslice(_s: &[i32]) {}
|
||||
|
||||
fn const_index_ok(s: &mut [i32]) {
|
||||
if let [ref first, ref second, _, ref fourth, ..] = *s {
|
||||
if let [_, _, ref mut third, ..] = *s {
|
||||
nop(&[first, second, third, fourth]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn const_index_from_end_ok(s: &mut [i32]) {
|
||||
if let [.., ref fourth, ref third, _, ref first] = *s {
|
||||
if let [.., ref mut second, _] = *s {
|
||||
nop(&[first, second, third, fourth]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn const_index_mixed(s: &mut [i32]) {
|
||||
if let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s {
|
||||
if let [ref mut from_begin0, ..] = *s {
|
||||
nop(&[from_begin0, from_end1, from_end3, from_end4]);
|
||||
}
|
||||
}
|
||||
if let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s {
|
||||
if let [.., ref mut from_end1] = *s {
|
||||
nop(&[from_begin0, from_begin1, from_begin3, from_end1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn const_index_and_subslice_ok(s: &mut [i32]) {
|
||||
if let [ref first, ref second, ..] = *s {
|
||||
if let [_, _, ref mut tail @ ..] = *s {
|
||||
nop(&[first, second]);
|
||||
nop_subslice(tail);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn const_index_and_subslice_from_end_ok(s: &mut [i32]) {
|
||||
if let [.., ref second, ref first] = *s {
|
||||
if let [ref mut tail @ .., _, _] = *s {
|
||||
nop(&[first, second]);
|
||||
nop_subslice(tail);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut v = [1,2,3,4];
|
||||
const_index_ok(&mut v);
|
||||
const_index_from_end_ok(&mut v);
|
||||
const_index_and_subslice_ok(&mut v);
|
||||
const_index_and_subslice_from_end_ok(&mut v);
|
||||
}
|
||||
|
|
@ -1,18 +1,8 @@
|
|||
//compile-flags: -Z borrowck=mir
|
||||
|
||||
#![feature(slice_patterns)]
|
||||
|
||||
fn nop(_s: &[& i32]) {}
|
||||
fn nop_subslice(_s: &[i32]) {}
|
||||
|
||||
fn const_index_ok(s: &mut [i32]) {
|
||||
if let [ref first, ref second, _, ref fourth, ..] = *s {
|
||||
if let [_, _, ref mut third, ..] = *s {
|
||||
nop(&[first, second, third, fourth]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn const_index_err(s: &mut [i32]) {
|
||||
if let [ref first, ref second, ..] = *s {
|
||||
if let [_, ref mut second2, ref mut third, ..] = *s { //~ERROR
|
||||
|
|
@ -21,14 +11,6 @@ fn const_index_err(s: &mut [i32]) {
|
|||
}
|
||||
}
|
||||
|
||||
fn const_index_from_end_ok(s: &mut [i32]) {
|
||||
if let [.., ref fourth, ref third, _, ref first] = *s {
|
||||
if let [.., ref mut second, _] = *s {
|
||||
nop(&[first, second, third, fourth]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn const_index_from_end_err(s: &mut [i32]) {
|
||||
if let [.., ref fourth, ref third, _, ref first] = *s {
|
||||
if let [.., ref mut third2, _, _] = *s { //~ERROR
|
||||
|
|
@ -39,9 +21,6 @@ fn const_index_from_end_err(s: &mut [i32]) {
|
|||
|
||||
fn const_index_mixed(s: &mut [i32]) {
|
||||
if let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s {
|
||||
if let [ref mut from_begin0, ..] = *s {
|
||||
nop(&[from_begin0, from_end1, from_end3, from_end4]);
|
||||
}
|
||||
if let [_, ref mut from_begin1, ..] = *s { //~ERROR
|
||||
nop(&[from_begin1, from_end1, from_end3, from_end4]);
|
||||
}
|
||||
|
|
@ -53,9 +32,6 @@ fn const_index_mixed(s: &mut [i32]) {
|
|||
}
|
||||
}
|
||||
if let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s {
|
||||
if let [.., ref mut from_end1] = *s {
|
||||
nop(&[from_begin0, from_begin1, from_begin3, from_end1]);
|
||||
}
|
||||
if let [.., ref mut from_end2, _] = *s { //~ERROR
|
||||
nop(&[from_begin0, from_begin1, from_begin3, from_end2]);
|
||||
}
|
||||
|
|
@ -68,15 +44,6 @@ fn const_index_mixed(s: &mut [i32]) {
|
|||
}
|
||||
}
|
||||
|
||||
fn const_index_and_subslice_ok(s: &mut [i32]) {
|
||||
if let [ref first, ref second, ..] = *s {
|
||||
if let [_, _, ref mut tail @ ..] = *s {
|
||||
nop(&[first, second]);
|
||||
nop_subslice(tail);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn const_index_and_subslice_err(s: &mut [i32]) {
|
||||
if let [ref first, ref second, ..] = *s {
|
||||
if let [_, ref mut tail @ ..] = *s { //~ERROR
|
||||
|
|
@ -86,15 +53,6 @@ fn const_index_and_subslice_err(s: &mut [i32]) {
|
|||
}
|
||||
}
|
||||
|
||||
fn const_index_and_subslice_from_end_ok(s: &mut [i32]) {
|
||||
if let [.., ref second, ref first] = *s {
|
||||
if let [ref mut tail @ .., _, _] = *s {
|
||||
nop(&[first, second]);
|
||||
nop_subslice(tail);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn const_index_and_subslice_from_end_err(s: &mut [i32]) {
|
||||
if let [.., ref second, ref first] = *s {
|
||||
if let [ref mut tail @ .., _] = *s { //~ERROR
|
||||
|
|
@ -115,13 +73,9 @@ fn subslices(s: &mut [i32]) {
|
|||
|
||||
fn main() {
|
||||
let mut v = [1,2,3,4];
|
||||
const_index_ok(&mut v);
|
||||
const_index_err(&mut v);
|
||||
const_index_from_end_ok(&mut v);
|
||||
const_index_from_end_err(&mut v);
|
||||
const_index_and_subslice_ok(&mut v);
|
||||
const_index_and_subslice_err(&mut v);
|
||||
const_index_and_subslice_from_end_ok(&mut v);
|
||||
const_index_and_subslice_from_end_err(&mut v);
|
||||
subslices(&mut v);
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
|
||||
--> $DIR/borrowck-slice-pattern-element-loan.rs:18:20
|
||||
--> $DIR/borrowck-slice-pattern-element-loan-slice.rs:8:20
|
||||
|
|
||||
LL | if let [ref first, ref second, ..] = *s {
|
||||
| ---------- immutable borrow occurs here
|
||||
|
|
@ -9,7 +9,7 @@ LL | nop(&[first, second, second2, third]);
|
|||
| ------ immutable borrow later used here
|
||||
|
||||
error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
|
||||
--> $DIR/borrowck-slice-pattern-element-loan.rs:34:21
|
||||
--> $DIR/borrowck-slice-pattern-element-loan-slice.rs:16:21
|
||||
|
|
||||
LL | if let [.., ref fourth, ref third, _, ref first] = *s {
|
||||
| --------- immutable borrow occurs here
|
||||
|
|
@ -19,18 +19,17 @@ LL | nop(&[first, third, third2, fourth]);
|
|||
| ----- immutable borrow later used here
|
||||
|
||||
error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
|
||||
--> $DIR/borrowck-slice-pattern-element-loan.rs:45:20
|
||||
--> $DIR/borrowck-slice-pattern-element-loan-slice.rs:24:20
|
||||
|
|
||||
LL | if let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s {
|
||||
| ------------- immutable borrow occurs here
|
||||
...
|
||||
LL | if let [_, ref mut from_begin1, ..] = *s {
|
||||
| ^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
|
||||
LL | nop(&[from_begin1, from_end1, from_end3, from_end4]);
|
||||
| --------- immutable borrow later used here
|
||||
|
||||
error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
|
||||
--> $DIR/borrowck-slice-pattern-element-loan.rs:48:23
|
||||
--> $DIR/borrowck-slice-pattern-element-loan-slice.rs:27:23
|
||||
|
|
||||
LL | if let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s {
|
||||
| ------------- immutable borrow occurs here
|
||||
|
|
@ -41,7 +40,7 @@ LL | nop(&[from_begin2, from_end1, from_end3, from_end4]);
|
|||
| --------- immutable borrow later used here
|
||||
|
||||
error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
|
||||
--> $DIR/borrowck-slice-pattern-element-loan.rs:51:26
|
||||
--> $DIR/borrowck-slice-pattern-element-loan-slice.rs:30:26
|
||||
|
|
||||
LL | if let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s {
|
||||
| ------------- immutable borrow occurs here
|
||||
|
|
@ -52,18 +51,17 @@ LL | nop(&[from_begin3, from_end1, from_end3, from_end4]);
|
|||
| --------- immutable borrow later used here
|
||||
|
||||
error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
|
||||
--> $DIR/borrowck-slice-pattern-element-loan.rs:59:21
|
||||
--> $DIR/borrowck-slice-pattern-element-loan-slice.rs:35:21
|
||||
|
|
||||
LL | if let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s {
|
||||
| --------------- immutable borrow occurs here
|
||||
...
|
||||
LL | if let [.., ref mut from_end2, _] = *s {
|
||||
| ^^^^^^^^^^^^^^^^^ mutable borrow occurs here
|
||||
LL | nop(&[from_begin0, from_begin1, from_begin3, from_end2]);
|
||||
| ----------- immutable borrow later used here
|
||||
|
||||
error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
|
||||
--> $DIR/borrowck-slice-pattern-element-loan.rs:62:21
|
||||
--> $DIR/borrowck-slice-pattern-element-loan-slice.rs:38:21
|
||||
|
|
||||
LL | if let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s {
|
||||
| --------------- immutable borrow occurs here
|
||||
|
|
@ -74,7 +72,7 @@ LL | nop(&[from_begin0, from_begin1, from_begin3, from_end3]);
|
|||
| ----------- immutable borrow later used here
|
||||
|
||||
error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
|
||||
--> $DIR/borrowck-slice-pattern-element-loan.rs:65:21
|
||||
--> $DIR/borrowck-slice-pattern-element-loan-slice.rs:41:21
|
||||
|
|
||||
LL | if let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s {
|
||||
| --------------- immutable borrow occurs here
|
||||
|
|
@ -85,7 +83,7 @@ LL | nop(&[from_begin0, from_begin1, from_begin3, from_end4]);
|
|||
| ----------- immutable borrow later used here
|
||||
|
||||
error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
|
||||
--> $DIR/borrowck-slice-pattern-element-loan.rs:82:20
|
||||
--> $DIR/borrowck-slice-pattern-element-loan-slice.rs:49:20
|
||||
|
|
||||
LL | if let [ref first, ref second, ..] = *s {
|
||||
| ---------- immutable borrow occurs here
|
||||
|
|
@ -95,7 +93,7 @@ LL | nop(&[first, second]);
|
|||
| ------ immutable borrow later used here
|
||||
|
||||
error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
|
||||
--> $DIR/borrowck-slice-pattern-element-loan.rs:100:17
|
||||
--> $DIR/borrowck-slice-pattern-element-loan-slice.rs:58:17
|
||||
|
|
||||
LL | if let [.., ref second, ref first] = *s {
|
||||
| ---------- immutable borrow occurs here
|
||||
|
|
@ -105,7 +103,7 @@ LL | nop(&[first, second]);
|
|||
| ------ immutable borrow later used here
|
||||
|
||||
error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
|
||||
--> $DIR/borrowck-slice-pattern-element-loan.rs:109:17
|
||||
--> $DIR/borrowck-slice-pattern-element-loan-slice.rs:67:17
|
||||
|
|
||||
LL | if let [_, _, _, ref s1 @ ..] = *s {
|
||||
| ----------- immutable borrow occurs here
|
||||
|
|
@ -269,6 +269,28 @@ fn subslice_pattern_reassign(a: &Allocator) {
|
|||
let[_, _y @ ..] = ar;
|
||||
}
|
||||
|
||||
fn index_field_mixed_ends(a: &Allocator) {
|
||||
let ar = [(a.alloc(), a.alloc()), (a.alloc(), a.alloc())];
|
||||
let[(_x, _), ..] = ar;
|
||||
let[(_, _y), _] = ar;
|
||||
let[_, (_, _w)] = ar;
|
||||
let[.., (_z, _)] = ar;
|
||||
}
|
||||
|
||||
fn subslice_mixed_min_lengths(a: &Allocator, c: i32) {
|
||||
let ar = [(a.alloc(), a.alloc()), (a.alloc(), a.alloc())];
|
||||
match c {
|
||||
0 => { let[_x, ..] = ar; }
|
||||
1 => { let[_x, _, ..] = ar; }
|
||||
2 => { let[_x, _] = ar; }
|
||||
3 => { let[(_x, _), _, ..] = ar; }
|
||||
4 => { let[.., (_x, _)] = ar; }
|
||||
5 => { let[.., (_x, _), _] = ar; }
|
||||
6 => { let [_y @ ..] = ar; }
|
||||
_ => { let [_y @ .., _] = ar; }
|
||||
}
|
||||
}
|
||||
|
||||
fn panic_after_return(a: &Allocator) -> Ptr<'_> {
|
||||
// Panic in the drop of `p` or `q` can leak
|
||||
let exceptions = vec![8, 9];
|
||||
|
|
@ -422,6 +444,16 @@ fn main() {
|
|||
run_test(|a| slice_pattern_reassign(a));
|
||||
run_test(|a| subslice_pattern_reassign(a));
|
||||
|
||||
run_test(|a| index_field_mixed_ends(a));
|
||||
run_test(|a| subslice_mixed_min_lengths(a, 0));
|
||||
run_test(|a| subslice_mixed_min_lengths(a, 1));
|
||||
run_test(|a| subslice_mixed_min_lengths(a, 2));
|
||||
run_test(|a| subslice_mixed_min_lengths(a, 3));
|
||||
run_test(|a| subslice_mixed_min_lengths(a, 4));
|
||||
run_test(|a| subslice_mixed_min_lengths(a, 5));
|
||||
run_test(|a| subslice_mixed_min_lengths(a, 6));
|
||||
run_test(|a| subslice_mixed_min_lengths(a, 7));
|
||||
|
||||
run_test(|a| {
|
||||
panic_after_return(a);
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue