2229: Don't move out of drop type
This commit is contained in:
@@ -399,7 +399,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// This restriction needs to be applied after we have handled adjustments for `move`
|
||||||
|
// closures. We want to make sure any adjustment that might make us move the place into
|
||||||
|
// the closure gets handled.
|
||||||
|
let (place, capture_kind) =
|
||||||
|
restrict_precision_for_drop_types(self, place, capture_kind, usage_span);
|
||||||
|
|
||||||
capture_info.capture_kind = capture_kind;
|
capture_info.capture_kind = capture_kind;
|
||||||
|
|
||||||
let capture_info = if let Some(existing) = processed.get(&place) {
|
let capture_info = if let Some(existing) = processed.get(&place) {
|
||||||
determine_capture_info(*existing, capture_info)
|
determine_capture_info(*existing, capture_info)
|
||||||
} else {
|
} else {
|
||||||
@@ -626,7 +633,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
self.tcx.struct_span_lint_hir(
|
self.tcx.struct_span_lint_hir(
|
||||||
lint::builtin::RUST_2021_INCOMPATIBLE_CLOSURE_CAPTURES,
|
lint::builtin::RUST_2021_INCOMPATIBLE_CLOSURE_CAPTURES,
|
||||||
closure_hir_id,
|
closure_hir_id,
|
||||||
closure_head_span,
|
closure_head_span,
|
||||||
|lint| {
|
|lint| {
|
||||||
let mut diagnostics_builder = lint.build(
|
let mut diagnostics_builder = lint.build(
|
||||||
format!(
|
format!(
|
||||||
@@ -1835,6 +1842,31 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
|
|||||||
self.borrow(assignee_place, diag_expr_id, ty::BorrowKind::MutBorrow);
|
self.borrow(assignee_place, diag_expr_id, ty::BorrowKind::MutBorrow);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Rust doesn't permit moving fields out of a type that implements drop
|
||||||
|
fn restrict_precision_for_drop_types<'a, 'tcx>(
|
||||||
|
fcx: &'a FnCtxt<'a, 'tcx>,
|
||||||
|
mut place: Place<'tcx>,
|
||||||
|
mut curr_mode: ty::UpvarCapture<'tcx>,
|
||||||
|
span: Span,
|
||||||
|
) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) {
|
||||||
|
let is_copy_type = fcx.infcx.type_is_copy_modulo_regions(fcx.param_env, place.ty(), span);
|
||||||
|
|
||||||
|
if let (false, UpvarCapture::ByValue(..)) = (is_copy_type, curr_mode) {
|
||||||
|
for i in 0..place.projections.len() {
|
||||||
|
match place.ty_before_projection(i).kind() {
|
||||||
|
ty::Adt(def, _) if def.destructor(fcx.tcx).is_some() => {
|
||||||
|
truncate_place_to_len_and_update_capture_kind(&mut place, &mut curr_mode, i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(place, curr_mode)
|
||||||
|
}
|
||||||
|
|
||||||
/// Truncate `place` so that an `unsafe` block isn't required to capture it.
|
/// Truncate `place` so that an `unsafe` block isn't required to capture it.
|
||||||
/// - No projections are applied to raw pointers, since these require unsafe blocks. We capture
|
/// - No projections are applied to raw pointers, since these require unsafe blocks. We capture
|
||||||
/// them completely.
|
/// them completely.
|
||||||
|
|||||||
62
src/test/ui/closures/2229_closure_analysis/issue-88476.rs
Normal file
62
src/test/ui/closures/2229_closure_analysis/issue-88476.rs
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
// edition:2021
|
||||||
|
|
||||||
|
#![feature(rustc_attrs)]
|
||||||
|
|
||||||
|
// Test that we can't move out of struct that impls `Drop`.
|
||||||
|
|
||||||
|
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
// Test that we restrict precision when moving not-`Copy` types, if any of the parent paths
|
||||||
|
// implement `Drop`. This is to ensure that we don't move out of a type that implements Drop.
|
||||||
|
pub fn test1() {
|
||||||
|
struct Foo(Rc<i32>);
|
||||||
|
|
||||||
|
impl Drop for Foo {
|
||||||
|
fn drop(self: &mut Foo) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
let f = Foo(Rc::new(1));
|
||||||
|
let x = #[rustc_capture_analysis] move || {
|
||||||
|
//~^ ERROR: attributes on expressions are experimental
|
||||||
|
//~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
|
||||||
|
//~| ERROR: First Pass analysis includes:
|
||||||
|
//~| ERROR: Min Capture analysis includes:
|
||||||
|
println!("{:?}", f.0);
|
||||||
|
//~^ NOTE: Capturing f[(0, 0)] -> ImmBorrow
|
||||||
|
//~| NOTE: Min Capture f[] -> ByValue
|
||||||
|
};
|
||||||
|
|
||||||
|
x();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that we don't restrict precision when moving `Copy` types(i.e. when copying),
|
||||||
|
// even if any of the parent paths implement `Drop`.
|
||||||
|
fn test2() {
|
||||||
|
struct Character {
|
||||||
|
hp: u32,
|
||||||
|
name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for Character {
|
||||||
|
fn drop(&mut self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
let character = Character { hp: 100, name: format!("A") };
|
||||||
|
|
||||||
|
let c = #[rustc_capture_analysis] move || {
|
||||||
|
//~^ ERROR: attributes on expressions are experimental
|
||||||
|
//~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
|
||||||
|
//~| ERROR: First Pass analysis includes:
|
||||||
|
//~| ERROR: Min Capture analysis includes:
|
||||||
|
println!("{}", character.hp)
|
||||||
|
//~^ NOTE: Capturing character[(0, 0)] -> ImmBorrow
|
||||||
|
//~| NOTE: Min Capture character[(0, 0)] -> ByValue
|
||||||
|
};
|
||||||
|
|
||||||
|
c();
|
||||||
|
|
||||||
|
println!("{}", character.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
error[E0658]: attributes on expressions are experimental
|
||||||
|
--> $DIR/issue-88476.rs:20:13
|
||||||
|
|
|
||||||
|
LL | let x = #[rustc_capture_analysis] move || {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= 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/issue-88476.rs:47:13
|
||||||
|
|
|
||||||
|
LL | let c = #[rustc_capture_analysis] move || {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= 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: First Pass analysis includes:
|
||||||
|
--> $DIR/issue-88476.rs:20:39
|
||||||
|
|
|
||||||
|
LL | let x = #[rustc_capture_analysis] move || {
|
||||||
|
| _______________________________________^
|
||||||
|
LL | |
|
||||||
|
LL | |
|
||||||
|
LL | |
|
||||||
|
... |
|
||||||
|
LL | |
|
||||||
|
LL | | };
|
||||||
|
| |_____^
|
||||||
|
|
|
||||||
|
note: Capturing f[(0, 0)] -> ImmBorrow
|
||||||
|
--> $DIR/issue-88476.rs:25:26
|
||||||
|
|
|
||||||
|
LL | println!("{:?}", f.0);
|
||||||
|
| ^^^
|
||||||
|
|
||||||
|
error: Min Capture analysis includes:
|
||||||
|
--> $DIR/issue-88476.rs:20:39
|
||||||
|
|
|
||||||
|
LL | let x = #[rustc_capture_analysis] move || {
|
||||||
|
| _______________________________________^
|
||||||
|
LL | |
|
||||||
|
LL | |
|
||||||
|
LL | |
|
||||||
|
... |
|
||||||
|
LL | |
|
||||||
|
LL | | };
|
||||||
|
| |_____^
|
||||||
|
|
|
||||||
|
note: Min Capture f[] -> ByValue
|
||||||
|
--> $DIR/issue-88476.rs:25:26
|
||||||
|
|
|
||||||
|
LL | println!("{:?}", f.0);
|
||||||
|
| ^^^
|
||||||
|
|
||||||
|
error: First Pass analysis includes:
|
||||||
|
--> $DIR/issue-88476.rs:47:39
|
||||||
|
|
|
||||||
|
LL | let c = #[rustc_capture_analysis] move || {
|
||||||
|
| _______________________________________^
|
||||||
|
LL | |
|
||||||
|
LL | |
|
||||||
|
LL | |
|
||||||
|
... |
|
||||||
|
LL | |
|
||||||
|
LL | | };
|
||||||
|
| |_____^
|
||||||
|
|
|
||||||
|
note: Capturing character[(0, 0)] -> ImmBorrow
|
||||||
|
--> $DIR/issue-88476.rs:52:24
|
||||||
|
|
|
||||||
|
LL | println!("{}", character.hp)
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: Min Capture analysis includes:
|
||||||
|
--> $DIR/issue-88476.rs:47:39
|
||||||
|
|
|
||||||
|
LL | let c = #[rustc_capture_analysis] move || {
|
||||||
|
| _______________________________________^
|
||||||
|
LL | |
|
||||||
|
LL | |
|
||||||
|
LL | |
|
||||||
|
... |
|
||||||
|
LL | |
|
||||||
|
LL | | };
|
||||||
|
| |_____^
|
||||||
|
|
|
||||||
|
note: Min Capture character[(0, 0)] -> ByValue
|
||||||
|
--> $DIR/issue-88476.rs:52:24
|
||||||
|
|
|
||||||
|
LL | println!("{}", character.hp)
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 6 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0658`.
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
// check-pass
|
||||||
|
// edition:2021
|
||||||
|
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
// Test that we restrict precision when moving not-`Copy` types, if any of the parent paths
|
||||||
|
// implement `Drop`. This is to ensure that we don't move out of a type that implements Drop.
|
||||||
|
pub fn test1() {
|
||||||
|
struct Foo(Rc<i32>);
|
||||||
|
|
||||||
|
impl Drop for Foo {
|
||||||
|
fn drop(self: &mut Foo) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
let f = Foo(Rc::new(1));
|
||||||
|
let x = move || {
|
||||||
|
println!("{:?}", f.0);
|
||||||
|
};
|
||||||
|
|
||||||
|
x();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Test that we don't restrict precision when moving `Copy` types(i.e. when copying),
|
||||||
|
// even if any of the parent paths implement `Drop`.
|
||||||
|
pub fn test2() {
|
||||||
|
struct Character {
|
||||||
|
hp: u32,
|
||||||
|
name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for Character {
|
||||||
|
fn drop(&mut self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
let character = Character { hp: 100, name: format!("A") };
|
||||||
|
|
||||||
|
let c = move || {
|
||||||
|
println!("{}", character.hp)
|
||||||
|
};
|
||||||
|
|
||||||
|
c();
|
||||||
|
|
||||||
|
println!("{}", character.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
Reference in New Issue
Block a user