Skip to content

Commit 74fc643

Browse files
committed
Only borrow place for matching under specific conditions
1 parent 685a4c6 commit 74fc643

11 files changed

+193
-49
lines changed

compiler/rustc_mir_build/src/build/expr/as_place.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ fn convert_to_hir_projections_and_truncate_for_capture<'tcx>(
100100
// single and multiple variants.
101101
// For single variants, enums are not captured completely.
102102
// We keep track of VariantIdx so we can use this information
103-
// if the next ProjectionElem is a Field
103+
// if the next ProjectionElem is a Field.
104104
variant = Some(*idx);
105105
continue;
106106
}

compiler/rustc_mir_build/src/build/expr/into.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
420420
| ExprKind::PlaceTypeAscription { .. }
421421
| ExprKind::ValueTypeAscription { .. } => {
422422
debug_assert!(Category::of(&expr.kind) == Some(Category::Place));
423+
423424
let place = unpack!(block = this.as_place(block, expr));
424425
let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place));
425426
this.cfg.push_assign(block, source_info, destination, rvalue);
@@ -436,6 +437,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
436437
}
437438

438439
debug_assert!(Category::of(&expr.kind) == Some(Category::Place));
440+
439441
let place = unpack!(block = this.as_place(block, expr));
440442
let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place));
441443
this.cfg.push_assign(block, source_info, destination, rvalue);

compiler/rustc_mir_build/src/build/matches/simplify.rs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
6868
let match_pairs = mem::take(&mut candidate.match_pairs);
6969

7070
if let [MatchPair { pattern: Pat { kind: box PatKind::Or { pats }, .. }, place }] =
71-
&*match_pairs.clone()
71+
&*match_pairs
7272
{
7373
existing_bindings.extend_from_slice(&new_bindings);
7474
mem::swap(&mut candidate.bindings, &mut existing_bindings);
@@ -155,12 +155,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
155155
ascription: thir::pattern::Ascription { variance, user_ty, user_ty_span },
156156
} => {
157157
// Apply the type ascription to the value at `match_pair.place`, which is the
158-
// value being matched, taking the variance field into account.
159-
let place = match_pair.place.clone().into_place(self.tcx, self.typeck_results);
160158
candidate.ascriptions.push(Ascription {
161159
span: user_ty_span,
162160
user_ty,
163-
source: place,
161+
source: match_pair.place.clone().into_place(self.tcx, self.typeck_results),
164162
variance,
165163
});
166164

@@ -175,12 +173,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
175173
}
176174

177175
PatKind::Binding { name, mutability, mode, var, ty, ref subpattern, is_primary: _ } => {
178-
let place = match_pair.place.clone().into_place(self.tcx, self.typeck_results);
179176
candidate.bindings.push(Binding {
180177
name,
181178
mutability,
182179
span: match_pair.pattern.span,
183-
source: place,
180+
source: match_pair.place.clone().into_place(self.tcx, self.typeck_results),
184181
var_id: var,
185182
var_ty: ty,
186183
binding_mode: mode,

compiler/rustc_mir_build/src/thir/cx/expr.rs

Lines changed: 17 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -455,32 +455,18 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
455455
);
456456

457457
let fake_reads = match self.typeck_results().closure_fake_reads.get(&def_id) {
458-
Some(vals) => {
459-
Some(
460-
vals.iter()
461-
.map(|(place, cause)| {
462-
(
463-
self.arena.alloc(
464-
self.convert_captured_hir_place(expr, place.clone()),
465-
),
466-
*cause,
467-
)
468-
// let var_hir_id = match val.base {
469-
// HirPlaceBase::Upvar(upvar_id) => {
470-
// debug!("upvar");
471-
// upvar_id.var_path.hir_id
472-
// }
473-
// _ => {
474-
// bug!(
475-
// "Do not know how to get HirId out of Rvalue and StaticItem"
476-
// );
477-
// }
478-
// };
479-
// self.fake_read_capture_upvar(expr, val.clone(), var_hir_id)
480-
})
481-
.collect(),
482-
)
483-
}
458+
Some(vals) => Some(
459+
vals.iter()
460+
.map(|(place, cause)| {
461+
(
462+
self.arena.alloc(
463+
self.convert_captured_hir_place(expr, place.clone()),
464+
),
465+
*cause,
466+
)
467+
})
468+
.collect(),
469+
),
484470
None => None,
485471
};
486472

@@ -1058,6 +1044,11 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
10581044
let temp_lifetime = self.region_scope_tree.temporary_scope(closure_expr.hir_id.local_id);
10591045
let var_ty = place.base_ty;
10601046

1047+
// The result of capture analysis in `rustc_typeck/check/upvar.rs`represents a captured path
1048+
// as it's seen for use within the closure and not at the time of closure creation.
1049+
//
1050+
// That is we see expect to see it start from a captured upvar and not something that is local
1051+
// to the closure's parent.
10611052
let var_hir_id = match place.base {
10621053
HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id,
10631054
base => bug!("Expected an upvar, found {:?}", base),

compiler/rustc_typeck/src/expr_use_visitor.rs

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ pub use self::ConsumeMode::*;
88
pub use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection};
99

1010
use rustc_hir as hir;
11-
use rustc_hir::def::{DefKind, Res};
11+
use rustc_hir::def::Res;
1212
use rustc_hir::def_id::LocalDefId;
1313
use rustc_hir::PatKind;
14-
use rustc_hir::QPath;
14+
//use rustc_hir::QPath;
1515
use rustc_index::vec::Idx;
1616
use rustc_infer::infer::InferCtxt;
1717
use rustc_middle::hir::place::ProjectionKind;
@@ -54,7 +54,6 @@ pub trait Delegate<'tcx> {
5454
// `diag_expr_id` is the id used for diagnostics (see `consume` for more details).
5555
fn mutate(&mut self, assignee_place: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId);
5656

57-
// [FIXME] RFC2229 This should also affect clippy ref: https://github.com/sexxi-goose/rust/pull/27
5857
fn fake_read(&mut self, place: Place<'tcx>, cause: FakeReadCause);
5958
}
6059

@@ -235,24 +234,30 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
235234
hir::ExprKind::Match(ref discr, arms, _) => {
236235
let discr_place = return_if_err!(self.mc.cat_expr(&discr));
237236

237+
// Matching should not always be considered a use of the place, hence
238+
// discr does not necessarily need to be borrowed.
238239
// We only want to borrow discr if the pattern contain something other
239-
// than wildcards
240+
// than wildcards.
240241
let ExprUseVisitor { ref mc, body_owner: _, delegate: _ } = *self;
241242
let mut needs_to_be_read = false;
242243
for arm in arms.iter() {
243244
return_if_err!(mc.cat_pattern(discr_place.clone(), &arm.pat, |_place, pat| {
244-
if let PatKind::Binding(_, _, _, opt_sub_pat) = pat.kind {
245-
if let None = opt_sub_pat {
246-
needs_to_be_read = true;
247-
}
248-
} else if let PatKind::TupleStruct(qpath, _, _) = &pat.kind {
249-
// If a TupleStruct has a Some PathSegment, we should read the discr_place
250-
// regardless if it contains a Wild pattern later
251-
if let QPath::Resolved(_, path) = qpath {
252-
if let Res::Def(DefKind::Ctor(_, _), _) = path.res {
245+
match &pat.kind {
246+
PatKind::Binding(_, _, _, opt_sub_pat) => {
247+
// If the opt_sub_pat is None, than the binding does not count as
248+
// a wildcard for the purpose of borrowing discr
249+
if let None = opt_sub_pat {
253250
needs_to_be_read = true;
254251
}
255252
}
253+
PatKind::TupleStruct(_, _, _)
254+
| PatKind::Struct(_, _, _)
255+
| PatKind::Lit(_) => {
256+
// If the PatKind is a TupleStruct, Struct, or Lit then we want
257+
// to borrow discr
258+
needs_to_be_read = true;
259+
}
260+
_ => {}
256261
}
257262
}));
258263
}
@@ -629,6 +634,8 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
629634
/// - When reporting the Place back to the Delegate, ensure that the UpvarId uses the enclosing
630635
/// closure as the DefId.
631636
fn walk_captures(&mut self, closure_expr: &hir::Expr<'_>) {
637+
debug!("walk_captures({:?})", closure_expr);
638+
632639
let closure_def_id = self.tcx().hir().local_def_id(closure_expr.hir_id).to_def_id();
633640
let upvars = self.tcx().upvars_mentioned(self.body_owner);
634641

@@ -645,10 +652,9 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
645652
if upvars.map_or(body_owner_is_closure, |upvars| {
646653
!upvars.contains_key(&upvar_id.var_path.hir_id)
647654
}) {
648-
// [FIXME] RFC2229 Update this comment
649-
// The nested closure might be capturing the current (enclosing) closure's local variables.
655+
// The nested closure might be fake reading the current (enclosing) closure's local variables.
650656
// We check if the root variable is ever mentioned within the enclosing closure, if not
651-
// then for the current body (if it's a closure) these aren't captures, we will ignore them.
657+
// then for the current body (if it's a closure) these do not require fake_read, we will ignore them.
652658
continue;
653659
}
654660
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//check-pass
2+
#![feature(capture_disjoint_fields)]
3+
//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
4+
#![warn(unused)]
5+
#![feature(rustc_attrs)]
6+
#![feature(btree_drain_filter)]
7+
8+
use std::collections::BTreeMap;
9+
use std::panic::{catch_unwind, AssertUnwindSafe};
10+
11+
fn main() {
12+
let mut map = BTreeMap::new();
13+
map.insert("a", ());
14+
map.insert("b", ());
15+
map.insert("c", ());
16+
17+
{
18+
let mut it = map.drain_filter(|_, _| true);
19+
catch_unwind(AssertUnwindSafe(|| while it.next().is_some() {})).unwrap_err();
20+
let result = catch_unwind(AssertUnwindSafe(|| it.next()));
21+
assert!(matches!(result, Ok(None)));
22+
}
23+
24+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
2+
--> $DIR/lit-pattern-matching-with-methods.rs:2:12
3+
|
4+
LL | #![feature(capture_disjoint_fields)]
5+
| ^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: `#[warn(incomplete_features)]` on by default
8+
= note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
9+
10+
warning: 1 warning emitted
11+
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
//check-pass
2+
#![feature(capture_disjoint_fields)]
3+
//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
4+
#![warn(unused)]
5+
#![feature(rustc_attrs)]
6+
7+
#[derive(Debug, Clone, Copy)]
8+
enum PointType {
9+
TwoD { x: u32, y: u32 },
10+
11+
ThreeD{ x: u32, y: u32, z: u32 }
12+
}
13+
14+
struct Points {
15+
points: Vec<PointType>,
16+
}
17+
18+
impl Points {
19+
pub fn test1(&mut self) -> Vec<usize> {
20+
(0..self.points.len())
21+
.filter_map(|i| {
22+
let idx = i as usize;
23+
match self.test2(idx) {
24+
PointType::TwoD { .. } => Some(i),
25+
PointType::ThreeD { .. } => None,
26+
}
27+
})
28+
.collect()
29+
}
30+
31+
pub fn test2(&mut self, i: usize) -> PointType {
32+
self.points[i]
33+
}
34+
}
35+
36+
fn main() {
37+
let mut points = Points {
38+
points: Vec::<PointType>::new()
39+
};
40+
41+
points.points.push(PointType::ThreeD { x:0, y:0, z:0 });
42+
points.points.push(PointType::TwoD{ x:0, y:0 });
43+
points.points.push(PointType::ThreeD{ x:0, y:0, z:0 });
44+
points.points.push(PointType::TwoD{ x:0, y:0 });
45+
46+
println!("{:?}", points.test1());
47+
println!("{:?}", points.points);
48+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
2+
--> $DIR/struct-pattern-matching-with-methods.rs:2:12
3+
|
4+
LL | #![feature(capture_disjoint_fields)]
5+
| ^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: `#[warn(incomplete_features)]` on by default
8+
= note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
9+
10+
warning: 1 warning emitted
11+
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//check-pass
2+
#![feature(capture_disjoint_fields)]
3+
//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
4+
5+
#[derive(Copy, Clone)]
6+
enum PointType {
7+
TwoD(u32, u32),
8+
ThreeD(u32, u32, u32)
9+
}
10+
11+
struct Points {
12+
points: Vec<PointType>,
13+
}
14+
15+
impl Points {
16+
pub fn test1(&mut self) -> Vec<usize> {
17+
(0..self.points.len())
18+
.filter_map(|i| {
19+
match self.test2(i) {
20+
PointType::TwoD (..) => Some(i),
21+
PointType::ThreeD (..) => None,
22+
}
23+
})
24+
.collect()
25+
}
26+
27+
pub fn test2(&mut self, i: usize) -> PointType {
28+
self.points[i]
29+
}
30+
}
31+
32+
fn main() {
33+
let mut points = Points {
34+
points: Vec::<PointType>::new()
35+
};
36+
37+
points.points.push(PointType::ThreeD(0,0,0));
38+
points.points.push(PointType::TwoD(0,0));
39+
points.points.push(PointType::ThreeD(0,0,1));
40+
points.points.push(PointType::TwoD(0,1));
41+
42+
println!("{:?}", points.test1());
43+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
2+
--> $DIR/tuple-struct-pattern-matching-with-methods.rs:2:12
3+
|
4+
LL | #![feature(capture_disjoint_fields)]
5+
| ^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: `#[warn(incomplete_features)]` on by default
8+
= note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
9+
10+
warning: 1 warning emitted
11+

0 commit comments

Comments
 (0)