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:
commit
5f9c7f9e6d
@ -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, _) => {
|
||||
|
@ -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(&"[..]");
|
||||
}
|
||||
};
|
||||
|
@ -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 {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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]
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
19
src/test/ui/nll/issue-51512.rs
Normal file
19
src/test/ui/nll/issue-51512.rs
Normal 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]
|
||||
}
|
13
src/test/ui/nll/issue-51512.stderr
Normal file
13
src/test/ui/nll/issue-51512.stderr
Normal 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`.
|
Loading…
Reference in New Issue
Block a user