Auto merge of #51729 - matthewjasper:move-errors, r=nikomatsakis
[NLL] Better move errors Make a number of changes to improve the quality of NLL cannot move errors. * Group errors that occur in the same `match` with the same cause. * Suggest `ref`, `&` or removing `*` to avoid the move. * Show the place being matched on. Differences from AST borrowck: * `&` is suggested over `ref` when matching on a place that can't be moved from. * Removing `*` is suggested instead of adding `&` when applicable. * Sub-pattern spans aren't used, this would probably need Spans on Places. Closes #45699 Closes #46627 Closes #51187 Closes #51189 r? @pnkfelix
This commit is contained in:
commit
ab8a67c12a
42 changed files with 997 additions and 321 deletions
|
|
@ -497,8 +497,8 @@ pub enum LocalKind {
|
|||
ReturnPointer,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
|
||||
pub struct VarBindingForm {
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
|
||||
pub struct VarBindingForm<'tcx> {
|
||||
/// Is variable bound via `x`, `mut x`, `ref x`, or `ref mut x`?
|
||||
pub binding_mode: ty::BindingMode,
|
||||
/// If an explicit type was provided for this variable binding,
|
||||
|
|
@ -508,21 +508,49 @@ pub struct VarBindingForm {
|
|||
/// doing so breaks incremental compilation (as of this writing),
|
||||
/// while a `Span` does not cause our tests to fail.
|
||||
pub opt_ty_info: Option<Span>,
|
||||
/// Place of the RHS of the =, or the subject of the `match` where this
|
||||
/// variable is initialized. None in the case of `let PATTERN;`.
|
||||
/// Some((None, ..)) in the case of and `let [mut] x = ...` because
|
||||
/// (a) the right-hand side isn't evaluated as a place expression.
|
||||
/// (b) it gives a way to separate this case from the remaining cases
|
||||
/// for diagnostics.
|
||||
pub opt_match_place: Option<(Option<Place<'tcx>>, Span)>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
|
||||
pub enum BindingForm {
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
|
||||
pub enum BindingForm<'tcx> {
|
||||
/// This is a binding for a non-`self` binding, or a `self` that has an explicit type.
|
||||
Var(VarBindingForm),
|
||||
Var(VarBindingForm<'tcx>),
|
||||
/// Binding for a `self`/`&self`/`&mut self` binding where the type is implicit.
|
||||
ImplicitSelf,
|
||||
}
|
||||
|
||||
CloneTypeFoldableAndLiftImpls! { BindingForm, }
|
||||
CloneTypeFoldableAndLiftImpls! { BindingForm<'tcx>, }
|
||||
|
||||
impl_stable_hash_for!(struct self::VarBindingForm { binding_mode, opt_ty_info });
|
||||
impl_stable_hash_for!(struct self::VarBindingForm<'tcx> {
|
||||
binding_mode,
|
||||
opt_ty_info,
|
||||
opt_match_place
|
||||
});
|
||||
|
||||
impl_stable_hash_for!(enum self::BindingForm { Var(binding), ImplicitSelf, });
|
||||
mod binding_form_impl {
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult};
|
||||
use ich::StableHashingContext;
|
||||
|
||||
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for super::BindingForm<'tcx> {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
use super::BindingForm::*;
|
||||
::std::mem::discriminant(self).hash_stable(hcx, hasher);
|
||||
|
||||
match self {
|
||||
Var(binding) => binding.hash_stable(hcx, hasher),
|
||||
ImplicitSelf => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A MIR local.
|
||||
///
|
||||
|
|
@ -542,7 +570,7 @@ pub struct LocalDecl<'tcx> {
|
|||
/// therefore it need not be visible across crates. pnkfelix
|
||||
/// currently hypothesized we *need* to wrap this in a
|
||||
/// `ClearCrossCrate` as long as it carries as `HirId`.
|
||||
pub is_user_variable: Option<ClearCrossCrate<BindingForm>>,
|
||||
pub is_user_variable: Option<ClearCrossCrate<BindingForm<'tcx>>>,
|
||||
|
||||
/// True if this is an internal local
|
||||
///
|
||||
|
|
@ -670,6 +698,7 @@ impl<'tcx> LocalDecl<'tcx> {
|
|||
Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
|
||||
binding_mode: ty::BindingMode::BindByValue(_),
|
||||
opt_ty_info: _,
|
||||
opt_match_place: _,
|
||||
}))) => true,
|
||||
|
||||
// FIXME: might be able to thread the distinction between
|
||||
|
|
@ -688,6 +717,7 @@ impl<'tcx> LocalDecl<'tcx> {
|
|||
Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
|
||||
binding_mode: ty::BindingMode::BindByValue(_),
|
||||
opt_ty_info: _,
|
||||
opt_match_place: _,
|
||||
}))) => true,
|
||||
|
||||
Some(ClearCrossCrate::Set(BindingForm::ImplicitSelf)) => true,
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@ use syntax_pos::Span;
|
|||
|
||||
use dataflow::indexes::BorrowIndex;
|
||||
use dataflow::move_paths::{HasMoveData, LookupResult, MoveData, MovePathIndex};
|
||||
use dataflow::move_paths::{IllegalMoveOriginKind, MoveError};
|
||||
use dataflow::Borrows;
|
||||
use dataflow::DataflowResultsConsumer;
|
||||
use dataflow::FlowAtLocation;
|
||||
|
|
@ -62,6 +61,7 @@ mod path_utils;
|
|||
crate mod place_ext;
|
||||
mod prefixes;
|
||||
mod used_muts;
|
||||
mod move_errors;
|
||||
|
||||
pub(crate) mod nll;
|
||||
|
||||
|
|
@ -147,40 +147,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
|
|||
let move_data: MoveData<'tcx> = match MoveData::gather_moves(mir, tcx) {
|
||||
Ok(move_data) => move_data,
|
||||
Err((move_data, move_errors)) => {
|
||||
for move_error in move_errors {
|
||||
let (span, kind): (Span, IllegalMoveOriginKind) = match move_error {
|
||||
MoveError::UnionMove { .. } => {
|
||||
unimplemented!("don't know how to report union move errors yet.")
|
||||
}
|
||||
MoveError::IllegalMove {
|
||||
cannot_move_out_of: o,
|
||||
} => (o.span, o.kind),
|
||||
};
|
||||
let origin = Origin::Mir;
|
||||
let mut err = match kind {
|
||||
IllegalMoveOriginKind::Static => {
|
||||
tcx.cannot_move_out_of(span, "static item", origin)
|
||||
}
|
||||
IllegalMoveOriginKind::BorrowedContent { target_ty: ty } => {
|
||||
// Inspect the type of the content behind the
|
||||
// borrow to provide feedback about why this
|
||||
// was a move rather than a copy.
|
||||
match ty.sty {
|
||||
ty::TyArray(..) | ty::TySlice(..) => {
|
||||
tcx.cannot_move_out_of_interior_noncopy(span, ty, None, origin)
|
||||
}
|
||||
_ => tcx.cannot_move_out_of(span, "borrowed content", origin),
|
||||
}
|
||||
}
|
||||
IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => {
|
||||
tcx.cannot_move_out_of_interior_of_drop(span, ty, origin)
|
||||
}
|
||||
IllegalMoveOriginKind::InteriorOfSliceOrArray { ty, is_index } => {
|
||||
tcx.cannot_move_out_of_interior_noncopy(span, ty, Some(is_index), origin)
|
||||
}
|
||||
};
|
||||
err.emit();
|
||||
}
|
||||
move_errors::report_move_errors(&mir, tcx, move_errors, &move_data);
|
||||
move_data
|
||||
}
|
||||
};
|
||||
|
|
|
|||
388
src/librustc_mir/borrow_check/move_errors.rs
Normal file
388
src/librustc_mir/borrow_check/move_errors.rs
Normal file
|
|
@ -0,0 +1,388 @@
|
|||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use rustc::hir;
|
||||
use rustc::mir::*;
|
||||
use rustc::ty::{self, TyCtxt};
|
||||
use rustc_errors::DiagnosticBuilder;
|
||||
use syntax_pos::Span;
|
||||
|
||||
use dataflow::move_paths::{IllegalMoveOrigin, IllegalMoveOriginKind, MoveData};
|
||||
use dataflow::move_paths::{LookupResult, MoveError, MovePathIndex};
|
||||
use util::borrowck_errors::{BorrowckErrors, Origin};
|
||||
|
||||
pub(crate) fn report_move_errors<'gcx, 'tcx>(
|
||||
mir: &Mir<'tcx>,
|
||||
tcx: TyCtxt<'_, 'gcx, 'tcx>,
|
||||
move_errors: Vec<MoveError<'tcx>>,
|
||||
move_data: &MoveData<'tcx>,
|
||||
) {
|
||||
MoveErrorCtxt {
|
||||
mir,
|
||||
tcx,
|
||||
move_data,
|
||||
}.report_errors(move_errors);
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct MoveErrorCtxt<'a, 'gcx: 'tcx, 'tcx: 'a> {
|
||||
mir: &'a Mir<'tcx>,
|
||||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
move_data: &'a MoveData<'tcx>,
|
||||
}
|
||||
|
||||
// Often when desugaring a pattern match we may have many individual moves in
|
||||
// MIR that are all part of one operation from the user's point-of-view. For
|
||||
// example:
|
||||
//
|
||||
// let (x, y) = foo()
|
||||
//
|
||||
// would move x from the 0 field of some temporary, and y from the 1 field. We
|
||||
// group such errors together for cleaner error reporting.
|
||||
//
|
||||
// Errors are kept separate if they are from places with different parent move
|
||||
// paths. For example, this generates two errors:
|
||||
//
|
||||
// let (&x, &y) = (&String::new(), &String::new());
|
||||
#[derive(Debug)]
|
||||
enum GroupedMoveError<'tcx> {
|
||||
// Match place can't be moved from
|
||||
// e.g. match x[0] { s => (), } where x: &[String]
|
||||
MovesFromMatchPlace {
|
||||
span: Span,
|
||||
move_from: Place<'tcx>,
|
||||
kind: IllegalMoveOriginKind<'tcx>,
|
||||
binds_to: Vec<Local>,
|
||||
},
|
||||
// Part of a pattern can't be moved from,
|
||||
// e.g. match &String::new() { &x => (), }
|
||||
MovesFromPattern {
|
||||
span: Span,
|
||||
move_from: MovePathIndex,
|
||||
kind: IllegalMoveOriginKind<'tcx>,
|
||||
binds_to: Vec<Local>,
|
||||
},
|
||||
// Everything that isn't from pattern matching.
|
||||
OtherIllegalMove {
|
||||
span: Span,
|
||||
kind: IllegalMoveOriginKind<'tcx>,
|
||||
},
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> MoveErrorCtxt<'a, 'gcx, 'tcx> {
|
||||
fn report_errors(self, move_errors: Vec<MoveError<'tcx>>) {
|
||||
let grouped_errors = self.group_move_errors(move_errors);
|
||||
for error in grouped_errors {
|
||||
self.report(error);
|
||||
}
|
||||
}
|
||||
|
||||
fn group_move_errors(self, errors: Vec<MoveError<'tcx>>) -> Vec<GroupedMoveError<'tcx>> {
|
||||
let mut grouped_errors = Vec::new();
|
||||
for error in errors {
|
||||
self.append_to_grouped_errors(&mut grouped_errors, error);
|
||||
}
|
||||
grouped_errors
|
||||
}
|
||||
|
||||
fn append_to_grouped_errors(
|
||||
self,
|
||||
grouped_errors: &mut Vec<GroupedMoveError<'tcx>>,
|
||||
error: MoveError<'tcx>,
|
||||
) {
|
||||
match error {
|
||||
MoveError::UnionMove { .. } => {
|
||||
unimplemented!("don't know how to report union move errors yet.")
|
||||
}
|
||||
MoveError::IllegalMove {
|
||||
cannot_move_out_of: IllegalMoveOrigin { location, kind },
|
||||
} => {
|
||||
let stmt_source_info = self.mir.source_info(location);
|
||||
if let Some(StatementKind::Assign(
|
||||
Place::Local(local),
|
||||
Rvalue::Use(Operand::Move(move_from)),
|
||||
)) = self.mir.basic_blocks()[location.block]
|
||||
.statements
|
||||
.get(location.statement_index)
|
||||
.map(|stmt| &stmt.kind)
|
||||
{
|
||||
let local_decl = &self.mir.local_decls[*local];
|
||||
if let Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
|
||||
opt_match_place: Some((ref opt_match_place, match_span)),
|
||||
binding_mode: _,
|
||||
opt_ty_info: _,
|
||||
}))) = local_decl.is_user_variable
|
||||
{
|
||||
// opt_match_place is the
|
||||
// match_span is the span of the expression being matched on
|
||||
// match *x.y { ... } match_place is Some(*x.y)
|
||||
// ^^^^ match_span is the span of *x.y
|
||||
// opt_match_place is None for let [mut] x = ... statements,
|
||||
// whether or not the right-hand side is a place expression
|
||||
|
||||
// HACK use scopes to determine if this assignment is
|
||||
// the initialization of a variable.
|
||||
// FIXME(matthewjasper) This would probably be more
|
||||
// reliable if it used the ever initialized dataflow
|
||||
// but move errors are currently reported before the
|
||||
// rest of borrowck has run.
|
||||
if self
|
||||
.mir
|
||||
.is_sub_scope(local_decl.source_info.scope, stmt_source_info.scope)
|
||||
{
|
||||
self.append_binding_error(
|
||||
grouped_errors,
|
||||
kind,
|
||||
move_from,
|
||||
*local,
|
||||
opt_match_place,
|
||||
match_span,
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
grouped_errors.push(GroupedMoveError::OtherIllegalMove {
|
||||
span: stmt_source_info.span,
|
||||
kind,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn append_binding_error(
|
||||
self,
|
||||
grouped_errors: &mut Vec<GroupedMoveError<'tcx>>,
|
||||
kind: IllegalMoveOriginKind<'tcx>,
|
||||
move_from: &Place<'tcx>,
|
||||
bind_to: Local,
|
||||
match_place: &Option<Place<'tcx>>,
|
||||
match_span: Span,
|
||||
) {
|
||||
debug!(
|
||||
"append_to_grouped_errors(match_place={:?}, match_span={:?})",
|
||||
match_place, match_span
|
||||
);
|
||||
|
||||
let from_simple_let = match_place.is_none();
|
||||
let match_place = match_place.as_ref().unwrap_or(move_from);
|
||||
|
||||
match self.move_data.rev_lookup.find(match_place) {
|
||||
// Error with the match place
|
||||
LookupResult::Parent(_) => {
|
||||
for ge in &mut *grouped_errors {
|
||||
if let GroupedMoveError::MovesFromMatchPlace { span, binds_to, .. } = ge {
|
||||
if match_span == *span {
|
||||
debug!("appending local({:?}) to list", bind_to);
|
||||
if !binds_to.is_empty() {
|
||||
binds_to.push(bind_to);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
debug!("found a new move error location");
|
||||
|
||||
// Don't need to point to x in let x = ... .
|
||||
let binds_to = if from_simple_let {
|
||||
vec![]
|
||||
} else {
|
||||
vec![bind_to]
|
||||
};
|
||||
grouped_errors.push(GroupedMoveError::MovesFromMatchPlace {
|
||||
span: match_span,
|
||||
move_from: match_place.clone(),
|
||||
kind,
|
||||
binds_to,
|
||||
});
|
||||
}
|
||||
// Error with the pattern
|
||||
LookupResult::Exact(_) => {
|
||||
let mpi = match self.move_data.rev_lookup.find(move_from) {
|
||||
LookupResult::Parent(Some(mpi)) => mpi,
|
||||
// move_from should be a projection from match_place.
|
||||
_ => unreachable!("Probably not unreachable..."),
|
||||
};
|
||||
for ge in &mut *grouped_errors {
|
||||
if let GroupedMoveError::MovesFromPattern {
|
||||
span,
|
||||
move_from: other_mpi,
|
||||
binds_to,
|
||||
..
|
||||
} = ge
|
||||
{
|
||||
if match_span == *span && mpi == *other_mpi {
|
||||
debug!("appending local({:?}) to list", bind_to);
|
||||
binds_to.push(bind_to);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
debug!("found a new move error location");
|
||||
grouped_errors.push(GroupedMoveError::MovesFromPattern {
|
||||
span: match_span,
|
||||
move_from: mpi,
|
||||
kind,
|
||||
binds_to: vec![bind_to],
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn report(self, error: GroupedMoveError<'tcx>) {
|
||||
let (mut err, err_span) = {
|
||||
let (span, kind): (Span, &IllegalMoveOriginKind) = match error {
|
||||
GroupedMoveError::MovesFromMatchPlace { span, ref kind, .. }
|
||||
| GroupedMoveError::MovesFromPattern { span, ref kind, .. }
|
||||
| GroupedMoveError::OtherIllegalMove { span, ref kind } => (span, kind),
|
||||
};
|
||||
let origin = Origin::Mir;
|
||||
(
|
||||
match kind {
|
||||
IllegalMoveOriginKind::Static => {
|
||||
self.tcx.cannot_move_out_of(span, "static item", origin)
|
||||
}
|
||||
IllegalMoveOriginKind::BorrowedContent { target_ty: ty } => {
|
||||
// Inspect the type of the content behind the
|
||||
// borrow to provide feedback about why this
|
||||
// was a move rather than a copy.
|
||||
match ty.sty {
|
||||
ty::TyArray(..) | ty::TySlice(..) => self
|
||||
.tcx
|
||||
.cannot_move_out_of_interior_noncopy(span, ty, None, origin),
|
||||
_ => self
|
||||
.tcx
|
||||
.cannot_move_out_of(span, "borrowed content", origin),
|
||||
}
|
||||
}
|
||||
IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => {
|
||||
self.tcx
|
||||
.cannot_move_out_of_interior_of_drop(span, ty, origin)
|
||||
}
|
||||
IllegalMoveOriginKind::InteriorOfSliceOrArray { ty, is_index } => self
|
||||
.tcx
|
||||
.cannot_move_out_of_interior_noncopy(span, ty, Some(*is_index), origin),
|
||||
},
|
||||
span,
|
||||
)
|
||||
};
|
||||
|
||||
self.add_move_hints(error, &mut err, err_span);
|
||||
err.emit();
|
||||
}
|
||||
|
||||
fn add_move_hints(
|
||||
self,
|
||||
error: GroupedMoveError<'tcx>,
|
||||
err: &mut DiagnosticBuilder<'a>,
|
||||
span: Span,
|
||||
) {
|
||||
match error {
|
||||
GroupedMoveError::MovesFromMatchPlace {
|
||||
mut binds_to,
|
||||
move_from,
|
||||
..
|
||||
} => {
|
||||
// Ok to suggest a borrow, since the target can't be moved from
|
||||
// anyway.
|
||||
if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(span) {
|
||||
match move_from {
|
||||
Place::Projection(ref proj)
|
||||
if self.suitable_to_remove_deref(proj, &snippet) =>
|
||||
{
|
||||
err.span_suggestion(
|
||||
span,
|
||||
"consider removing this dereference operator",
|
||||
format!("{}", &snippet[1..]),
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
err.span_suggestion(
|
||||
span,
|
||||
"consider using a reference instead",
|
||||
format!("&{}", snippet),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
binds_to.sort();
|
||||
binds_to.dedup();
|
||||
for local in binds_to {
|
||||
let bind_to = &self.mir.local_decls[local];
|
||||
let binding_span = bind_to.source_info.span;
|
||||
err.span_label(
|
||||
binding_span,
|
||||
format!(
|
||||
"move occurs because {} has type `{}`, \
|
||||
which does not implement the `Copy` trait",
|
||||
bind_to.name.unwrap(),
|
||||
bind_to.ty
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
GroupedMoveError::MovesFromPattern { mut binds_to, .. } => {
|
||||
// Suggest ref, since there might be a move in
|
||||
// another match arm
|
||||
binds_to.sort();
|
||||
binds_to.dedup();
|
||||
for local in binds_to {
|
||||
let bind_to = &self.mir.local_decls[local];
|
||||
let binding_span = bind_to.source_info.span;
|
||||
|
||||
// Suggest ref mut when the user has already written mut.
|
||||
let ref_kind = match bind_to.mutability {
|
||||
Mutability::Not => "ref",
|
||||
Mutability::Mut => "ref mut",
|
||||
};
|
||||
match bind_to.name {
|
||||
Some(name) => {
|
||||
err.span_suggestion(
|
||||
binding_span,
|
||||
"to prevent move, use ref or ref mut",
|
||||
format!("{} {:?}", ref_kind, name),
|
||||
);
|
||||
}
|
||||
None => {
|
||||
err.span_label(
|
||||
span,
|
||||
format!("Local {:?} is not suitable for ref", bind_to),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Nothing to suggest.
|
||||
GroupedMoveError::OtherIllegalMove { .. } => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn suitable_to_remove_deref(self, proj: &PlaceProjection<'tcx>, snippet: &str) -> bool {
|
||||
let is_shared_ref = |ty: ty::Ty| match ty.sty {
|
||||
ty::TypeVariants::TyRef(.., hir::Mutability::MutImmutable) => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
proj.elem == ProjectionElem::Deref && snippet.starts_with('*') && match proj.base {
|
||||
Place::Local(local) => {
|
||||
let local_decl = &self.mir.local_decls[local];
|
||||
// If this is a temporary, then this could be from an
|
||||
// overloaded * operator.
|
||||
local_decl.is_user_variable.is_some() && is_shared_ref(local_decl.ty)
|
||||
}
|
||||
Place::Static(ref st) => is_shared_ref(st.ty),
|
||||
Place::Projection(ref proj) => match proj.elem {
|
||||
ProjectionElem::Field(_, ty) => is_shared_ref(ty),
|
||||
_ => false,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -115,11 +115,21 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
// Declare the bindings, which may create a source scope.
|
||||
let remainder_span = remainder_scope.span(this.hir.tcx(),
|
||||
&this.hir.region_scope_tree);
|
||||
let scope = this.declare_bindings(None, remainder_span, lint_level, &pattern,
|
||||
ArmHasGuard(false));
|
||||
|
||||
let scope;
|
||||
|
||||
// Evaluate the initializer, if present.
|
||||
if let Some(init) = initializer {
|
||||
let initializer_span = init.span();
|
||||
|
||||
scope = this.declare_bindings(
|
||||
None,
|
||||
remainder_span,
|
||||
lint_level,
|
||||
&pattern,
|
||||
ArmHasGuard(false),
|
||||
Some((None, initializer_span)),
|
||||
);
|
||||
unpack!(block = this.in_opt_scope(
|
||||
opt_destruction_scope.map(|de|(de, source_info)), block, |this| {
|
||||
let scope = (init_scope, source_info);
|
||||
|
|
@ -128,6 +138,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
})
|
||||
}));
|
||||
} else {
|
||||
scope = this.declare_bindings(None, remainder_span, lint_level, &pattern,
|
||||
ArmHasGuard(false), None);
|
||||
|
||||
// FIXME(#47184): We currently only insert `UserAssertTy` statements for
|
||||
// patterns that are bindings, this is as we do not want to deconstruct
|
||||
// the type being assertion to match the pattern.
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@
|
|||
//! See docs in build/expr/mod.rs
|
||||
|
||||
use build::{BlockAnd, BlockAndExtension, Builder};
|
||||
use build::expr::category::Category;
|
||||
use hair::*;
|
||||
use rustc::middle::region;
|
||||
use rustc::mir::*;
|
||||
|
|
@ -57,23 +56,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
});
|
||||
}
|
||||
|
||||
// Careful here not to cause an infinite cycle. If we always
|
||||
// called `into`, then for places like `x.f`, it would
|
||||
// eventually fallback to us, and we'd loop. There's a reason
|
||||
// for this: `as_temp` is the point where we bridge the "by
|
||||
// reference" semantics of `as_place` with the "by value"
|
||||
// semantics of `into`, `as_operand`, `as_rvalue`, and (of
|
||||
// course) `as_temp`.
|
||||
match Category::of(&expr.kind).unwrap() {
|
||||
Category::Place => {
|
||||
let place = unpack!(block = this.as_place(block, expr));
|
||||
let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place));
|
||||
this.cfg.push_assign(block, source_info, &Place::Local(temp), rvalue);
|
||||
}
|
||||
_ => {
|
||||
unpack!(block = this.into(&Place::Local(temp), block, expr));
|
||||
}
|
||||
}
|
||||
unpack!(block = this.into(&Place::Local(temp), block, expr));
|
||||
|
||||
// In constants, temp_lifetime is None. We should not need to drop
|
||||
// anything because no values with a destructor can be created in
|
||||
|
|
|
|||
|
|
@ -288,6 +288,37 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
block.unit()
|
||||
}
|
||||
|
||||
// Avoid creating a temporary
|
||||
ExprKind::VarRef { .. } |
|
||||
ExprKind::SelfRef |
|
||||
ExprKind::StaticRef { .. } => {
|
||||
debug_assert!(Category::of(&expr.kind) == Some(Category::Place));
|
||||
|
||||
let place = unpack!(block = this.as_place(block, expr));
|
||||
let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place));
|
||||
this.cfg.push_assign(block, source_info, destination, rvalue);
|
||||
block.unit()
|
||||
}
|
||||
ExprKind::Index { .. } |
|
||||
ExprKind::Deref { .. } |
|
||||
ExprKind::Field { .. } => {
|
||||
debug_assert!(Category::of(&expr.kind) == Some(Category::Place));
|
||||
|
||||
// Create a "fake" temporary variable so that we check that the
|
||||
// value is Sized. Usually, this is caught in type checking, but
|
||||
// in the case of box expr there is no such check.
|
||||
if let Place::Projection(..) = destination {
|
||||
this.local_decls.push(LocalDecl::new_temp(expr.ty, expr.span));
|
||||
}
|
||||
|
||||
debug_assert!(Category::of(&expr.kind) == Some(Category::Place));
|
||||
|
||||
let place = unpack!(block = this.as_place(block, expr));
|
||||
let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place));
|
||||
this.cfg.push_assign(block, source_info, destination, rvalue);
|
||||
block.unit()
|
||||
}
|
||||
|
||||
// these are the cases that are more naturally handled by some other mode
|
||||
ExprKind::Unary { .. } |
|
||||
ExprKind::Binary { .. } |
|
||||
|
|
@ -300,18 +331,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
ExprKind::Unsize { .. } |
|
||||
ExprKind::Repeat { .. } |
|
||||
ExprKind::Borrow { .. } |
|
||||
ExprKind::VarRef { .. } |
|
||||
ExprKind::SelfRef |
|
||||
ExprKind::StaticRef { .. } |
|
||||
ExprKind::Array { .. } |
|
||||
ExprKind::Tuple { .. } |
|
||||
ExprKind::Adt { .. } |
|
||||
ExprKind::Closure { .. } |
|
||||
ExprKind::Index { .. } |
|
||||
ExprKind::Deref { .. } |
|
||||
ExprKind::Literal { .. } |
|
||||
ExprKind::Yield { .. } |
|
||||
ExprKind::Field { .. } => {
|
||||
ExprKind::Yield { .. } => {
|
||||
debug_assert!(match Category::of(&expr.kind).unwrap() {
|
||||
Category::Rvalue(RvalueFunc::Into) => false,
|
||||
_ => true,
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@
|
|||
//! which can fallback to `into`. So if one of the `ExprKind` variants is not, in fact,
|
||||
//! implemented in the category where it is supposed to be, there will be a problem.
|
||||
//!
|
||||
//! Of those fallbacks, the most interesting one is `as_temp`, because
|
||||
//! Of those fallbacks, the most interesting one is `into`, because
|
||||
//! it discriminates based on the category of the expression. This is
|
||||
//! basically the point where the "by value" operations are bridged
|
||||
//! over to the "by reference" mode (`as_place`).
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
arms: Vec<Arm<'tcx>>)
|
||||
-> BlockAnd<()> {
|
||||
let tcx = self.hir.tcx();
|
||||
let discriminant_span = discriminant.span();
|
||||
let discriminant_place = unpack!(block = self.as_place(block, discriminant));
|
||||
|
||||
// Matching on a `discriminant_place` with an uninhabited type doesn't
|
||||
|
|
@ -96,7 +97,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
let scope = self.declare_bindings(None, body.span,
|
||||
LintLevel::Inherited,
|
||||
&arm.patterns[0],
|
||||
ArmHasGuard(arm.guard.is_some()));
|
||||
ArmHasGuard(arm.guard.is_some()),
|
||||
Some((Some(&discriminant_place), discriminant_span)));
|
||||
(body, scope.unwrap_or(self.source_scope))
|
||||
}).collect();
|
||||
|
||||
|
|
@ -254,7 +256,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
_ => {
|
||||
let place = unpack!(block = self.as_place(block, initializer));
|
||||
self.place_into_pattern(block, irrefutable_pat, &place)
|
||||
self.place_into_pattern(block, irrefutable_pat, &place, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -262,7 +264,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
pub fn place_into_pattern(&mut self,
|
||||
mut block: BasicBlock,
|
||||
irrefutable_pat: Pattern<'tcx>,
|
||||
initializer: &Place<'tcx>)
|
||||
initializer: &Place<'tcx>,
|
||||
set_match_place: bool)
|
||||
-> BlockAnd<()> {
|
||||
// create a dummy candidate
|
||||
let mut candidate = Candidate {
|
||||
|
|
@ -288,6 +291,25 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
candidate.match_pairs);
|
||||
}
|
||||
|
||||
// for matches and function arguments, the place that is being matched
|
||||
// can be set when creating the variables. But the place for
|
||||
// let PATTERN = ... might not even exist until we do the assignment.
|
||||
// so we set it here instead
|
||||
if set_match_place {
|
||||
for binding in &candidate.bindings {
|
||||
let local = self.var_local_id(binding.var_id, OutsideGuard);
|
||||
|
||||
if let Some(ClearCrossCrate::Set(BindingForm::Var(
|
||||
VarBindingForm {opt_match_place: Some((ref mut match_place, _)), .. }
|
||||
))) = self.local_decls[local].is_user_variable
|
||||
{
|
||||
*match_place = Some(initializer.clone());
|
||||
} else {
|
||||
bug!("Let binding to non-user variable.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// now apply the bindings, which will also declare the variables
|
||||
self.bind_matched_candidate_for_arm_body(block, &candidate.bindings);
|
||||
|
||||
|
|
@ -302,7 +324,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
scope_span: Span,
|
||||
lint_level: LintLevel,
|
||||
pattern: &Pattern<'tcx>,
|
||||
has_guard: ArmHasGuard)
|
||||
has_guard: ArmHasGuard,
|
||||
opt_match_place: Option<(Option<&Place<'tcx>>, Span)>)
|
||||
-> Option<SourceScope> {
|
||||
assert!(!(visibility_scope.is_some() && lint_level.is_explicit()),
|
||||
"can't have both a visibility and a lint scope at the same time");
|
||||
|
|
@ -326,7 +349,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
};
|
||||
let visibility_scope = visibility_scope.unwrap();
|
||||
this.declare_binding(source_info, visibility_scope, mutability, name, mode, var,
|
||||
ty, has_guard);
|
||||
ty, has_guard, opt_match_place.map(|(x, y)| (x.cloned(), y)));
|
||||
});
|
||||
visibility_scope
|
||||
}
|
||||
|
|
@ -1121,7 +1144,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
mode: BindingMode,
|
||||
var_id: NodeId,
|
||||
var_ty: Ty<'tcx>,
|
||||
has_guard: ArmHasGuard)
|
||||
has_guard: ArmHasGuard,
|
||||
opt_match_place: Option<(Option<Place<'tcx>>, Span)>)
|
||||
{
|
||||
debug!("declare_binding(var_id={:?}, name={:?}, mode={:?}, var_ty={:?}, \
|
||||
visibility_scope={:?}, source_info={:?})",
|
||||
|
|
@ -1146,6 +1170,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
// idents in pat; but complex w/ unclear UI payoff.
|
||||
// Instead, just abandon providing diagnostic info.
|
||||
opt_ty_info: None,
|
||||
opt_match_place,
|
||||
}))),
|
||||
};
|
||||
let for_arm_body = self.local_decls.push(local.clone());
|
||||
|
|
|
|||
|
|
@ -705,6 +705,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
|
||||
if let Some(pattern) = pattern {
|
||||
let pattern = self.hir.pattern_from_hir(pattern);
|
||||
let span = pattern.span;
|
||||
|
||||
match *pattern.kind {
|
||||
// Don't introduce extra copies for simple bindings
|
||||
|
|
@ -716,15 +717,19 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
} else {
|
||||
let binding_mode = ty::BindingMode::BindByValue(mutability.into());
|
||||
Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
|
||||
binding_mode, opt_ty_info })))
|
||||
binding_mode,
|
||||
opt_ty_info,
|
||||
opt_match_place: Some((Some(place.clone()), span)),
|
||||
})))
|
||||
};
|
||||
self.var_indices.insert(var, LocalsForNode::One(local));
|
||||
}
|
||||
_ => {
|
||||
scope = self.declare_bindings(scope, ast_body.span,
|
||||
LintLevel::Inherited, &pattern,
|
||||
matches::ArmHasGuard(false));
|
||||
unpack!(block = self.place_into_pattern(block, pattern, &place));
|
||||
matches::ArmHasGuard(false),
|
||||
Some((Some(&place), span)));
|
||||
unpack!(block = self.place_into_pattern(block, pattern, &place, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,8 +109,7 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> {
|
|||
match *place {
|
||||
Place::Local(local) => Ok(self.builder.data.rev_lookup.locals[local]),
|
||||
Place::Static(..) => {
|
||||
let span = self.builder.mir.source_info(self.loc).span;
|
||||
Err(MoveError::cannot_move_out_of(span, Static))
|
||||
Err(MoveError::cannot_move_out_of(self.loc, Static))
|
||||
}
|
||||
Place::Projection(ref proj) => {
|
||||
self.move_path_for_projection(place, proj)
|
||||
|
|
@ -133,13 +132,13 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> {
|
|||
let mir = self.builder.mir;
|
||||
let tcx = self.builder.tcx;
|
||||
let place_ty = proj.base.ty(mir, tcx).to_ty(tcx);
|
||||
match place_ty.sty {
|
||||
match place_ty.sty {
|
||||
ty::TyRef(..) | ty::TyRawPtr(..) =>
|
||||
return Err(MoveError::cannot_move_out_of(
|
||||
mir.source_info(self.loc).span,
|
||||
self.loc,
|
||||
BorrowedContent { target_ty: place.ty(mir, tcx).to_ty(tcx) })),
|
||||
ty::TyAdt(adt, _) if adt.has_dtor(tcx) && !adt.is_box() =>
|
||||
return Err(MoveError::cannot_move_out_of(mir.source_info(self.loc).span,
|
||||
return Err(MoveError::cannot_move_out_of(self.loc,
|
||||
InteriorOfTypeWithDestructor {
|
||||
container_ty: place_ty
|
||||
})),
|
||||
|
|
@ -148,7 +147,7 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> {
|
|||
return Err(MoveError::UnionMove { path: base }),
|
||||
ty::TySlice(_) =>
|
||||
return Err(MoveError::cannot_move_out_of(
|
||||
mir.source_info(self.loc).span,
|
||||
self.loc,
|
||||
InteriorOfSliceOrArray {
|
||||
ty: place_ty, is_index: match proj.elem {
|
||||
ProjectionElem::Index(..) => true,
|
||||
|
|
@ -158,7 +157,7 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> {
|
|||
ty::TyArray(..) => match proj.elem {
|
||||
ProjectionElem::Index(..) =>
|
||||
return Err(MoveError::cannot_move_out_of(
|
||||
mir.source_info(self.loc).span,
|
||||
self.loc,
|
||||
InteriorOfSliceOrArray {
|
||||
ty: place_ty, is_index: true
|
||||
})),
|
||||
|
|
|
|||
|
|
@ -209,7 +209,7 @@ pub enum InitKind {
|
|||
Deep,
|
||||
/// Only does a shallow init
|
||||
Shallow,
|
||||
/// This doesn't initialize the variabe on panic (and a panic is possible).
|
||||
/// This doesn't initialize the variable on panic (and a panic is possible).
|
||||
NonPanicPathOnly,
|
||||
}
|
||||
|
||||
|
|
@ -271,7 +271,7 @@ impl<'tcx> MovePathLookup<'tcx> {
|
|||
|
||||
#[derive(Debug)]
|
||||
pub struct IllegalMoveOrigin<'tcx> {
|
||||
pub(crate) span: Span,
|
||||
pub(crate) location: Location,
|
||||
pub(crate) kind: IllegalMoveOriginKind<'tcx>,
|
||||
}
|
||||
|
||||
|
|
@ -304,8 +304,8 @@ pub enum MoveError<'tcx> {
|
|||
}
|
||||
|
||||
impl<'tcx> MoveError<'tcx> {
|
||||
fn cannot_move_out_of(span: Span, kind: IllegalMoveOriginKind<'tcx>) -> Self {
|
||||
let origin = IllegalMoveOrigin { span, kind };
|
||||
fn cannot_move_out_of(location: Location, kind: IllegalMoveOriginKind<'tcx>) -> Self {
|
||||
let origin = IllegalMoveOrigin { location, kind };
|
||||
MoveError::IllegalMove { cannot_move_out_of: origin }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -315,6 +315,15 @@ pub enum LogicalOp {
|
|||
Or,
|
||||
}
|
||||
|
||||
impl<'tcx> ExprRef<'tcx> {
|
||||
pub fn span(&self) -> Span {
|
||||
match self {
|
||||
ExprRef::Hair(expr) => expr.span,
|
||||
ExprRef::Mirror(expr) => expr.span,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// The Mirror trait
|
||||
|
||||
|
|
|
|||
|
|
@ -18,9 +18,9 @@ impl Drop for S {
|
|||
|
||||
fn move_in_match() {
|
||||
match (S {f:"foo".to_string()}) {
|
||||
//[mir]~^ ERROR [E0509]
|
||||
S {f:_s} => {}
|
||||
//[ast]~^ ERROR cannot move out of type `S`, which implements the `Drop` trait [E0509]
|
||||
//[mir]~^^ ERROR [E0509]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,13 +21,13 @@ fn main() {
|
|||
// END RUST SOURCE
|
||||
|
||||
// START rustc.norm2.InstCombine.before.mir
|
||||
// _5 = Len(_1);
|
||||
// _4 = Len(_1);
|
||||
// ...
|
||||
// _10 = Len(_1);
|
||||
// _8 = Len(_1);
|
||||
// END rustc.norm2.InstCombine.before.mir
|
||||
|
||||
// START rustc.norm2.InstCombine.after.mir
|
||||
// _5 = const 2usize;
|
||||
// _4 = const 2usize;
|
||||
// ...
|
||||
// _10 = const 2usize;
|
||||
// _8 = const 2usize;
|
||||
// END rustc.norm2.InstCombine.after.mir
|
||||
|
|
|
|||
|
|
@ -22,12 +22,9 @@ fn main() {
|
|||
// START rustc.test.CopyPropagation.before.mir
|
||||
// bb0: {
|
||||
// ...
|
||||
// _3 = _1;
|
||||
// _2 = _1;
|
||||
// ...
|
||||
// _2 = move _3;
|
||||
// ...
|
||||
// _4 = _2;
|
||||
// _0 = move _4;
|
||||
// _0 = _2;
|
||||
// ...
|
||||
// return;
|
||||
// }
|
||||
|
|
@ -35,7 +32,7 @@ fn main() {
|
|||
// START rustc.test.CopyPropagation.after.mir
|
||||
// bb0: {
|
||||
// ...
|
||||
// _0 = move _1;
|
||||
// _0 = _1;
|
||||
// ...
|
||||
// return;
|
||||
// }
|
||||
|
|
|
|||
|
|
@ -117,13 +117,11 @@ fn main() {
|
|||
// START rustc.arg_src.CopyPropagation.before.mir
|
||||
// bb0: {
|
||||
// ...
|
||||
// _3 = _1;
|
||||
// _2 = move _3;
|
||||
// _2 = _1;
|
||||
// ...
|
||||
// _1 = const 123i32;
|
||||
// ...
|
||||
// _4 = _2;
|
||||
// _0 = move _4;
|
||||
// _0 = _2;
|
||||
// ...
|
||||
// return;
|
||||
// }
|
||||
|
|
@ -131,11 +129,11 @@ fn main() {
|
|||
// START rustc.arg_src.CopyPropagation.after.mir
|
||||
// bb0: {
|
||||
// ...
|
||||
// _3 = _1;
|
||||
// _2 = _1;
|
||||
// ...
|
||||
// _1 = const 123i32;
|
||||
// ...
|
||||
// _0 = move _3;
|
||||
// _0 = _2;
|
||||
// ...
|
||||
// return;
|
||||
// }
|
||||
|
|
|
|||
|
|
@ -68,13 +68,9 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
|
|||
// START rustc.main-{{closure}}.SimplifyCfg-qualify-consts.after.mir
|
||||
// fn main::{{closure}}(_1: [closure@NodeId(18) d:&'14s D]) -> i32 {
|
||||
// let mut _0: i32;
|
||||
// let mut _2: i32;
|
||||
//
|
||||
// bb0: {
|
||||
// StorageLive(_2);
|
||||
// _2 = ((*(_1.0: &'14s D)).0: i32);
|
||||
// _0 = move _2;
|
||||
// StorageDead(_2);
|
||||
// _0 = ((*(_1.0: &'14s D)).0: i32);
|
||||
// return;
|
||||
// }
|
||||
// END rustc.main-{{closure}}.SimplifyCfg-qualify-consts.after.mir
|
||||
|
|
|
|||
|
|
@ -70,14 +70,10 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
|
|||
// ...
|
||||
// let _2: &'16_0rs D;
|
||||
// ...
|
||||
// let mut _3: i32;
|
||||
// bb0: {
|
||||
// StorageLive(_2);
|
||||
// _2 = &'16_0rs (*(_1.0: &'19s D));
|
||||
// StorageLive(_3);
|
||||
// _3 = ((*_2).0: i32);
|
||||
// _0 = move _3;
|
||||
// StorageDead(_3);
|
||||
// _0 = ((*_2).0: i32);
|
||||
// EndRegion('16_0rs);
|
||||
// StorageDead(_2);
|
||||
// return;
|
||||
|
|
|
|||
|
|
@ -78,14 +78,10 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
|
|||
// ...
|
||||
// let _2: &'16_0rs D;
|
||||
// ...
|
||||
// let mut _3: i32;
|
||||
// bb0: {
|
||||
// StorageLive(_2);
|
||||
// _2 = &'16_0rs (_1.0: D);
|
||||
// StorageLive(_3);
|
||||
// _3 = ((*_2).0: i32);
|
||||
// _0 = move _3;
|
||||
// StorageDead(_3);
|
||||
// _0 = ((*_2).0: i32);
|
||||
// EndRegion('16_0rs);
|
||||
// StorageDead(_2);
|
||||
// drop(_1) -> [return: bb2, unwind: bb1];
|
||||
|
|
|
|||
|
|
@ -76,13 +76,9 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
|
|||
// START rustc.main-{{closure}}.SimplifyCfg-qualify-consts.after.mir
|
||||
// fn main::{{closure}}(_1: [closure@NodeId(22) r:&'19s D]) -> i32 {
|
||||
// let mut _0: i32;
|
||||
// let mut _2: i32;
|
||||
//
|
||||
// bb0: {
|
||||
// StorageLive(_2);
|
||||
// _2 = ((*(_1.0: &'21_1rs D)).0: i32);
|
||||
// _0 = move _2;
|
||||
// StorageDead(_2);
|
||||
// _0 = ((*(_1.0: &'21_1rs D)).0: i32);
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
|
|
|
|||
|
|
@ -65,52 +65,45 @@ unsafe impl<'a, #[may_dangle] 'b> Drop for D1<'a, 'b> {
|
|||
|
||||
// START rustc.main.QualifyAndPromoteConstants.before.mir
|
||||
// fn main() -> () {
|
||||
// let mut _0: ();
|
||||
// let mut _0: ();
|
||||
// let mut _1: &'12ds S1;
|
||||
// let mut _2: &'12ds S1;
|
||||
// let mut _3: D1<'12ds, '10s>;
|
||||
// let mut _2: D1<'12ds, '10s>;
|
||||
// let mut _3: &'12ds S1;
|
||||
// let mut _4: &'12ds S1;
|
||||
// let mut _5: &'12ds S1;
|
||||
// let mut _6: S1;
|
||||
// let mut _5: S1;
|
||||
// let mut _6: &'10s S1;
|
||||
// let mut _7: &'10s S1;
|
||||
// let mut _8: &'10s S1;
|
||||
// let mut _9: S1;
|
||||
//
|
||||
// let mut _8: S1;
|
||||
// bb0: {
|
||||
// StorageLive(_2);
|
||||
// StorageLive(_3);
|
||||
// StorageLive(_4);
|
||||
// StorageLive(_5);
|
||||
// _5 = S1::{{constructor}}(const "ex1",);
|
||||
// _4 = &'12ds _5;
|
||||
// _3 = &'12ds (*_4);
|
||||
// StorageLive(_6);
|
||||
// _6 = S1::{{constructor}}(const "ex1",);
|
||||
// _5 = &'12ds _6;
|
||||
// _4 = &'12ds (*_5);
|
||||
// StorageLive(_7);
|
||||
// StorageLive(_8);
|
||||
// StorageLive(_9);
|
||||
// _9 = S1::{{constructor}}(const "dang1",);
|
||||
// _8 = &'10s _9;
|
||||
// _7 = &'10s (*_8);
|
||||
// _3 = D1<'12ds, '10s>::{{constructor}}(move _4, move _7);
|
||||
// _8 = S1::{{constructor}}(const "dang1",);
|
||||
// _7 = &'10s _8;
|
||||
// _6 = &'10s (*_7);
|
||||
// _2 = D1<'12ds, '10s>::{{constructor}}(move _3, move _6);
|
||||
// EndRegion('10s);
|
||||
// StorageDead(_7);
|
||||
// StorageDead(_4);
|
||||
// _2 = (_3.0: &'12ds S1);
|
||||
// _1 = move _2;
|
||||
// StorageDead(_2);
|
||||
// drop(_3) -> [return: bb2, unwind: bb1];
|
||||
// StorageDead(_6);
|
||||
// StorageDead(_3);
|
||||
// _1 = (_2.0: &'12ds S1);
|
||||
// drop(_2) -> [return: bb2, unwind: bb1];
|
||||
// }
|
||||
//
|
||||
// bb1: {
|
||||
// resume;
|
||||
// }
|
||||
//
|
||||
// bb2: {
|
||||
// StorageDead(_3);
|
||||
// StorageDead(_2);
|
||||
// StorageDead(_7);
|
||||
// StorageDead(_8);
|
||||
// StorageDead(_9);
|
||||
// StorageDead(_4);
|
||||
// StorageDead(_5);
|
||||
// StorageDead(_6);
|
||||
// EndRegion('12ds);
|
||||
// _0 = ();
|
||||
// return;
|
||||
|
|
@ -119,51 +112,44 @@ unsafe impl<'a, #[may_dangle] 'b> Drop for D1<'a, 'b> {
|
|||
// END rustc.main.QualifyAndPromoteConstants.before.mir
|
||||
|
||||
// START rustc.main.QualifyAndPromoteConstants.after.mir
|
||||
// fn main() -> () {
|
||||
// fn main() -> (){
|
||||
// let mut _0: ();
|
||||
// let mut _1: &'12ds S1;
|
||||
// let mut _2: &'12ds S1;
|
||||
// let mut _3: D1<'12ds, '10s>;
|
||||
// let mut _2: D1<'12ds, '10s>;
|
||||
// let mut _3: &'12ds S1;
|
||||
// let mut _4: &'12ds S1;
|
||||
// let mut _5: &'12ds S1;
|
||||
// let mut _6: S1;
|
||||
// let mut _5: S1;
|
||||
// let mut _6: &'10s S1;
|
||||
// let mut _7: &'10s S1;
|
||||
// let mut _8: &'10s S1;
|
||||
// let mut _9: S1;
|
||||
// let mut _10: &'10s S1;
|
||||
// let mut _11: &'12ds S1;
|
||||
//
|
||||
// let mut _8: S1;
|
||||
// let mut _9: &'10s S1;
|
||||
// let mut _10: &'12ds S1;
|
||||
// bb0: {
|
||||
// StorageLive(_2);
|
||||
// StorageLive(_3);
|
||||
// StorageLive(_4);
|
||||
// StorageLive(_5);
|
||||
// _11 = promoted[1];
|
||||
// _5 = &'12ds (*_11);
|
||||
// _4 = &'12ds (*_5);
|
||||
// _10 = promoted[1];
|
||||
// _4 = &'12ds (*_10);
|
||||
// _3 = &'12ds (*_4);
|
||||
// StorageLive(_6);
|
||||
// StorageLive(_7);
|
||||
// StorageLive(_8);
|
||||
// _10 = promoted[0];
|
||||
// _8 = &'10s (*_10);
|
||||
// _7 = &'10s (*_8);
|
||||
// _3 = D1<'12ds, '10s>::{{constructor}}(move _4, move _7);
|
||||
// _9 = promoted[0];
|
||||
// _7 = &'10s (*_9);
|
||||
// _6 = &'10s (*_7);
|
||||
// _2 = D1<'12ds, '10s>::{{constructor}}(move _3, move _6);
|
||||
// EndRegion('10s);
|
||||
// StorageDead(_7);
|
||||
// StorageDead(_4);
|
||||
// _2 = (_3.0: &'12ds S1);
|
||||
// _1 = move _2;
|
||||
// StorageDead(_2);
|
||||
// drop(_3) -> [return: bb2, unwind: bb1];
|
||||
// StorageDead(_6);
|
||||
// StorageDead(_3);
|
||||
// _1 = (_2.0: &'12ds S1);
|
||||
// drop(_2) -> [return: bb2, unwind: bb1];
|
||||
// }
|
||||
//
|
||||
// bb1: {
|
||||
// resume;
|
||||
// }
|
||||
//
|
||||
// bb2: {
|
||||
// StorageDead(_3);
|
||||
// StorageDead(_8);
|
||||
// StorageDead(_5);
|
||||
// StorageDead(_2);
|
||||
// StorageDead(_7);
|
||||
// StorageDead(_4);
|
||||
// EndRegion('12ds);
|
||||
// _0 = ();
|
||||
// return;
|
||||
|
|
|
|||
|
|
@ -38,11 +38,9 @@ fn foo<T: Copy>(_t: T, q: &i32) -> i32 {
|
|||
// ...
|
||||
// _7 = &(*_2);
|
||||
// _5 = (move _6, move _7);
|
||||
// _9 = move (_5.0: &i32);
|
||||
// _10 = move (_5.1: &i32);
|
||||
// StorageLive(_8);
|
||||
// _8 = (*_9);
|
||||
// _0 = move _8;
|
||||
// _8 = move (_5.0: &i32);
|
||||
// _9 = move (_5.1: &i32);
|
||||
// _0 = (*_8);
|
||||
// ...
|
||||
// return;
|
||||
// }
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ fn foo<T: Copy>(_t: T, q: i32) -> i32 {
|
|||
// _5 = (move _6, move _7);
|
||||
// _8 = move (_5.0: i32);
|
||||
// _9 = move (_5.1: i32);
|
||||
// _0 = move _8;
|
||||
// _0 = _8;
|
||||
// ...
|
||||
// return;
|
||||
// }
|
||||
|
|
|
|||
|
|
@ -182,8 +182,8 @@ fn main() {
|
|||
// ...
|
||||
// _1 = move (_13.0: i128);
|
||||
// ...
|
||||
// _17 = const 7i32 as u128 (Misc);
|
||||
// _14 = const compiler_builtins::int::shift::rust_i128_shro(_1, move _17) -> bb16;
|
||||
// _16 = const 7i32 as u128 (Misc);
|
||||
// _14 = const compiler_builtins::int::shift::rust_i128_shro(_1, move _16) -> bb16;
|
||||
// ...
|
||||
// _1 = move (_14.0: i128);
|
||||
// ...
|
||||
|
|
@ -195,8 +195,8 @@ fn main() {
|
|||
// ...
|
||||
// assert(!move (_13.1: bool), "attempt to shift left with overflow") -> bb8;
|
||||
// ...
|
||||
// _16 = const 6i32 as u128 (Misc);
|
||||
// _13 = const compiler_builtins::int::shift::rust_i128_shlo(_1, move _16) -> bb14;
|
||||
// _15 = const 6i32 as u128 (Misc);
|
||||
// _13 = const compiler_builtins::int::shift::rust_i128_shlo(_1, move _15) -> bb14;
|
||||
// ...
|
||||
// assert(!move (_14.1: bool), "attempt to shift right with overflow") -> bb9;
|
||||
// END rustc.test_signed.Lower128Bit.after.mir
|
||||
|
|
@ -218,8 +218,8 @@ fn main() {
|
|||
// ...
|
||||
// _1 = move (_7.0: u128);
|
||||
// ...
|
||||
// _11 = const 7i32 as u128 (Misc);
|
||||
// _8 = const compiler_builtins::int::shift::rust_u128_shro(_1, move _11) -> bb14;
|
||||
// _10 = const 7i32 as u128 (Misc);
|
||||
// _8 = const compiler_builtins::int::shift::rust_u128_shro(_1, move _10) -> bb14;
|
||||
// ...
|
||||
// _1 = move (_8.0: u128);
|
||||
// ...
|
||||
|
|
@ -231,8 +231,8 @@ fn main() {
|
|||
// ...
|
||||
// assert(!move (_7.1: bool), "attempt to shift left with overflow") -> bb6;
|
||||
// ...
|
||||
// _10 = const 6i32 as u128 (Misc);
|
||||
// _7 = const compiler_builtins::int::shift::rust_u128_shlo(_1, move _10) -> bb12;
|
||||
// _9 = const 6i32 as u128 (Misc);
|
||||
// _7 = const compiler_builtins::int::shift::rust_u128_shlo(_1, move _9) -> bb12;
|
||||
// ...
|
||||
// assert(!move (_8.1: bool), "attempt to shift right with overflow") -> bb7;
|
||||
// END rustc.test_unsigned.Lower128Bit.after.mir
|
||||
|
|
|
|||
|
|
@ -176,11 +176,11 @@ fn main() {
|
|||
// ...
|
||||
// _1 = const compiler_builtins::int::addsub::rust_i128_sub(_1, const 2i128) -> bb6;
|
||||
// ...
|
||||
// _11 = const 7i32 as u32 (Misc);
|
||||
// _1 = const compiler_builtins::int::shift::rust_i128_shr(_1, move _11) -> bb9;
|
||||
// _10 = const 7i32 as u32 (Misc);
|
||||
// _1 = const compiler_builtins::int::shift::rust_i128_shr(_1, move _10) -> bb9;
|
||||
// ...
|
||||
// _12 = const 6i32 as u32 (Misc);
|
||||
// _1 = const compiler_builtins::int::shift::rust_i128_shl(_1, move _12) -> bb10;
|
||||
// _11 = const 6i32 as u32 (Misc);
|
||||
// _1 = const compiler_builtins::int::shift::rust_i128_shl(_1, move _11) -> bb10;
|
||||
// END rustc.test_signed.Lower128Bit.after.mir
|
||||
|
||||
// START rustc.test_unsigned.Lower128Bit.after.mir
|
||||
|
|
@ -194,9 +194,9 @@ fn main() {
|
|||
// ...
|
||||
// _1 = const compiler_builtins::int::addsub::rust_u128_sub(_1, const 2u128) -> bb4;
|
||||
// ...
|
||||
// _5 = const 7i32 as u32 (Misc);
|
||||
// _1 = const compiler_builtins::int::shift::rust_u128_shr(_1, move _5) -> bb7;
|
||||
// _4 = const 7i32 as u32 (Misc);
|
||||
// _1 = const compiler_builtins::int::shift::rust_u128_shr(_1, move _4) -> bb7;
|
||||
// ...
|
||||
// _6 = const 6i32 as u32 (Misc);
|
||||
// _1 = const compiler_builtins::int::shift::rust_u128_shl(_1, move _6) -> bb8;
|
||||
// _5 = const 6i32 as u32 (Misc);
|
||||
// _1 = const compiler_builtins::int::shift::rust_u128_shl(_1, move _5) -> bb8;
|
||||
// END rustc.test_unsigned.Lower128Bit.after.mir
|
||||
|
|
|
|||
|
|
@ -32,9 +32,9 @@ fn main() {
|
|||
|
||||
// END RUST SOURCE
|
||||
// START rustc.main.nll.0.mir
|
||||
// | '_#2r | {bb2[0..=6], bb3[0..=1]}
|
||||
// | '_#3r | {bb2[1..=6], bb3[0..=1]}
|
||||
// | '_#4r | {bb2[5..=6], bb3[0..=1]}
|
||||
// | '_#2r | {bb2[0..=3], bb3[0..=1]}
|
||||
// | '_#3r | {bb2[1..=3], bb3[0..=1]}
|
||||
// | '_#4r | {bb2[3], bb3[0..=1]}
|
||||
// END rustc.main.nll.0.mir
|
||||
// START rustc.main.nll.0.mir
|
||||
// let _6: &'_#4r usize;
|
||||
|
|
@ -43,7 +43,5 @@ fn main() {
|
|||
// ...
|
||||
// _2 = &'_#2r _1[_3];
|
||||
// ...
|
||||
// _7 = _2;
|
||||
// ...
|
||||
// _6 = move _7;
|
||||
// _6 = _2;
|
||||
// END rustc.main.nll.0.mir
|
||||
|
|
|
|||
|
|
@ -67,10 +67,7 @@ fn main() {
|
|||
// Validate(Suspend(ReScope(Remainder(BlockRemainder { block: ItemLocalId(25), first_statement_index: 0 }))), [(*_2): i32]);
|
||||
// _3 = &ReErased (*_2);
|
||||
// Validate(Acquire, [(*_3): i32/ReScope(Remainder(BlockRemainder { block: ItemLocalId(25), first_statement_index: 0 })) (imm)]);
|
||||
// StorageLive(_4);
|
||||
// _4 = (*_3);
|
||||
// _0 = move _4;
|
||||
// StorageDead(_4);
|
||||
// _0 = (*_3);
|
||||
// EndRegion(ReScope(Remainder(BlockRemainder { block: ItemLocalId(25), first_statement_index: 0 })));
|
||||
// StorageDead(_3);
|
||||
// return;
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
error[E0508]: cannot move out of type `[NonCopy; 1]`, a non-copy array
|
||||
--> $DIR/E0508.rs:18:18
|
||||
|
|
||||
LL | let _value = array[0]; //[ast]~ ERROR [E0508]
|
||||
| ^^^^^^^^ cannot move out of here
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0508`.
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
error[E0508]: cannot move out of type `[NonCopy; 1]`, a non-copy array
|
||||
--> $DIR/E0508.rs:18:18
|
||||
|
|
||||
LL | let _value = array[0]; //[ast]~ ERROR [E0508]
|
||||
| ^^^^^^^^ cannot move out of here
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0508`.
|
||||
|
|
@ -8,13 +8,9 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// revisions: ast mir
|
||||
//[mir]compile-flags: -Z borrowck=mir
|
||||
|
||||
struct NonCopy;
|
||||
|
||||
fn main() {
|
||||
let array = [NonCopy; 1];
|
||||
let _value = array[0]; //[ast]~ ERROR [E0508]
|
||||
//[mir]~^ ERROR [E0508]
|
||||
let _value = array[0]; //~ ERROR [E0508]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
error[E0508]: cannot move out of type `[NonCopy; 1]`, a non-copy array
|
||||
--> $DIR/E0508.rs:18:18
|
||||
--> $DIR/E0508.rs:15:18
|
||||
|
|
||||
LL | let _value = array[0]; //[ast]~ ERROR [E0508]
|
||||
LL | let _value = array[0]; //~ ERROR [E0508]
|
||||
| ^^^^^^^^
|
||||
| |
|
||||
| cannot move out of here
|
||||
|
|
@ -1,40 +1,46 @@
|
|||
error[E0507]: cannot move out of borrowed content
|
||||
--> $DIR/borrowck-move-error-with-note.rs:23:19
|
||||
--> $DIR/borrowck-move-error-with-note.rs:21:11
|
||||
|
|
||||
LL | match *f { //~ ERROR cannot move out of
|
||||
| ^^
|
||||
| |
|
||||
| cannot move out of borrowed content
|
||||
| help: consider removing this dereference operator: `f`
|
||||
LL | //~| cannot move out
|
||||
LL | Foo::Foo1(num1,
|
||||
| ^^^^ cannot move out of borrowed content
|
||||
|
||||
error[E0507]: cannot move out of borrowed content
|
||||
--> $DIR/borrowck-move-error-with-note.rs:24:19
|
||||
|
|
||||
| ---- move occurs because num1 has type `std::boxed::Box<u32>`, which does not implement the `Copy` trait
|
||||
LL | num2) => (),
|
||||
| ^^^^ cannot move out of borrowed content
|
||||
|
||||
error[E0507]: cannot move out of borrowed content
|
||||
--> $DIR/borrowck-move-error-with-note.rs:25:19
|
||||
|
|
||||
| ---- move occurs because num2 has type `std::boxed::Box<u32>`, which does not implement the `Copy` trait
|
||||
LL | Foo::Foo2(num) => (),
|
||||
| ^^^ cannot move out of borrowed content
|
||||
| --- move occurs because num has type `std::boxed::Box<u32>`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0509]: cannot move out of type `S`, which implements the `Drop` trait
|
||||
--> $DIR/borrowck-move-error-with-note.rs:42:16
|
||||
--> $DIR/borrowck-move-error-with-note.rs:39:11
|
||||
|
|
||||
LL | f: _s,
|
||||
| ^^ cannot move out of here
|
||||
|
||||
error[E0509]: cannot move out of type `S`, which implements the `Drop` trait
|
||||
--> $DIR/borrowck-move-error-with-note.rs:43:16
|
||||
LL | match (S {f: "foo".to_string(), g: "bar".to_string()}) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of here
|
||||
help: to prevent move, use ref or ref mut
|
||||
|
|
||||
LL | g: _t
|
||||
| ^^ cannot move out of here
|
||||
LL | f: ref _s,
|
||||
| ^^^^^^
|
||||
help: to prevent move, use ref or ref mut
|
||||
|
|
||||
LL | g: ref _t
|
||||
| ^^^^^^
|
||||
|
||||
error[E0507]: cannot move out of borrowed content
|
||||
--> $DIR/borrowck-move-error-with-note.rs:59:9
|
||||
--> $DIR/borrowck-move-error-with-note.rs:57:11
|
||||
|
|
||||
LL | match a.a { //~ ERROR cannot move out of
|
||||
| ^^^
|
||||
| |
|
||||
| cannot move out of borrowed content
|
||||
| help: consider using a reference instead: `&a.a`
|
||||
LL | //~| cannot move out
|
||||
LL | n => {
|
||||
| ^ cannot move out of borrowed content
|
||||
| - move occurs because n has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
Some errors occurred: E0507, E0509.
|
||||
For more information about an error, try `rustc --explain E0507`.
|
||||
|
|
|
|||
|
|
@ -1,15 +1,17 @@
|
|||
error[E0508]: cannot move out of type `[Foo]`, a non-copy slice
|
||||
--> $DIR/borrowck-move-out-of-vec-tail.rs:30:33
|
||||
--> $DIR/borrowck-move-out-of-vec-tail.rs:29:19
|
||||
|
|
||||
LL | &[Foo { string: a },
|
||||
| ^ cannot move out of here
|
||||
|
||||
error[E0508]: cannot move out of type `[Foo]`, a non-copy slice
|
||||
--> $DIR/borrowck-move-out-of-vec-tail.rs:34:33
|
||||
LL | match tail {
|
||||
| ^^^^ cannot move out of here
|
||||
help: to prevent move, use ref or ref mut
|
||||
|
|
||||
LL | Foo { string: b }] => {
|
||||
| ^ cannot move out of here
|
||||
LL | &[Foo { string: ref a },
|
||||
| ^^^^^
|
||||
help: to prevent move, use ref or ref mut
|
||||
|
|
||||
LL | Foo { string: ref b }] => {
|
||||
| ^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0508`.
|
||||
|
|
|
|||
|
|
@ -23,54 +23,68 @@ LL | _b.use_ref();
|
|||
| -- borrow later used here
|
||||
|
||||
error[E0508]: cannot move out of type `[std::boxed::Box<isize>]`, a non-copy slice
|
||||
--> $DIR/borrowck-vec-pattern-nesting.rs:44:15
|
||||
--> $DIR/borrowck-vec-pattern-nesting.rs:43:11
|
||||
|
|
||||
LL | match vec {
|
||||
| ^^^ cannot move out of here
|
||||
LL | &mut [_a, //~ ERROR cannot move out
|
||||
| ^^ cannot move out of here
|
||||
| -- help: to prevent move, use ref or ref mut: `ref _a`
|
||||
|
||||
error[E0508]: cannot move out of type `[std::boxed::Box<isize>]`, a non-copy slice
|
||||
--> $DIR/borrowck-vec-pattern-nesting.rs:57:13
|
||||
|
|
||||
LL | let a = vec[0]; //~ ERROR cannot move out
|
||||
| ^^^^^^ cannot move out of here
|
||||
| ^^^^^^
|
||||
| |
|
||||
| cannot move out of here
|
||||
| help: consider using a reference instead: `&vec[0]`
|
||||
|
||||
error[E0508]: cannot move out of type `[std::boxed::Box<isize>]`, a non-copy slice
|
||||
--> $DIR/borrowck-vec-pattern-nesting.rs:67:10
|
||||
--> $DIR/borrowck-vec-pattern-nesting.rs:64:11
|
||||
|
|
||||
LL | match vec {
|
||||
| ^^^ cannot move out of here
|
||||
...
|
||||
LL | _b] => {}
|
||||
| ^^ cannot move out of here
|
||||
| -- help: to prevent move, use ref or ref mut: `ref _b`
|
||||
|
||||
error[E0508]: cannot move out of type `[std::boxed::Box<isize>]`, a non-copy slice
|
||||
--> $DIR/borrowck-vec-pattern-nesting.rs:70:13
|
||||
|
|
||||
LL | let a = vec[0]; //~ ERROR cannot move out
|
||||
| ^^^^^^ cannot move out of here
|
||||
| ^^^^^^
|
||||
| |
|
||||
| cannot move out of here
|
||||
| help: consider using a reference instead: `&vec[0]`
|
||||
|
||||
error[E0508]: cannot move out of type `[std::boxed::Box<isize>]`, a non-copy slice
|
||||
--> $DIR/borrowck-vec-pattern-nesting.rs:78:15
|
||||
--> $DIR/borrowck-vec-pattern-nesting.rs:77:11
|
||||
|
|
||||
LL | &mut [_a, _b, _c] => {} //~ ERROR cannot move out
|
||||
| ^^ cannot move out of here
|
||||
|
||||
error[E0508]: cannot move out of type `[std::boxed::Box<isize>]`, a non-copy slice
|
||||
--> $DIR/borrowck-vec-pattern-nesting.rs:78:19
|
||||
LL | match vec {
|
||||
| ^^^ cannot move out of here
|
||||
help: to prevent move, use ref or ref mut
|
||||
|
|
||||
LL | &mut [_a, _b, _c] => {} //~ ERROR cannot move out
|
||||
| ^^ cannot move out of here
|
||||
|
||||
error[E0508]: cannot move out of type `[std::boxed::Box<isize>]`, a non-copy slice
|
||||
--> $DIR/borrowck-vec-pattern-nesting.rs:78:23
|
||||
LL | &mut [ref _a, _b, _c] => {} //~ ERROR cannot move out
|
||||
| ^^^^^^
|
||||
help: to prevent move, use ref or ref mut
|
||||
|
|
||||
LL | &mut [_a, _b, _c] => {} //~ ERROR cannot move out
|
||||
| ^^ cannot move out of here
|
||||
LL | &mut [_a, ref _b, _c] => {} //~ ERROR cannot move out
|
||||
| ^^^^^^
|
||||
help: to prevent move, use ref or ref mut
|
||||
|
|
||||
LL | &mut [_a, _b, ref _c] => {} //~ ERROR cannot move out
|
||||
| ^^^^^^
|
||||
|
||||
error[E0508]: cannot move out of type `[std::boxed::Box<isize>]`, a non-copy slice
|
||||
--> $DIR/borrowck-vec-pattern-nesting.rs:82:13
|
||||
|
|
||||
LL | let a = vec[0]; //~ ERROR cannot move out
|
||||
| ^^^^^^ cannot move out of here
|
||||
| ^^^^^^
|
||||
| |
|
||||
| cannot move out of here
|
||||
| help: consider using a reference instead: `&vec[0]`
|
||||
|
||||
error: aborting due to 10 previous errors
|
||||
error: aborting due to 8 previous errors
|
||||
|
||||
Some errors occurred: E0506, E0508.
|
||||
For more information about an error, try `rustc --explain E0506`.
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
error[E0507]: cannot move out of borrowed content
|
||||
--> $DIR/issue-51415.rs:16:47
|
||||
--> $DIR/issue-51415.rs:16:42
|
||||
|
|
||||
LL | let opt = a.iter().enumerate().find(|(_, &s)| {
|
||||
| ^ cannot move out of borrowed content
|
||||
| ^^^^^-^
|
||||
| | |
|
||||
| | help: to prevent move, use ref or ref mut: `ref s`
|
||||
| cannot move out of borrowed content
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
error[E0509]: cannot move out of type `S`, which implements the `Drop` trait
|
||||
--> $DIR/overlapping_spans.rs:21:14
|
||||
--> $DIR/overlapping_spans.rs:20:11
|
||||
|
|
||||
LL | match (S {f:"foo".to_string()}) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of here
|
||||
LL | S {f:_s} => {} //~ ERROR cannot move out
|
||||
| ^^ cannot move out of here
|
||||
| -- help: to prevent move, use ref or ref mut: `ref _s`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
error[E0509]: cannot move out of type `DropStruct`, which implements the `Drop` trait
|
||||
--> $DIR/E0509.rs:26:23
|
||||
|
|
||||
LL | let fancy_field = drop_struct.fancy; //~ ERROR E0509
|
||||
| ^^^^^^^^^^^^^^^^^ cannot move out of here
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0509`.
|
||||
|
|
@ -2,7 +2,10 @@ error[E0507]: cannot move out of borrowed content
|
|||
--> $DIR/issue-40402-1.rs:19:13
|
||||
|
|
||||
LL | let e = f.v[0]; //~ ERROR cannot move out of indexed content
|
||||
| ^^^^^^ cannot move out of borrowed content
|
||||
| ^^^^^^
|
||||
| |
|
||||
| cannot move out of borrowed content
|
||||
| help: consider using a reference instead: `&f.v[0]`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -1,15 +1,14 @@
|
|||
error[E0507]: cannot move out of borrowed content
|
||||
--> $DIR/issue-40402-2.rs:15:10
|
||||
--> $DIR/issue-40402-2.rs:15:18
|
||||
|
|
||||
LL | let (a, b) = x[0]; //~ ERROR cannot move out of indexed content
|
||||
| ^ cannot move out of borrowed content
|
||||
| - - ^^^^
|
||||
| | | |
|
||||
| | | cannot move out of borrowed content
|
||||
| | | help: consider using a reference instead: `&x[0]`
|
||||
| | move occurs because b has type `std::string::String`, which does not implement the `Copy` trait
|
||||
| move occurs because a has type `std::string::String`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0507]: cannot move out of borrowed content
|
||||
--> $DIR/issue-40402-2.rs:15:13
|
||||
|
|
||||
LL | let (a, b) = x[0]; //~ ERROR cannot move out of indexed content
|
||||
| ^ cannot move out of borrowed content
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0507`.
|
||||
|
|
|
|||
|
|
@ -1,8 +1,14 @@
|
|||
error[E0507]: cannot move out of borrowed content
|
||||
--> $DIR/moves-based-on-type-block-bad.rs:37:28
|
||||
--> $DIR/moves-based-on-type-block-bad.rs:34:19
|
||||
|
|
||||
LL | match hellothere.x { //~ ERROR cannot move out
|
||||
| ^^^^^^^^^^^^
|
||||
| |
|
||||
| cannot move out of borrowed content
|
||||
| help: consider using a reference instead: `&hellothere.x`
|
||||
...
|
||||
LL | box E::Bar(x) => println!("{}", x.to_string()),
|
||||
| ^ cannot move out of borrowed content
|
||||
| - move occurs because x has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
|||
130
src/test/ui/nll/move-errors.rs
Normal file
130
src/test/ui/nll/move-errors.rs
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![allow(unused)]
|
||||
#![feature(nll)]
|
||||
|
||||
struct A(String);
|
||||
struct C(D);
|
||||
|
||||
fn suggest_remove_deref() {
|
||||
let a = &A("".to_string());
|
||||
let b = *a;
|
||||
//~^ ERROR
|
||||
}
|
||||
|
||||
fn suggest_borrow() {
|
||||
let a = [A("".to_string())];
|
||||
let b = a[0];
|
||||
//~^ ERROR
|
||||
}
|
||||
|
||||
fn suggest_borrow2() {
|
||||
let mut a = A("".to_string());
|
||||
let r = &&mut a;
|
||||
let s = **r;
|
||||
//~^ ERROR
|
||||
}
|
||||
|
||||
fn suggest_borrow3() {
|
||||
use std::rc::Rc;
|
||||
let mut a = A("".to_string());
|
||||
let r = Rc::new(a);
|
||||
let s = *r;
|
||||
//~^ ERROR
|
||||
}
|
||||
|
||||
fn suggest_borrow4() {
|
||||
let a = [A("".to_string())][0];
|
||||
//~^ ERROR
|
||||
}
|
||||
|
||||
fn suggest_borrow5() {
|
||||
let a = &A("".to_string());
|
||||
let A(s) = *a;
|
||||
//~^ ERROR
|
||||
}
|
||||
|
||||
fn suggest_ref() {
|
||||
let c = C(D(String::new()));
|
||||
let C(D(s)) = c;
|
||||
//~^ ERROR
|
||||
}
|
||||
|
||||
fn suggest_nothing() {
|
||||
let a = &A("".to_string());
|
||||
let b;
|
||||
b = *a;
|
||||
//~^ ERROR
|
||||
}
|
||||
|
||||
enum B {
|
||||
V(String),
|
||||
U(D),
|
||||
}
|
||||
|
||||
struct D(String);
|
||||
|
||||
impl Drop for D {
|
||||
fn drop(&mut self) {}
|
||||
}
|
||||
|
||||
struct F(String, String);
|
||||
|
||||
impl Drop for F {
|
||||
fn drop(&mut self) {}
|
||||
}
|
||||
|
||||
fn probably_suggest_borrow() {
|
||||
let x = [B::V(String::new())];
|
||||
match x[0] {
|
||||
//~^ ERROR
|
||||
B::U(d) => (),
|
||||
B::V(s) => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn have_to_suggest_ref() {
|
||||
let x = B::V(String::new());
|
||||
match x {
|
||||
//~^ ERROR
|
||||
B::V(s) => drop(s),
|
||||
B::U(D(s)) => (),
|
||||
};
|
||||
}
|
||||
|
||||
fn two_separate_errors() {
|
||||
let x = (D(String::new()), &String::new());
|
||||
match x {
|
||||
//~^ ERROR
|
||||
//~^^ ERROR
|
||||
(D(s), &t) => (),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn have_to_suggest_double_ref() {
|
||||
let x = F(String::new(), String::new());
|
||||
match x {
|
||||
//~^ ERROR
|
||||
F(s, mut t) => (),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn double_binding(x: &Result<String, String>) {
|
||||
match *x {
|
||||
//~^ ERROR
|
||||
Ok(s) | Err(s) => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
||||
140
src/test/ui/nll/move-errors.stderr
Normal file
140
src/test/ui/nll/move-errors.stderr
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
error[E0507]: cannot move out of borrowed content
|
||||
--> $DIR/move-errors.rs:19:13
|
||||
|
|
||||
LL | let b = *a;
|
||||
| ^^
|
||||
| |
|
||||
| cannot move out of borrowed content
|
||||
| help: consider removing this dereference operator: `a`
|
||||
|
||||
error[E0508]: cannot move out of type `[A; 1]`, a non-copy array
|
||||
--> $DIR/move-errors.rs:25:13
|
||||
|
|
||||
LL | let b = a[0];
|
||||
| ^^^^
|
||||
| |
|
||||
| cannot move out of here
|
||||
| help: consider using a reference instead: `&a[0]`
|
||||
|
||||
error[E0507]: cannot move out of borrowed content
|
||||
--> $DIR/move-errors.rs:32:13
|
||||
|
|
||||
LL | let s = **r;
|
||||
| ^^^
|
||||
| |
|
||||
| cannot move out of borrowed content
|
||||
| help: consider using a reference instead: `&**r`
|
||||
|
||||
error[E0507]: cannot move out of borrowed content
|
||||
--> $DIR/move-errors.rs:40:13
|
||||
|
|
||||
LL | let s = *r;
|
||||
| ^^
|
||||
| |
|
||||
| cannot move out of borrowed content
|
||||
| help: consider using a reference instead: `&*r`
|
||||
|
||||
error[E0508]: cannot move out of type `[A; 1]`, a non-copy array
|
||||
--> $DIR/move-errors.rs:45:13
|
||||
|
|
||||
LL | let a = [A("".to_string())][0];
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| cannot move out of here
|
||||
| help: consider using a reference instead: `&[A("".to_string())][0]`
|
||||
|
||||
error[E0507]: cannot move out of borrowed content
|
||||
--> $DIR/move-errors.rs:51:16
|
||||
|
|
||||
LL | let A(s) = *a;
|
||||
| - ^^
|
||||
| | |
|
||||
| | cannot move out of borrowed content
|
||||
| | help: consider removing this dereference operator: `a`
|
||||
| move occurs because s has type `std::string::String`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0509]: cannot move out of type `D`, which implements the `Drop` trait
|
||||
--> $DIR/move-errors.rs:57:19
|
||||
|
|
||||
LL | let C(D(s)) = c;
|
||||
| - ^ cannot move out of here
|
||||
| |
|
||||
| help: to prevent move, use ref or ref mut: `ref s`
|
||||
|
||||
error[E0507]: cannot move out of borrowed content
|
||||
--> $DIR/move-errors.rs:64:9
|
||||
|
|
||||
LL | b = *a;
|
||||
| ^^ cannot move out of borrowed content
|
||||
|
||||
error[E0508]: cannot move out of type `[B; 1]`, a non-copy array
|
||||
--> $DIR/move-errors.rs:87:11
|
||||
|
|
||||
LL | match x[0] {
|
||||
| ^^^^
|
||||
| |
|
||||
| cannot move out of here
|
||||
| help: consider using a reference instead: `&x[0]`
|
||||
LL | //~^ ERROR
|
||||
LL | B::U(d) => (),
|
||||
| - move occurs because d has type `D`, which does not implement the `Copy` trait
|
||||
LL | B::V(s) => (),
|
||||
| - move occurs because s has type `std::string::String`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0509]: cannot move out of type `D`, which implements the `Drop` trait
|
||||
--> $DIR/move-errors.rs:96:11
|
||||
|
|
||||
LL | match x {
|
||||
| ^ cannot move out of here
|
||||
...
|
||||
LL | B::U(D(s)) => (),
|
||||
| - help: to prevent move, use ref or ref mut: `ref s`
|
||||
|
||||
error[E0509]: cannot move out of type `D`, which implements the `Drop` trait
|
||||
--> $DIR/move-errors.rs:105:11
|
||||
|
|
||||
LL | match x {
|
||||
| ^ cannot move out of here
|
||||
...
|
||||
LL | (D(s), &t) => (),
|
||||
| - help: to prevent move, use ref or ref mut: `ref s`
|
||||
|
||||
error[E0507]: cannot move out of borrowed content
|
||||
--> $DIR/move-errors.rs:105:11
|
||||
|
|
||||
LL | match x {
|
||||
| ^ cannot move out of borrowed content
|
||||
...
|
||||
LL | (D(s), &t) => (),
|
||||
| - help: to prevent move, use ref or ref mut: `ref t`
|
||||
|
||||
error[E0509]: cannot move out of type `F`, which implements the `Drop` trait
|
||||
--> $DIR/move-errors.rs:115:11
|
||||
|
|
||||
LL | match x {
|
||||
| ^ cannot move out of here
|
||||
help: to prevent move, use ref or ref mut
|
||||
|
|
||||
LL | F(ref s, mut t) => (),
|
||||
| ^^^^^
|
||||
help: to prevent move, use ref or ref mut
|
||||
|
|
||||
LL | F(s, ref mut t) => (),
|
||||
| ^^^^^^^^^
|
||||
|
||||
error[E0507]: cannot move out of borrowed content
|
||||
--> $DIR/move-errors.rs:123:11
|
||||
|
|
||||
LL | match *x {
|
||||
| ^^
|
||||
| |
|
||||
| cannot move out of borrowed content
|
||||
| help: consider removing this dereference operator: `x`
|
||||
LL | //~^ ERROR
|
||||
LL | Ok(s) | Err(s) => (),
|
||||
| - move occurs because s has type `std::string::String`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to 14 previous errors
|
||||
|
||||
Some errors occurred: E0507, E0508, E0509.
|
||||
For more information about an error, try `rustc --explain E0507`.
|
||||
Loading…
Add table
Add a link
Reference in a new issue