mirror of
https://github.com/rust-lang/rust.git
synced 2025-06-04 19:29:07 +00:00
2229: Don't move out of drop type
This commit is contained in:
parent
c2a408840a
commit
153aa71c14
@ -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;
|
||||
|
||||
let capture_info = if let Some(existing) = processed.get(&place) {
|
||||
determine_capture_info(*existing, capture_info)
|
||||
} else {
|
||||
@ -626,7 +633,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
self.tcx.struct_span_lint_hir(
|
||||
lint::builtin::RUST_2021_INCOMPATIBLE_CLOSURE_CAPTURES,
|
||||
closure_hir_id,
|
||||
closure_head_span,
|
||||
closure_head_span,
|
||||
|lint| {
|
||||
let mut diagnostics_builder = lint.build(
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/// 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.
|
||||
/// - No projections are applied to raw pointers, since these require unsafe blocks. We capture
|
||||
/// 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() {}
|
Loading…
Reference in New Issue
Block a user