Auto merge of #51688 - spastorino:error-note-field-after-move, r=nikomatsakis

Fix erroneous error note when using field after move

Closes #51512

r? @nikomatsakis
This commit is contained in:
bors 2018-06-25 06:44:08 +00:00
commit 5f9c7f9e6d
10 changed files with 766 additions and 484 deletions

View File

@ -680,7 +680,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
let mut err = self.cannot_act_on_moved_value(use_span,
verb,
msg,
&format!("{}", nl),
Some(format!("{}", nl)),
Origin::Ast);
let need_note = match lp.ty.sty {
ty::TypeVariants::TyClosure(id, _) => {

View File

@ -52,7 +52,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
self.moved_error_reported.insert(root_place.clone());
let item_msg = match self.describe_place(place) {
let item_msg = match self.describe_place_with_options(place, IncludingDowncast(true)) {
Some(name) => format!("`{}`", name),
None => "value".to_owned(),
};
@ -60,7 +60,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
.cannot_act_on_uninitialized_variable(
span,
desired_action.as_noun(),
&self.describe_place(place).unwrap_or("_".to_owned()),
&self
.describe_place_with_options(place, IncludingDowncast(true))
.unwrap_or("_".to_owned()),
Origin::Mir,
)
.span_label(span, format!("use of possibly uninitialized {}", item_msg))
@ -72,14 +74,17 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
span,
desired_action.as_noun(),
msg,
&self.describe_place(place).unwrap_or("_".to_owned()),
self.describe_place_with_options(&place, IncludingDowncast(true)),
Origin::Mir,
);
let mut is_loop_move = false;
for moi in mois {
for moi in &mois {
let move_msg = ""; //FIXME: add " (into closure)"
let move_span = self.mir.source_info(self.move_data.moves[*moi].source).span;
let move_span = self
.mir
.source_info(self.move_data.moves[**moi].source)
.span;
if span == move_span {
err.span_label(
span,
@ -116,16 +121,23 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
};
if needs_note {
let note_msg = match self.describe_place(place) {
Some(name) => format!("`{}`", name),
None => "value".to_owned(),
};
let mpi = self.move_data.moves[*mois[0]].path;
let place = &self.move_data.move_paths[mpi].place;
err.note(&format!(
"move occurs because {} has type `{}`, \
which does not implement the `Copy` trait",
note_msg, ty
));
if let Some(ty) = self.retrieve_type_for_place(place) {
let note_msg = match self
.describe_place_with_options(place, IncludingDowncast(true))
{
Some(name) => format!("`{}`", name),
None => "value".to_owned(),
};
err.note(&format!(
"move occurs because {} has type `{}`, \
which does not implement the `Copy` trait",
note_msg, ty
));
}
}
}
@ -644,8 +656,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
let local_decl = &self.mir.local_decls[*local];
if let Some(name) = local_decl.name {
if local_decl.can_be_made_mutable() {
err.span_label(local_decl.source_info.span,
format!("consider changing this to `mut {}`", name));
err.span_label(
local_decl.source_info.span,
format!("consider changing this to `mut {}`", name),
);
}
}
}
@ -654,12 +668,26 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
}
}
pub(super) struct IncludingDowncast(bool);
impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
// End-user visible description of `place` if one can be found. If the
// place is a temporary for instance, None will be returned.
pub(super) fn describe_place(&self, place: &Place<'tcx>) -> Option<String> {
self.describe_place_with_options(place, IncludingDowncast(false))
}
// End-user visible description of `place` if one can be found. If the
// place is a temporary for instance, None will be returned.
// `IncludingDowncast` parameter makes the function return `Err` if `ProjectionElem` is
// `Downcast` and `IncludingDowncast` is true
pub(super) fn describe_place_with_options(
&self,
place: &Place<'tcx>,
including_downcast: IncludingDowncast,
) -> Option<String> {
let mut buf = String::new();
match self.append_place_to_string(place, &mut buf, false) {
match self.append_place_to_string(place, &mut buf, false, &including_downcast) {
Ok(()) => Some(buf),
Err(()) => None,
}
@ -671,6 +699,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
place: &Place<'tcx>,
buf: &mut String,
mut autoderef: bool,
including_downcast: &IncludingDowncast,
) -> Result<(), ()> {
match *place {
Place::Local(local) => {
@ -692,15 +721,33 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
}
} else {
if autoderef {
self.append_place_to_string(&proj.base, buf, autoderef)?;
self.append_place_to_string(
&proj.base,
buf,
autoderef,
&including_downcast,
)?;
} else {
buf.push_str(&"*");
self.append_place_to_string(&proj.base, buf, autoderef)?;
self.append_place_to_string(
&proj.base,
buf,
autoderef,
&including_downcast,
)?;
}
}
}
ProjectionElem::Downcast(..) => {
self.append_place_to_string(&proj.base, buf, autoderef)?;
self.append_place_to_string(
&proj.base,
buf,
autoderef,
&including_downcast,
)?;
if including_downcast.0 {
return Err(());
}
}
ProjectionElem::Field(field, _ty) => {
autoderef = true;
@ -711,14 +758,24 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
buf.push_str(&name);
} else {
let field_name = self.describe_field(&proj.base, field);
self.append_place_to_string(&proj.base, buf, autoderef)?;
self.append_place_to_string(
&proj.base,
buf,
autoderef,
&including_downcast,
)?;
buf.push_str(&format!(".{}", field_name));
}
}
ProjectionElem::Index(index) => {
autoderef = true;
self.append_place_to_string(&proj.base, buf, autoderef)?;
self.append_place_to_string(
&proj.base,
buf,
autoderef,
&including_downcast,
)?;
buf.push_str("[");
if let Err(_) = self.append_local_to_string(index, buf) {
buf.push_str("..");
@ -730,7 +787,12 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
// Since it isn't possible to borrow an element on a particular index and
// then use another while the borrow is held, don't output indices details
// to avoid confusing the end-user
self.append_place_to_string(&proj.base, buf, autoderef)?;
self.append_place_to_string(
&proj.base,
buf,
autoderef,
&including_downcast,
)?;
buf.push_str(&"[..]");
}
};

View File

@ -15,13 +15,13 @@ use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::hir::map::definitions::DefPathData;
use rustc::infer::InferCtxt;
use rustc::ty::{self, ParamEnv, TyCtxt};
use rustc::ty::query::Providers;
use rustc::lint::builtin::UNUSED_MUT;
use rustc::mir::{self, AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind};
use rustc::mir::{ClearCrossCrate, Local, Location, Place, Mir, Mutability, Operand};
use rustc::mir::{Projection, ProjectionElem, Rvalue, Field, Statement, StatementKind};
use rustc::mir::{ClearCrossCrate, Local, Location, Mir, Mutability, Operand, Place};
use rustc::mir::{Field, Projection, ProjectionElem, Rvalue, Statement, StatementKind};
use rustc::mir::{Terminator, TerminatorKind};
use rustc::ty::query::Providers;
use rustc::ty::{self, ParamEnv, TyCtxt};
use rustc_data_structures::control_flow_graph::dominators::Dominators;
use rustc_data_structures::fx::FxHashSet;
@ -33,20 +33,20 @@ use std::rc::Rc;
use syntax_pos::Span;
use dataflow::{do_dataflow, DebugFormatted};
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;
use dataflow::MoveDataParamEnv;
use dataflow::{DataflowResultsConsumer};
use dataflow::{MaybeInitializedPlaces, MaybeUninitializedPlaces};
use dataflow::{do_dataflow, DebugFormatted};
use dataflow::{EverInitializedPlaces, MovingOutStatements};
use dataflow::Borrows;
use dataflow::indexes::BorrowIndex;
use dataflow::move_paths::{IllegalMoveOriginKind, MoveError};
use dataflow::move_paths::{HasMoveData, LookupResult, MoveData, MovePathIndex};
use dataflow::{MaybeInitializedPlaces, MaybeUninitializedPlaces};
use util::borrowck_errors::{BorrowckErrors, Origin};
use util::collect_writes::FindAssignments;
use self::borrow_set::{BorrowSet, BorrowData};
use self::borrow_set::{BorrowData, BorrowSet};
use self::flows::Flows;
use self::location::LocationTable;
use self::prefixes::PrefixSet;
@ -58,9 +58,9 @@ crate mod borrow_set;
mod error_reporting;
mod flows;
mod location;
mod path_utils;
crate mod place_ext;
mod prefixes;
mod path_utils;
mod used_muts;
pub(crate) mod nll;
@ -72,10 +72,7 @@ pub fn provide(providers: &mut Providers) {
};
}
fn mir_borrowck<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId,
) -> BorrowCheckResult<'tcx> {
fn mir_borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> BorrowCheckResult<'tcx> {
let input_mir = tcx.mir_validated(def_id);
debug!("run query mir_borrowck: {}", tcx.item_path_str(def_id));
@ -103,7 +100,8 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
let tcx = infcx.tcx;
let attributes = tcx.get_attrs(def_id);
let param_env = tcx.param_env(def_id);
let id = tcx.hir
let id = tcx
.hir
.as_local_node_id(def_id)
.expect("do_mir_borrowck: non-local DefId");
@ -138,9 +136,10 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
// 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)
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 } => {
@ -277,16 +276,21 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
// Note that this set is expected to be small - only upvars from closures
// would have a chance of erroneously adding non-user-defined mutable vars
// to the set.
let temporary_used_locals: FxHashSet<Local> =
mbcx.used_mut.iter()
.filter(|&local| !mbcx.mir.local_decls[*local].is_user_variable.is_some())
.cloned()
.collect();
let temporary_used_locals: FxHashSet<Local> = mbcx
.used_mut
.iter()
.filter(|&local| !mbcx.mir.local_decls[*local].is_user_variable.is_some())
.cloned()
.collect();
mbcx.gather_used_muts(temporary_used_locals);
debug!("mbcx.used_mut: {:?}", mbcx.used_mut);
for local in mbcx.mir.mut_vars_and_args_iter().filter(|local| !mbcx.used_mut.contains(local)) {
for local in mbcx
.mir
.mut_vars_and_args_iter()
.filter(|local| !mbcx.used_mut.contains(local))
{
if let ClearCrossCrate::Set(ref vsi) = mbcx.mir.source_scope_local_data {
let local_decl = &mbcx.mir.local_decls[local];
@ -297,7 +301,9 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
// Skip over locals that begin with an underscore or have no name
match local_decl.name {
Some(name) => if name.as_str().starts_with("_") { continue; },
Some(name) => if name.as_str().starts_with("_") {
continue;
},
None => continue,
}
@ -308,10 +314,9 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
UNUSED_MUT,
vsi[local_decl.source_info.scope].lint_root,
span,
"variable does not need to be mutable"
)
.span_suggestion_short(mut_span, "remove this `mut`", "".to_owned())
.emit();
"variable does not need to be mutable",
).span_suggestion_short(mut_span, "remove this `mut`", "".to_owned())
.emit();
}
}
@ -419,12 +424,13 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
);
}
StatementKind::ReadForMatch(ref place) => {
self.access_place(ContextKind::ReadForMatch.new(location),
(place, span),
(Deep, Read(ReadKind::Borrow(BorrowKind::Shared))),
LocalMutationIsAllowed::No,
flow_state,
);
self.access_place(
ContextKind::ReadForMatch.new(location),
(place, span),
(Deep, Read(ReadKind::Borrow(BorrowKind::Shared))),
LocalMutationIsAllowed::No,
flow_state,
);
}
StatementKind::SetDiscriminant {
ref place,
@ -479,10 +485,10 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
// ignored when consuming results (update to
// flow_state already handled).
}
StatementKind::Nop |
StatementKind::UserAssertTy(..) |
StatementKind::Validate(..) |
StatementKind::StorageLive(..) => {
StatementKind::Nop
| StatementKind::UserAssertTy(..)
| StatementKind::Validate(..)
| StatementKind::StorageLive(..) => {
// `Nop`, `UserAssertTy`, `Validate`, and `StorageLive` are irrelevant
// to borrow check.
}
@ -596,11 +602,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
use rustc::mir::interpret::EvalErrorKind::BoundsCheck;
if let BoundsCheck { ref len, ref index } = *msg {
self.consume_operand(ContextKind::Assert.new(loc), (len, span), flow_state);
self.consume_operand(
ContextKind::Assert.new(loc),
(index, span),
flow_state,
);
self.consume_operand(ContextKind::Assert.new(loc), (index, span), flow_state);
}
}
@ -660,8 +662,8 @@ enum MutateMode {
WriteAndRead,
}
use self::ShallowOrDeep::{Deep, Shallow};
use self::ReadOrWrite::{Activation, Read, Reservation, Write};
use self::ShallowOrDeep::{Deep, Shallow};
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
enum ArtificialField {
@ -795,10 +797,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
span: Span,
) {
let gcx = self.tcx.global_tcx();
let drop_field = |
mir: &mut MirBorrowckCtxt<'cx, 'gcx, 'tcx>,
(index, field): (usize, ty::Ty<'gcx>),
| {
let drop_field = |mir: &mut MirBorrowckCtxt<'cx, 'gcx, 'tcx>,
(index, field): (usize, ty::Ty<'gcx>)| {
let field_ty = gcx.normalize_erasing_regions(mir.param_env, field);
let place = drop_place.clone().field(Field::new(index), field_ty);
@ -820,23 +820,31 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
}
// Same as above, but for tuples.
ty::TyTuple(tys) => {
tys.iter().cloned().enumerate()
tys.iter()
.cloned()
.enumerate()
.for_each(|field| drop_field(self, field));
}
// Closures also have disjoint fields, but they are only
// directly accessed in the body of the closure.
ty::TyClosure(def, substs)
if *drop_place == Place::Local(Local::new(1)) && !self.mir.upvar_decls.is_empty()
=> {
substs.upvar_tys(def, self.tcx).enumerate()
if *drop_place == Place::Local(Local::new(1))
&& !self.mir.upvar_decls.is_empty() =>
{
substs
.upvar_tys(def, self.tcx)
.enumerate()
.for_each(|field| drop_field(self, field));
}
// Generators also have disjoint fields, but they are only
// directly accessed in the body of the generator.
ty::TyGenerator(def, substs, _)
if *drop_place == Place::Local(Local::new(1)) && !self.mir.upvar_decls.is_empty()
=> {
substs.upvar_tys(def, self.tcx).enumerate()
if *drop_place == Place::Local(Local::new(1))
&& !self.mir.upvar_decls.is_empty() =>
{
substs
.upvar_tys(def, self.tcx)
.enumerate()
.for_each(|field| drop_field(self, field));
}
_ => {
@ -888,7 +896,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
}
}
if self.access_place_error_reported
if self
.access_place_error_reported
.contains(&(place_span.0.clone(), place_span.1))
{
debug!(
@ -931,10 +940,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
) -> bool {
debug!(
"check_access_for_conflict(context={:?}, place_span={:?}, sd={:?}, rw={:?})",
context,
place_span,
sd,
rw,
context, place_span, sd, rw,
);
let mut error_reported = false;
@ -951,8 +957,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
(sd, place_span.0),
&borrow_set,
flow_state.borrows_in_scope(location),
|this, borrow_index, borrow|
match (rw, borrow.kind) {
|this, borrow_index, borrow| match (rw, borrow.kind) {
// Obviously an activation is compatible with its own
// reservation (or even prior activating uses of same
// borrow); so don't check if they interfere.
@ -989,12 +994,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
}
ReadKind::Borrow(bk) => {
error_reported = true;
this.report_conflicting_borrow(
context,
place_span,
bk,
&borrow,
)
this.report_conflicting_borrow(context, place_span, bk, &borrow)
}
}
Control::Break
@ -1026,12 +1026,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
match kind {
WriteKind::MutableBorrow(bk) => {
error_reported = true;
this.report_conflicting_borrow(
context,
place_span,
bk,
&borrow,
)
this.report_conflicting_borrow(context, place_span, bk, &borrow)
}
WriteKind::StorageDeadOrDrop => {
error_reported = true;
@ -1185,7 +1180,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
// moved into the closure and subsequently used by the closure,
// in order to populate our used_mut set.
if let AggregateKind::Closure(def_id, _) = &**aggregate_kind {
let BorrowCheckResult { used_mut_upvars, .. } = self.tcx.mir_borrowck(*def_id);
let BorrowCheckResult {
used_mut_upvars, ..
} = self.tcx.mir_borrowck(*def_id);
debug!("{:?} used_mut_upvars={:?}", def_id, used_mut_upvars);
for field in used_mut_upvars {
match operands[field.index()] {
@ -1197,9 +1194,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
self.used_mut_upvars.push(field);
}
}
Operand::Move(Place::Static(..)) |
Operand::Copy(..) |
Operand::Constant(..) => {}
Operand::Move(Place::Static(..))
| Operand::Copy(..)
| Operand::Constant(..) => {}
}
}
}
@ -1280,7 +1277,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
Place::Static(statik) => {
// Thread-locals might be dropped after the function exits, but
// "true" statics will never be.
let is_thread_local = self.tcx
let is_thread_local = self
.tcx
.get_attrs(statik.def_id)
.iter()
.any(|attr| attr.check_name("thread_local"));
@ -1676,8 +1674,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
Reservation(WriteKind::MutableBorrow(borrow_kind @ BorrowKind::Unique))
| Reservation(WriteKind::MutableBorrow(borrow_kind @ BorrowKind::Mut { .. }))
| Write(WriteKind::MutableBorrow(borrow_kind @ BorrowKind::Unique))
| Write(WriteKind::MutableBorrow(borrow_kind @ BorrowKind::Mut { .. })) =>
{
| Write(WriteKind::MutableBorrow(borrow_kind @ BorrowKind::Mut { .. })) => {
let is_local_mutation_allowed = match borrow_kind {
BorrowKind::Unique => LocalMutationIsAllowed::Yes,
BorrowKind::Mut { .. } => is_local_mutation_allowed,
@ -1747,28 +1744,33 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
// `act` and `acted_on` are strings that let us abstract over
// the verbs used in some diagnostic messages.
let act; let acted_on;
let act;
let acted_on;
match error_access {
AccessKind::Mutate => {
let item_msg = match the_place_err {
Place::Projection(box Projection {
base: _,
elem: ProjectionElem::Deref }
) => match self.describe_place(place) {
Some(description) =>
format!("`{}` which is behind a `&` reference", description),
elem: ProjectionElem::Deref,
}) => match self.describe_place(place) {
Some(description) => {
format!("`{}` which is behind a `&` reference", description)
}
None => format!("data in a `&` reference"),
},
_ => item_msg,
};
err = self.tcx.cannot_assign(span, &item_msg, Origin::Mir);
act = "assign"; acted_on = "written";
act = "assign";
acted_on = "written";
}
AccessKind::MutableBorrow => {
err = self.tcx
err = self
.tcx
.cannot_borrow_path_as_mutable(span, &item_msg, Origin::Mir);
act = "borrow as mutable"; acted_on = "borrowed as mutable";
act = "borrow as mutable";
acted_on = "borrowed as mutable";
}
}
@ -1783,23 +1785,27 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
let local_decl = &self.mir.local_decls[*local];
assert_eq!(local_decl.mutability, Mutability::Not);
err.span_label(span, format!("cannot {ACT}", ACT=act));
err.span_suggestion(local_decl.source_info.span,
"consider changing this to be mutable",
format!("mut {}", local_decl.name.unwrap()));
err.span_label(span, format!("cannot {ACT}", ACT = act));
err.span_suggestion(
local_decl.source_info.span,
"consider changing this to be mutable",
format!("mut {}", local_decl.name.unwrap()),
);
}
// complete hack to approximate old AST-borrowck
// diagnostic: if the span starts with a mutable borrow of
// a local variable, then just suggest the user remove it.
Place::Local(_) if {
if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(span) {
snippet.starts_with("&mut ")
} else {
false
}
} => {
err.span_label(span, format!("cannot {ACT}", ACT=act));
Place::Local(_)
if {
if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(span) {
snippet.starts_with("&mut ")
} else {
false
}
} =>
{
err.span_label(span, format!("cannot {ACT}", ACT = act));
err.span_label(span, "try removing `&mut` here");
}
@ -1808,29 +1814,40 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
//
// FIXME: can this case be generalized to work for an
// arbitrary base for the projection?
Place::Projection(box Projection { base: Place::Local(local),
elem: ProjectionElem::Deref })
if self.mir.local_decls[*local].is_nonref_binding() =>
Place::Projection(box Projection {
base: Place::Local(local),
elem: ProjectionElem::Deref,
}) if self.mir.local_decls[*local].is_nonref_binding() =>
{
let (err_help_span, suggested_code) =
find_place_to_suggest_ampmut(self.tcx, self.mir, *local);
err.span_suggestion(err_help_span,
"consider changing this to be a mutable reference",
suggested_code);
err.span_suggestion(
err_help_span,
"consider changing this to be a mutable reference",
suggested_code,
);
let local_decl = &self.mir.local_decls[*local];
if let Some(name) = local_decl.name {
err.span_label(
span, format!("`{NAME}` is a `&` reference, \
so the data it refers to cannot be {ACTED_ON}",
NAME=name, ACTED_ON=acted_on));
span,
format!(
"`{NAME}` is a `&` reference, \
so the data it refers to cannot be {ACTED_ON}",
NAME = name,
ACTED_ON = acted_on
),
);
} else {
err.span_label(span, format!("cannot {ACT} through `&`-reference", ACT=act));
err.span_label(
span,
format!("cannot {ACT} through `&`-reference", ACT = act),
);
}
}
_ => {
err.span_label(span, format!("cannot {ACT}", ACT=act));
err.span_label(span, format!("cannot {ACT}", ACT = act));
}
}
@ -1852,10 +1869,11 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
// for example, if the RHS is present and the Type is not, then the type is going to
// be inferred *from* the RHS, which means we should highlight that (and suggest
// that they borrow the RHS mutably).
fn find_place_to_suggest_ampmut<'cx, 'gcx, 'tcx>(tcx: TyCtxt<'cx, 'gcx, 'tcx>,
mir: &Mir<'tcx>,
local: Local) -> (Span, String)
{
fn find_place_to_suggest_ampmut<'cx, 'gcx, 'tcx>(
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
mir: &Mir<'tcx>,
local: Local,
) -> (Span, String) {
// This implementation attempts to emulate AST-borrowck prioritization
// by trying (3.), then (2.) and finally falling back on (1.).
let locations = mir.find_assignments(local);
@ -1877,7 +1895,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
// if this is a variable binding with an explicit type,
// try to highlight that for the suggestion.
Some(ClearCrossCrate::Set(mir::BindingForm::Var(mir::VarBindingForm {
opt_ty_info: Some(ty_span), .. }))) => ty_span,
opt_ty_info: Some(ty_span),
..
}))) => ty_span,
Some(ClearCrossCrate::Clear) => bug!("saw cleared local state"),
@ -1896,7 +1916,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
fn add_used_mut<'d>(
&mut self,
root_place: RootPlace<'d, 'tcx>,
flow_state: &Flows<'cx, 'gcx, 'tcx>
flow_state: &Flows<'cx, 'gcx, 'tcx>,
) {
match root_place {
RootPlace {
@ -1944,29 +1964,32 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
let local = &self.mir.local_decls[local];
match local.mutability {
Mutability::Not => match is_local_mutation_allowed {
LocalMutationIsAllowed::Yes => {
Ok(RootPlace {
place,
is_local_mutation_allowed: LocalMutationIsAllowed::Yes
})
}
LocalMutationIsAllowed::ExceptUpvars => {
Ok(RootPlace {
place,
is_local_mutation_allowed: LocalMutationIsAllowed::ExceptUpvars
})
}
LocalMutationIsAllowed::Yes => Ok(RootPlace {
place,
is_local_mutation_allowed: LocalMutationIsAllowed::Yes,
}),
LocalMutationIsAllowed::ExceptUpvars => Ok(RootPlace {
place,
is_local_mutation_allowed: LocalMutationIsAllowed::ExceptUpvars,
}),
LocalMutationIsAllowed::No => Err(place),
},
Mutability::Mut => Ok(RootPlace { place, is_local_mutation_allowed }),
Mutability::Mut => Ok(RootPlace {
place,
is_local_mutation_allowed,
}),
}
}
Place::Static(ref static_) =>
Place::Static(ref static_) => {
if self.tcx.is_static(static_.def_id) != Some(hir::Mutability::MutMutable) {
Err(place)
} else {
Ok(RootPlace { place, is_local_mutation_allowed })
},
Ok(RootPlace {
place,
is_local_mutation_allowed,
})
}
}
Place::Projection(ref proj) => {
match proj.elem {
ProjectionElem::Deref => {
@ -2004,7 +2027,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
// `*mut` raw pointers are always mutable, regardless of
// context. The users have to check by themselves.
hir::MutMutable => {
return Ok(RootPlace { place, is_local_mutation_allowed });
return Ok(RootPlace {
place,
is_local_mutation_allowed,
});
}
}
}
@ -2063,7 +2089,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
// }
// ```
let _ = self.is_mutable(&proj.base, is_local_mutation_allowed)?;
Ok(RootPlace { place, is_local_mutation_allowed })
Ok(RootPlace {
place,
is_local_mutation_allowed,
})
}
}
} else {
@ -2083,7 +2112,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
match *place {
Place::Projection(ref proj) => match proj.elem {
ProjectionElem::Field(field, _ty) => {
let is_projection_from_ty_closure = proj.base
let is_projection_from_ty_closure = proj
.base
.ty(self.mir, self.tcx)
.to_ty(self.tcx)
.is_closure();
@ -2185,4 +2215,3 @@ impl ContextKind {
}
}
}

View File

@ -8,15 +8,18 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use rustc::ty::{self, TyCtxt};
use rustc::session::config::BorrowckMode;
use rustc::ty::{self, TyCtxt};
use rustc_errors::{DiagnosticBuilder, DiagnosticId};
use syntax_pos::{MultiSpan, Span};
use std::fmt;
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Origin { Ast, Mir }
pub enum Origin {
Ast,
Mir,
}
impl fmt::Display for Origin {
fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
@ -53,94 +56,130 @@ impl Origin {
}
pub trait BorrowckErrors<'cx>: Sized + Copy {
fn struct_span_err_with_code<S: Into<MultiSpan>>(self,
sp: S,
msg: &str,
code: DiagnosticId)
-> DiagnosticBuilder<'cx>;
fn struct_span_err_with_code<S: Into<MultiSpan>>(
self,
sp: S,
msg: &str,
code: DiagnosticId,
) -> DiagnosticBuilder<'cx>;
fn struct_span_err<S: Into<MultiSpan>>(self,
sp: S,
msg: &str)
-> DiagnosticBuilder<'cx>;
fn struct_span_err<S: Into<MultiSpan>>(self, sp: S, msg: &str) -> DiagnosticBuilder<'cx>;
/// Cancels the given error if we shouldn't emit errors for a given
/// origin in the current mode.
///
/// Always make sure that the error gets passed through this function
/// before you return it.
fn cancel_if_wrong_origin(self,
diag: DiagnosticBuilder<'cx>,
o: Origin)
-> DiagnosticBuilder<'cx>;
fn cancel_if_wrong_origin(
self,
diag: DiagnosticBuilder<'cx>,
o: Origin,
) -> DiagnosticBuilder<'cx>;
fn cannot_move_when_borrowed(self, span: Span, desc: &str, o: Origin)
-> DiagnosticBuilder<'cx>
{
let err = struct_span_err!(self, span, E0505,
"cannot move out of `{}` because it is borrowed{OGN}",
desc, OGN=o);
fn cannot_move_when_borrowed(
self,
span: Span,
desc: &str,
o: Origin,
) -> DiagnosticBuilder<'cx> {
let err = struct_span_err!(
self,
span,
E0505,
"cannot move out of `{}` because it is borrowed{OGN}",
desc,
OGN = o
);
self.cancel_if_wrong_origin(err, o)
}
fn cannot_use_when_mutably_borrowed(self,
span: Span,
desc: &str,
borrow_span: Span,
borrow_desc: &str,
o: Origin)
-> DiagnosticBuilder<'cx>
{
let mut err = struct_span_err!(self, span, E0503,
"cannot use `{}` because it was mutably borrowed{OGN}",
desc, OGN=o);
fn cannot_use_when_mutably_borrowed(
self,
span: Span,
desc: &str,
borrow_span: Span,
borrow_desc: &str,
o: Origin,
) -> DiagnosticBuilder<'cx> {
let mut err = struct_span_err!(
self,
span,
E0503,
"cannot use `{}` because it was mutably borrowed{OGN}",
desc,
OGN = o
);
err.span_label(borrow_span, format!("borrow of `{}` occurs here", borrow_desc));
err.span_label(
borrow_span,
format!("borrow of `{}` occurs here", borrow_desc),
);
err.span_label(span, format!("use of borrowed `{}`", borrow_desc));
self.cancel_if_wrong_origin(err, o)
}
fn cannot_act_on_uninitialized_variable(self,
span: Span,
verb: &str,
desc: &str,
o: Origin)
-> DiagnosticBuilder<'cx>
{
let err = struct_span_err!(self, span, E0381,
"{} of possibly uninitialized variable: `{}`{OGN}",
verb, desc, OGN=o);
fn cannot_act_on_uninitialized_variable(
self,
span: Span,
verb: &str,
desc: &str,
o: Origin,
) -> DiagnosticBuilder<'cx> {
let err = struct_span_err!(
self,
span,
E0381,
"{} of possibly uninitialized variable: `{}`{OGN}",
verb,
desc,
OGN = o
);
self.cancel_if_wrong_origin(err, o)
}
fn cannot_mutably_borrow_multiply(self,
new_loan_span: Span,
desc: &str,
opt_via: &str,
old_loan_span: Span,
old_opt_via: &str,
old_load_end_span: Option<Span>,
o: Origin)
-> DiagnosticBuilder<'cx>
{
let mut err = struct_span_err!(self, new_loan_span, E0499,
"cannot borrow `{}`{} as mutable more than once at a time{OGN}",
desc, opt_via, OGN=o);
fn cannot_mutably_borrow_multiply(
self,
new_loan_span: Span,
desc: &str,
opt_via: &str,
old_loan_span: Span,
old_opt_via: &str,
old_load_end_span: Option<Span>,
o: Origin,
) -> DiagnosticBuilder<'cx> {
let mut err = struct_span_err!(
self,
new_loan_span,
E0499,
"cannot borrow `{}`{} as mutable more than once at a time{OGN}",
desc,
opt_via,
OGN = o
);
if old_loan_span == new_loan_span {
// Both borrows are happening in the same place
// Meaning the borrow is occurring in a loop
err.span_label(new_loan_span,
format!("mutable borrow starts here in previous \
iteration of loop{}", opt_via));
err.span_label(
new_loan_span,
format!(
"mutable borrow starts here in previous \
iteration of loop{}",
opt_via
),
);
if let Some(old_load_end_span) = old_load_end_span {
err.span_label(old_load_end_span, "mutable borrow ends here");
}
} else {
err.span_label(old_loan_span,
format!("first mutable borrow occurs here{}", old_opt_via));
err.span_label(new_loan_span,
format!("second mutable borrow occurs here{}", opt_via));
err.span_label(
old_loan_span,
format!("first mutable borrow occurs here{}", old_opt_via),
);
err.span_label(
new_loan_span,
format!("second mutable borrow occurs here{}", opt_via),
);
if let Some(old_load_end_span) = old_load_end_span {
err.span_label(old_load_end_span, "first borrow ends here");
}
@ -148,166 +187,222 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
self.cancel_if_wrong_origin(err, o)
}
fn cannot_uniquely_borrow_by_two_closures(self,
new_loan_span: Span,
desc: &str,
old_loan_span: Span,
old_load_end_span: Option<Span>,
o: Origin)
-> DiagnosticBuilder<'cx>
{
let mut err = struct_span_err!(self, new_loan_span, E0524,
"two closures require unique access to `{}` at the same time{OGN}",
desc, OGN=o);
err.span_label(
old_loan_span,
"first closure is constructed here");
err.span_label(
fn cannot_uniquely_borrow_by_two_closures(
self,
new_loan_span: Span,
desc: &str,
old_loan_span: Span,
old_load_end_span: Option<Span>,
o: Origin,
) -> DiagnosticBuilder<'cx> {
let mut err = struct_span_err!(
self,
new_loan_span,
"second closure is constructed here");
E0524,
"two closures require unique access to `{}` at the same time{OGN}",
desc,
OGN = o
);
err.span_label(old_loan_span, "first closure is constructed here");
err.span_label(new_loan_span, "second closure is constructed here");
if let Some(old_load_end_span) = old_load_end_span {
err.span_label(
old_load_end_span,
"borrow from first closure ends here");
err.span_label(old_load_end_span, "borrow from first closure ends here");
}
self.cancel_if_wrong_origin(err, o)
}
fn cannot_uniquely_borrow_by_one_closure(self,
new_loan_span: Span,
desc_new: &str,
opt_via: &str,
old_loan_span: Span,
noun_old: &str,
old_opt_via: &str,
previous_end_span: Option<Span>,
o: Origin)
-> DiagnosticBuilder<'cx>
{
let mut err = struct_span_err!(self, new_loan_span, E0500,
"closure requires unique access to `{}` but {} is already borrowed{}{OGN}",
desc_new, noun_old, old_opt_via, OGN=o);
err.span_label(new_loan_span,
format!("closure construction occurs here{}", opt_via));
err.span_label(old_loan_span,
format!("borrow occurs here{}", old_opt_via));
fn cannot_uniquely_borrow_by_one_closure(
self,
new_loan_span: Span,
desc_new: &str,
opt_via: &str,
old_loan_span: Span,
noun_old: &str,
old_opt_via: &str,
previous_end_span: Option<Span>,
o: Origin,
) -> DiagnosticBuilder<'cx> {
let mut err = struct_span_err!(
self,
new_loan_span,
E0500,
"closure requires unique access to `{}` but {} is already borrowed{}{OGN}",
desc_new,
noun_old,
old_opt_via,
OGN = o
);
err.span_label(
new_loan_span,
format!("closure construction occurs here{}", opt_via),
);
err.span_label(old_loan_span, format!("borrow occurs here{}", old_opt_via));
if let Some(previous_end_span) = previous_end_span {
err.span_label(previous_end_span, "borrow ends here");
}
self.cancel_if_wrong_origin(err, o)
}
fn cannot_reborrow_already_uniquely_borrowed(self,
new_loan_span: Span,
desc_new: &str,
opt_via: &str,
kind_new: &str,
old_loan_span: Span,
old_opt_via: &str,
previous_end_span: Option<Span>,
o: Origin)
-> DiagnosticBuilder<'cx>
{
let mut err = struct_span_err!(self, new_loan_span, E0501,
"cannot borrow `{}`{} as {} because previous closure \
requires unique access{OGN}",
desc_new, opt_via, kind_new, OGN=o);
err.span_label(new_loan_span,
format!("borrow occurs here{}", opt_via));
err.span_label(old_loan_span,
format!("closure construction occurs here{}", old_opt_via));
fn cannot_reborrow_already_uniquely_borrowed(
self,
new_loan_span: Span,
desc_new: &str,
opt_via: &str,
kind_new: &str,
old_loan_span: Span,
old_opt_via: &str,
previous_end_span: Option<Span>,
o: Origin,
) -> DiagnosticBuilder<'cx> {
let mut err = struct_span_err!(
self,
new_loan_span,
E0501,
"cannot borrow `{}`{} as {} because previous closure \
requires unique access{OGN}",
desc_new,
opt_via,
kind_new,
OGN = o
);
err.span_label(new_loan_span, format!("borrow occurs here{}", opt_via));
err.span_label(
old_loan_span,
format!("closure construction occurs here{}", old_opt_via),
);
if let Some(previous_end_span) = previous_end_span {
err.span_label(previous_end_span, "borrow from closure ends here");
}
self.cancel_if_wrong_origin(err, o)
}
fn cannot_reborrow_already_borrowed(self,
span: Span,
desc_new: &str,
msg_new: &str,
kind_new: &str,
old_span: Span,
noun_old: &str,
kind_old: &str,
msg_old: &str,
old_load_end_span: Option<Span>,
o: Origin)
-> DiagnosticBuilder<'cx>
{
let mut err = struct_span_err!(self, span, E0502,
"cannot borrow `{}`{} as {} because {} is also borrowed as {}{}{OGN}",
desc_new, msg_new, kind_new, noun_old, kind_old, msg_old, OGN=o);
fn cannot_reborrow_already_borrowed(
self,
span: Span,
desc_new: &str,
msg_new: &str,
kind_new: &str,
old_span: Span,
noun_old: &str,
kind_old: &str,
msg_old: &str,
old_load_end_span: Option<Span>,
o: Origin,
) -> DiagnosticBuilder<'cx> {
let mut err = struct_span_err!(
self,
span,
E0502,
"cannot borrow `{}`{} as {} because {} is also borrowed as {}{}{OGN}",
desc_new,
msg_new,
kind_new,
noun_old,
kind_old,
msg_old,
OGN = o
);
err.span_label(span, format!("{} borrow occurs here{}", kind_new, msg_new));
err.span_label(old_span, format!("{} borrow occurs here{}", kind_old, msg_old));
err.span_label(
old_span,
format!("{} borrow occurs here{}", kind_old, msg_old),
);
if let Some(old_load_end_span) = old_load_end_span {
err.span_label(old_load_end_span, format!("{} borrow ends here", kind_old));
}
self.cancel_if_wrong_origin(err, o)
}
fn cannot_assign_to_borrowed(self, span: Span, borrow_span: Span, desc: &str, o: Origin)
-> DiagnosticBuilder<'cx>
{
let mut err = struct_span_err!(self, span, E0506,
"cannot assign to `{}` because it is borrowed{OGN}",
desc, OGN=o);
fn cannot_assign_to_borrowed(
self,
span: Span,
borrow_span: Span,
desc: &str,
o: Origin,
) -> DiagnosticBuilder<'cx> {
let mut err = struct_span_err!(
self,
span,
E0506,
"cannot assign to `{}` because it is borrowed{OGN}",
desc,
OGN = o
);
err.span_label(borrow_span, format!("borrow of `{}` occurs here", desc));
err.span_label(span, format!("assignment to borrowed `{}` occurs here", desc));
err.span_label(
span,
format!("assignment to borrowed `{}` occurs here", desc),
);
self.cancel_if_wrong_origin(err, o)
}
fn cannot_move_into_closure(self, span: Span, desc: &str, o: Origin)
-> DiagnosticBuilder<'cx>
{
let err = struct_span_err!(self, span, E0504,
"cannot move `{}` into closure because it is borrowed{OGN}",
desc, OGN=o);
fn cannot_move_into_closure(self, span: Span, desc: &str, o: Origin) -> DiagnosticBuilder<'cx> {
let err = struct_span_err!(
self,
span,
E0504,
"cannot move `{}` into closure because it is borrowed{OGN}",
desc,
OGN = o
);
self.cancel_if_wrong_origin(err, o)
}
fn cannot_reassign_immutable(self, span: Span, desc: &str, is_arg: bool, o: Origin)
-> DiagnosticBuilder<'cx>
{
fn cannot_reassign_immutable(
self,
span: Span,
desc: &str,
is_arg: bool,
o: Origin,
) -> DiagnosticBuilder<'cx> {
let msg = if is_arg {
"to immutable argument"
} else {
"twice to immutable variable"
};
let err = struct_span_err!(self, span, E0384,
"cannot assign {} `{}`{OGN}",
msg, desc, OGN=o);
let err = struct_span_err!(
self,
span,
E0384,
"cannot assign {} `{}`{OGN}",
msg,
desc,
OGN = o
);
self.cancel_if_wrong_origin(err, o)
}
fn cannot_assign(self, span: Span, desc: &str, o: Origin)
-> DiagnosticBuilder<'cx>
{
let err = struct_span_err!(self, span, E0594,
"cannot assign to {}{OGN}",
desc, OGN=o);
fn cannot_assign(self, span: Span, desc: &str, o: Origin) -> DiagnosticBuilder<'cx> {
let err = struct_span_err!(self, span, E0594, "cannot assign to {}{OGN}", desc, OGN = o);
self.cancel_if_wrong_origin(err, o)
}
fn cannot_assign_static(self, span: Span, desc: &str, o: Origin)
-> DiagnosticBuilder<'cx>
{
fn cannot_assign_static(self, span: Span, desc: &str, o: Origin) -> DiagnosticBuilder<'cx> {
self.cannot_assign(span, &format!("immutable static item `{}`", desc), o)
}
fn cannot_move_out_of(self, move_from_span: Span, move_from_desc: &str, o: Origin)
-> DiagnosticBuilder<'cx>
{
let mut err = struct_span_err!(self, move_from_span, E0507,
"cannot move out of {}{OGN}",
move_from_desc, OGN=o);
fn cannot_move_out_of(
self,
move_from_span: Span,
move_from_desc: &str,
o: Origin,
) -> DiagnosticBuilder<'cx> {
let mut err = struct_span_err!(
self,
move_from_span,
E0507,
"cannot move out of {}{OGN}",
move_from_desc,
OGN = o
);
err.span_label(
move_from_span,
format!("cannot move out of {}", move_from_desc));
format!("cannot move out of {}", move_from_desc),
);
self.cancel_if_wrong_origin(err, o)
}
@ -315,210 +410,274 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
/// Signal an error due to an attempt to move out of the interior
/// of an array or slice. `is_index` is None when error origin
/// didn't capture whether there was an indexing operation or not.
fn cannot_move_out_of_interior_noncopy(self,
move_from_span: Span,
ty: ty::Ty,
is_index: Option<bool>,
o: Origin)
-> DiagnosticBuilder<'cx>
{
fn cannot_move_out_of_interior_noncopy(
self,
move_from_span: Span,
ty: ty::Ty,
is_index: Option<bool>,
o: Origin,
) -> DiagnosticBuilder<'cx> {
let type_name = match (&ty.sty, is_index) {
(&ty::TyArray(_, _), Some(true)) |
(&ty::TyArray(_, _), None) => "array",
(&ty::TySlice(_), _) => "slice",
(&ty::TyArray(_, _), Some(true)) | (&ty::TyArray(_, _), None) => "array",
(&ty::TySlice(_), _) => "slice",
_ => span_bug!(move_from_span, "this path should not cause illegal move"),
};
let mut err = struct_span_err!(self, move_from_span, E0508,
"cannot move out of type `{}`, \
a non-copy {}{OGN}",
ty, type_name, OGN=o);
let mut err = struct_span_err!(
self,
move_from_span,
E0508,
"cannot move out of type `{}`, \
a non-copy {}{OGN}",
ty,
type_name,
OGN = o
);
err.span_label(move_from_span, "cannot move out of here");
self.cancel_if_wrong_origin(err, o)
}
fn cannot_move_out_of_interior_of_drop(self,
move_from_span: Span,
container_ty: ty::Ty,
o: Origin)
-> DiagnosticBuilder<'cx>
{
let mut err = struct_span_err!(self, move_from_span, E0509,
"cannot move out of type `{}`, \
which implements the `Drop` trait{OGN}",
container_ty, OGN=o);
fn cannot_move_out_of_interior_of_drop(
self,
move_from_span: Span,
container_ty: ty::Ty,
o: Origin,
) -> DiagnosticBuilder<'cx> {
let mut err = struct_span_err!(
self,
move_from_span,
E0509,
"cannot move out of type `{}`, \
which implements the `Drop` trait{OGN}",
container_ty,
OGN = o
);
err.span_label(move_from_span, "cannot move out of here");
self.cancel_if_wrong_origin(err, o)
}
fn cannot_act_on_moved_value(self,
use_span: Span,
verb: &str,
optional_adverb_for_moved: &str,
moved_path: &str,
o: Origin)
-> DiagnosticBuilder<'cx>
{
let err = struct_span_err!(self, use_span, E0382,
"{} of {}moved value: `{}`{OGN}",
verb, optional_adverb_for_moved, moved_path, OGN=o);
fn cannot_act_on_moved_value(
self,
use_span: Span,
verb: &str,
optional_adverb_for_moved: &str,
moved_path: Option<String>,
o: Origin,
) -> DiagnosticBuilder<'cx> {
let moved_path = moved_path
.map(|mp| format!(": `{}`", mp))
.unwrap_or("".to_owned());
let err = struct_span_err!(
self,
use_span,
E0382,
"{} of {}moved value{}{OGN}",
verb,
optional_adverb_for_moved,
moved_path,
OGN = o
);
self.cancel_if_wrong_origin(err, o)
}
fn cannot_partially_reinit_an_uninit_struct(self,
span: Span,
uninit_path: &str,
o: Origin)
-> DiagnosticBuilder<'cx>
{
let err = struct_span_err!(self,
span,
E0383,
"partial reinitialization of uninitialized structure `{}`{OGN}",
uninit_path, OGN=o);
fn cannot_partially_reinit_an_uninit_struct(
self,
span: Span,
uninit_path: &str,
o: Origin,
) -> DiagnosticBuilder<'cx> {
let err = struct_span_err!(
self,
span,
E0383,
"partial reinitialization of uninitialized structure `{}`{OGN}",
uninit_path,
OGN = o
);
self.cancel_if_wrong_origin(err, o)
}
fn closure_cannot_assign_to_borrowed(self,
span: Span,
descr: &str,
o: Origin)
-> DiagnosticBuilder<'cx>
{
let err = struct_span_err!(self, span, E0595, "closure cannot assign to {}{OGN}",
descr, OGN=o);
fn closure_cannot_assign_to_borrowed(
self,
span: Span,
descr: &str,
o: Origin,
) -> DiagnosticBuilder<'cx> {
let err = struct_span_err!(
self,
span,
E0595,
"closure cannot assign to {}{OGN}",
descr,
OGN = o
);
self.cancel_if_wrong_origin(err, o)
}
fn cannot_borrow_path_as_mutable(self,
span: Span,
path: &str,
o: Origin)
-> DiagnosticBuilder<'cx>
{
let err = struct_span_err!(self, span, E0596, "cannot borrow {} as mutable{OGN}",
path, OGN=o);
fn cannot_borrow_path_as_mutable(
self,
span: Span,
path: &str,
o: Origin,
) -> DiagnosticBuilder<'cx> {
let err = struct_span_err!(
self,
span,
E0596,
"cannot borrow {} as mutable{OGN}",
path,
OGN = o
);
self.cancel_if_wrong_origin(err, o)
}
fn cannot_borrow_across_generator_yield(self,
span: Span,
yield_span: Span,
o: Origin)
-> DiagnosticBuilder<'cx>
{
let mut err = struct_span_err!(self,
span,
E0626,
"borrow may still be in use when generator yields{OGN}",
OGN=o);
fn cannot_borrow_across_generator_yield(
self,
span: Span,
yield_span: Span,
o: Origin,
) -> DiagnosticBuilder<'cx> {
let mut err = struct_span_err!(
self,
span,
E0626,
"borrow may still be in use when generator yields{OGN}",
OGN = o
);
err.span_label(yield_span, "possible yield occurs here");
self.cancel_if_wrong_origin(err, o)
}
fn path_does_not_live_long_enough(self,
span: Span,
path: &str,
o: Origin)
-> DiagnosticBuilder<'cx>
{
let err = struct_span_err!(self, span, E0597, "{} does not live long enough{OGN}",
path, OGN=o);
fn path_does_not_live_long_enough(
self,
span: Span,
path: &str,
o: Origin,
) -> DiagnosticBuilder<'cx> {
let err = struct_span_err!(
self,
span,
E0597,
"{} does not live long enough{OGN}",
path,
OGN = o
);
self.cancel_if_wrong_origin(err, o)
}
fn lifetime_too_short_for_reborrow(self,
span: Span,
path: &str,
o: Origin)
-> DiagnosticBuilder<'cx>
{
let err = struct_span_err!(self, span, E0598,
"lifetime of {} is too short to guarantee \
its contents can be safely reborrowed{OGN}",
path, OGN=o);
fn lifetime_too_short_for_reborrow(
self,
span: Span,
path: &str,
o: Origin,
) -> DiagnosticBuilder<'cx> {
let err = struct_span_err!(
self,
span,
E0598,
"lifetime of {} is too short to guarantee \
its contents can be safely reborrowed{OGN}",
path,
OGN = o
);
self.cancel_if_wrong_origin(err, o)
}
fn cannot_act_on_capture_in_sharable_fn(self,
span: Span,
bad_thing: &str,
help: (Span, &str),
o: Origin)
-> DiagnosticBuilder<'cx>
{
fn cannot_act_on_capture_in_sharable_fn(
self,
span: Span,
bad_thing: &str,
help: (Span, &str),
o: Origin,
) -> DiagnosticBuilder<'cx> {
let (help_span, help_msg) = help;
let mut err = struct_span_err!(self, span, E0387,
"{} in a captured outer variable in an `Fn` closure{OGN}",
bad_thing, OGN=o);
let mut err = struct_span_err!(
self,
span,
E0387,
"{} in a captured outer variable in an `Fn` closure{OGN}",
bad_thing,
OGN = o
);
err.span_help(help_span, help_msg);
self.cancel_if_wrong_origin(err, o)
}
fn cannot_assign_into_immutable_reference(self,
span: Span,
bad_thing: &str,
o: Origin)
-> DiagnosticBuilder<'cx>
{
let mut err = struct_span_err!(self, span, E0389, "{} in a `&` reference{OGN}",
bad_thing, OGN=o);
fn cannot_assign_into_immutable_reference(
self,
span: Span,
bad_thing: &str,
o: Origin,
) -> DiagnosticBuilder<'cx> {
let mut err = struct_span_err!(
self,
span,
E0389,
"{} in a `&` reference{OGN}",
bad_thing,
OGN = o
);
err.span_label(span, "assignment into an immutable reference");
self.cancel_if_wrong_origin(err, o)
}
fn cannot_capture_in_long_lived_closure(self,
closure_span: Span,
borrowed_path: &str,
capture_span: Span,
o: Origin)
-> DiagnosticBuilder<'cx>
{
let mut err = struct_span_err!(self, closure_span, E0373,
"closure may outlive the current function, \
but it borrows {}, \
which is owned by the current function{OGN}",
borrowed_path, OGN=o);
fn cannot_capture_in_long_lived_closure(
self,
closure_span: Span,
borrowed_path: &str,
capture_span: Span,
o: Origin,
) -> DiagnosticBuilder<'cx> {
let mut err = struct_span_err!(
self,
closure_span,
E0373,
"closure may outlive the current function, \
but it borrows {}, \
which is owned by the current function{OGN}",
borrowed_path,
OGN = o
);
err.span_label(capture_span, format!("{} is borrowed here", borrowed_path))
.span_label(closure_span, format!("may outlive borrowed value {}", borrowed_path));
.span_label(
closure_span,
format!("may outlive borrowed value {}", borrowed_path),
);
self.cancel_if_wrong_origin(err, o)
}
}
impl<'cx, 'gcx, 'tcx> BorrowckErrors<'cx> for TyCtxt<'cx, 'gcx, 'tcx> {
fn struct_span_err_with_code<S: Into<MultiSpan>>(self,
sp: S,
msg: &str,
code: DiagnosticId)
-> DiagnosticBuilder<'cx>
{
fn struct_span_err_with_code<S: Into<MultiSpan>>(
self,
sp: S,
msg: &str,
code: DiagnosticId,
) -> DiagnosticBuilder<'cx> {
self.sess.struct_span_err_with_code(sp, msg, code)
}
fn struct_span_err<S: Into<MultiSpan>>(self,
sp: S,
msg: &str)
-> DiagnosticBuilder<'cx>
{
fn struct_span_err<S: Into<MultiSpan>>(self, sp: S, msg: &str) -> DiagnosticBuilder<'cx> {
self.sess.struct_span_err(sp, msg)
}
fn cancel_if_wrong_origin(self,
mut diag: DiagnosticBuilder<'cx>,
o: Origin)
-> DiagnosticBuilder<'cx>
{
fn cancel_if_wrong_origin(
self,
mut diag: DiagnosticBuilder<'cx>,
o: Origin,
) -> DiagnosticBuilder<'cx> {
if !o.should_emit_errors(self.borrowck_mode()) {
self.sess.diagnostic().cancel(&mut diag);
}

View File

@ -7,7 +7,7 @@ LL | //~^ value moved here
LL | let _y = a.y; //~ ERROR use of moved
| ^^^ value used here after move
|
= note: move occurs because `a.y` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
= note: move occurs because `a.x` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
error[E0382]: use of moved value: `a.y`
--> $DIR/borrowck-box-insensitivity.rs:108:14
@ -18,7 +18,7 @@ LL | //~^ value moved here
LL | let _y = a.y; //~ ERROR use of collaterally moved
| ^^^ value used here after move
|
= note: move occurs because `a.y` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
= note: move occurs because `a.x.x` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
error: aborting due to 2 previous errors

View File

@ -20,7 +20,7 @@ pub fn main(){
//~| ERROR use of moved value: `(maybe as std::prelude::v1::Some).0` (Ast) [E0382]
//~| ERROR use of moved value: `maybe` (Mir) [E0382]
//~| ERROR use of moved value: `maybe` (Mir) [E0382]
//~| ERROR use of moved value: `maybe.0` (Mir) [E0382]
//~| ERROR use of moved value (Mir) [E0382]
//~| ERROR borrow of moved value: `maybe` (Mir) [E0382]
}
}

View File

@ -26,7 +26,7 @@ LL | if let Some(thing) = maybe {
LL | | }
| |_________^ value used here after move
|
= note: move occurs because `maybe` has type `std::option::Option<std::vec::Vec<bool>>`, which does not implement the `Copy` trait
= note: move occurs because value has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait
error[E0382]: borrow of moved value: `maybe` (Mir)
--> $DIR/issue-41962.rs:17:9
@ -38,7 +38,7 @@ LL | if let Some(thing) = maybe {
LL | | }
| |_________^ value borrowed here after move
|
= note: move occurs because `maybe` has type `std::option::Option<std::vec::Vec<bool>>`, which does not implement the `Copy` trait
= note: move occurs because value has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait
error[E0382]: use of moved value: `maybe` (Mir)
--> $DIR/issue-41962.rs:17:16
@ -49,15 +49,15 @@ LL | if let Some(thing) = maybe {
| | value moved here
| value used here after move
|
= note: move occurs because `maybe` has type `std::option::Option<std::vec::Vec<bool>>`, which does not implement the `Copy` trait
= note: move occurs because value has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait
error[E0382]: use of moved value: `maybe.0` (Mir)
error[E0382]: use of moved value (Mir)
--> $DIR/issue-41962.rs:17:21
|
LL | if let Some(thing) = maybe {
| ^^^^^ value moved here in previous iteration of loop
|
= note: move occurs because `maybe.0` has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait
= note: move occurs because value has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait
error: aborting due to 6 previous errors

View File

@ -7,7 +7,7 @@ LL | Foo {f} => {}
LL | touch(&x); //~ ERROR use of partially moved value: `x`
| ^^ value borrowed here after move
|
= note: move occurs because `x` has type `Foo<std::string::String>`, which does not implement the `Copy` trait
= note: move occurs because `x.f` has type `std::string::String`, which does not implement the `Copy` trait
error: aborting due to previous error

View File

@ -0,0 +1,19 @@
// 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(warnings)]
#![feature(nll)]
fn main() {
let range = 0..1;
let r = range;
let x = range.start;
//~^ ERROR use of moved value: `range.start` [E0382]
}

View File

@ -0,0 +1,13 @@
error[E0382]: use of moved value: `range.start`
--> $DIR/issue-51512.rs:17:13
|
LL | let r = range;
| ----- value moved here
LL | let x = range.start;
| ^^^^^^^^^^^ value used here after move
|
= note: move occurs because `range` has type `std::ops::Range<i32>`, which does not implement the `Copy` trait
error: aborting due to previous error
For more information about this error, try `rustc --explain E0382`.