Skip to content

Commit 65c3c90

Browse files
committed
Restrict amount of ignored locals.
1 parent c51fc38 commit 65c3c90

File tree

8 files changed

+135
-13
lines changed

8 files changed

+135
-13
lines changed

compiler/rustc_middle/src/mir/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -902,6 +902,8 @@ pub enum LocalInfo<'tcx> {
902902
AggregateTemp,
903903
/// A temporary created during the pass `Derefer` to avoid it's retagging
904904
DerefTemp,
905+
/// A temporary created for borrow checking.
906+
FakeBorrow,
905907
}
906908

907909
impl<'tcx> LocalDecl<'tcx> {

compiler/rustc_middle/src/mir/query.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,8 @@ pub struct GeneratorSavedTy<'tcx> {
140140
pub ty: Ty<'tcx>,
141141
/// Source info corresponding to the local in the original MIR body.
142142
pub source_info: SourceInfo,
143-
/// Whether the local was introduced as a raw pointer to a static.
144-
pub is_static_ptr: bool,
143+
/// Whether the local should be ignored for trait bound computations.
144+
pub ignore_for_traits: bool,
145145
}
146146

147147
/// The layout of generator state.

compiler/rustc_middle/src/ty/util.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -625,7 +625,7 @@ impl<'tcx> TyCtxt<'tcx> {
625625
generator_layout
626626
.field_tys
627627
.iter()
628-
.filter(|decl| !decl.is_static_ptr)
628+
.filter(|decl| !decl.ignore_for_traits)
629629
.map(|decl| ty::EarlyBinder(decl.ty))
630630
}
631631

compiler/rustc_mir_build/src/build/matches/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1749,6 +1749,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
17491749
let fake_borrow_ty = tcx.mk_imm_ref(tcx.lifetimes.re_erased, fake_borrow_deref_ty);
17501750
let mut fake_borrow_temp = LocalDecl::new(fake_borrow_ty, temp_span);
17511751
fake_borrow_temp.internal = self.local_decls[matched_place.local].internal;
1752+
fake_borrow_temp.local_info = Some(Box::new(LocalInfo::FakeBorrow));
17521753
let fake_borrow_temp = self.local_decls.push(fake_borrow_temp);
17531754

17541755
(matched_place, fake_borrow_temp)

compiler/rustc_mir_transform/src/generator.rs

+28-9
Original file line numberDiff line numberDiff line change
@@ -879,7 +879,7 @@ fn sanitize_witness<'tcx>(
879879

880880
let mut mismatches = Vec::new();
881881
for fty in &layout.field_tys {
882-
if fty.is_static_ptr {
882+
if fty.ignore_for_traits {
883883
continue;
884884
}
885885
let decl_ty = tcx.normalize_erasing_regions(param_env, fty.ty);
@@ -904,6 +904,7 @@ fn sanitize_witness<'tcx>(
904904
}
905905

906906
fn compute_layout<'tcx>(
907+
tcx: TyCtxt<'tcx>,
907908
liveness: LivenessInfo,
908909
body: &Body<'tcx>,
909910
) -> (
@@ -923,15 +924,33 @@ fn compute_layout<'tcx>(
923924
let mut locals = IndexVec::<GeneratorSavedLocal, _>::new();
924925
let mut tys = IndexVec::<GeneratorSavedLocal, _>::new();
925926
for (saved_local, local) in saved_locals.iter_enumerated() {
927+
debug!("generator saved local {:?} => {:?}", saved_local, local);
928+
926929
locals.push(local);
927930
let decl = &body.local_decls[local];
928-
let decl = GeneratorSavedTy {
929-
ty: decl.ty,
930-
source_info: decl.source_info,
931-
is_static_ptr: decl.internal,
931+
debug!(?decl);
932+
933+
let ignore_for_traits = if tcx.sess.opts.unstable_opts.drop_tracking_mir {
934+
match decl.local_info {
935+
// Do not include raw pointers created from accessing `static` items, as those could
936+
// well be re-created by another access to the same static.
937+
Some(box LocalInfo::StaticRef { is_thread_local, .. }) => !is_thread_local,
938+
// Fake borrows are only read by fake reads, so do not have any reality in
939+
// post-analysis MIR.
940+
Some(box LocalInfo::FakeBorrow) => true,
941+
_ => false,
942+
}
943+
} else {
944+
// FIXME(#105084) HIR-based drop tracking does not account for all the temporaries that
945+
// MIR building may introduce. This leads to wrongly ignored types, but this is
946+
// necessary for internal consistency and to avoid ICEs.
947+
decl.internal
932948
};
949+
let decl =
950+
GeneratorSavedTy { ty: decl.ty, source_info: decl.source_info, ignore_for_traits };
951+
debug!(?decl);
952+
933953
tys.push(decl);
934-
debug!("generator saved local {:?} => {:?}", saved_local, local);
935954
}
936955

937956
// Leave empty variants for the UNRESUMED, RETURNED, and POISONED states.
@@ -1401,7 +1420,7 @@ pub(crate) fn mir_generator_witnesses<'tcx>(
14011420
// Extract locals which are live across suspension point into `layout`
14021421
// `remap` gives a mapping from local indices onto generator struct indices
14031422
// `storage_liveness` tells us which locals have live storage at suspension points
1404-
let (_, generator_layout, _) = compute_layout(liveness_info, body);
1423+
let (_, generator_layout, _) = compute_layout(tcx, liveness_info, body);
14051424

14061425
if tcx.sess.opts.unstable_opts.drop_tracking_mir {
14071426
check_suspend_tys(tcx, &generator_layout, &body);
@@ -1503,7 +1522,7 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
15031522
// Extract locals which are live across suspension point into `layout`
15041523
// `remap` gives a mapping from local indices onto generator struct indices
15051524
// `storage_liveness` tells us which locals have live storage at suspension points
1506-
let (remap, layout, storage_liveness) = compute_layout(liveness_info, body);
1525+
let (remap, layout, storage_liveness) = compute_layout(tcx, liveness_info, body);
15071526

15081527
let can_return = can_return(tcx, body, tcx.param_env(body.source.def_id()));
15091528

@@ -1700,7 +1719,7 @@ fn check_suspend_tys<'tcx>(tcx: TyCtxt<'tcx>, layout: &GeneratorLayout<'tcx>, bo
17001719
let decl = &layout.field_tys[local];
17011720
debug!(?decl);
17021721

1703-
if !decl.is_static_ptr && linted_tys.insert(decl.ty) {
1722+
if !decl.ignore_for_traits && linted_tys.insert(decl.ty) {
17041723
let Some(hir_id) = decl.source_info.scope.lint_root(&body.source_scopes) else { continue };
17051724

17061725
check_must_not_suspend_ty(

compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2389,7 +2389,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
23892389
for &local in variant {
23902390
let decl = &generator_info.field_tys[local];
23912391
debug!(?decl);
2392-
if ty_matches(ty::Binder::dummy(decl.ty)) && !decl.is_static_ptr {
2392+
if ty_matches(ty::Binder::dummy(decl.ty)) && !decl.ignore_for_traits {
23932393
interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(
23942394
decl.source_info.span,
23952395
Some((None, source_info.span, None, from_awaited_ty)),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
error[E0382]: borrow of moved value: `g`
2+
--> $DIR/issue-105084.rs:44:14
3+
|
4+
LL | let mut g = || {
5+
| ----- move occurs because `g` has type `[generator@$DIR/issue-105084.rs:22:17: 22:19]`, which does not implement the `Copy` trait
6+
...
7+
LL | let mut h = copy(g);
8+
| - value moved here
9+
...
10+
LL | Pin::new(&mut g).resume(());
11+
| ^^^^^^ value borrowed here after move
12+
|
13+
note: consider changing this parameter type in function `copy` to borrow instead if owning the value isn't necessary
14+
--> $DIR/issue-105084.rs:17:21
15+
|
16+
LL | fn copy<T: Copy>(x: T) -> T {
17+
| ---- ^ this parameter takes ownership of the value
18+
| |
19+
| in this function
20+
help: consider cloning the value if the performance cost is acceptable
21+
|
22+
LL | let mut h = copy(g.clone());
23+
| ++++++++
24+
25+
error[E0277]: the trait bound `Box<(i32, ())>: Copy` is not satisfied in `[generator@$DIR/issue-105084.rs:22:17: 22:19]`
26+
--> $DIR/issue-105084.rs:38:17
27+
|
28+
LL | let mut g = || {
29+
| -- within this `[generator@$DIR/issue-105084.rs:22:17: 22:19]`
30+
...
31+
LL | let mut h = copy(g);
32+
| ^^^^ within `[generator@$DIR/issue-105084.rs:22:17: 22:19]`, the trait `Copy` is not implemented for `Box<(i32, ())>`
33+
|
34+
note: generator does not implement `Copy` as this value is used across a yield
35+
--> $DIR/issue-105084.rs:28:25
36+
|
37+
LL | let t = box (5, yield);
38+
| --------^^^^^-
39+
| | |
40+
| | yield occurs here, with `box (5, yield)` maybe used later
41+
| has type `Box<(i32, ())>` which does not implement `Copy`
42+
note: required by a bound in `copy`
43+
--> $DIR/issue-105084.rs:17:12
44+
|
45+
LL | fn copy<T: Copy>(x: T) -> T {
46+
| ^^^^ required by this bound in `copy`
47+
48+
error: aborting due to 2 previous errors
49+
50+
Some errors have detailed explanations: E0277, E0382.
51+
For more information about an error, try `rustc --explain E0277`.

tests/ui/generator/issue-105084.rs

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// revisions: no_drop_tracking drop_tracking drop_tracking_mir
2+
// [drop_tracking] compile-flags: -Zdrop-tracking
3+
// [drop_tracking_mir] compile-flags: -Zdrop-tracking-mir
4+
// [no_drop_tracking] known-bug: #105084
5+
// [no_drop_tracking] check-pass
6+
// [drop_tracking] known-bug: #105084
7+
// [drop_tracking] check-pass
8+
9+
#![feature(generators)]
10+
#![feature(generator_clone)]
11+
#![feature(generator_trait)]
12+
#![feature(box_syntax)]
13+
14+
use std::ops::Generator;
15+
use std::pin::Pin;
16+
17+
fn copy<T: Copy>(x: T) -> T {
18+
x
19+
}
20+
21+
fn main() {
22+
let mut g = || {
23+
// This is desuraged as 4 stages:
24+
// - allocate a `*mut u8` with `exchange_malloc`;
25+
// - create a Box that is ignored for trait computations;
26+
// - compute fields (and yields);
27+
// - assign to `t`.
28+
let t = box (5, yield);
29+
drop(t);
30+
};
31+
32+
// Allocate the temporary box.
33+
Pin::new(&mut g).resume(());
34+
35+
// The temporary box is in generator locals.
36+
// As it is not taken into account for trait computation,
37+
// the generator is `Copy`.
38+
let mut h = copy(g);
39+
//[drop_tracking_mir]~^ ERROR the trait bound `Box<(i32, ())>: Copy` is not satisfied in
40+
41+
// We now have 2 boxes with the same backing allocation:
42+
// one inside `g` and one inside `h`.
43+
// Proceed and drop `t` in `g`.
44+
Pin::new(&mut g).resume(());
45+
//[drop_tracking_mir]~^ ERROR borrow of moved value: `g`
46+
47+
// Proceed and drop `t` in `h` -> double free!
48+
Pin::new(&mut h).resume(());
49+
}

0 commit comments

Comments
 (0)