Skip to content

Commit 8a8b285

Browse files
Rollup merge of rust-lang#87069 - sexxi-goose:copy_ref_always, r=nikomatsakis
ExprUseVisitor: Treat ByValue use of Copy types as ImmBorrow r? ``@nikomatsakis``
2 parents afe024c + 75291ee commit 8a8b285

File tree

9 files changed

+110
-57
lines changed

9 files changed

+110
-57
lines changed

compiler/rustc_typeck/src/check/upvar.rs

Lines changed: 5 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1528,20 +1528,11 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
15281528
&mut self,
15291529
place_with_id: &PlaceWithHirId<'tcx>,
15301530
diag_expr_id: hir::HirId,
1531-
mode: euv::ConsumeMode,
15321531
) {
15331532
debug!(
1534-
"adjust_upvar_borrow_kind_for_consume(place_with_id={:?}, diag_expr_id={:?}, mode={:?})",
1535-
place_with_id, diag_expr_id, mode
1533+
"adjust_upvar_borrow_kind_for_consume(place_with_id={:?}, diag_expr_id={:?})",
1534+
place_with_id, diag_expr_id
15361535
);
1537-
1538-
// Copy type being used as ByValue are equivalent to ImmBorrow and don't require any
1539-
// escalation.
1540-
match mode {
1541-
euv::ConsumeMode::Copy => return,
1542-
euv::ConsumeMode::Move => {}
1543-
};
1544-
15451536
let tcx = self.fcx.tcx;
15461537
let upvar_id = if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base {
15471538
upvar_id
@@ -1716,22 +1707,14 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
17161707
}
17171708
}
17181709

1719-
fn consume(
1720-
&mut self,
1721-
place_with_id: &PlaceWithHirId<'tcx>,
1722-
diag_expr_id: hir::HirId,
1723-
mode: euv::ConsumeMode,
1724-
) {
1725-
debug!(
1726-
"consume(place_with_id={:?}, diag_expr_id={:?}, mode={:?})",
1727-
place_with_id, diag_expr_id, mode
1728-
);
1710+
fn consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId) {
1711+
debug!("consume(place_with_id={:?}, diag_expr_id={:?})", place_with_id, diag_expr_id);
17291712

17301713
if !self.capture_information.contains_key(&place_with_id.place) {
17311714
self.init_capture_info_for_place(&place_with_id, diag_expr_id);
17321715
}
17331716

1734-
self.adjust_upvar_borrow_kind_for_consume(&place_with_id, diag_expr_id, mode);
1717+
self.adjust_upvar_borrow_kind_for_consume(&place_with_id, diag_expr_id);
17351718
}
17361719

17371720
fn borrow(

compiler/rustc_typeck/src/expr_use_visitor.rs

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
//! normal visitor, which just walks the entire body in one shot, the
33
//! `ExprUseVisitor` determines how expressions are being used.
44
5-
pub use self::ConsumeMode::*;
6-
75
// Export these here so that Clippy can use them.
86
pub use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection};
97

@@ -28,19 +26,20 @@ use crate::mem_categorization as mc;
2826
/// This trait defines the callbacks you can expect to receive when
2927
/// employing the ExprUseVisitor.
3028
pub trait Delegate<'tcx> {
31-
// The value found at `place` is either copied or moved, depending
29+
// The value found at `place` is moved, depending
3230
// on `mode`. Where `diag_expr_id` is the id used for diagnostics for `place`.
3331
//
32+
// Use of a `Copy` type in a ByValue context is considered a use
33+
// by `ImmBorrow` and `borrow` is called instead. This is because
34+
// a shared borrow is the "minimum access" that would be needed
35+
// to perform a copy.
36+
//
37+
//
3438
// The parameter `diag_expr_id` indicates the HIR id that ought to be used for
3539
// diagnostics. Around pattern matching such as `let pat = expr`, the diagnostic
3640
// id will be the id of the expression `expr` but the place itself will have
3741
// the id of the binding in the pattern `pat`.
38-
fn consume(
39-
&mut self,
40-
place_with_id: &PlaceWithHirId<'tcx>,
41-
diag_expr_id: hir::HirId,
42-
mode: ConsumeMode,
43-
);
42+
fn consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId);
4443

4544
// The value found at `place` is being borrowed with kind `bk`.
4645
// `diag_expr_id` is the id used for diagnostics (see `consume` for more details).
@@ -60,7 +59,7 @@ pub trait Delegate<'tcx> {
6059
}
6160

6261
#[derive(Copy, Clone, PartialEq, Debug)]
63-
pub enum ConsumeMode {
62+
enum ConsumeMode {
6463
Copy, // reference to x where x has a type that copies
6564
Move, // reference to x where x has a type that moves
6665
}
@@ -141,10 +140,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
141140
}
142141

143142
fn delegate_consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId) {
144-
debug!("delegate_consume(place_with_id={:?})", place_with_id);
145-
146-
let mode = copy_or_move(&self.mc, place_with_id);
147-
self.delegate.consume(place_with_id, diag_expr_id, mode);
143+
delegate_consume(&self.mc, self.delegate, place_with_id, diag_expr_id)
148144
}
149145

150146
fn consume_exprs(&mut self, exprs: &[hir::Expr<'_>]) {
@@ -653,9 +649,8 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
653649
delegate.borrow(place, discr_place.hir_id, bk);
654650
}
655651
ty::BindByValue(..) => {
656-
let mode = copy_or_move(mc, &place);
657652
debug!("walk_pat binding consuming pat");
658-
delegate.consume(place, discr_place.hir_id, mode);
653+
delegate_consume(mc, *delegate, place, discr_place.hir_id);
659654
}
660655
}
661656
}
@@ -773,8 +768,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
773768

774769
match capture_info.capture_kind {
775770
ty::UpvarCapture::ByValue(_) => {
776-
let mode = copy_or_move(&self.mc, &place_with_id);
777-
self.delegate.consume(&place_with_id, place_with_id.hir_id, mode);
771+
self.delegate_consume(&place_with_id, place_with_id.hir_id);
778772
}
779773
ty::UpvarCapture::ByRef(upvar_borrow) => {
780774
self.delegate.borrow(
@@ -798,8 +792,28 @@ fn copy_or_move<'a, 'tcx>(
798792
place_with_id.place.ty(),
799793
mc.tcx().hir().span(place_with_id.hir_id),
800794
) {
801-
Move
795+
ConsumeMode::Move
802796
} else {
803-
Copy
797+
ConsumeMode::Copy
798+
}
799+
}
800+
801+
// - If a place is used in a `ByValue` context then move it if it's not a `Copy` type.
802+
// - If the place that is a `Copy` type consider it a `ImmBorrow`.
803+
fn delegate_consume<'a, 'tcx>(
804+
mc: &mc::MemCategorizationContext<'a, 'tcx>,
805+
delegate: &mut (dyn Delegate<'tcx> + 'a),
806+
place_with_id: &PlaceWithHirId<'tcx>,
807+
diag_expr_id: hir::HirId,
808+
) {
809+
debug!("delegate_consume(place_with_id={:?})", place_with_id);
810+
811+
let mode = copy_or_move(&mc, place_with_id);
812+
813+
match mode {
814+
ConsumeMode::Move => delegate.consume(place_with_id, diag_expr_id),
815+
ConsumeMode::Copy => {
816+
delegate.borrow(place_with_id, diag_expr_id, ty::BorrowKind::ImmBorrow)
817+
}
804818
}
805819
}

src/test/ui/closures/2229_closure_analysis/move_closure.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,21 @@ fn box_mut_2() {
195195
//~| NOTE: Min Capture p_foo[Deref,Deref,(0, 0)] -> UniqueImmBorrow
196196
}
197197

198+
// Test that move closures can take ownership of Copy type
199+
fn returned_closure_owns_copy_type_data() -> impl Fn() -> i32 {
200+
let x = 10;
201+
202+
let c = #[rustc_capture_analysis] move || x;
203+
//~^ ERROR: attributes on expressions are experimental
204+
//~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
205+
//~| First Pass analysis includes:
206+
//~| NOTE: Capturing x[] -> ImmBorrow
207+
//~| Min Capture analysis includes:
208+
//~| NOTE: Min Capture x[] -> ByValue
209+
210+
c
211+
}
212+
198213
fn main() {
199214
simple_move_closure();
200215
simple_ref();

src/test/ui/closures/2229_closure_analysis/move_closure.stderr

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,39 @@ LL | let c = #[rustc_capture_analysis] move || p_foo.x += 10;
8888
= note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
8989
= help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
9090

91+
error[E0658]: attributes on expressions are experimental
92+
--> $DIR/move_closure.rs:202:13
93+
|
94+
LL | let c = #[rustc_capture_analysis] move || x;
95+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
96+
|
97+
= note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
98+
= help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
99+
100+
error: First Pass analysis includes:
101+
--> $DIR/move_closure.rs:202:39
102+
|
103+
LL | let c = #[rustc_capture_analysis] move || x;
104+
| ^^^^^^^^^
105+
|
106+
note: Capturing x[] -> ImmBorrow
107+
--> $DIR/move_closure.rs:202:47
108+
|
109+
LL | let c = #[rustc_capture_analysis] move || x;
110+
| ^
111+
112+
error: Min Capture analysis includes:
113+
--> $DIR/move_closure.rs:202:39
114+
|
115+
LL | let c = #[rustc_capture_analysis] move || x;
116+
| ^^^^^^^^^
117+
|
118+
note: Min Capture x[] -> ByValue
119+
--> $DIR/move_closure.rs:202:47
120+
|
121+
LL | let c = #[rustc_capture_analysis] move || x;
122+
| ^
123+
91124
error: First Pass analysis includes:
92125
--> $DIR/move_closure.rs:15:5
93126
|
@@ -424,6 +457,6 @@ note: Min Capture p_foo[Deref,Deref,(0, 0)] -> UniqueImmBorrow
424457
LL | let c = #[rustc_capture_analysis] move || p_foo.x += 10;
425458
| ^^^^^^^
426459

427-
error: aborting due to 30 previous errors
460+
error: aborting due to 33 previous errors
428461

429462
For more information about this error, try `rustc --explain E0658`.

src/test/ui/closures/2229_closure_analysis/run_pass/move_closure.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
// Test that move closures compile properly with `capture_disjoint_fields` enabled.
55

6+
#![allow(unused)]
7+
68
fn simple_ref() {
79
let mut s = 10;
810
let ref_s = &mut s;
@@ -92,6 +94,15 @@ fn data_moved_but_not_fn_once() {
9294
c();
9395
}
9496

97+
// Test that move closures can take ownership of Copy type
98+
fn returned_closure_owns_copy_type_data() -> impl Fn() -> i32 {
99+
let x = 10;
100+
101+
let c = move || x;
102+
103+
c
104+
}
105+
95106
fn main() {
96107
simple_ref();
97108
struct_contains_ref_to_another_struct();
@@ -100,4 +111,6 @@ fn main() {
100111

101112
disjoint_via_ref();
102113
data_moved_but_not_fn_once();
114+
115+
returned_closure_owns_copy_type_data();
103116
}

src/tools/clippy/clippy_lints/src/escape.rs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use rustc_span::source_map::Span;
1111
use rustc_span::symbol::kw;
1212
use rustc_target::abi::LayoutOf;
1313
use rustc_target::spec::abi::Abi;
14-
use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
14+
use rustc_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
1515

1616
#[derive(Copy, Clone)]
1717
pub struct BoxedLocal {
@@ -133,13 +133,10 @@ fn is_argument(map: rustc_middle::hir::map::Map<'_>, id: HirId) -> bool {
133133
}
134134

135135
impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> {
136-
fn consume(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, mode: ConsumeMode) {
136+
fn consume(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId) {
137137
if cmt.place.projections.is_empty() {
138138
if let PlaceBase::Local(lid) = cmt.place.base {
139-
if let ConsumeMode::Move = mode {
140-
// moved out or in. clearly can't be localized
141-
self.set.remove(&lid);
142-
}
139+
self.set.remove(&lid);
143140
let map = &self.cx.tcx.hir();
144141
if let Some(Node::Binding(_)) = map.find(cmt.hir_id) {
145142
if self.set.contains(&lid) {

src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use rustc_infer::infer::TyCtxtInferExt;
77
use rustc_lint::LateContext;
88
use rustc_middle::{mir::FakeReadCause, ty};
99
use rustc_span::source_map::Span;
10-
use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
10+
use rustc_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
1111

1212
pub(super) fn check(cx: &LateContext<'_>, arg: &Expr<'_>, body: &Expr<'_>) {
1313
if let Some(higher::Range {
@@ -82,7 +82,7 @@ struct MutatePairDelegate<'a, 'tcx> {
8282
}
8383

8484
impl<'tcx> Delegate<'tcx> for MutatePairDelegate<'_, 'tcx> {
85-
fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId, _: ConsumeMode) {}
85+
fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
8686

8787
fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, diag_expr_id: HirId, bk: ty::BorrowKind) {
8888
if let ty::BorrowKind::MutBorrow = bk {

src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -326,10 +326,8 @@ impl MovedVariablesCtxt {
326326
}
327327

328328
impl<'tcx> euv::Delegate<'tcx> for MovedVariablesCtxt {
329-
fn consume(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, _: HirId, mode: euv::ConsumeMode) {
330-
if let euv::ConsumeMode::Move = mode {
331-
self.move_common(cmt);
332-
}
329+
fn consume(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, _: HirId) {
330+
self.move_common(cmt);
333331
}
334332

335333
fn borrow(&mut self, _: &euv::PlaceWithHirId<'tcx>, _: HirId, _: ty::BorrowKind) {}

src/tools/clippy/clippy_utils/src/usage.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use rustc_lint::LateContext;
1010
use rustc_middle::hir::map::Map;
1111
use rustc_middle::mir::FakeReadCause;
1212
use rustc_middle::ty;
13-
use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
13+
use rustc_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
1414

1515
/// Returns a set of mutated local variable IDs, or `None` if mutations could not be determined.
1616
pub fn mutated_variables<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) -> Option<HirIdSet> {
@@ -67,7 +67,7 @@ impl<'tcx> MutVarsDelegate {
6767
}
6868

6969
impl<'tcx> Delegate<'tcx> for MutVarsDelegate {
70-
fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId, _: ConsumeMode) {}
70+
fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
7171

7272
fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, bk: ty::BorrowKind) {
7373
if let ty::BorrowKind::MutBorrow = bk {

0 commit comments

Comments
 (0)