Skip to content

Commit 074d757

Browse files
committed
Consider mutations as borrows in drop tracking
This is needed to match MIR more conservative approximation of any borrowed value being live across a suspend point (See #94067). This change considers an expression such as `x.y = z` to be a borrow of `x` and therefore keeps `x` live across suspend points.
1 parent f90b06d commit 074d757

File tree

4 files changed

+123
-3
lines changed

4 files changed

+123
-3
lines changed

compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs

+9-3
Original file line numberDiff line numberDiff line change
@@ -93,19 +93,25 @@ impl<'tcx> expr_use_visitor::Delegate<'tcx> for ExprUseDelegate<'tcx> {
9393
fn borrow(
9494
&mut self,
9595
place_with_id: &expr_use_visitor::PlaceWithHirId<'tcx>,
96-
_diag_expr_id: HirId,
96+
diag_expr_id: HirId,
9797
_bk: rustc_middle::ty::BorrowKind,
9898
) {
99+
debug!("borrow {:?}; diag_expr_id={:?}", place_with_id, diag_expr_id);
99100
self.places
100101
.borrowed
101102
.insert(TrackedValue::from_place_with_projections_allowed(place_with_id));
102103
}
103104

104105
fn mutate(
105106
&mut self,
106-
_assignee_place: &expr_use_visitor::PlaceWithHirId<'tcx>,
107-
_diag_expr_id: HirId,
107+
assignee_place: &expr_use_visitor::PlaceWithHirId<'tcx>,
108+
diag_expr_id: HirId,
108109
) {
110+
debug!("mutate {:?}; diag_expr_id={:?}", assignee_place, diag_expr_id);
111+
// Count mutations as a borrow.
112+
self.places
113+
.borrowed
114+
.insert(TrackedValue::from_place_with_projections_allowed(assignee_place));
109115
}
110116

111117
fn fake_read(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Derived from an ICE found in tokio-xmpp during a crater run.
2+
// edition:2021
3+
// compile-flags: -Zdrop-tracking
4+
5+
#![allow(dead_code)]
6+
7+
#[derive(Clone)]
8+
struct InfoResult {
9+
node: Option<std::rc::Rc<String>>
10+
}
11+
12+
struct Agent {
13+
info_result: InfoResult
14+
}
15+
16+
impl Agent {
17+
async fn handle(&mut self) {
18+
let mut info = self.info_result.clone();
19+
info.node = None;
20+
let element = parse_info(info);
21+
let _ = send_element(element).await;
22+
}
23+
}
24+
25+
struct Element {
26+
}
27+
28+
async fn send_element(_: Element) {}
29+
30+
fn parse(_: &[u8]) -> Result<(), ()> {
31+
Ok(())
32+
}
33+
34+
fn parse_info(_: InfoResult) -> Element {
35+
Element { }
36+
}
37+
38+
fn assert_send<T: Send>(_: T) {}
39+
40+
fn main() {
41+
let agent = Agent { info_result: InfoResult { node: None } };
42+
// FIXME: It would be nice for this to work. See #94067.
43+
assert_send(agent.handle());
44+
//~^ cannot be sent between threads safely
45+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
error: future cannot be sent between threads safely
2+
--> $DIR/drop-track-field-assign-nonsend.rs:43:17
3+
|
4+
LL | assert_send(agent.handle());
5+
| ^^^^^^^^^^^^^^ future returned by `handle` is not `Send`
6+
|
7+
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<String>`
8+
note: future is not `Send` as this value is used across an await
9+
--> $DIR/drop-track-field-assign-nonsend.rs:21:38
10+
|
11+
LL | let mut info = self.info_result.clone();
12+
| -------- has type `InfoResult` which is not `Send`
13+
...
14+
LL | let _ = send_element(element).await;
15+
| ^^^^^^ await occurs here, with `mut info` maybe used later
16+
LL | }
17+
| - `mut info` is later dropped here
18+
note: required by a bound in `assert_send`
19+
--> $DIR/drop-track-field-assign-nonsend.rs:38:19
20+
|
21+
LL | fn assert_send<T: Send>(_: T) {}
22+
| ^^^^ required by this bound in `assert_send`
23+
24+
error: aborting due to previous error
25+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Derived from an ICE found in tokio-xmpp during a crater run.
2+
// edition:2021
3+
// compile-flags: -Zdrop-tracking
4+
// build-pass
5+
6+
#![allow(dead_code)]
7+
8+
#[derive(Clone)]
9+
struct InfoResult {
10+
node: Option<String>
11+
}
12+
13+
struct Agent {
14+
info_result: InfoResult
15+
}
16+
17+
impl Agent {
18+
async fn handle(&mut self) {
19+
let mut info = self.info_result.clone();
20+
info.node = Some("bar".into());
21+
let element = parse_info(info);
22+
let _ = send_element(element).await;
23+
}
24+
}
25+
26+
struct Element {
27+
}
28+
29+
async fn send_element(_: Element) {}
30+
31+
fn parse(_: &[u8]) -> Result<(), ()> {
32+
Ok(())
33+
}
34+
35+
fn parse_info(_: InfoResult) -> Element {
36+
Element { }
37+
}
38+
39+
fn main() {
40+
let mut agent = Agent {
41+
info_result: InfoResult { node: None }
42+
};
43+
let _ = agent.handle();
44+
}

0 commit comments

Comments
 (0)