Skip to content

Commit 1007011

Browse files
authored
Rollup merge of #94068 - eholk:drop-track-field-assign, r=tmandry
Consider mutations as borrows in generator 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. r? `@nikomatsakis`
2 parents ae6770e + 074d757 commit 1007011

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)