diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 12eacdf25e2..fbbc1fba877 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -1116,14 +1116,21 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { place_with_id, diag_expr_id, mode ); - let place = truncate_capture_for_move(place_with_id.place.clone()); match (self.capture_clause, mode) { // In non-move closures, we only care about moves (hir::CaptureBy::Ref, euv::Copy) => return, + // We want to capture Copy types that read through a ref via a reborrow + (hir::CaptureBy::Value, euv::Copy) + if place_with_id.place.deref_tys().any(ty::TyS::is_ref) => + { + return; + } + (hir::CaptureBy::Ref, euv::Move) | (hir::CaptureBy::Value, euv::Move | euv::Copy) => {} }; + let place = truncate_capture_for_move(place_with_id.place.clone()); let place_with_id = PlaceWithHirId { place: place.clone(), hir_id: place_with_id.hir_id }; if !self.capture_information.contains_key(&place) { diff --git a/src/test/ui/closures/2229_closure_analysis/move_closure.rs b/src/test/ui/closures/2229_closure_analysis/move_closure.rs index d57c2280438..1c574da5f48 100644 --- a/src/test/ui/closures/2229_closure_analysis/move_closure.rs +++ b/src/test/ui/closures/2229_closure_analysis/move_closure.rs @@ -6,7 +6,25 @@ //~| NOTE: see issue #53488 #![feature(rustc_attrs)] -// Test we truncate derefs properly +fn simple_move_closure() { + struct S(String); + struct T(S); + + let t = T(S("s".into())); + let mut c = #[rustc_capture_analysis] + //~^ ERROR: attributes on expressions are experimental + //~| NOTE: see issue #15701 + move || { + //~^ ERROR: First Pass analysis includes: + //~| ERROR: Min Capture analysis includes: + t.0.0 = "new S".into(); + //~^ NOTE: Capturing t[(0, 0),(0, 0)] -> ByValue + //~| NOTE: Min Capture t[(0, 0),(0, 0)] -> ByValue + }; + c(); +} + +// Test move closure use reborrows when using references fn simple_ref() { let mut s = 10; let ref_s = &mut s; @@ -24,8 +42,8 @@ fn simple_ref() { c(); } -// Test we truncate derefs properly -fn struct_contains_ref_to_another_struct() { +// Test move closure use reborrows when using references +fn struct_contains_ref_to_another_struct_1() { struct S(String); struct T<'a>(&'a mut S); @@ -46,27 +64,78 @@ fn struct_contains_ref_to_another_struct() { c(); } -// Test that we don't reduce precision when there is nothing deref. -fn no_ref() { - struct S(String); - struct T(S); +// Test that we can use reborrows to read data of Copy types +// i.e. without truncating derefs +fn struct_contains_ref_to_another_struct_2() { + struct S(i32); + struct T<'a>(&'a S); + + let s = S(0); + let t = T(&s); - let t = T(S("s".into())); let mut c = #[rustc_capture_analysis] //~^ ERROR: attributes on expressions are experimental //~| NOTE: see issue #15701 move || { //~^ ERROR: First Pass analysis includes: //~| ERROR: Min Capture analysis includes: - t.0.0 = "new S".into(); - //~^ NOTE: Capturing t[(0, 0),(0, 0)] -> ByValue - //~| NOTE: Min Capture t[(0, 0),(0, 0)] -> ByValue + let _t = t.0.0; + //~^ NOTE: Capturing t[(0, 0),Deref,(0, 0)] -> ImmBorrow + //~| NOTE: Min Capture t[(0, 0),Deref,(0, 0)] -> ImmBorrow }; + + c(); +} + +// Test that we can use truncate to move out of !Copy types +fn struct_contains_ref_to_another_struct_3() { + struct S(String); + struct T<'a>(&'a S); + + let s = S("s".into()); + let t = T(&s); + + let mut c = #[rustc_capture_analysis] + //~^ ERROR: attributes on expressions are experimental + //~| NOTE: see issue #15701 + move || { + //~^ ERROR: First Pass analysis includes: + //~| ERROR: Min Capture analysis includes: + let _t = t.0.0; + //~^ NOTE: Capturing t[(0, 0),Deref,(0, 0)] -> ImmBorrow + //~| NOTE: Capturing t[(0, 0)] -> ByValue + //~| NOTE: Min Capture t[(0, 0)] -> ByValue + }; + + c(); +} + +// Test that derefs of box are truncated in move closures +fn truncate_box_derefs() { + struct S(i32); + + let b = Box::new(S(10)); + + let c = #[rustc_capture_analysis] + //~^ ERROR: attributes on expressions are experimental + //~| NOTE: see issue #15701 + move || { + //~^ ERROR: First Pass analysis includes: + //~| ERROR: Min Capture analysis includes: + let _t = b.0; + //~^ NOTE: Capturing b[Deref,(0, 0)] -> ByValue + //~| NOTE: Capturing b[] -> ByValue + //~| NOTE: Min Capture b[] -> ByValue + }; + c(); } fn main() { + simple_move_closure(); simple_ref(); - struct_contains_ref_to_another_struct(); - no_ref(); + struct_contains_ref_to_another_struct_1(); + struct_contains_ref_to_another_struct_2(); + struct_contains_ref_to_another_struct_3(); + truncate_box_derefs(); } diff --git a/src/test/ui/closures/2229_closure_analysis/move_closure.stderr b/src/test/ui/closures/2229_closure_analysis/move_closure.stderr index 554dc11f6ba..b91ef4dd85c 100644 --- a/src/test/ui/closures/2229_closure_analysis/move_closure.stderr +++ b/src/test/ui/closures/2229_closure_analysis/move_closure.stderr @@ -8,7 +8,7 @@ LL | let mut c = #[rustc_capture_analysis] = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable error[E0658]: attributes on expressions are experimental - --> $DIR/move_closure.rs:35:17 + --> $DIR/move_closure.rs:32:17 | LL | let mut c = #[rustc_capture_analysis] | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | let mut c = #[rustc_capture_analysis] = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable error[E0658]: attributes on expressions are experimental - --> $DIR/move_closure.rs:55:17 + --> $DIR/move_closure.rs:53:17 | LL | let mut c = #[rustc_capture_analysis] | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,6 +25,33 @@ LL | let mut c = #[rustc_capture_analysis] = note: see issue #15701 for more information = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable +error[E0658]: attributes on expressions are experimental + --> $DIR/move_closure.rs:76:17 + | +LL | let mut c = #[rustc_capture_analysis] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #15701 for more information + = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable + +error[E0658]: attributes on expressions are experimental + --> $DIR/move_closure.rs:98:17 + | +LL | let mut c = #[rustc_capture_analysis] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #15701 for more information + = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable + +error[E0658]: attributes on expressions are experimental + --> $DIR/move_closure.rs:119:13 + | +LL | let c = #[rustc_capture_analysis] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #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/move_closure.rs:3:12 | @@ -40,78 +67,6 @@ error: First Pass analysis includes: LL | / move || { LL | | LL | | -LL | | *ref_s += 10; -LL | | -LL | | -LL | | }; - | |_____^ - | -note: Capturing ref_s[Deref] -> UniqueImmBorrow - --> $DIR/move_closure.rs:20:9 - | -LL | *ref_s += 10; - | ^^^^^^ - -error: Min Capture analysis includes: - --> $DIR/move_closure.rs:17:5 - | -LL | / move || { -LL | | -LL | | -LL | | *ref_s += 10; -LL | | -LL | | -LL | | }; - | |_____^ - | -note: Min Capture ref_s[Deref] -> UniqueImmBorrow - --> $DIR/move_closure.rs:20:9 - | -LL | *ref_s += 10; - | ^^^^^^ - -error: First Pass analysis includes: - --> $DIR/move_closure.rs:38:5 - | -LL | / move || { -LL | | -LL | | -LL | | t.0.0 = "new s".into(); -LL | | -LL | | -LL | | }; - | |_____^ - | -note: Capturing t[(0, 0),Deref,(0, 0)] -> UniqueImmBorrow - --> $DIR/move_closure.rs:41:9 - | -LL | t.0.0 = "new s".into(); - | ^^^^^ - -error: Min Capture analysis includes: - --> $DIR/move_closure.rs:38:5 - | -LL | / move || { -LL | | -LL | | -LL | | t.0.0 = "new s".into(); -LL | | -LL | | -LL | | }; - | |_____^ - | -note: Min Capture t[(0, 0),Deref,(0, 0)] -> UniqueImmBorrow - --> $DIR/move_closure.rs:41:9 - | -LL | t.0.0 = "new s".into(); - | ^^^^^ - -error: First Pass analysis includes: - --> $DIR/move_closure.rs:58:5 - | -LL | / move || { -LL | | -LL | | LL | | t.0.0 = "new S".into(); LL | | LL | | @@ -119,13 +74,13 @@ LL | | }; | |_____^ | note: Capturing t[(0, 0),(0, 0)] -> ByValue - --> $DIR/move_closure.rs:61:9 + --> $DIR/move_closure.rs:20:9 | LL | t.0.0 = "new S".into(); | ^^^^^ error: Min Capture analysis includes: - --> $DIR/move_closure.rs:58:5 + --> $DIR/move_closure.rs:17:5 | LL | / move || { LL | | @@ -137,11 +92,201 @@ LL | | }; | |_____^ | note: Min Capture t[(0, 0),(0, 0)] -> ByValue - --> $DIR/move_closure.rs:61:9 + --> $DIR/move_closure.rs:20:9 | LL | t.0.0 = "new S".into(); | ^^^^^ -error: aborting due to 9 previous errors; 1 warning emitted +error: First Pass analysis includes: + --> $DIR/move_closure.rs:35:5 + | +LL | / move || { +LL | | +LL | | +LL | | *ref_s += 10; +LL | | +LL | | +LL | | }; + | |_____^ + | +note: Capturing ref_s[Deref] -> UniqueImmBorrow + --> $DIR/move_closure.rs:38:9 + | +LL | *ref_s += 10; + | ^^^^^^ + +error: Min Capture analysis includes: + --> $DIR/move_closure.rs:35:5 + | +LL | / move || { +LL | | +LL | | +LL | | *ref_s += 10; +LL | | +LL | | +LL | | }; + | |_____^ + | +note: Min Capture ref_s[Deref] -> UniqueImmBorrow + --> $DIR/move_closure.rs:38:9 + | +LL | *ref_s += 10; + | ^^^^^^ + +error: First Pass analysis includes: + --> $DIR/move_closure.rs:56:5 + | +LL | / move || { +LL | | +LL | | +LL | | t.0.0 = "new s".into(); +LL | | +LL | | +LL | | }; + | |_____^ + | +note: Capturing t[(0, 0),Deref,(0, 0)] -> UniqueImmBorrow + --> $DIR/move_closure.rs:59:9 + | +LL | t.0.0 = "new s".into(); + | ^^^^^ + +error: Min Capture analysis includes: + --> $DIR/move_closure.rs:56:5 + | +LL | / move || { +LL | | +LL | | +LL | | t.0.0 = "new s".into(); +LL | | +LL | | +LL | | }; + | |_____^ + | +note: Min Capture t[(0, 0),Deref,(0, 0)] -> UniqueImmBorrow + --> $DIR/move_closure.rs:59:9 + | +LL | t.0.0 = "new s".into(); + | ^^^^^ + +error: First Pass analysis includes: + --> $DIR/move_closure.rs:79:5 + | +LL | / move || { +LL | | +LL | | +LL | | let _t = t.0.0; +LL | | +LL | | +LL | | }; + | |_____^ + | +note: Capturing t[(0, 0),Deref,(0, 0)] -> ImmBorrow + --> $DIR/move_closure.rs:82:18 + | +LL | let _t = t.0.0; + | ^^^^^ + +error: Min Capture analysis includes: + --> $DIR/move_closure.rs:79:5 + | +LL | / move || { +LL | | +LL | | +LL | | let _t = t.0.0; +LL | | +LL | | +LL | | }; + | |_____^ + | +note: Min Capture t[(0, 0),Deref,(0, 0)] -> ImmBorrow + --> $DIR/move_closure.rs:82:18 + | +LL | let _t = t.0.0; + | ^^^^^ + +error: First Pass analysis includes: + --> $DIR/move_closure.rs:101:5 + | +LL | / move || { +LL | | +LL | | +LL | | let _t = t.0.0; +... | +LL | | +LL | | }; + | |_____^ + | +note: Capturing t[(0, 0),Deref,(0, 0)] -> ImmBorrow + --> $DIR/move_closure.rs:104:18 + | +LL | let _t = t.0.0; + | ^^^^^ +note: Capturing t[(0, 0)] -> ByValue + --> $DIR/move_closure.rs:104:18 + | +LL | let _t = t.0.0; + | ^^^^^ + +error: Min Capture analysis includes: + --> $DIR/move_closure.rs:101:5 + | +LL | / move || { +LL | | +LL | | +LL | | let _t = t.0.0; +... | +LL | | +LL | | }; + | |_____^ + | +note: Min Capture t[(0, 0)] -> ByValue + --> $DIR/move_closure.rs:104:18 + | +LL | let _t = t.0.0; + | ^^^^^ + +error: First Pass analysis includes: + --> $DIR/move_closure.rs:122:5 + | +LL | / move || { +LL | | +LL | | +LL | | let _t = b.0; +... | +LL | | +LL | | }; + | |_____^ + | +note: Capturing b[Deref,(0, 0)] -> ByValue + --> $DIR/move_closure.rs:125:18 + | +LL | let _t = b.0; + | ^^^ +note: Capturing b[] -> ByValue + --> $DIR/move_closure.rs:125:18 + | +LL | let _t = b.0; + | ^^^ + +error: Min Capture analysis includes: + --> $DIR/move_closure.rs:122:5 + | +LL | / move || { +LL | | +LL | | +LL | | let _t = b.0; +... | +LL | | +LL | | }; + | |_____^ + | +note: Min Capture b[] -> ByValue + --> $DIR/move_closure.rs:125:18 + | +LL | let _t = b.0; + | ^^^ + +error: aborting due to 18 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0658`.