Rollup merge of #75304 - Aaron1011:feature/diag-deref-move-out, r=estebank
Note when a a move/borrow error is caused by a deref coercion Fixes #73268 When a deref coercion occurs, we may end up with a move error if the base value has been partially moved out of. However, we do not indicate anywhere that a deref coercion is occuring, resulting in an error message with a confusing span. This PR adds an explicit note to move errors when a deref coercion is involved. We mention the name of the type that the deref-coercion resolved to, as well as the `Deref::Target` associated type being used.
This commit is contained in:
commit
fa4cfeb597
|
@ -4,6 +4,7 @@ use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_hir::lang_items::LangItem;
|
use rustc_hir::lang_items::LangItem;
|
||||||
use rustc_macros::HashStable;
|
use rustc_macros::HashStable;
|
||||||
|
use rustc_span::Span;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
|
||||||
pub enum PointerCast {
|
pub enum PointerCast {
|
||||||
|
@ -113,6 +114,9 @@ pub enum Adjust<'tcx> {
|
||||||
pub struct OverloadedDeref<'tcx> {
|
pub struct OverloadedDeref<'tcx> {
|
||||||
pub region: ty::Region<'tcx>,
|
pub region: ty::Region<'tcx>,
|
||||||
pub mutbl: hir::Mutability,
|
pub mutbl: hir::Mutability,
|
||||||
|
/// The `Span` associated with the field access or method call
|
||||||
|
/// that triggered this overloaded deref.
|
||||||
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> OverloadedDeref<'tcx> {
|
impl<'tcx> OverloadedDeref<'tcx> {
|
||||||
|
|
|
@ -612,8 +612,11 @@ impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::Adjust<'a> {
|
||||||
impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::OverloadedDeref<'a> {
|
impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::OverloadedDeref<'a> {
|
||||||
type Lifted = ty::adjustment::OverloadedDeref<'tcx>;
|
type Lifted = ty::adjustment::OverloadedDeref<'tcx>;
|
||||||
fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
|
fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
|
||||||
tcx.lift(&self.region)
|
tcx.lift(&self.region).map(|region| ty::adjustment::OverloadedDeref {
|
||||||
.map(|region| ty::adjustment::OverloadedDeref { region, mutbl: self.mutbl })
|
region,
|
||||||
|
mutbl: self.mutbl,
|
||||||
|
span: self.span,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -66,7 +66,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
let span = use_spans.args_or_use();
|
let span = use_spans.args_or_use();
|
||||||
|
|
||||||
let move_site_vec = self.get_moved_indexes(location, mpi);
|
let move_site_vec = self.get_moved_indexes(location, mpi);
|
||||||
debug!("report_use_of_moved_or_uninitialized: move_site_vec={:?}", move_site_vec);
|
debug!(
|
||||||
|
"report_use_of_moved_or_uninitialized: move_site_vec={:?} use_spans={:?}",
|
||||||
|
move_site_vec, use_spans
|
||||||
|
);
|
||||||
let move_out_indices: Vec<_> =
|
let move_out_indices: Vec<_> =
|
||||||
move_site_vec.iter().map(|move_site| move_site.moi).collect();
|
move_site_vec.iter().map(|move_site| move_site.moi).collect();
|
||||||
|
|
||||||
|
@ -229,6 +232,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Deref::deref takes &self, which cannot cause a move
|
||||||
|
FnSelfUseKind::DerefCoercion { .. } => unreachable!(),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
err.span_label(
|
err.span_label(
|
||||||
|
@ -355,6 +360,20 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
self.note_type_does_not_implement_copy(&mut err, ¬e_msg, ty, span, partial_str);
|
self.note_type_does_not_implement_copy(&mut err, ¬e_msg, ty, span, partial_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let UseSpans::FnSelfUse {
|
||||||
|
kind: FnSelfUseKind::DerefCoercion { deref_target, deref_target_ty },
|
||||||
|
..
|
||||||
|
} = use_spans
|
||||||
|
{
|
||||||
|
err.note(&format!(
|
||||||
|
"{} occurs due to deref coercion to `{}`",
|
||||||
|
desired_action.as_noun(),
|
||||||
|
deref_target_ty
|
||||||
|
));
|
||||||
|
|
||||||
|
err.span_note(deref_target, "deref defined here");
|
||||||
|
}
|
||||||
|
|
||||||
if let Some((_, mut old_err)) =
|
if let Some((_, mut old_err)) =
|
||||||
self.move_error_reported.insert(move_out_indices, (used_place, err))
|
self.move_error_reported.insert(move_out_indices, (used_place, err))
|
||||||
{
|
{
|
||||||
|
@ -945,7 +964,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
name: &str,
|
name: &str,
|
||||||
borrow: &BorrowData<'tcx>,
|
borrow: &BorrowData<'tcx>,
|
||||||
drop_span: Span,
|
drop_span: Span,
|
||||||
borrow_spans: UseSpans,
|
borrow_spans: UseSpans<'tcx>,
|
||||||
explanation: BorrowExplanation,
|
explanation: BorrowExplanation,
|
||||||
) -> DiagnosticBuilder<'cx> {
|
) -> DiagnosticBuilder<'cx> {
|
||||||
debug!(
|
debug!(
|
||||||
|
@ -1146,7 +1165,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
location: Location,
|
location: Location,
|
||||||
borrow: &BorrowData<'tcx>,
|
borrow: &BorrowData<'tcx>,
|
||||||
drop_span: Span,
|
drop_span: Span,
|
||||||
borrow_spans: UseSpans,
|
borrow_spans: UseSpans<'tcx>,
|
||||||
proper_span: Span,
|
proper_span: Span,
|
||||||
explanation: BorrowExplanation,
|
explanation: BorrowExplanation,
|
||||||
) -> DiagnosticBuilder<'cx> {
|
) -> DiagnosticBuilder<'cx> {
|
||||||
|
@ -1274,7 +1293,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
|
|
||||||
fn report_escaping_closure_capture(
|
fn report_escaping_closure_capture(
|
||||||
&mut self,
|
&mut self,
|
||||||
use_span: UseSpans,
|
use_span: UseSpans<'tcx>,
|
||||||
var_span: Span,
|
var_span: Span,
|
||||||
fr_name: &RegionName,
|
fr_name: &RegionName,
|
||||||
category: ConstraintCategory,
|
category: ConstraintCategory,
|
||||||
|
|
|
@ -501,7 +501,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
fn later_use_kind(
|
fn later_use_kind(
|
||||||
&self,
|
&self,
|
||||||
borrow: &BorrowData<'tcx>,
|
borrow: &BorrowData<'tcx>,
|
||||||
use_spans: UseSpans,
|
use_spans: UseSpans<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
) -> (LaterUseKind, Span) {
|
) -> (LaterUseKind, Span) {
|
||||||
match use_spans {
|
match use_spans {
|
||||||
|
|
|
@ -11,7 +11,7 @@ use rustc_middle::mir::{
|
||||||
PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
|
PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
|
||||||
};
|
};
|
||||||
use rustc_middle::ty::print::Print;
|
use rustc_middle::ty::print::Print;
|
||||||
use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt};
|
use rustc_middle::ty::{self, DefIdTree, Instance, Ty, TyCtxt};
|
||||||
use rustc_span::{
|
use rustc_span::{
|
||||||
hygiene::{DesugaringKind, ForLoopLoc},
|
hygiene::{DesugaringKind, ForLoopLoc},
|
||||||
symbol::sym,
|
symbol::sym,
|
||||||
|
@ -538,7 +538,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
|
|
||||||
/// The span(s) associated to a use of a place.
|
/// The span(s) associated to a use of a place.
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||||
pub(super) enum UseSpans {
|
pub(super) enum UseSpans<'tcx> {
|
||||||
/// The access is caused by capturing a variable for a closure.
|
/// The access is caused by capturing a variable for a closure.
|
||||||
ClosureUse {
|
ClosureUse {
|
||||||
/// This is true if the captured variable was from a generator.
|
/// This is true if the captured variable was from a generator.
|
||||||
|
@ -558,7 +558,7 @@ pub(super) enum UseSpans {
|
||||||
fn_call_span: Span,
|
fn_call_span: Span,
|
||||||
/// The definition span of the method being called
|
/// The definition span of the method being called
|
||||||
fn_span: Span,
|
fn_span: Span,
|
||||||
kind: FnSelfUseKind,
|
kind: FnSelfUseKind<'tcx>,
|
||||||
},
|
},
|
||||||
/// This access is caused by a `match` or `if let` pattern.
|
/// This access is caused by a `match` or `if let` pattern.
|
||||||
PatUse(Span),
|
PatUse(Span),
|
||||||
|
@ -567,22 +567,32 @@ pub(super) enum UseSpans {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||||
pub(super) enum FnSelfUseKind {
|
pub(super) enum FnSelfUseKind<'tcx> {
|
||||||
/// A normal method call of the form `receiver.foo(a, b, c)`
|
/// A normal method call of the form `receiver.foo(a, b, c)`
|
||||||
Normal { self_arg: Ident, implicit_into_iter: bool },
|
Normal { self_arg: Ident, implicit_into_iter: bool },
|
||||||
/// A call to `FnOnce::call_once`, desugared from `my_closure(a, b, c)`
|
/// A call to `FnOnce::call_once`, desugared from `my_closure(a, b, c)`
|
||||||
FnOnceCall,
|
FnOnceCall,
|
||||||
/// A call to an operator trait, desuraged from operator syntax (e.g. `a << b`)
|
/// A call to an operator trait, desuraged from operator syntax (e.g. `a << b`)
|
||||||
Operator { self_arg: Ident },
|
Operator { self_arg: Ident },
|
||||||
|
DerefCoercion {
|
||||||
|
/// The `Span` of the `Target` associated type
|
||||||
|
/// in the `Deref` impl we are using.
|
||||||
|
deref_target: Span,
|
||||||
|
/// The type `T::Deref` we are dereferencing to
|
||||||
|
deref_target_ty: Ty<'tcx>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UseSpans {
|
impl UseSpans<'_> {
|
||||||
pub(super) fn args_or_use(self) -> Span {
|
pub(super) fn args_or_use(self) -> Span {
|
||||||
match self {
|
match self {
|
||||||
UseSpans::ClosureUse { args_span: span, .. }
|
UseSpans::ClosureUse { args_span: span, .. }
|
||||||
| UseSpans::PatUse(span)
|
| UseSpans::PatUse(span)
|
||||||
| UseSpans::FnSelfUse { var_span: span, .. }
|
|
||||||
| UseSpans::OtherUse(span) => span,
|
| UseSpans::OtherUse(span) => span,
|
||||||
|
UseSpans::FnSelfUse {
|
||||||
|
fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, ..
|
||||||
|
} => fn_call_span,
|
||||||
|
UseSpans::FnSelfUse { var_span, .. } => var_span,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -590,8 +600,11 @@ impl UseSpans {
|
||||||
match self {
|
match self {
|
||||||
UseSpans::ClosureUse { var_span: span, .. }
|
UseSpans::ClosureUse { var_span: span, .. }
|
||||||
| UseSpans::PatUse(span)
|
| UseSpans::PatUse(span)
|
||||||
| UseSpans::FnSelfUse { var_span: span, .. }
|
|
||||||
| UseSpans::OtherUse(span) => span,
|
| UseSpans::OtherUse(span) => span,
|
||||||
|
UseSpans::FnSelfUse {
|
||||||
|
fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, ..
|
||||||
|
} => fn_call_span,
|
||||||
|
UseSpans::FnSelfUse { var_span, .. } => var_span,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -754,7 +767,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
&self,
|
&self,
|
||||||
moved_place: PlaceRef<'tcx>, // Could also be an upvar.
|
moved_place: PlaceRef<'tcx>, // Could also be an upvar.
|
||||||
location: Location,
|
location: Location,
|
||||||
) -> UseSpans {
|
) -> UseSpans<'tcx> {
|
||||||
use self::UseSpans::*;
|
use self::UseSpans::*;
|
||||||
|
|
||||||
let stmt = match self.body[location.block].statements.get(location.statement_index) {
|
let stmt = match self.body[location.block].statements.get(location.statement_index) {
|
||||||
|
@ -809,36 +822,64 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
kind: TerminatorKind::Call { fn_span, from_hir_call, .. }, ..
|
kind: TerminatorKind::Call { fn_span, from_hir_call, .. }, ..
|
||||||
}) = &self.body[location.block].terminator
|
}) = &self.body[location.block].terminator
|
||||||
{
|
{
|
||||||
let method_did = if let Some(method_did) =
|
let (method_did, method_substs) = if let Some(info) =
|
||||||
crate::util::find_self_call(self.infcx.tcx, &self.body, target_temp, location.block)
|
crate::util::find_self_call(self.infcx.tcx, &self.body, target_temp, location.block)
|
||||||
{
|
{
|
||||||
method_did
|
info
|
||||||
} else {
|
} else {
|
||||||
return normal_ret;
|
return normal_ret;
|
||||||
};
|
};
|
||||||
|
|
||||||
let tcx = self.infcx.tcx;
|
let tcx = self.infcx.tcx;
|
||||||
|
|
||||||
let parent = tcx.parent(method_did);
|
let parent = tcx.parent(method_did);
|
||||||
let is_fn_once = parent == tcx.lang_items().fn_once_trait();
|
let is_fn_once = parent == tcx.lang_items().fn_once_trait();
|
||||||
let is_operator = !from_hir_call
|
let is_operator = !from_hir_call
|
||||||
&& parent.map_or(false, |p| tcx.lang_items().group(LangItemGroup::Op).contains(&p));
|
&& parent.map_or(false, |p| tcx.lang_items().group(LangItemGroup::Op).contains(&p));
|
||||||
|
let is_deref = !from_hir_call && tcx.is_diagnostic_item(sym::deref_method, method_did);
|
||||||
let fn_call_span = *fn_span;
|
let fn_call_span = *fn_span;
|
||||||
|
|
||||||
let self_arg = tcx.fn_arg_names(method_did)[0];
|
let self_arg = tcx.fn_arg_names(method_did)[0];
|
||||||
|
|
||||||
|
debug!(
|
||||||
|
"terminator = {:?} from_hir_call={:?}",
|
||||||
|
self.body[location.block].terminator, from_hir_call
|
||||||
|
);
|
||||||
|
|
||||||
|
// Check for a 'special' use of 'self' -
|
||||||
|
// an FnOnce call, an operator (e.g. `<<`), or a
|
||||||
|
// deref coercion.
|
||||||
let kind = if is_fn_once {
|
let kind = if is_fn_once {
|
||||||
FnSelfUseKind::FnOnceCall
|
Some(FnSelfUseKind::FnOnceCall)
|
||||||
} else if is_operator {
|
} else if is_operator {
|
||||||
FnSelfUseKind::Operator { self_arg }
|
Some(FnSelfUseKind::Operator { self_arg })
|
||||||
|
} else if is_deref {
|
||||||
|
let deref_target =
|
||||||
|
tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| {
|
||||||
|
Instance::resolve(tcx, self.param_env, deref_target, method_substs)
|
||||||
|
.transpose()
|
||||||
|
});
|
||||||
|
if let Some(Ok(instance)) = deref_target {
|
||||||
|
let deref_target_ty = instance.ty(tcx, self.param_env);
|
||||||
|
Some(FnSelfUseKind::DerefCoercion {
|
||||||
|
deref_target: tcx.def_span(instance.def_id()),
|
||||||
|
deref_target_ty,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let kind = kind.unwrap_or_else(|| {
|
||||||
|
// This isn't a 'special' use of `self`
|
||||||
debug!("move_spans: method_did={:?}, fn_call_span={:?}", method_did, fn_call_span);
|
debug!("move_spans: method_did={:?}, fn_call_span={:?}", method_did, fn_call_span);
|
||||||
let implicit_into_iter = matches!(
|
let implicit_into_iter = matches!(
|
||||||
fn_call_span.desugaring_kind(),
|
fn_call_span.desugaring_kind(),
|
||||||
Some(DesugaringKind::ForLoop(ForLoopLoc::IntoIter))
|
Some(DesugaringKind::ForLoop(ForLoopLoc::IntoIter))
|
||||||
);
|
);
|
||||||
FnSelfUseKind::Normal { self_arg, implicit_into_iter }
|
FnSelfUseKind::Normal { self_arg, implicit_into_iter }
|
||||||
};
|
});
|
||||||
|
|
||||||
return FnSelfUse {
|
return FnSelfUse {
|
||||||
var_span: stmt.source_info.span,
|
var_span: stmt.source_info.span,
|
||||||
|
@ -859,7 +900,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
/// and its usage of the local assigned at `location`.
|
/// and its usage of the local assigned at `location`.
|
||||||
/// This is done by searching in statements succeeding `location`
|
/// This is done by searching in statements succeeding `location`
|
||||||
/// and originating from `maybe_closure_span`.
|
/// and originating from `maybe_closure_span`.
|
||||||
pub(super) fn borrow_spans(&self, use_span: Span, location: Location) -> UseSpans {
|
pub(super) fn borrow_spans(&self, use_span: Span, location: Location) -> UseSpans<'tcx> {
|
||||||
use self::UseSpans::*;
|
use self::UseSpans::*;
|
||||||
debug!("borrow_spans: use_span={:?} location={:?}", use_span, location);
|
debug!("borrow_spans: use_span={:?} location={:?}", use_span, location);
|
||||||
|
|
||||||
|
@ -963,7 +1004,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
|
|
||||||
/// Helper to retrieve span(s) of given borrow from the current MIR
|
/// Helper to retrieve span(s) of given borrow from the current MIR
|
||||||
/// representation
|
/// representation
|
||||||
pub(super) fn retrieve_borrow_spans(&self, borrow: &BorrowData<'_>) -> UseSpans {
|
pub(super) fn retrieve_borrow_spans(&self, borrow: &BorrowData<'_>) -> UseSpans<'tcx> {
|
||||||
let span = self.body.source_info(borrow.reserve_location).span;
|
let span = self.body.source_info(borrow.reserve_location).span;
|
||||||
self.borrow_spans(span, borrow.reserve_location)
|
self.borrow_spans(span, borrow.reserve_location)
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ enum GroupedMoveError<'tcx> {
|
||||||
// Everything that isn't from pattern matching.
|
// Everything that isn't from pattern matching.
|
||||||
OtherIllegalMove {
|
OtherIllegalMove {
|
||||||
original_path: Place<'tcx>,
|
original_path: Place<'tcx>,
|
||||||
use_spans: UseSpans,
|
use_spans: UseSpans<'tcx>,
|
||||||
kind: IllegalMoveOriginKind<'tcx>,
|
kind: IllegalMoveOriginKind<'tcx>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -222,7 +222,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||||
let (mut err, err_span) = {
|
let (mut err, err_span) = {
|
||||||
let (span, use_spans, original_path, kind): (
|
let (span, use_spans, original_path, kind): (
|
||||||
Span,
|
Span,
|
||||||
Option<UseSpans>,
|
Option<UseSpans<'tcx>>,
|
||||||
Place<'tcx>,
|
Place<'tcx>,
|
||||||
&IllegalMoveOriginKind<'_>,
|
&IllegalMoveOriginKind<'_>,
|
||||||
) = match error {
|
) = match error {
|
||||||
|
@ -291,7 +291,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||||
move_place: Place<'tcx>,
|
move_place: Place<'tcx>,
|
||||||
deref_target_place: Place<'tcx>,
|
deref_target_place: Place<'tcx>,
|
||||||
span: Span,
|
span: Span,
|
||||||
use_spans: Option<UseSpans>,
|
use_spans: Option<UseSpans<'tcx>>,
|
||||||
) -> DiagnosticBuilder<'a> {
|
) -> DiagnosticBuilder<'a> {
|
||||||
// Inspect the type of the content behind the
|
// Inspect the type of the content behind the
|
||||||
// borrow to provide feedback about why this
|
// borrow to provide feedback about why this
|
||||||
|
|
|
@ -17,7 +17,7 @@ use rustc_middle::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind
|
||||||
use rustc_middle::mir::{Field, ProjectionElem, Promoted, Rvalue, Statement, StatementKind};
|
use rustc_middle::mir::{Field, ProjectionElem, Promoted, Rvalue, Statement, StatementKind};
|
||||||
use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind};
|
use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind};
|
||||||
use rustc_middle::ty::query::Providers;
|
use rustc_middle::ty::query::Providers;
|
||||||
use rustc_middle::ty::{self, InstanceDef, RegionVid, TyCtxt};
|
use rustc_middle::ty::{self, InstanceDef, ParamEnv, RegionVid, TyCtxt};
|
||||||
use rustc_session::lint::builtin::{MUTABLE_BORROW_RESERVATION_CONFLICT, UNUSED_MUT};
|
use rustc_session::lint::builtin::{MUTABLE_BORROW_RESERVATION_CONFLICT, UNUSED_MUT};
|
||||||
use rustc_span::{Span, Symbol, DUMMY_SP};
|
use rustc_span::{Span, Symbol, DUMMY_SP};
|
||||||
|
|
||||||
|
@ -287,6 +287,7 @@ fn do_mir_borrowck<'a, 'tcx>(
|
||||||
if let Err((move_data, move_errors)) = move_data_results {
|
if let Err((move_data, move_errors)) = move_data_results {
|
||||||
let mut promoted_mbcx = MirBorrowckCtxt {
|
let mut promoted_mbcx = MirBorrowckCtxt {
|
||||||
infcx,
|
infcx,
|
||||||
|
param_env,
|
||||||
body: promoted_body,
|
body: promoted_body,
|
||||||
mir_def_id: def.did,
|
mir_def_id: def.did,
|
||||||
move_data: &move_data,
|
move_data: &move_data,
|
||||||
|
@ -320,6 +321,7 @@ fn do_mir_borrowck<'a, 'tcx>(
|
||||||
|
|
||||||
let mut mbcx = MirBorrowckCtxt {
|
let mut mbcx = MirBorrowckCtxt {
|
||||||
infcx,
|
infcx,
|
||||||
|
param_env,
|
||||||
body,
|
body,
|
||||||
mir_def_id: def.did,
|
mir_def_id: def.did,
|
||||||
move_data: &mdpe.move_data,
|
move_data: &mdpe.move_data,
|
||||||
|
@ -473,6 +475,7 @@ fn do_mir_borrowck<'a, 'tcx>(
|
||||||
|
|
||||||
crate struct MirBorrowckCtxt<'cx, 'tcx> {
|
crate struct MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
crate infcx: &'cx InferCtxt<'cx, 'tcx>,
|
crate infcx: &'cx InferCtxt<'cx, 'tcx>,
|
||||||
|
param_env: ParamEnv<'tcx>,
|
||||||
body: &'cx Body<'tcx>,
|
body: &'cx Body<'tcx>,
|
||||||
mir_def_id: LocalDefId,
|
mir_def_id: LocalDefId,
|
||||||
move_data: &'cx MoveData<'tcx>,
|
move_data: &'cx MoveData<'tcx>,
|
||||||
|
|
|
@ -101,7 +101,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ConstMutationChecker<'a, 'tcx> {
|
||||||
.note("each usage of a `const` item creates a new temporary")
|
.note("each usage of a `const` item creates a new temporary")
|
||||||
.note("the mutable reference will refer to this temporary, not the original `const` item");
|
.note("the mutable reference will refer to this temporary, not the original `const` item");
|
||||||
|
|
||||||
if let Some(method_did) = method_did {
|
if let Some((method_did, _substs)) = method_did {
|
||||||
lint.span_note(self.tcx.def_span(method_did), "mutable reference created due to call to this method");
|
lint.span_note(self.tcx.def_span(method_did), "mutable reference created due to call to this method");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,30 +1,31 @@
|
||||||
use rustc_middle::mir::*;
|
use rustc_middle::mir::*;
|
||||||
|
use rustc_middle::ty::subst::SubstsRef;
|
||||||
use rustc_middle::ty::{self, TyCtxt};
|
use rustc_middle::ty::{self, TyCtxt};
|
||||||
use rustc_span::def_id::DefId;
|
use rustc_span::def_id::DefId;
|
||||||
|
|
||||||
/// Checks if the specified `local` is used as the `self` prameter of a method call
|
/// Checks if the specified `local` is used as the `self` prameter of a method call
|
||||||
/// in the provided `BasicBlock`. If it is, then the `DefId` of the called method is
|
/// in the provided `BasicBlock`. If it is, then the `DefId` of the called method is
|
||||||
/// returned.
|
/// returned.
|
||||||
pub fn find_self_call(
|
pub fn find_self_call<'tcx>(
|
||||||
tcx: TyCtxt<'_>,
|
tcx: TyCtxt<'tcx>,
|
||||||
body: &Body<'_>,
|
body: &Body<'tcx>,
|
||||||
local: Local,
|
local: Local,
|
||||||
block: BasicBlock,
|
block: BasicBlock,
|
||||||
) -> Option<DefId> {
|
) -> Option<(DefId, SubstsRef<'tcx>)> {
|
||||||
debug!("find_self_call(local={:?}): terminator={:?}", local, &body[block].terminator);
|
debug!("find_self_call(local={:?}): terminator={:?}", local, &body[block].terminator);
|
||||||
if let Some(Terminator { kind: TerminatorKind::Call { func, args, .. }, .. }) =
|
if let Some(Terminator { kind: TerminatorKind::Call { func, args, .. }, .. }) =
|
||||||
&body[block].terminator
|
&body[block].terminator
|
||||||
{
|
{
|
||||||
debug!("find_self_call: func={:?}", func);
|
debug!("find_self_call: func={:?}", func);
|
||||||
if let Operand::Constant(box Constant { literal: ty::Const { ty, .. }, .. }) = func {
|
if let Operand::Constant(box Constant { literal: ty::Const { ty, .. }, .. }) = func {
|
||||||
if let ty::FnDef(def_id, _) = *ty.kind() {
|
if let ty::FnDef(def_id, substs) = *ty.kind() {
|
||||||
if let Some(ty::AssocItem { fn_has_self_parameter: true, .. }) =
|
if let Some(ty::AssocItem { fn_has_self_parameter: true, .. }) =
|
||||||
tcx.opt_associated_item(def_id)
|
tcx.opt_associated_item(def_id)
|
||||||
{
|
{
|
||||||
debug!("find_self_call: args={:?}", args);
|
debug!("find_self_call: args={:?}", args);
|
||||||
if let [Operand::Move(self_place) | Operand::Copy(self_place), ..] = **args {
|
if let [Operand::Move(self_place) | Operand::Copy(self_place), ..] = **args {
|
||||||
if self_place.as_local() == Some(local) {
|
if self_place.as_local() == Some(local) {
|
||||||
return Some(def_id);
|
return Some((def_id, substs));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -117,7 +117,14 @@ fn apply_adjustment<'a, 'tcx>(
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
overloaded_place(cx, hir_expr, adjustment.target, Some(call), vec![expr.to_ref()])
|
overloaded_place(
|
||||||
|
cx,
|
||||||
|
hir_expr,
|
||||||
|
adjustment.target,
|
||||||
|
Some(call),
|
||||||
|
vec![expr.to_ref()],
|
||||||
|
deref.span,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
Adjust::Borrow(AutoBorrow::Ref(_, m)) => {
|
Adjust::Borrow(AutoBorrow::Ref(_, m)) => {
|
||||||
ExprKind::Borrow { borrow_kind: m.to_borrow_kind(), arg: expr.to_ref() }
|
ExprKind::Borrow { borrow_kind: m.to_borrow_kind(), arg: expr.to_ref() }
|
||||||
|
@ -277,7 +284,14 @@ fn make_mirror_unadjusted<'a, 'tcx>(
|
||||||
|
|
||||||
hir::ExprKind::Index(ref lhs, ref index) => {
|
hir::ExprKind::Index(ref lhs, ref index) => {
|
||||||
if cx.typeck_results().is_method_call(expr) {
|
if cx.typeck_results().is_method_call(expr) {
|
||||||
overloaded_place(cx, expr, expr_ty, None, vec![lhs.to_ref(), index.to_ref()])
|
overloaded_place(
|
||||||
|
cx,
|
||||||
|
expr,
|
||||||
|
expr_ty,
|
||||||
|
None,
|
||||||
|
vec![lhs.to_ref(), index.to_ref()],
|
||||||
|
expr.span,
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
ExprKind::Index { lhs: lhs.to_ref(), index: index.to_ref() }
|
ExprKind::Index { lhs: lhs.to_ref(), index: index.to_ref() }
|
||||||
}
|
}
|
||||||
|
@ -285,7 +299,7 @@ fn make_mirror_unadjusted<'a, 'tcx>(
|
||||||
|
|
||||||
hir::ExprKind::Unary(hir::UnOp::UnDeref, ref arg) => {
|
hir::ExprKind::Unary(hir::UnOp::UnDeref, ref arg) => {
|
||||||
if cx.typeck_results().is_method_call(expr) {
|
if cx.typeck_results().is_method_call(expr) {
|
||||||
overloaded_place(cx, expr, expr_ty, None, vec![arg.to_ref()])
|
overloaded_place(cx, expr, expr_ty, None, vec![arg.to_ref()], expr.span)
|
||||||
} else {
|
} else {
|
||||||
ExprKind::Deref { arg: arg.to_ref() }
|
ExprKind::Deref { arg: arg.to_ref() }
|
||||||
}
|
}
|
||||||
|
@ -1025,6 +1039,7 @@ fn overloaded_place<'a, 'tcx>(
|
||||||
place_ty: Ty<'tcx>,
|
place_ty: Ty<'tcx>,
|
||||||
overloaded_callee: Option<(DefId, SubstsRef<'tcx>)>,
|
overloaded_callee: Option<(DefId, SubstsRef<'tcx>)>,
|
||||||
args: Vec<ExprRef<'tcx>>,
|
args: Vec<ExprRef<'tcx>>,
|
||||||
|
span: Span,
|
||||||
) -> ExprKind<'tcx> {
|
) -> ExprKind<'tcx> {
|
||||||
// For an overloaded *x or x[y] expression of type T, the method
|
// For an overloaded *x or x[y] expression of type T, the method
|
||||||
// call returns an &T and we must add the deref so that the types
|
// call returns an &T and we must add the deref so that the types
|
||||||
|
@ -1040,24 +1055,24 @@ fn overloaded_place<'a, 'tcx>(
|
||||||
// `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`.
|
// `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`.
|
||||||
let (region, mutbl) = match *recv_ty.kind() {
|
let (region, mutbl) = match *recv_ty.kind() {
|
||||||
ty::Ref(region, _, mutbl) => (region, mutbl),
|
ty::Ref(region, _, mutbl) => (region, mutbl),
|
||||||
_ => span_bug!(expr.span, "overloaded_place: receiver is not a reference"),
|
_ => span_bug!(span, "overloaded_place: receiver is not a reference"),
|
||||||
};
|
};
|
||||||
let ref_ty = cx.tcx.mk_ref(region, ty::TypeAndMut { ty: place_ty, mutbl });
|
let ref_ty = cx.tcx.mk_ref(region, ty::TypeAndMut { ty: place_ty, mutbl });
|
||||||
|
|
||||||
// construct the complete expression `foo()` for the overloaded call,
|
// construct the complete expression `foo()` for the overloaded call,
|
||||||
// which will yield the &T type
|
// which will yield the &T type
|
||||||
let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id);
|
let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id);
|
||||||
let fun = method_callee(cx, expr, expr.span, overloaded_callee);
|
let fun = method_callee(cx, expr, span, overloaded_callee);
|
||||||
let ref_expr = Expr {
|
let ref_expr = Expr {
|
||||||
temp_lifetime,
|
temp_lifetime,
|
||||||
ty: ref_ty,
|
ty: ref_ty,
|
||||||
span: expr.span,
|
span,
|
||||||
kind: ExprKind::Call {
|
kind: ExprKind::Call {
|
||||||
ty: fun.ty,
|
ty: fun.ty,
|
||||||
fun: fun.to_ref(),
|
fun: fun.to_ref(),
|
||||||
args,
|
args,
|
||||||
from_hir_call: false,
|
from_hir_call: false,
|
||||||
fn_span: expr.span,
|
fn_span: span,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -416,7 +416,9 @@ symbols! {
|
||||||
deny,
|
deny,
|
||||||
deprecated,
|
deprecated,
|
||||||
deref,
|
deref,
|
||||||
|
deref_method,
|
||||||
deref_mut,
|
deref_mut,
|
||||||
|
deref_target,
|
||||||
derive,
|
derive,
|
||||||
diagnostic,
|
diagnostic,
|
||||||
direct,
|
direct,
|
||||||
|
|
|
@ -27,6 +27,7 @@ pub struct Autoderef<'a, 'tcx> {
|
||||||
// Meta infos:
|
// Meta infos:
|
||||||
infcx: &'a InferCtxt<'a, 'tcx>,
|
infcx: &'a InferCtxt<'a, 'tcx>,
|
||||||
span: Span,
|
span: Span,
|
||||||
|
overloaded_span: Span,
|
||||||
body_id: hir::HirId,
|
body_id: hir::HirId,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
|
||||||
|
@ -98,10 +99,12 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
|
||||||
body_id: hir::HirId,
|
body_id: hir::HirId,
|
||||||
span: Span,
|
span: Span,
|
||||||
base_ty: Ty<'tcx>,
|
base_ty: Ty<'tcx>,
|
||||||
|
overloaded_span: Span,
|
||||||
) -> Autoderef<'a, 'tcx> {
|
) -> Autoderef<'a, 'tcx> {
|
||||||
Autoderef {
|
Autoderef {
|
||||||
infcx,
|
infcx,
|
||||||
span,
|
span,
|
||||||
|
overloaded_span,
|
||||||
body_id,
|
body_id,
|
||||||
param_env,
|
param_env,
|
||||||
state: AutoderefSnapshot {
|
state: AutoderefSnapshot {
|
||||||
|
@ -190,6 +193,10 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
|
||||||
self.span
|
self.span
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn overloaded_span(&self) -> Span {
|
||||||
|
self.overloaded_span
|
||||||
|
}
|
||||||
|
|
||||||
pub fn reached_recursion_limit(&self) -> bool {
|
pub fn reached_recursion_limit(&self) -> bool {
|
||||||
self.state.reached_recursion_limit
|
self.state.reached_recursion_limit
|
||||||
}
|
}
|
||||||
|
|
|
@ -483,7 +483,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||||
};
|
};
|
||||||
|
|
||||||
if let ty::Ref(region, base_ty, mutbl) = *real_ty.kind() {
|
if let ty::Ref(region, base_ty, mutbl) = *real_ty.kind() {
|
||||||
let mut autoderef = Autoderef::new(self, param_env, body_id, span, base_ty);
|
let mut autoderef = Autoderef::new(self, param_env, body_id, span, base_ty, span);
|
||||||
if let Some(steps) = autoderef.find_map(|(ty, steps)| {
|
if let Some(steps) = autoderef.find_map(|(ty, steps)| {
|
||||||
// Re-add the `&`
|
// Re-add the `&`
|
||||||
let ty = self.tcx.mk_ref(region, TypeAndMut { ty, mutbl });
|
let ty = self.tcx.mk_ref(region, TypeAndMut { ty, mutbl });
|
||||||
|
|
|
@ -12,7 +12,18 @@ use std::iter;
|
||||||
|
|
||||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
pub fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'tcx> {
|
pub fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'tcx> {
|
||||||
Autoderef::new(self, self.param_env, self.body_id, span, base_ty)
|
Autoderef::new(self, self.param_env, self.body_id, span, base_ty, span)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Like `autoderef`, but provides a custom `Span` to use for calls to
|
||||||
|
/// an overloaded `Deref` operator
|
||||||
|
pub fn autoderef_overloaded_span(
|
||||||
|
&'a self,
|
||||||
|
span: Span,
|
||||||
|
base_ty: Ty<'tcx>,
|
||||||
|
overloaded_span: Span,
|
||||||
|
) -> Autoderef<'a, 'tcx> {
|
||||||
|
Autoderef::new(self, self.param_env, self.body_id, span, base_ty, overloaded_span)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn try_overloaded_deref(
|
pub fn try_overloaded_deref(
|
||||||
|
@ -44,7 +55,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
|InferOk { value: method, obligations: o }| {
|
|InferOk { value: method, obligations: o }| {
|
||||||
obligations.extend(o);
|
obligations.extend(o);
|
||||||
if let ty::Ref(region, _, mutbl) = *method.sig.output().kind() {
|
if let ty::Ref(region, _, mutbl) = *method.sig.output().kind() {
|
||||||
Some(OverloadedDeref { region, mutbl })
|
Some(OverloadedDeref {
|
||||||
|
region,
|
||||||
|
mutbl,
|
||||||
|
span: autoderef.overloaded_span(),
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,7 +137,8 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
|
||||||
) -> Ty<'tcx> {
|
) -> Ty<'tcx> {
|
||||||
// Commit the autoderefs by calling `autoderef` again, but this
|
// Commit the autoderefs by calling `autoderef` again, but this
|
||||||
// time writing the results into the various typeck results.
|
// time writing the results into the various typeck results.
|
||||||
let mut autoderef = self.autoderef(self.span, unadjusted_self_ty);
|
let mut autoderef =
|
||||||
|
self.autoderef_overloaded_span(self.span, unadjusted_self_ty, self.call_expr.span);
|
||||||
let (_, n) = match autoderef.nth(pick.autoderefs) {
|
let (_, n) = match autoderef.nth(pick.autoderefs) {
|
||||||
Some(n) => n,
|
Some(n) => n,
|
||||||
None => {
|
None => {
|
||||||
|
|
|
@ -446,9 +446,10 @@ fn method_autoderef_steps<'tcx>(
|
||||||
tcx.infer_ctxt().enter_with_canonical(DUMMY_SP, &goal, |ref infcx, goal, inference_vars| {
|
tcx.infer_ctxt().enter_with_canonical(DUMMY_SP, &goal, |ref infcx, goal, inference_vars| {
|
||||||
let ParamEnvAnd { param_env, value: self_ty } = goal;
|
let ParamEnvAnd { param_env, value: self_ty } = goal;
|
||||||
|
|
||||||
let mut autoderef = Autoderef::new(infcx, param_env, hir::CRATE_HIR_ID, DUMMY_SP, self_ty)
|
let mut autoderef =
|
||||||
.include_raw_pointers()
|
Autoderef::new(infcx, param_env, hir::CRATE_HIR_ID, DUMMY_SP, self_ty, DUMMY_SP)
|
||||||
.silence_errors();
|
.include_raw_pointers()
|
||||||
|
.silence_errors();
|
||||||
let mut reached_raw_pointer = false;
|
let mut reached_raw_pointer = false;
|
||||||
let mut steps: Vec<_> = autoderef
|
let mut steps: Vec<_> = autoderef
|
||||||
.by_ref()
|
.by_ref()
|
||||||
|
|
|
@ -242,7 +242,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
) {
|
) {
|
||||||
let method = self.register_infer_ok_obligations(ok);
|
let method = self.register_infer_ok_obligations(ok);
|
||||||
if let ty::Ref(region, _, mutbl) = *method.sig.output().kind() {
|
if let ty::Ref(region, _, mutbl) = *method.sig.output().kind() {
|
||||||
*deref = OverloadedDeref { region, mutbl };
|
*deref = OverloadedDeref { region, mutbl, span: deref.span };
|
||||||
}
|
}
|
||||||
// If this is a union field, also throw an error for `DerefMut` of `ManuallyDrop` (see RFC 2514).
|
// If this is a union field, also throw an error for `DerefMut` of `ManuallyDrop` (see RFC 2514).
|
||||||
// This helps avoid accidental drops.
|
// This helps avoid accidental drops.
|
||||||
|
|
|
@ -63,11 +63,13 @@
|
||||||
pub trait Deref {
|
pub trait Deref {
|
||||||
/// The resulting type after dereferencing.
|
/// The resulting type after dereferencing.
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
#[rustc_diagnostic_item = "deref_target"]
|
||||||
type Target: ?Sized;
|
type Target: ?Sized;
|
||||||
|
|
||||||
/// Dereferences the value.
|
/// Dereferences the value.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
#[rustc_diagnostic_item = "deref_method"]
|
||||||
fn deref(&self) -> &Self::Target;
|
fn deref(&self) -> &Self::Target;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -149,7 +149,7 @@ error: function cannot return without recursing
|
||||||
LL | fn deref(&self) -> &Baz {
|
LL | fn deref(&self) -> &Baz {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
|
| ^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
|
||||||
LL | self.as_ref()
|
LL | self.as_ref()
|
||||||
| ---- recursive call site
|
| ------------- recursive call site
|
||||||
|
|
|
|
||||||
= help: a `loop` may express intention better if this is on purpose
|
= help: a `loop` may express intention better if this is on purpose
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
|
struct NotCopy {
|
||||||
|
inner: bool
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NotCopy {
|
||||||
|
fn inner_method(&self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Foo {
|
||||||
|
first: NotCopy,
|
||||||
|
second: NotCopy
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for Foo {
|
||||||
|
type Target = NotCopy;
|
||||||
|
fn deref(&self) -> &NotCopy {
|
||||||
|
&self.second
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn use_field(val: Foo) {
|
||||||
|
let _val = val.first;
|
||||||
|
val.inner; //~ ERROR borrow of
|
||||||
|
}
|
||||||
|
|
||||||
|
fn use_method(val: Foo) {
|
||||||
|
let _val = val.first;
|
||||||
|
val.inner_method(); //~ ERROR borrow of
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,35 @@
|
||||||
|
error[E0382]: borrow of partially moved value: `val`
|
||||||
|
--> $DIR/move-deref-coercion.rs:25:5
|
||||||
|
|
|
||||||
|
LL | let _val = val.first;
|
||||||
|
| --------- value partially moved here
|
||||||
|
LL | val.inner;
|
||||||
|
| ^^^^^^^^^ value borrowed here after partial move
|
||||||
|
|
|
||||||
|
= note: partial move occurs because `val.first` has type `NotCopy`, which does not implement the `Copy` trait
|
||||||
|
= note: borrow occurs due to deref coercion to `NotCopy`
|
||||||
|
note: deref defined here
|
||||||
|
--> $DIR/move-deref-coercion.rs:17:5
|
||||||
|
|
|
||||||
|
LL | type Target = NotCopy;
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error[E0382]: borrow of partially moved value: `val`
|
||||||
|
--> $DIR/move-deref-coercion.rs:30:5
|
||||||
|
|
|
||||||
|
LL | let _val = val.first;
|
||||||
|
| --------- value partially moved here
|
||||||
|
LL | val.inner_method();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^ value borrowed here after partial move
|
||||||
|
|
|
||||||
|
= note: partial move occurs because `val.first` has type `NotCopy`, which does not implement the `Copy` trait
|
||||||
|
= note: borrow occurs due to deref coercion to `NotCopy`
|
||||||
|
note: deref defined here
|
||||||
|
--> $DIR/move-deref-coercion.rs:17:5
|
||||||
|
|
|
||||||
|
LL | type Target = NotCopy;
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0382`.
|
|
@ -1,5 +1,5 @@
|
||||||
error[E0382]: borrow of moved value: `arc_v`
|
error[E0382]: borrow of moved value: `arc_v`
|
||||||
--> $DIR/no-capture-arc.rs:14:18
|
--> $DIR/no-capture-arc.rs:14:16
|
||||||
|
|
|
|
||||||
LL | let arc_v = Arc::new(v);
|
LL | let arc_v = Arc::new(v);
|
||||||
| ----- move occurs because `arc_v` has type `Arc<Vec<i32>>`, which does not implement the `Copy` trait
|
| ----- move occurs because `arc_v` has type `Arc<Vec<i32>>`, which does not implement the `Copy` trait
|
||||||
|
@ -10,7 +10,14 @@ LL | assert_eq!((*arc_v)[3], 4);
|
||||||
| ----- variable moved due to use in closure
|
| ----- variable moved due to use in closure
|
||||||
...
|
...
|
||||||
LL | assert_eq!((*arc_v)[2], 3);
|
LL | assert_eq!((*arc_v)[2], 3);
|
||||||
| ^^^^^ value borrowed here after move
|
| ^^^^^^^^ value borrowed here after move
|
||||||
|
|
|
||||||
|
= note: borrow occurs due to deref coercion to `Vec<i32>`
|
||||||
|
note: deref defined here
|
||||||
|
--> $SRC_DIR/alloc/src/sync.rs:LL:COL
|
||||||
|
|
|
||||||
|
LL | type Target = T;
|
||||||
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error[E0382]: borrow of moved value: `arc_v`
|
error[E0382]: borrow of moved value: `arc_v`
|
||||||
--> $DIR/no-reuse-move-arc.rs:12:18
|
--> $DIR/no-reuse-move-arc.rs:12:16
|
||||||
|
|
|
|
||||||
LL | let arc_v = Arc::new(v);
|
LL | let arc_v = Arc::new(v);
|
||||||
| ----- move occurs because `arc_v` has type `Arc<Vec<i32>>`, which does not implement the `Copy` trait
|
| ----- move occurs because `arc_v` has type `Arc<Vec<i32>>`, which does not implement the `Copy` trait
|
||||||
|
@ -10,7 +10,14 @@ LL | assert_eq!((*arc_v)[3], 4);
|
||||||
| ----- variable moved due to use in closure
|
| ----- variable moved due to use in closure
|
||||||
...
|
...
|
||||||
LL | assert_eq!((*arc_v)[2], 3);
|
LL | assert_eq!((*arc_v)[2], 3);
|
||||||
| ^^^^^ value borrowed here after move
|
| ^^^^^^^^ value borrowed here after move
|
||||||
|
|
|
||||||
|
= note: borrow occurs due to deref coercion to `Vec<i32>`
|
||||||
|
note: deref defined here
|
||||||
|
--> $SRC_DIR/alloc/src/sync.rs:LL:COL
|
||||||
|
|
|
||||||
|
LL | type Target = T;
|
||||||
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue