Skip to content

Commit 197ad75

Browse files
nbdd0121compiler-errors
authored andcommitted
Stop considering moved-out locals when computing auto traits for generators
1 parent a1f5ac6 commit 197ad75

File tree

3 files changed

+66
-12
lines changed

3 files changed

+66
-12
lines changed

compiler/rustc_mir_transform/src/coroutine.rs

+39-5
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,11 @@ use rustc_middle::ty::{
6969
};
7070
use rustc_middle::{bug, span_bug};
7171
use rustc_mir_dataflow::impls::{
72-
MaybeBorrowedLocals, MaybeLiveLocals, MaybeRequiresStorage, MaybeStorageLive,
73-
always_storage_live_locals,
72+
MaybeBorrowedLocals, MaybeInitializedPlaces, MaybeLiveLocals, MaybeRequiresStorage,
73+
MaybeStorageLive, always_storage_live_locals,
7474
};
75-
use rustc_mir_dataflow::{Analysis, Results, ResultsVisitor};
75+
use rustc_mir_dataflow::move_paths::MoveData;
76+
use rustc_mir_dataflow::{self, Analysis, MaybeReachable, Results, ResultsVisitor};
7677
use rustc_span::def_id::{DefId, LocalDefId};
7778
use rustc_span::{Span, sym};
7879
use rustc_target::spec::PanicStrategy;
@@ -633,6 +634,12 @@ struct LivenessInfo {
633634
/// Which locals are live across any suspension point.
634635
saved_locals: CoroutineSavedLocals,
635636

637+
/// Which locals are live *and* initialized across any suspension point.
638+
///
639+
/// A local that is live but is not initialized (i.e. it has been moved out of) does
640+
/// not need to be accounted for in auto trait checking.
641+
init_locals: DenseBitSet<Local>,
642+
636643
/// The set of saved locals live at each suspension point.
637644
live_locals_at_suspension_points: Vec<DenseBitSet<CoroutineSavedLocal>>,
638645

@@ -686,10 +693,18 @@ fn locals_live_across_suspend_points<'tcx>(
686693
let mut liveness =
687694
MaybeLiveLocals.iterate_to_fixpoint(tcx, body, Some("coroutine")).into_results_cursor(body);
688695

696+
let move_data = MoveData::gather_moves(body, tcx, |_| true);
697+
698+
// Calculate the set of locals which are initialized
699+
let mut inits = MaybeInitializedPlaces::new(tcx, body, &move_data)
700+
.iterate_to_fixpoint(tcx, body, Some("coroutine"))
701+
.into_results_cursor(body);
702+
689703
let mut storage_liveness_map = IndexVec::from_elem(None, &body.basic_blocks);
690704
let mut live_locals_at_suspension_points = Vec::new();
691705
let mut source_info_at_suspension_points = Vec::new();
692706
let mut live_locals_at_any_suspension_point = DenseBitSet::new_empty(body.local_decls.len());
707+
let mut init_locals_at_any_suspension_point = DenseBitSet::new_empty(body.local_decls.len());
693708

694709
for (block, data) in body.basic_blocks.iter_enumerated() {
695710
if let TerminatorKind::Yield { .. } = data.terminator().kind {
@@ -727,12 +742,26 @@ fn locals_live_across_suspend_points<'tcx>(
727742
// The coroutine argument is ignored.
728743
live_locals.remove(SELF_ARG);
729744

730-
debug!("loc = {:?}, live_locals = {:?}", loc, live_locals);
745+
inits.seek_to_block_end(block);
746+
let mut init_locals: DenseBitSet<_> = DenseBitSet::new_empty(body.local_decls.len());
747+
if let MaybeReachable::Reachable(bitset) = inits.get() {
748+
for move_path_index in bitset.iter() {
749+
if let Some(local) = move_data.move_paths[move_path_index].place.as_local() {
750+
init_locals.insert(local);
751+
}
752+
}
753+
}
754+
init_locals.intersect(&live_locals);
755+
756+
debug!(
757+
"loc = {:?}, live_locals = {:?}, init_locals = {:?}",
758+
loc, live_locals, init_locals
759+
);
731760

732761
// Add the locals live at this suspension point to the set of locals which live across
733762
// any suspension points
734763
live_locals_at_any_suspension_point.union(&live_locals);
735-
764+
init_locals_at_any_suspension_point.union(&init_locals);
736765
live_locals_at_suspension_points.push(live_locals);
737766
source_info_at_suspension_points.push(data.terminator().source_info);
738767
}
@@ -757,6 +786,7 @@ fn locals_live_across_suspend_points<'tcx>(
757786

758787
LivenessInfo {
759788
saved_locals,
789+
init_locals: init_locals_at_any_suspension_point,
760790
live_locals_at_suspension_points,
761791
source_info_at_suspension_points,
762792
storage_conflicts,
@@ -929,6 +959,7 @@ fn compute_layout<'tcx>(
929959
) {
930960
let LivenessInfo {
931961
saved_locals,
962+
init_locals,
932963
live_locals_at_suspension_points,
933964
source_info_at_suspension_points,
934965
storage_conflicts,
@@ -950,6 +981,9 @@ fn compute_layout<'tcx>(
950981
// this code runs on pre-cleanup MIR, and `ignore_for_traits = false` is the safer
951982
// default.
952983
let ignore_for_traits = match decl.local_info {
984+
// If only the storage is required to be live, but local is not initialized,
985+
// then we can ignore such type for auto trait purposes.
986+
_ if !init_locals.contains(local) => true,
953987
// Do not include raw pointers created from accessing `static` items, as those could
954988
// well be re-created by another access to the same static.
955989
ClearCrossCrate::Set(box LocalInfo::StaticRef { is_thread_local, .. }) => {

tests/ui/async-await/field-assign-nonsend.stderr

+4-7
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,11 @@ LL | assert_send(agent.handle());
55
| ^^^^^^^^^^^^^^ future returned by `handle` is not `Send`
66
|
77
= 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/field-assign-nonsend.rs:20:39
8+
note: captured value is not `Send` because `&mut` references cannot be sent unless their referent is `Send`
9+
--> $DIR/field-assign-nonsend.rs:16:21
1010
|
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
11+
LL | async fn handle(&mut self) {
12+
| ^^^^^^^^^ has type `&mut Agent` which is not `Send`, because `Agent` is not `Send`
1613
note: required by a bound in `assert_send`
1714
--> $DIR/field-assign-nonsend.rs:37:19
1815
|
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//@ check-pass
2+
//@ edition:2021
3+
4+
use core::marker::PhantomData;
5+
6+
struct B(PhantomData<*const ()>);
7+
8+
fn do_sth(_: &B) {}
9+
10+
async fn foo() {}
11+
12+
async fn test() {
13+
let b = B(PhantomData);
14+
do_sth(&b);
15+
drop(b);
16+
foo().await;
17+
}
18+
19+
fn assert_send<T: Send>(_: T) {}
20+
21+
fn main() {
22+
assert_send(test());
23+
}

0 commit comments

Comments
 (0)