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:
bors 2018-06-29 12:40:12 +00:00
commit ab8a67c12a
42 changed files with 997 additions and 321 deletions

View file

@ -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,

View file

@ -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
}
};

View 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,
},
}
}
}

View file

@ -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.

View file

@ -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

View file

@ -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,

View file

@ -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`).

View file

@ -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());

View file

@ -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));
}
}
}

View file

@ -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
})),

View file

@ -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 }
}
}

View file

@ -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

View file

@ -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]
}
}

View file

@ -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

View file

@ -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;
// }

View file

@ -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;
// }

View file

@ -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

View file

@ -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;

View file

@ -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];

View file

@ -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;
// }
// }

View file

@ -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;

View file

@ -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;
// }

View file

@ -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;
// }

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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`.

View file

@ -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`.

View file

@ -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]
}

View file

@ -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

View file

@ -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`.

View file

@ -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`.

View file

@ -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`.

View file

@ -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

View file

@ -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

View file

@ -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`.

View file

@ -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

View file

@ -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`.

View file

@ -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

View 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() {
}

View 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`.