mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-26 16:54:01 +00:00
Use the correct FakeReadCause
This commit is contained in:
parent
b6cf070eb4
commit
685a4c6b6b
@ -47,6 +47,7 @@ use rustc_hir::{
|
||||
};
|
||||
use rustc_index::vec::{Idx, IndexVec};
|
||||
use rustc_macros::HashStable;
|
||||
use rustc_middle::mir::FakeReadCause;
|
||||
use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
|
||||
use rustc_session::config::{BorrowckMode, CrateType, OutputFilenames};
|
||||
use rustc_session::lint::{Level, Lint};
|
||||
@ -430,8 +431,7 @@ pub struct TypeckResults<'tcx> {
|
||||
/// see `MinCaptureInformationMap` for more details.
|
||||
pub closure_min_captures: ty::MinCaptureInformationMap<'tcx>,
|
||||
|
||||
/// [FIXME] RFC2229 Change to use HashSet instead of Vec
|
||||
pub closure_fake_reads: FxHashMap<DefId, Vec<HirPlace<'tcx>>>,
|
||||
pub closure_fake_reads: FxHashMap<DefId, Vec<(HirPlace<'tcx>, FakeReadCause)>>,
|
||||
|
||||
/// Stores the type, expression, span and optional scope span of all types
|
||||
/// that are live across the yield of this generator (if a generator).
|
||||
|
@ -94,14 +94,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
)
|
||||
);
|
||||
}
|
||||
// ROX:
|
||||
//
|
||||
// Where the handling of destructure patterns start
|
||||
//
|
||||
// let (a, b, c, _ ) = something
|
||||
//
|
||||
// (a, b, c, _) is the pattern
|
||||
// something is the initializer
|
||||
StmtKind::Let { remainder_scope, init_scope, pattern, initializer, lint_level } => {
|
||||
let ignores_expr_result = matches!(*pattern.kind, PatKind::Wild);
|
||||
this.block_context.push(BlockFrame::Statement { ignores_expr_result });
|
||||
@ -133,8 +125,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
ArmHasGuard(false),
|
||||
Some((None, initializer_span)),
|
||||
);
|
||||
// This is where we get into pattern handling of the let
|
||||
// statement
|
||||
this.expr_into_pattern(block, pattern.clone(), init)
|
||||
})
|
||||
}
|
||||
|
@ -84,6 +84,7 @@ fn convert_to_hir_projections_and_truncate_for_capture<'tcx>(
|
||||
mir_projections: &[PlaceElem<'tcx>],
|
||||
) -> Vec<HirProjectionKind> {
|
||||
let mut hir_projections = Vec::new();
|
||||
let mut variant = None;
|
||||
|
||||
for mir_projection in mir_projections {
|
||||
let hir_projection = match mir_projection {
|
||||
@ -91,13 +92,17 @@ fn convert_to_hir_projections_and_truncate_for_capture<'tcx>(
|
||||
ProjectionElem::Field(field, _) => {
|
||||
// We will never encouter this for multivariant enums,
|
||||
// read the comment for `Downcast`.
|
||||
HirProjectionKind::Field(field.index() as u32, VariantIdx::new(0))
|
||||
let variant = variant.unwrap_or(VariantIdx::new(0));
|
||||
HirProjectionKind::Field(field.index() as u32, variant)
|
||||
}
|
||||
ProjectionElem::Downcast(..) => {
|
||||
// This projections exist only for enums that have
|
||||
// multiple variants. Since such enums that are captured
|
||||
// completely, we can stop here.
|
||||
break;
|
||||
ProjectionElem::Downcast(.., idx) => {
|
||||
// This projections exist for enums that have
|
||||
// single and multiple variants.
|
||||
// For single variants, enums are not captured completely.
|
||||
// We keep track of VariantIdx so we can use this information
|
||||
// if the next ProjectionElem is a Field
|
||||
variant = Some(*idx);
|
||||
continue;
|
||||
}
|
||||
ProjectionElem::Index(..)
|
||||
| ProjectionElem::ConstantIndex { .. }
|
||||
@ -107,7 +112,7 @@ fn convert_to_hir_projections_and_truncate_for_capture<'tcx>(
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
variant = None;
|
||||
hir_projections.push(hir_projection);
|
||||
}
|
||||
|
||||
@ -231,13 +236,12 @@ fn to_upvars_resolved_place_builder<'a, 'tcx>(
|
||||
from_builder.projection
|
||||
)
|
||||
} else {
|
||||
// FIXME(project-rfc-2229#24): Handle this case properly
|
||||
debug!(
|
||||
"No associated capture found for {:?}[{:#?}]",
|
||||
var_hir_id, from_builder.projection,
|
||||
);
|
||||
}
|
||||
return Err(upvar_resolved_place_builder);
|
||||
return Err(from_builder);
|
||||
};
|
||||
|
||||
let closure_ty = typeck_results
|
||||
@ -289,11 +293,10 @@ impl<'tcx> PlaceBuilder<'tcx> {
|
||||
if let PlaceBase::Local(local) = self.base {
|
||||
Place { local, projection: tcx.intern_place_elems(&self.projection) }
|
||||
} else {
|
||||
self.try_upvars_resolved(tcx, typeck_results).into_place(tcx, typeck_results)
|
||||
self.expect_upvars_resolved(tcx, typeck_results).into_place(tcx, typeck_results)
|
||||
}
|
||||
}
|
||||
|
||||
/// ROX: Function that will be called when we really do need a place
|
||||
fn expect_upvars_resolved<'a>(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
@ -302,14 +305,14 @@ impl<'tcx> PlaceBuilder<'tcx> {
|
||||
to_upvars_resolved_place_builder(self, tcx, typeck_results).unwrap()
|
||||
}
|
||||
|
||||
fn try_upvars_resolved<'a>(
|
||||
crate fn try_upvars_resolved<'a>(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
typeck_results: &'a ty::TypeckResults<'tcx>,
|
||||
) -> PlaceBuilder<'tcx> {
|
||||
) -> Result<PlaceBuilder<'tcx>, PlaceBuilder<'tcx>> {
|
||||
match to_upvars_resolved_place_builder(self, tcx, typeck_results) {
|
||||
Ok(upvars_resolved) => upvars_resolved,
|
||||
Err(upvars_unresolved) => upvars_unresolved,
|
||||
Ok(upvars_resolved) => Ok(upvars_resolved),
|
||||
Err(upvars_unresolved) => Err(upvars_unresolved),
|
||||
}
|
||||
}
|
||||
|
||||
@ -376,7 +379,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
block.and(place_builder.into_place(self.tcx, self.typeck_results))
|
||||
}
|
||||
|
||||
// ROX: As place builder
|
||||
/// This is used when constructing a compound `Place`, so that we can avoid creating
|
||||
/// intermediate `Place` values until we know the full set of projections.
|
||||
crate fn as_place_builder(
|
||||
|
@ -165,7 +165,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
|
||||
block.and(Rvalue::Aggregate(box AggregateKind::Tuple, fields))
|
||||
}
|
||||
ExprKind::Closure { closure_id, substs, upvars, movability, fake_reads } => {
|
||||
ExprKind::Closure {
|
||||
closure_id,
|
||||
substs,
|
||||
upvars,
|
||||
movability,
|
||||
fake_reads: opt_fake_reads,
|
||||
} => {
|
||||
// see (*) above
|
||||
let operands: Vec<_> = upvars
|
||||
.into_iter()
|
||||
@ -204,18 +210,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
if let Some(fake_reads) = opt_fake_reads {
|
||||
for (thir_place, cause) in fake_reads.into_iter() {
|
||||
let place_builder =
|
||||
unpack!(block = this.as_place_builder(block, thir_place));
|
||||
|
||||
if let Some(fake_reads) = fake_reads {
|
||||
for thir_place in fake_reads.into_iter() {
|
||||
// = this.hir.mirror(thir_place);
|
||||
let mir_place = unpack!(block = this.as_place(block, thir_place));
|
||||
// [FIXME] RFC2229 FakeReadCause can be ForLet or ForMatch, need to use the correct one
|
||||
this.cfg.push_fake_read(
|
||||
block,
|
||||
source_info,
|
||||
FakeReadCause::ForMatchedPlace,
|
||||
mir_place,
|
||||
);
|
||||
if let Ok(place_builder_resolved) =
|
||||
place_builder.clone().try_upvars_resolved(this.tcx, this.typeck_results)
|
||||
{
|
||||
let mir_place = place_builder_resolved
|
||||
.clone()
|
||||
.into_place(this.tcx, this.typeck_results);
|
||||
this.cfg.push_fake_read(block, source_info, cause, mir_place);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -280,7 +280,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
let field_names: Vec<_> =
|
||||
(0..adt_def.variants[variant_index].fields.len()).map(Field::new).collect();
|
||||
|
||||
// ROX: This is probably here the function record/struct update pattern is done.
|
||||
let fields: Vec<_> = if let Some(FruInfo { base, field_types }) = base {
|
||||
let place_builder = unpack!(block = this.as_place_builder(block, base));
|
||||
|
||||
|
@ -1,6 +1,3 @@
|
||||
// ROX: this folder contains all code for handling patterns, including exhaustiveness checking etc.
|
||||
// We want to be careful ^^'
|
||||
|
||||
//! Code related to match expressions. These are sufficiently complex to
|
||||
//! warrant their own module and submodules. :) This main module includes the
|
||||
//! high-level algorithm, the submodules contain the details.
|
||||
@ -100,7 +97,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
let scrutinee_place =
|
||||
unpack!(block = self.lower_scrutinee(block, scrutinee, scrutinee_span,));
|
||||
|
||||
let mut arm_candidates = self.create_match_candidates(scrutinee_place.clone(), &arms);
|
||||
let mut arm_candidates =
|
||||
self.create_match_candidates(scrutinee_place.clone(), &arms.clone());
|
||||
|
||||
let match_has_guard = arms.iter().any(|arm| arm.guard.is_some());
|
||||
let mut candidates =
|
||||
@ -127,8 +125,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
scrutinee_span: Span,
|
||||
) -> BlockAnd<PlaceBuilder<'tcx>> {
|
||||
let scrutinee_place_builder = unpack!(block = self.as_place_builder(block, scrutinee));
|
||||
let scrutinee_place =
|
||||
scrutinee_place_builder.clone().into_place(self.tcx, self.typeck_results);
|
||||
// Matching on a `scrutinee_place` with an uninhabited type doesn't
|
||||
// generate any memory reads by itself, and so if the place "expression"
|
||||
// contains unsafe operations like raw pointer dereferences or union
|
||||
@ -146,7 +142,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
// check safety.
|
||||
let cause_matched_place = FakeReadCause::ForMatchedPlace;
|
||||
let source_info = self.source_info(scrutinee_span);
|
||||
self.cfg.push_fake_read(block, source_info, cause_matched_place, scrutinee_place);
|
||||
|
||||
if let Ok(scrutinee_builder) =
|
||||
scrutinee_place_builder.clone().try_upvars_resolved(self.tcx, self.typeck_results)
|
||||
{
|
||||
let scrutinee_place =
|
||||
scrutinee_builder.clone().into_place(self.tcx, self.typeck_results);
|
||||
self.cfg.push_fake_read(block, source_info, cause_matched_place, scrutinee_place);
|
||||
}
|
||||
|
||||
block.and(scrutinee_place_builder)
|
||||
}
|
||||
@ -228,7 +231,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
fn lower_match_arms(
|
||||
&mut self,
|
||||
destination: Place<'tcx>,
|
||||
scrutinee_place: PlaceBuilder<'tcx>,
|
||||
scrutinee_place_builder: PlaceBuilder<'tcx>,
|
||||
scrutinee_span: Span,
|
||||
arm_candidates: Vec<(&'_ Arm<'_, 'tcx>, Candidate<'_, 'tcx>)>,
|
||||
outer_source_info: SourceInfo,
|
||||
@ -242,17 +245,23 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
let arm_source_info = self.source_info(arm.span);
|
||||
let arm_scope = (arm.scope, arm_source_info);
|
||||
self.in_scope(arm_scope, arm.lint_level, |this| {
|
||||
let body = arm.body.clone();
|
||||
let mut opt_scrutinee_place: Option<(Option<&Place<'tcx>>, Span)> = None;
|
||||
let scrutinee_place: Place<'tcx>;
|
||||
if let Ok(scrutinee_builder) = scrutinee_place_builder
|
||||
.clone()
|
||||
.try_upvars_resolved(this.tcx, this.typeck_results)
|
||||
{
|
||||
scrutinee_place =
|
||||
scrutinee_builder.clone().into_place(this.tcx, this.typeck_results);
|
||||
opt_scrutinee_place = Some((Some(&scrutinee_place), scrutinee_span));
|
||||
}
|
||||
let scope = this.declare_bindings(
|
||||
None,
|
||||
arm.span,
|
||||
&arm.pattern,
|
||||
ArmHasGuard(arm.guard.is_some()),
|
||||
Some((
|
||||
Some(
|
||||
&scrutinee_place.clone().into_place(this.tcx, this.typeck_results),
|
||||
),
|
||||
scrutinee_span,
|
||||
)),
|
||||
opt_scrutinee_place,
|
||||
);
|
||||
|
||||
let arm_block = this.bind_pattern(
|
||||
@ -457,15 +466,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
}
|
||||
|
||||
_ => {
|
||||
// Converts the destruct pattern into a place
|
||||
//
|
||||
// We don't want to convert to a place right away
|
||||
// because in case of such pattern inside a closure, the projections matching a
|
||||
// captured place might have not been applied.
|
||||
// [FIXME] Need to find where this is happening and make the necessary changes there once
|
||||
// Candidate is modified
|
||||
//
|
||||
// We want to use a place builder; Maybe use `as_place_builder`
|
||||
let place_builder = unpack!(block = self.as_place_builder(block, initializer));
|
||||
self.place_into_pattern(block, irrefutable_pat, place_builder, true)
|
||||
}
|
||||
@ -479,12 +479,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
initializer: PlaceBuilder<'tcx>,
|
||||
set_match_place: bool,
|
||||
) -> BlockAnd<()> {
|
||||
let place = initializer.clone().into_place(self.tcx, self.typeck_results);
|
||||
let mut candidate = Candidate::new(initializer, &irrefutable_pat, false);
|
||||
|
||||
let mut candidate = Candidate::new(initializer.clone(), &irrefutable_pat, false);
|
||||
let fake_borrow_temps =
|
||||
self.lower_match_tree(block, irrefutable_pat.span, false, &mut [&mut candidate]);
|
||||
|
||||
// For matches and function arguments, the place that is being matched
|
||||
// can be set when creating the variables. But the place for
|
||||
// let PATTERN = ... might not even exist until we do the assignment.
|
||||
@ -499,7 +496,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
VarBindingForm { opt_match_place: Some((ref mut match_place, _)), .. },
|
||||
)))) = self.local_decls[local].local_info
|
||||
{
|
||||
*match_place = Some(place);
|
||||
if let Ok(match_pair_resolved) =
|
||||
initializer.clone().try_upvars_resolved(self.tcx, self.typeck_results)
|
||||
{
|
||||
let place = match_pair_resolved
|
||||
.clone()
|
||||
.into_place(self.tcx, self.typeck_results);
|
||||
*match_place = Some(place);
|
||||
}
|
||||
} else {
|
||||
bug!("Let binding to non-user variable.")
|
||||
}
|
||||
@ -1461,7 +1465,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
|
||||
// Insert a Shallow borrow of any places that is switched on.
|
||||
if let Some(fb) = fake_borrows {
|
||||
fb.insert(match_place.clone().into_place(self.tcx, self.typeck_results));
|
||||
if let Ok(match_place_resolved) =
|
||||
match_place.clone().try_upvars_resolved(self.tcx, self.typeck_results)
|
||||
{
|
||||
let resolved_place =
|
||||
match_place_resolved.clone().into_place(self.tcx, self.typeck_results);
|
||||
fb.insert(resolved_place);
|
||||
}
|
||||
}
|
||||
|
||||
// perform the test, branching to one of N blocks. For each of
|
||||
@ -1776,28 +1786,36 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
}
|
||||
Guard::IfLet(pat, scrutinee) => {
|
||||
let scrutinee_span = scrutinee.span;
|
||||
let scrutinee_place = unpack!(
|
||||
let scrutinee_place_builder = unpack!(
|
||||
block = self.lower_scrutinee(block, scrutinee.clone(), scrutinee_span)
|
||||
);
|
||||
let mut guard_candidate = Candidate::new(scrutinee_place.clone(), &pat, false);
|
||||
let mut guard_candidate =
|
||||
Candidate::new(scrutinee_place_builder.clone(), &pat, false);
|
||||
let wildcard = Pat::wildcard_from_ty(pat.ty);
|
||||
let mut otherwise_candidate =
|
||||
Candidate::new(scrutinee_place.clone(), &wildcard, false);
|
||||
Candidate::new(scrutinee_place_builder.clone(), &wildcard, false);
|
||||
let fake_borrow_temps = self.lower_match_tree(
|
||||
block,
|
||||
pat.span,
|
||||
false,
|
||||
&mut [&mut guard_candidate, &mut otherwise_candidate],
|
||||
);
|
||||
let mut opt_scrutinee_place: Option<(Option<&Place<'tcx>>, Span)> = None;
|
||||
let scrutinee_place: Place<'tcx>;
|
||||
if let Ok(scrutinee_builder) = scrutinee_place_builder
|
||||
.clone()
|
||||
.try_upvars_resolved(self.tcx, self.typeck_results)
|
||||
{
|
||||
scrutinee_place =
|
||||
scrutinee_builder.clone().into_place(self.tcx, self.typeck_results);
|
||||
opt_scrutinee_place = Some((Some(&scrutinee_place), scrutinee_span));
|
||||
}
|
||||
self.declare_bindings(
|
||||
None,
|
||||
pat.span.to(arm_span.unwrap()),
|
||||
pat,
|
||||
ArmHasGuard(false),
|
||||
Some((
|
||||
Some(&scrutinee_place.clone().into_place(tcx, self.typeck_results)),
|
||||
scrutinee.span,
|
||||
)),
|
||||
opt_scrutinee_place,
|
||||
);
|
||||
let post_guard_block = self.bind_pattern(
|
||||
self.source_info(pat.span),
|
||||
|
@ -149,9 +149,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
candidate: &mut Candidate<'pat, 'tcx>,
|
||||
) -> Result<(), MatchPair<'pat, 'tcx>> {
|
||||
let tcx = self.tcx;
|
||||
// Generate place to be used in Ascription
|
||||
// Generate place to be used in Binding
|
||||
let place = match_pair.place.clone().into_place(tcx, self.typeck_results);
|
||||
match *match_pair.pattern.kind {
|
||||
PatKind::AscribeUserType {
|
||||
ref subpattern,
|
||||
@ -159,6 +156,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
} => {
|
||||
// Apply the type ascription to the value at `match_pair.place`, which is the
|
||||
// value being matched, taking the variance field into account.
|
||||
let place = match_pair.place.clone().into_place(self.tcx, self.typeck_results);
|
||||
candidate.ascriptions.push(Ascription {
|
||||
span: user_ty_span,
|
||||
user_ty,
|
||||
@ -177,6 +175,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
}
|
||||
|
||||
PatKind::Binding { name, mutability, mode, var, ty, ref subpattern, is_primary: _ } => {
|
||||
let place = match_pair.place.clone().into_place(self.tcx, self.typeck_results);
|
||||
candidate.bindings.push(Binding {
|
||||
name,
|
||||
mutability,
|
||||
|
@ -156,7 +156,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
test: &Test<'tcx>,
|
||||
make_target_blocks: impl FnOnce(&mut Self) -> Vec<BasicBlock>,
|
||||
) {
|
||||
let place = place_builder.clone().into_place(self.tcx, self.typeck_results);
|
||||
let place: Place<'tcx>;
|
||||
if let Ok(test_place_builder) =
|
||||
place_builder.clone().try_upvars_resolved(self.tcx, self.typeck_results)
|
||||
{
|
||||
place = test_place_builder.clone().into_place(self.tcx, self.typeck_results);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
debug!(
|
||||
"perform_test({:?}, {:?}: {:?}, {:?})",
|
||||
block,
|
||||
|
@ -455,27 +455,32 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
|
||||
);
|
||||
|
||||
let fake_reads = match self.typeck_results().closure_fake_reads.get(&def_id) {
|
||||
Some(vals) => Some(self.arena.alloc_from_iter(vals
|
||||
.iter()
|
||||
.filter(|val| match val.base {
|
||||
HirPlaceBase::Upvar(_) => true,
|
||||
_ => false,
|
||||
})
|
||||
.map(|val| {
|
||||
let var_hir_id = match val.base {
|
||||
HirPlaceBase::Upvar(upvar_id) => {
|
||||
debug!("upvar");
|
||||
upvar_id.var_path.hir_id
|
||||
}
|
||||
_ => {
|
||||
bug!(
|
||||
"Do not know how to get HirId out of Rvalue and StaticItem"
|
||||
);
|
||||
}
|
||||
};
|
||||
self.fake_read_capture_upvar(expr, val.clone(), var_hir_id)
|
||||
})
|
||||
)),
|
||||
Some(vals) => {
|
||||
Some(
|
||||
vals.iter()
|
||||
.map(|(place, cause)| {
|
||||
(
|
||||
self.arena.alloc(
|
||||
self.convert_captured_hir_place(expr, place.clone()),
|
||||
),
|
||||
*cause,
|
||||
)
|
||||
// let var_hir_id = match val.base {
|
||||
// HirPlaceBase::Upvar(upvar_id) => {
|
||||
// debug!("upvar");
|
||||
// upvar_id.var_path.hir_id
|
||||
// }
|
||||
// _ => {
|
||||
// bug!(
|
||||
// "Do not know how to get HirId out of Rvalue and StaticItem"
|
||||
// );
|
||||
// }
|
||||
// };
|
||||
// self.fake_read_capture_upvar(expr, val.clone(), var_hir_id)
|
||||
})
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
|
||||
@ -1045,23 +1050,26 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
|
||||
ExprKind::Deref { arg: ref_expr }
|
||||
}
|
||||
|
||||
fn fake_read_capture_upvar(
|
||||
fn convert_captured_hir_place(
|
||||
&mut self,
|
||||
closure_expr: &'tcx hir::Expr<'tcx>,
|
||||
place: HirPlace<'tcx>,
|
||||
hir_id: hir::HirId,
|
||||
) -> Expr<'thir, 'tcx> {
|
||||
let temp_lifetime = self.region_scope_tree.temporary_scope(closure_expr.hir_id.local_id);
|
||||
let var_ty = place.base_ty;
|
||||
|
||||
let var_hir_id = match place.base {
|
||||
HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id,
|
||||
base => bug!("Expected an upvar, found {:?}", base),
|
||||
};
|
||||
|
||||
let mut captured_place_expr = Expr {
|
||||
temp_lifetime,
|
||||
ty: var_ty,
|
||||
span: closure_expr.span,
|
||||
kind: self.convert_var(hir_id),
|
||||
kind: self.convert_var(var_hir_id),
|
||||
};
|
||||
// [FIXME] RFC2229 Maybe we should introduce an immutable borrow of the fake capture so that we don't
|
||||
// end up moving this place
|
||||
|
||||
for proj in place.projections.iter() {
|
||||
let kind = match proj.kind {
|
||||
HirProjectionKind::Deref => {
|
||||
@ -1095,48 +1103,9 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
|
||||
upvar_ty: Ty<'tcx>,
|
||||
) -> Expr<'thir, 'tcx> {
|
||||
let upvar_capture = captured_place.info.capture_kind;
|
||||
let captured_place_expr =
|
||||
self.convert_captured_hir_place(closure_expr, captured_place.place.clone());
|
||||
let temp_lifetime = self.region_scope_tree.temporary_scope(closure_expr.hir_id.local_id);
|
||||
let var_ty = captured_place.place.base_ty;
|
||||
|
||||
// The result of capture analysis in `rustc_typeck/check/upvar.rs`represents a captured path
|
||||
// as it's seen for use within the closure and not at the time of closure creation.
|
||||
//
|
||||
// That is we see expect to see it start from a captured upvar and not something that is local
|
||||
// to the closure's parent.
|
||||
let var_hir_id = match captured_place.place.base {
|
||||
HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id,
|
||||
base => bug!("Expected an upvar, found {:?}", base),
|
||||
};
|
||||
|
||||
let mut captured_place_expr = Expr {
|
||||
temp_lifetime,
|
||||
ty: var_ty,
|
||||
span: closure_expr.span,
|
||||
kind: self.convert_var(var_hir_id),
|
||||
};
|
||||
|
||||
for proj in captured_place.place.projections.iter() {
|
||||
let kind = match proj.kind {
|
||||
HirProjectionKind::Deref => {
|
||||
ExprKind::Deref { arg: self.arena.alloc(captured_place_expr) }
|
||||
}
|
||||
HirProjectionKind::Field(field, ..) => {
|
||||
// Variant index will always be 0, because for multi-variant
|
||||
// enums, we capture the enum entirely.
|
||||
ExprKind::Field {
|
||||
lhs: self.arena.alloc(captured_place_expr),
|
||||
name: Field::new(field as usize),
|
||||
}
|
||||
}
|
||||
HirProjectionKind::Index | HirProjectionKind::Subslice => {
|
||||
// We don't capture these projections, so we can ignore them here
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
captured_place_expr =
|
||||
Expr { temp_lifetime, ty: proj.ty, span: closure_expr.span, kind };
|
||||
}
|
||||
|
||||
match upvar_capture {
|
||||
ty::UpvarCapture::ByValue(_) => captured_place_expr,
|
||||
|
@ -9,7 +9,7 @@ use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::infer::canonical::Canonical;
|
||||
use rustc_middle::middle::region;
|
||||
use rustc_middle::mir::{BinOp, BorrowKind, Field, UnOp};
|
||||
use rustc_middle::mir::{BinOp, BorrowKind, FakeReadCause, Field, UnOp};
|
||||
use rustc_middle::ty::adjustment::PointerCast;
|
||||
use rustc_middle::ty::subst::SubstsRef;
|
||||
use rustc_middle::ty::{AdtDef, Const, Ty, UpvarSubsts, UserType};
|
||||
@ -281,7 +281,7 @@ pub enum ExprKind<'thir, 'tcx> {
|
||||
substs: UpvarSubsts<'tcx>,
|
||||
upvars: &'thir [Expr<'thir, 'tcx>],
|
||||
movability: Option<hir::Movability>,
|
||||
fake_reads: Option<&'thir mut [Expr<'thir, 'tcx>]>,
|
||||
fake_reads: Option<Vec<(&'thir mut Expr<'thir, 'tcx>, FakeReadCause)>>,
|
||||
},
|
||||
Literal {
|
||||
literal: &'tcx Const<'tcx>,
|
||||
|
@ -34,7 +34,6 @@ use super::writeback::Resolver;
|
||||
use super::FnCtxt;
|
||||
|
||||
use crate::expr_use_visitor as euv;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
@ -42,6 +41,7 @@ use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
|
||||
use rustc_infer::infer::UpvarRegion;
|
||||
use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection, ProjectionKind};
|
||||
use rustc_middle::mir::FakeReadCause;
|
||||
use rustc_middle::ty::fold::TypeFoldable;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeckResults, UpvarSubsts};
|
||||
use rustc_session::lint;
|
||||
@ -248,7 +248,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
let final_tupled_upvars_type = self.tcx.mk_tup(final_upvar_tys.iter());
|
||||
self.demand_suptype(span, substs.tupled_upvars_ty(), final_tupled_upvars_type);
|
||||
|
||||
let fake_reads = delegate.fake_reads.into_iter().map(|fake_read| fake_read).collect();
|
||||
let fake_reads =
|
||||
delegate.fake_reads.into_iter().map(|(place, cause)| (place, cause)).collect();
|
||||
self.typeck_results.borrow_mut().closure_fake_reads.insert(closure_def_id, fake_reads);
|
||||
|
||||
// If we are also inferred the closure kind here,
|
||||
@ -1153,7 +1154,7 @@ struct InferBorrowKind<'a, 'tcx> {
|
||||
/// Place { V1, [ProjectionKind::Field(Index=1, Variant=0)] } : CaptureKind { E2, MutableBorrow }
|
||||
/// ```
|
||||
capture_information: InferredCaptureInformation<'tcx>,
|
||||
fake_reads: FxHashSet<Place<'tcx>>, // these need to be fake read.
|
||||
fake_reads: Vec<(Place<'tcx>, FakeReadCause)>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
|
||||
@ -1415,9 +1416,9 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
|
||||
fn fake_read(&mut self, place: Place<'tcx>) {
|
||||
fn fake_read(&mut self, place: Place<'tcx>, cause: FakeReadCause) {
|
||||
if let PlaceBase::Upvar(_) = place.base {
|
||||
self.fake_reads.insert(place);
|
||||
self.fake_reads.push((place, cause));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,7 @@ use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
|
||||
use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
|
||||
use rustc_infer::infer::InferCtxt;
|
||||
use rustc_middle::hir::place::Place as HirPlace;
|
||||
use rustc_middle::mir::FakeReadCause;
|
||||
use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast};
|
||||
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
@ -368,18 +369,20 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
||||
}
|
||||
|
||||
fn visit_fake_reads_map(&mut self) {
|
||||
let mut resolved_closure_fake_reads: FxHashMap<DefId, Vec<HirPlace<'tcx>>> =
|
||||
Default::default();
|
||||
let mut resolved_closure_fake_reads: FxHashMap<
|
||||
DefId,
|
||||
Vec<(HirPlace<'tcx>, FakeReadCause)>,
|
||||
> = Default::default();
|
||||
for (closure_def_id, fake_reads) in
|
||||
self.fcx.typeck_results.borrow().closure_fake_reads.iter()
|
||||
{
|
||||
let mut resolved_fake_reads = Vec::<HirPlace<'tcx>>::new();
|
||||
for fake_read in fake_reads.iter() {
|
||||
let mut resolved_fake_reads = Vec::<(HirPlace<'tcx>, FakeReadCause)>::new();
|
||||
for (place, cause) in fake_reads.iter() {
|
||||
let locatable =
|
||||
self.tcx().hir().local_def_id_to_hir_id(closure_def_id.expect_local());
|
||||
|
||||
let resolved_fake_read = self.resolve(fake_read.clone(), &locatable);
|
||||
resolved_fake_reads.push(resolved_fake_read);
|
||||
let resolved_fake_read = self.resolve(place.clone(), &locatable);
|
||||
resolved_fake_reads.push((resolved_fake_read, *cause));
|
||||
}
|
||||
resolved_closure_fake_reads.insert(*closure_def_id, resolved_fake_reads);
|
||||
}
|
||||
|
@ -8,13 +8,14 @@ pub use self::ConsumeMode::*;
|
||||
pub use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection};
|
||||
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
// use rustc_hir::Pat;
|
||||
use rustc_hir::PatKind;
|
||||
use rustc_hir::QPath;
|
||||
use rustc_index::vec::Idx;
|
||||
use rustc_infer::infer::InferCtxt;
|
||||
use rustc_middle::hir::place::ProjectionKind;
|
||||
use rustc_middle::mir::FakeReadCause;
|
||||
use rustc_middle::ty::{self, adjustment, TyCtxt};
|
||||
use rustc_target::abi::VariantIdx;
|
||||
|
||||
@ -54,7 +55,7 @@ pub trait Delegate<'tcx> {
|
||||
fn mutate(&mut self, assignee_place: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId);
|
||||
|
||||
// [FIXME] RFC2229 This should also affect clippy ref: https://github.com/sexxi-goose/rust/pull/27
|
||||
fn fake_read(&mut self, place: Place<'tcx>);
|
||||
fn fake_read(&mut self, place: Place<'tcx>, cause: FakeReadCause);
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
@ -237,18 +238,26 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
|
||||
// We only want to borrow discr if the pattern contain something other
|
||||
// than wildcards
|
||||
let ExprUseVisitor { ref mc, body_owner: _, delegate: _ } = *self;
|
||||
let mut res = false;
|
||||
let mut needs_to_be_read = false;
|
||||
for arm in arms.iter() {
|
||||
return_if_err!(mc.cat_pattern(discr_place.clone(), &arm.pat, |_place, pat| {
|
||||
if let PatKind::Binding(_, _, _, opt_sub_pat) = pat.kind {
|
||||
if let None = opt_sub_pat {
|
||||
res = true;
|
||||
needs_to_be_read = true;
|
||||
}
|
||||
} else if let PatKind::TupleStruct(qpath, _, _) = &pat.kind {
|
||||
// If a TupleStruct has a Some PathSegment, we should read the discr_place
|
||||
// regardless if it contains a Wild pattern later
|
||||
if let QPath::Resolved(_, path) = qpath {
|
||||
if let Res::Def(DefKind::Ctor(_, _), _) = path.res {
|
||||
needs_to_be_read = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
if res {
|
||||
if needs_to_be_read {
|
||||
self.borrow_expr(&discr, ty::ImmBorrow);
|
||||
}
|
||||
|
||||
@ -539,6 +548,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
|
||||
}
|
||||
|
||||
fn walk_arm(&mut self, discr_place: &PlaceWithHirId<'tcx>, arm: &hir::Arm<'_>) {
|
||||
self.delegate.fake_read(discr_place.place.clone(), FakeReadCause::ForMatchedPlace);
|
||||
self.walk_pat(discr_place, &arm.pat);
|
||||
|
||||
if let Some(hir::Guard::If(ref e)) = arm.guard {
|
||||
@ -551,6 +561,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
|
||||
/// Walks a pat that occurs in isolation (i.e., top-level of fn argument or
|
||||
/// let binding, and *not* a match arm or nested pat.)
|
||||
fn walk_irrefutable_pat(&mut self, discr_place: &PlaceWithHirId<'tcx>, pat: &hir::Pat<'_>) {
|
||||
self.delegate.fake_read(discr_place.place.clone(), FakeReadCause::ForLet);
|
||||
self.walk_pat(discr_place, pat);
|
||||
}
|
||||
|
||||
@ -558,8 +569,6 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
|
||||
fn walk_pat(&mut self, discr_place: &PlaceWithHirId<'tcx>, pat: &hir::Pat<'_>) {
|
||||
debug!("walk_pat(discr_place={:?}, pat={:?})", discr_place, pat);
|
||||
|
||||
self.delegate.fake_read(discr_place.place.clone());
|
||||
|
||||
let tcx = self.tcx();
|
||||
let ExprUseVisitor { ref mc, body_owner: _, ref mut delegate } = *self;
|
||||
return_if_err!(mc.cat_pattern(discr_place.clone(), pat, |place, pat| {
|
||||
@ -620,10 +629,6 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
|
||||
/// - When reporting the Place back to the Delegate, ensure that the UpvarId uses the enclosing
|
||||
/// closure as the DefId.
|
||||
fn walk_captures(&mut self, closure_expr: &hir::Expr<'_>) {
|
||||
// Over here we walk a closure that is nested inside the current body
|
||||
// If the current body is a closure, then we also want to report back any fake reads,
|
||||
// starting off of variables that are captured by our parent as well.
|
||||
|
||||
let closure_def_id = self.tcx().hir().local_def_id(closure_expr.hir_id).to_def_id();
|
||||
let upvars = self.tcx().upvars_mentioned(self.body_owner);
|
||||
|
||||
@ -633,15 +638,14 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
|
||||
ty::Closure(..) | ty::Generator(..)
|
||||
);
|
||||
|
||||
// [FIXME] RFC2229 Closures within closures don't work
|
||||
if let Some(fake_reads) = self.mc.typeck_results.closure_fake_reads.get(&closure_def_id) {
|
||||
for fake_read in fake_reads.iter() {
|
||||
// Use this as a reference for if we should promote the fake read
|
||||
for (fake_read, cause) in fake_reads.iter() {
|
||||
match fake_read.base {
|
||||
PlaceBase::Upvar(upvar_id) => {
|
||||
if upvars.map_or(body_owner_is_closure, |upvars| {
|
||||
!upvars.contains_key(&upvar_id.var_path.hir_id)
|
||||
}) {
|
||||
// [FIXME] RFC2229 Update this comment
|
||||
// The nested closure might be capturing the current (enclosing) closure's local variables.
|
||||
// We check if the root variable is ever mentioned within the enclosing closure, if not
|
||||
// then for the current body (if it's a closure) these aren't captures, we will ignore them.
|
||||
@ -655,14 +659,13 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
|
||||
);
|
||||
}
|
||||
};
|
||||
self.delegate.fake_read(fake_read.clone());
|
||||
self.delegate.fake_read(fake_read.clone(), *cause);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(min_captures) = self.mc.typeck_results.closure_min_captures.get(&closure_def_id)
|
||||
{
|
||||
for (var_hir_id, min_list) in min_captures.iter() {
|
||||
// Use this as a reference for if we should promote the fake read
|
||||
if upvars.map_or(body_owner_is_closure, |upvars| !upvars.contains_key(var_hir_id)) {
|
||||
// The nested closure might be capturing the current (enclosing) closure's local variables.
|
||||
// We check if the root variable is ever mentioned within the enclosing closure, if not
|
||||
|
@ -7,19 +7,6 @@ LL | #![feature(capture_disjoint_fields)]
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
= note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
|
||||
|
||||
warning: irrefutable `if let` pattern
|
||||
--> $DIR/closure-origin-single-variant-diagnostics.rs:18:9
|
||||
|
|
||||
LL | / if let SingleVariant::Point(ref mut x, _) = point {
|
||||
LL | |
|
||||
LL | | *x += 1;
|
||||
LL | | }
|
||||
| |_________^
|
||||
|
|
||||
= note: `#[warn(irrefutable_let_patterns)]` on by default
|
||||
= note: this pattern will always match, so the `if let` is useless
|
||||
= help: consider replacing the `if let` with a `let`
|
||||
|
||||
error[E0382]: use of moved value: `c`
|
||||
--> $DIR/closure-origin-single-variant-diagnostics.rs:21:13
|
||||
|
|
||||
|
@ -1,17 +1,19 @@
|
||||
//check-pass
|
||||
#![feature(capture_disjoint_fields)]
|
||||
#![feature(rustc_attrs)]
|
||||
//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
|
||||
#![warn(unused)]
|
||||
|
||||
fn main() {
|
||||
let _z = 9;
|
||||
let t = (String::from("Hello"), String::from("World"));
|
||||
let g = (String::from("Mr"), String::from("Goose"));
|
||||
|
||||
let a = #[rustc_capture_analysis] || {
|
||||
let a = || {
|
||||
let (_, g2) = g;
|
||||
println!("{}", g2);
|
||||
let c = #[rustc_capture_analysis] || {
|
||||
//~^ WARN unused variable: `g2`
|
||||
let c = || {
|
||||
let (_, t2) = t;
|
||||
println!("{}", t2);
|
||||
//~^ WARN unused variable: `t2`
|
||||
};
|
||||
|
||||
c();
|
||||
|
@ -1,23 +1,5 @@
|
||||
error[E0658]: attributes on expressions are experimental
|
||||
--> $DIR/destructure-pattern-closure-within-closure.rs:9:13
|
||||
|
|
||||
LL | let a = #[rustc_capture_analysis] || {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
|
||||
= help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
|
||||
|
||||
error[E0658]: attributes on expressions are experimental
|
||||
--> $DIR/destructure-pattern-closure-within-closure.rs:12:17
|
||||
|
|
||||
LL | let c = #[rustc_capture_analysis] || {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
|
||||
= help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
|
||||
|
||||
warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/destructure-pattern-closure-within-closure.rs:1:12
|
||||
--> $DIR/destructure-pattern-closure-within-closure.rs:2:12
|
||||
|
|
||||
LL | #![feature(capture_disjoint_fields)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -25,86 +7,24 @@ LL | #![feature(capture_disjoint_fields)]
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
= note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
|
||||
|
||||
error: First Pass analysis includes:
|
||||
--> $DIR/destructure-pattern-closure-within-closure.rs:12:43
|
||||
|
|
||||
LL | let c = #[rustc_capture_analysis] || {
|
||||
| ___________________________________________^
|
||||
LL | | let (_, t2) = t;
|
||||
LL | | println!("{}", t2);
|
||||
LL | | };
|
||||
| |_________^
|
||||
|
|
||||
note: Capturing t[(1, 0)] -> ByValue
|
||||
--> $DIR/destructure-pattern-closure-within-closure.rs:13:27
|
||||
warning: unused variable: `t2`
|
||||
--> $DIR/destructure-pattern-closure-within-closure.rs:15:21
|
||||
|
|
||||
LL | let (_, t2) = t;
|
||||
| ^
|
||||
| ^^ help: if this is intentional, prefix it with an underscore: `_t2`
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/destructure-pattern-closure-within-closure.rs:4:9
|
||||
|
|
||||
LL | #![warn(unused)]
|
||||
| ^^^^^^
|
||||
= note: `#[warn(unused_variables)]` implied by `#[warn(unused)]`
|
||||
|
||||
error: Min Capture analysis includes:
|
||||
--> $DIR/destructure-pattern-closure-within-closure.rs:12:43
|
||||
|
|
||||
LL | let c = #[rustc_capture_analysis] || {
|
||||
| ___________________________________________^
|
||||
LL | | let (_, t2) = t;
|
||||
LL | | println!("{}", t2);
|
||||
LL | | };
|
||||
| |_________^
|
||||
|
|
||||
note: Min Capture t[(1, 0)] -> ByValue
|
||||
--> $DIR/destructure-pattern-closure-within-closure.rs:13:27
|
||||
|
|
||||
LL | let (_, t2) = t;
|
||||
| ^
|
||||
|
||||
error: First Pass analysis includes:
|
||||
--> $DIR/destructure-pattern-closure-within-closure.rs:9:39
|
||||
|
|
||||
LL | let a = #[rustc_capture_analysis] || {
|
||||
| _______________________________________^
|
||||
LL | | let (_, g2) = g;
|
||||
LL | | println!("{}", g2);
|
||||
LL | | let c = #[rustc_capture_analysis] || {
|
||||
... |
|
||||
LL | | c();
|
||||
LL | | };
|
||||
| |_____^
|
||||
|
|
||||
note: Capturing g[(1, 0)] -> ByValue
|
||||
--> $DIR/destructure-pattern-closure-within-closure.rs:10:23
|
||||
warning: unused variable: `g2`
|
||||
--> $DIR/destructure-pattern-closure-within-closure.rs:12:17
|
||||
|
|
||||
LL | let (_, g2) = g;
|
||||
| ^
|
||||
note: Capturing t[(1, 0)] -> ByValue
|
||||
--> $DIR/destructure-pattern-closure-within-closure.rs:13:27
|
||||
|
|
||||
LL | let (_, t2) = t;
|
||||
| ^
|
||||
| ^^ help: if this is intentional, prefix it with an underscore: `_g2`
|
||||
|
||||
error: Min Capture analysis includes:
|
||||
--> $DIR/destructure-pattern-closure-within-closure.rs:9:39
|
||||
|
|
||||
LL | let a = #[rustc_capture_analysis] || {
|
||||
| _______________________________________^
|
||||
LL | | let (_, g2) = g;
|
||||
LL | | println!("{}", g2);
|
||||
LL | | let c = #[rustc_capture_analysis] || {
|
||||
... |
|
||||
LL | | c();
|
||||
LL | | };
|
||||
| |_____^
|
||||
|
|
||||
note: Min Capture g[(1, 0)] -> ByValue
|
||||
--> $DIR/destructure-pattern-closure-within-closure.rs:10:23
|
||||
|
|
||||
LL | let (_, g2) = g;
|
||||
| ^
|
||||
note: Min Capture t[(1, 0)] -> ByValue
|
||||
--> $DIR/destructure-pattern-closure-within-closure.rs:13:27
|
||||
|
|
||||
LL | let (_, t2) = t;
|
||||
| ^
|
||||
warning: 3 warnings emitted
|
||||
|
||||
error: aborting due to 6 previous errors; 1 warning emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
|
@ -1,118 +0,0 @@
|
||||
//check-pass
|
||||
#![feature(capture_disjoint_fields)]
|
||||
//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
|
||||
#![warn(unused)]
|
||||
|
||||
struct Point {
|
||||
x: u32,
|
||||
y: u32,
|
||||
}
|
||||
|
||||
fn test1() {
|
||||
let _z = 9;
|
||||
let t = (String::from("Hello"), String::from("World"));
|
||||
|
||||
let c = || {
|
||||
let (t1, t2) = t;
|
||||
println!("{} {}", t1, t2);
|
||||
};
|
||||
|
||||
c();
|
||||
}
|
||||
|
||||
fn test2() {
|
||||
let _z = 9;
|
||||
let t = (String::from("Hello"), String::from("World"));
|
||||
|
||||
let c = || {
|
||||
let (t1, _) = t;
|
||||
println!("{}", t1);
|
||||
};
|
||||
|
||||
c();
|
||||
}
|
||||
|
||||
fn test3() {
|
||||
let _z = 9;
|
||||
let t = (String::from("Hello"), String::from("World"));
|
||||
|
||||
let c = || {
|
||||
let (_, t2) = t;
|
||||
println!("{}", t2);
|
||||
};
|
||||
|
||||
c();
|
||||
}
|
||||
|
||||
fn test4() {
|
||||
let _z = 9;
|
||||
let t = (String::from("Hello"), String::from("World"));
|
||||
//~^ WARN unused variable: `t`
|
||||
|
||||
let c = || {
|
||||
let (_, _) = t;
|
||||
};
|
||||
|
||||
c();
|
||||
}
|
||||
|
||||
fn test5() {
|
||||
let _z = 9;
|
||||
let t = (String::new(), String::new());
|
||||
let _c = || {
|
||||
let _a = match t {
|
||||
(t1, _) => t1,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
fn test6() {
|
||||
let _z = 9;
|
||||
let t = (String::new(), String::new());
|
||||
let _c = || {
|
||||
let _a = match t {
|
||||
(_, t2) => t2,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
fn test7() {
|
||||
let x = 0;
|
||||
//~^ WARN unused variable: `x`
|
||||
let tup = (1, 2);
|
||||
//~^ WARN unused variable: `tup`
|
||||
let p = Point { x: 10, y: 20 };
|
||||
|
||||
let c = || {
|
||||
let _ = x;
|
||||
let Point { x, y } = p; // 1
|
||||
//~^ WARN unused variable: `x`
|
||||
println!("{}", y);
|
||||
let (_, _) = tup; // 2
|
||||
};
|
||||
|
||||
c();
|
||||
}
|
||||
|
||||
fn test8() {
|
||||
let _z = 9;
|
||||
let t = (String::from("Hello"), String::from("World"));
|
||||
|
||||
let c = || {
|
||||
let (_, t) = t;
|
||||
println!("{}", t);
|
||||
};
|
||||
|
||||
c();
|
||||
}
|
||||
|
||||
fn main() {
|
||||
test1();
|
||||
test2();
|
||||
test3();
|
||||
test4();
|
||||
test5();
|
||||
test6();
|
||||
test7();
|
||||
test8();
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/destructure_patterns-1.rs:2:12
|
||||
|
|
||||
LL | #![feature(capture_disjoint_fields)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
= note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
|
||||
|
||||
warning: unused variable: `t`
|
||||
--> $DIR/destructure_patterns-1.rs:49:9
|
||||
|
|
||||
LL | let t = (String::from("Hello"), String::from("World"));
|
||||
| ^ help: if this is intentional, prefix it with an underscore: `_t`
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/destructure_patterns-1.rs:4:9
|
||||
|
|
||||
LL | #![warn(unused)]
|
||||
| ^^^^^^
|
||||
= note: `#[warn(unused_variables)]` implied by `#[warn(unused)]`
|
||||
|
||||
warning: unused variable: `x`
|
||||
--> $DIR/destructure_patterns-1.rs:88:21
|
||||
|
|
||||
LL | let Point { x, y } = p; // 1
|
||||
| ^ help: try ignoring the field: `x: _`
|
||||
|
||||
warning: unused variable: `x`
|
||||
--> $DIR/destructure_patterns-1.rs:80:9
|
||||
|
|
||||
LL | let x = 0;
|
||||
| ^ help: if this is intentional, prefix it with an underscore: `_x`
|
||||
|
||||
warning: unused variable: `tup`
|
||||
--> $DIR/destructure_patterns-1.rs:82:9
|
||||
|
|
||||
LL | let tup = (1, 2);
|
||||
| ^^^ help: if this is intentional, prefix it with an underscore: `_tup`
|
||||
|
||||
warning: 5 warnings emitted
|
||||
|
@ -1,52 +1,124 @@
|
||||
//check-pass
|
||||
#![feature(capture_disjoint_fields)]
|
||||
#![feature(rustc_attrs)]
|
||||
//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
|
||||
#![warn(unused)]
|
||||
|
||||
struct S {
|
||||
a: String,
|
||||
b: String,
|
||||
struct Point {
|
||||
x: u32,
|
||||
y: u32,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let t = (String::new(), String::new());
|
||||
fn test1() {
|
||||
let t = (String::from("Hello"), String::from("World"));
|
||||
|
||||
let s = S {
|
||||
a: String::new(),
|
||||
b: String::new(),
|
||||
};
|
||||
|
||||
let c = #[rustc_capture_analysis] || {
|
||||
let c = || {
|
||||
let (t1, t2) = t;
|
||||
//~^ WARN unused variable: `t1`
|
||||
//~| WARN unused variable: `t2`
|
||||
};
|
||||
|
||||
|
||||
// MIR Build
|
||||
//
|
||||
// Create place for the initalizer in let which is `t`
|
||||
//
|
||||
// I'm reading Field 1 from `t`, so apply Field projections;
|
||||
//
|
||||
// new place -> t[1]
|
||||
//
|
||||
// I'm reading Field 2 from `t`, so apply Field projections;
|
||||
//
|
||||
// new place -> t[2]
|
||||
//
|
||||
// New
|
||||
// ---------
|
||||
//
|
||||
// I'm building something starting at `t`
|
||||
//
|
||||
// I read field 1 from `t`
|
||||
//
|
||||
// I need to use `t[1]`, therefore the place must be constructable
|
||||
//
|
||||
// Find the capture index for `t[1]` for this closure.
|
||||
//
|
||||
// I read field 2 from `t`
|
||||
//
|
||||
// I need to use `t[2]`, therefore the place must be constructable
|
||||
//
|
||||
// Find the capture index for `t[2]` for this closure.
|
||||
|
||||
c();
|
||||
}
|
||||
|
||||
fn test2() {
|
||||
let t = (String::from("Hello"), String::from("World"));
|
||||
|
||||
let c = || {
|
||||
let (t1, _) = t;
|
||||
//~^ WARN unused variable: `t1`
|
||||
};
|
||||
|
||||
c();
|
||||
}
|
||||
|
||||
fn test3() {
|
||||
let t = (String::from("Hello"), String::from("World"));
|
||||
|
||||
let c = || {
|
||||
let (_, t2) = t;
|
||||
//~^ WARN unused variable: `t2`
|
||||
};
|
||||
|
||||
c();
|
||||
}
|
||||
|
||||
fn test4() {
|
||||
let t = (String::from("Hello"), String::from("World"));
|
||||
//~^ WARN unused variable: `t`
|
||||
|
||||
let c = || {
|
||||
let (_, _) = t;
|
||||
};
|
||||
|
||||
c();
|
||||
}
|
||||
|
||||
fn test5() {
|
||||
let t = (String::new(), String::new());
|
||||
let _c = || {
|
||||
let _a = match t {
|
||||
(t1, _) => t1,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
fn test6() {
|
||||
let t = (String::new(), String::new());
|
||||
let _c = || {
|
||||
let _a = match t {
|
||||
(_, t2) => t2,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
fn test7() {
|
||||
let t = (String::new(), String::new());
|
||||
let _c = || {
|
||||
let _a = match t {
|
||||
(t1, t2) => (t1, t2),
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
// [FIXME] RFC2229 Add an explanation for test
|
||||
fn test8() {
|
||||
let x = 0;
|
||||
//~^ WARN unused variable: `x`
|
||||
let tup = (1, 2);
|
||||
//~^ WARN unused variable: `tup`
|
||||
let p = Point { x: 10, y: 20 };
|
||||
|
||||
let c = || {
|
||||
let _ = x;
|
||||
let Point { x, y } = p; // 1
|
||||
//~^ WARN unused variable: `x`
|
||||
println!("{}", y);
|
||||
let (_, _) = tup; // 2
|
||||
};
|
||||
|
||||
c();
|
||||
}
|
||||
|
||||
fn test9() {
|
||||
let _z = 9;
|
||||
let t = (String::from("Hello"), String::from("World"));
|
||||
|
||||
let c = || {
|
||||
let (_, t) = t;
|
||||
println!("{}", t);
|
||||
};
|
||||
|
||||
c();
|
||||
}
|
||||
|
||||
fn main() {
|
||||
test1();
|
||||
test2();
|
||||
test3();
|
||||
test4();
|
||||
test5();
|
||||
test6();
|
||||
test7();
|
||||
test8();
|
||||
test9();
|
||||
}
|
||||
|
@ -1,14 +1,5 @@
|
||||
error[E0658]: attributes on expressions are experimental
|
||||
--> $DIR/destructure_patterns.rs:17:13
|
||||
|
|
||||
LL | let c = #[rustc_capture_analysis] || {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
|
||||
= help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
|
||||
|
||||
warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/destructure_patterns.rs:1:12
|
||||
--> $DIR/destructure_patterns.rs:2:12
|
||||
|
|
||||
LL | #![feature(capture_disjoint_fields)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -16,46 +7,60 @@ LL | #![feature(capture_disjoint_fields)]
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
= note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
|
||||
|
||||
error: First Pass analysis includes:
|
||||
--> $DIR/destructure_patterns.rs:17:39
|
||||
|
|
||||
LL | let c = #[rustc_capture_analysis] || {
|
||||
| _______________________________________^
|
||||
LL | | let (t1, t2) = t;
|
||||
LL | | };
|
||||
| |_____^
|
||||
|
|
||||
note: Capturing t[(0, 0)] -> ByValue
|
||||
--> $DIR/destructure_patterns.rs:18:24
|
||||
warning: unused variable: `t1`
|
||||
--> $DIR/destructure_patterns.rs:15:14
|
||||
|
|
||||
LL | let (t1, t2) = t;
|
||||
| ^
|
||||
note: Capturing t[(1, 0)] -> ByValue
|
||||
--> $DIR/destructure_patterns.rs:18:24
|
||||
| ^^ help: if this is intentional, prefix it with an underscore: `_t1`
|
||||
|
|
||||
LL | let (t1, t2) = t;
|
||||
| ^
|
||||
note: the lint level is defined here
|
||||
--> $DIR/destructure_patterns.rs:4:9
|
||||
|
|
||||
LL | #![warn(unused)]
|
||||
| ^^^^^^
|
||||
= note: `#[warn(unused_variables)]` implied by `#[warn(unused)]`
|
||||
|
||||
error: Min Capture analysis includes:
|
||||
--> $DIR/destructure_patterns.rs:17:39
|
||||
|
|
||||
LL | let c = #[rustc_capture_analysis] || {
|
||||
| _______________________________________^
|
||||
LL | | let (t1, t2) = t;
|
||||
LL | | };
|
||||
| |_____^
|
||||
|
|
||||
note: Min Capture t[(0, 0)] -> ByValue
|
||||
--> $DIR/destructure_patterns.rs:18:24
|
||||
warning: unused variable: `t2`
|
||||
--> $DIR/destructure_patterns.rs:15:18
|
||||
|
|
||||
LL | let (t1, t2) = t;
|
||||
| ^
|
||||
note: Min Capture t[(1, 0)] -> ByValue
|
||||
--> $DIR/destructure_patterns.rs:18:24
|
||||
| ^^ help: if this is intentional, prefix it with an underscore: `_t2`
|
||||
|
||||
warning: unused variable: `t1`
|
||||
--> $DIR/destructure_patterns.rs:27:14
|
||||
|
|
||||
LL | let (t1, t2) = t;
|
||||
| ^
|
||||
LL | let (t1, _) = t;
|
||||
| ^^ help: if this is intentional, prefix it with an underscore: `_t1`
|
||||
|
||||
error: aborting due to 3 previous errors; 1 warning emitted
|
||||
warning: unused variable: `t2`
|
||||
--> $DIR/destructure_patterns.rs:38:17
|
||||
|
|
||||
LL | let (_, t2) = t;
|
||||
| ^^ help: if this is intentional, prefix it with an underscore: `_t2`
|
||||
|
||||
warning: unused variable: `t`
|
||||
--> $DIR/destructure_patterns.rs:46:9
|
||||
|
|
||||
LL | let t = (String::from("Hello"), String::from("World"));
|
||||
| ^ help: if this is intentional, prefix it with an underscore: `_t`
|
||||
|
||||
warning: unused variable: `x`
|
||||
--> $DIR/destructure_patterns.rs:93:21
|
||||
|
|
||||
LL | let Point { x, y } = p; // 1
|
||||
| ^ help: try ignoring the field: `x: _`
|
||||
|
||||
warning: unused variable: `x`
|
||||
--> $DIR/destructure_patterns.rs:85:9
|
||||
|
|
||||
LL | let x = 0;
|
||||
| ^ help: if this is intentional, prefix it with an underscore: `_x`
|
||||
|
||||
warning: unused variable: `tup`
|
||||
--> $DIR/destructure_patterns.rs:87:9
|
||||
|
|
||||
LL | let tup = (1, 2);
|
||||
| ^^^ help: if this is intentional, prefix it with an underscore: `_tup`
|
||||
|
||||
warning: 9 warnings emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
|
@ -1,12 +1,25 @@
|
||||
//check-pass
|
||||
#![feature(capture_disjoint_fields)]
|
||||
//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
fn main() {
|
||||
fn test1() {
|
||||
let foo = [1, 2, 3];
|
||||
let c = #[rustc_capture_analysis] || {
|
||||
//~^ ERROR: attributes on expressions are experimental
|
||||
//~| ERROR: First Pass analysis includes:
|
||||
let c = || {
|
||||
match foo { _ => () };
|
||||
};
|
||||
}
|
||||
|
||||
fn test2() {
|
||||
let foo = Some([1, 2, 3]);
|
||||
let c = || {
|
||||
match foo {
|
||||
Some(_) => 1,
|
||||
_ => 2
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
test1();
|
||||
test2();
|
||||
}
|
||||
|
@ -1,14 +1,5 @@
|
||||
error[E0658]: attributes on expressions are experimental
|
||||
--> $DIR/no_capture_with_wildcard_match.rs:7:13
|
||||
|
|
||||
LL | let c = #[rustc_capture_analysis] || {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
|
||||
= help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
|
||||
|
||||
warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/no_capture_with_wildcard_match.rs:1:12
|
||||
--> $DIR/no_capture_with_wildcard_match.rs:2:12
|
||||
|
|
||||
LL | #![feature(capture_disjoint_fields)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -16,17 +7,5 @@ LL | #![feature(capture_disjoint_fields)]
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
= note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
|
||||
|
||||
error: First Pass analysis includes:
|
||||
--> $DIR/no_capture_with_wildcard_match.rs:7:39
|
||||
|
|
||||
LL | let c = #[rustc_capture_analysis] || {
|
||||
| _______________________________________^
|
||||
LL | |
|
||||
LL | |
|
||||
LL | | match foo { _ => () };
|
||||
LL | | };
|
||||
| |_____^
|
||||
warning: 1 warning emitted
|
||||
|
||||
error: aborting due to 2 previous errors; 1 warning emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
|
@ -1,4 +1,6 @@
|
||||
//check-pass
|
||||
#![feature(capture_disjoint_fields)]
|
||||
//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
struct S {
|
||||
@ -12,7 +14,7 @@ fn main() {
|
||||
b: String::new(),
|
||||
};
|
||||
|
||||
let c = #[rustc_capture_analysis] || {
|
||||
let c = || {
|
||||
let s2 = S {
|
||||
a: format!("New a"),
|
||||
..s
|
||||
|
@ -1,14 +1,5 @@
|
||||
error[E0658]: attributes on expressions are experimental
|
||||
--> $DIR/struct_update_syntax.rs:15:13
|
||||
|
|
||||
LL | let c = #[rustc_capture_analysis] || {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
|
||||
= help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
|
||||
|
||||
warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/struct_update_syntax.rs:1:12
|
||||
--> $DIR/struct_update_syntax.rs:2:12
|
||||
|
|
||||
LL | #![feature(capture_disjoint_fields)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -16,42 +7,5 @@ LL | #![feature(capture_disjoint_fields)]
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
= note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
|
||||
|
||||
error: First Pass analysis includes:
|
||||
--> $DIR/struct_update_syntax.rs:15:39
|
||||
|
|
||||
LL | let c = #[rustc_capture_analysis] || {
|
||||
| _______________________________________^
|
||||
LL | | let s2 = S {
|
||||
LL | | a: format!("New a"),
|
||||
LL | | ..s
|
||||
LL | | };
|
||||
LL | | };
|
||||
| |_____^
|
||||
|
|
||||
note: Capturing s[(1, 0)] -> ByValue
|
||||
--> $DIR/struct_update_syntax.rs:18:15
|
||||
|
|
||||
LL | ..s
|
||||
| ^
|
||||
warning: 1 warning emitted
|
||||
|
||||
error: Min Capture analysis includes:
|
||||
--> $DIR/struct_update_syntax.rs:15:39
|
||||
|
|
||||
LL | let c = #[rustc_capture_analysis] || {
|
||||
| _______________________________________^
|
||||
LL | | let s2 = S {
|
||||
LL | | a: format!("New a"),
|
||||
LL | | ..s
|
||||
LL | | };
|
||||
LL | | };
|
||||
| |_____^
|
||||
|
|
||||
note: Min Capture s[(1, 0)] -> ByValue
|
||||
--> $DIR/struct_update_syntax.rs:18:15
|
||||
|
|
||||
LL | ..s
|
||||
| ^
|
||||
|
||||
error: aborting due to 3 previous errors; 1 warning emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
|
@ -189,18 +189,19 @@ LL | drop(_x3);
|
||||
error[E0382]: use of moved value: `tup`
|
||||
--> $DIR/borrowck-move-ref-pattern.rs:43:14
|
||||
|
|
||||
LL | let mut tup = (U, U, U);
|
||||
| ------- move occurs because `tup` has type `(U, U, U)`, which does not implement the `Copy` trait
|
||||
LL | let c1 = || {
|
||||
| -- value moved into closure here
|
||||
LL | let (ref _x0, _x1, _) = tup;
|
||||
| --- variable moved due to use in closure
|
||||
LL | };
|
||||
LL | let c2 = || {
|
||||
| ^^ value used here after move
|
||||
LL |
|
||||
LL | let (ref mut _x0, _, _x2) = tup;
|
||||
| --- use occurs due to use in closure
|
||||
LL | let mut tup = (U, U, U);
|
||||
| ------- move occurs because `tup` has type `(U, U, U)`, which does not implement the `Copy` trait
|
||||
LL | let c1 = || {
|
||||
| -- value moved into closure here
|
||||
LL | let (ref _x0, _x1, _) = tup;
|
||||
| --- variable moved due to use in closure
|
||||
LL | };
|
||||
LL | let c2 = || {
|
||||
| ______________^
|
||||
LL | |
|
||||
LL | | let (ref mut _x0, _, _x2) = tup;
|
||||
LL | | };
|
||||
| |_____^ value used here after move
|
||||
|
||||
error: aborting due to 18 previous errors
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user