Skip to content

Commit c6a97d3

Browse files
committed
emit StorageLive and schedule StorageDead for let-else after matching
1 parent 2801f9a commit c6a97d3

File tree

6 files changed

+36
-69
lines changed

6 files changed

+36
-69
lines changed

compiler/rustc_mir_build/src/builder/block.rs

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use rustc_span::Span;
66
use tracing::debug;
77

88
use crate::builder::ForGuard::OutsideGuard;
9-
use crate::builder::matches::{DeclareLetBindings, EmitStorageLive, ScheduleDrops};
9+
use crate::builder::matches::{DeclareLetBindings, ScheduleDrops};
1010
use crate::builder::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
1111

1212
impl<'a, 'tcx> Builder<'a, 'tcx> {
@@ -199,15 +199,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
199199
None,
200200
Some((Some(&destination), initializer_span)),
201201
);
202-
this.visit_primary_bindings(pattern, &mut |this, node, span| {
203-
this.storage_live_binding(
204-
block,
205-
node,
206-
span,
207-
OutsideGuard,
208-
ScheduleDrops::Yes,
209-
);
210-
});
211202
let else_block_span = this.thir[*else_block].span;
212203
let (matching, failure) =
213204
this.in_if_then_scope(last_remainder_scope, else_block_span, |this| {
@@ -218,7 +209,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
218209
None,
219210
initializer_span,
220211
DeclareLetBindings::No,
221-
EmitStorageLive::No,
222212
)
223213
});
224214
matching.and(failure)

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

Lines changed: 8 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -69,18 +69,6 @@ pub(crate) enum DeclareLetBindings {
6969
LetNotPermitted,
7070
}
7171

72-
/// Used by [`Builder::bind_matched_candidate_for_arm_body`] to determine
73-
/// whether or not to call [`Builder::storage_live_binding`] to emit
74-
/// [`StatementKind::StorageLive`].
75-
#[derive(Clone, Copy)]
76-
pub(crate) enum EmitStorageLive {
77-
/// Yes, emit `StorageLive` as normal.
78-
Yes,
79-
/// No, don't emit `StorageLive`. The caller has taken responsibility for
80-
/// emitting `StorageLive` as appropriate.
81-
No,
82-
}
83-
8472
/// Used by [`Builder::storage_live_binding`] and [`Builder::bind_matched_candidate_for_arm_body`]
8573
/// to decide whether to schedule drops.
8674
#[derive(Clone, Copy, Debug)]
@@ -207,7 +195,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
207195
Some(args.variable_source_info.scope),
208196
args.variable_source_info.span,
209197
args.declare_let_bindings,
210-
EmitStorageLive::Yes,
211198
),
212199
_ => {
213200
let mut block = block;
@@ -479,7 +466,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
479466
&built_match_tree.fake_borrow_temps,
480467
scrutinee_span,
481468
Some((arm, match_scope)),
482-
EmitStorageLive::Yes,
483469
);
484470

485471
this.fixed_temps_scope = old_dedup_scope;
@@ -533,7 +519,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
533519
fake_borrow_temps: &[(Place<'tcx>, Local, FakeBorrowKind)],
534520
scrutinee_span: Span,
535521
arm_match_scope: Option<(&Arm<'tcx>, region::Scope)>,
536-
emit_storage_live: EmitStorageLive,
537522
) -> BasicBlock {
538523
if branch.sub_branches.len() == 1 {
539524
let [sub_branch] = branch.sub_branches.try_into().unwrap();
@@ -544,7 +529,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
544529
scrutinee_span,
545530
arm_match_scope,
546531
ScheduleDrops::Yes,
547-
emit_storage_live,
548532
)
549533
} else {
550534
// It's helpful to avoid scheduling drops multiple times to save
@@ -577,7 +561,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
577561
scrutinee_span,
578562
arm_match_scope,
579563
schedule_drops,
580-
emit_storage_live,
581564
);
582565
if arm.is_none() {
583566
schedule_drops = ScheduleDrops::No;
@@ -741,7 +724,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
741724
&[],
742725
irrefutable_pat.span,
743726
None,
744-
EmitStorageLive::Yes,
745727
)
746728
.unit()
747729
}
@@ -2364,7 +2346,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
23642346
source_scope: Option<SourceScope>,
23652347
scope_span: Span,
23662348
declare_let_bindings: DeclareLetBindings,
2367-
emit_storage_live: EmitStorageLive,
23682349
) -> BlockAnd<()> {
23692350
let expr_span = self.thir[expr_id].span;
23702351
let scrutinee = unpack!(block = self.lower_scrutinee(block, expr_id, expr_span));
@@ -2398,14 +2379,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
23982379
}
23992380
}
24002381

2401-
let success = self.bind_pattern(
2402-
self.source_info(pat.span),
2403-
branch,
2404-
&[],
2405-
expr_span,
2406-
None,
2407-
emit_storage_live,
2408-
);
2382+
let success = self.bind_pattern(self.source_info(pat.span), branch, &[], expr_span, None);
24092383

24102384
// If branch coverage is enabled, record this branch.
24112385
self.visit_coverage_conditional_let(pat, success, built_tree.otherwise_block);
@@ -2428,7 +2402,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
24282402
scrutinee_span: Span,
24292403
arm_match_scope: Option<(&Arm<'tcx>, region::Scope)>,
24302404
schedule_drops: ScheduleDrops,
2431-
emit_storage_live: EmitStorageLive,
24322405
) -> BasicBlock {
24332406
debug!("bind_and_guard_matched_candidate(subbranch={:?})", sub_branch);
24342407

@@ -2547,7 +2520,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
25472520
post_guard_block,
25482521
ScheduleDrops::Yes,
25492522
by_value_bindings,
2550-
emit_storage_live,
25512523
);
25522524

25532525
post_guard_block
@@ -2559,7 +2531,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
25592531
block,
25602532
schedule_drops,
25612533
sub_branch.bindings.iter(),
2562-
emit_storage_live,
25632534
);
25642535
block
25652536
}
@@ -2730,7 +2701,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
27302701
block: BasicBlock,
27312702
schedule_drops: ScheduleDrops,
27322703
bindings: impl IntoIterator<Item = &'b Binding<'tcx>>,
2733-
emit_storage_live: EmitStorageLive,
27342704
) where
27352705
'tcx: 'b,
27362706
{
@@ -2740,19 +2710,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
27402710
// Assign each of the bindings. This may trigger moves out of the candidate.
27412711
for binding in bindings {
27422712
let source_info = self.source_info(binding.span);
2743-
let local = match emit_storage_live {
2744-
// Here storages are already alive, probably because this is a binding
2745-
// from let-else.
2746-
// We just need to schedule drop for the value.
2747-
EmitStorageLive::No => self.var_local_id(binding.var_id, OutsideGuard).into(),
2748-
EmitStorageLive::Yes => self.storage_live_binding(
2749-
block,
2750-
binding.var_id,
2751-
binding.span,
2752-
OutsideGuard,
2753-
schedule_drops,
2754-
),
2755-
};
2713+
let local = self.storage_live_binding(
2714+
block,
2715+
binding.var_id,
2716+
binding.span,
2717+
OutsideGuard,
2718+
schedule_drops,
2719+
);
27562720
if matches!(schedule_drops, ScheduleDrops::Yes) {
27572721
self.schedule_drop_for_binding(binding.var_id, binding.span, OutsideGuard);
27582722
}

tests/mir-opt/building/issue_101867.main.built.after.mir

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ fn main() -> () {
2424
_1 = Option::<u8>::Some(const 1_u8);
2525
FakeRead(ForLet(None), _1);
2626
AscribeUserType(_1, o, UserTypeProjection { base: UserType(1), projs: [] });
27-
StorageLive(_5);
2827
PlaceMention(_1);
2928
_6 = discriminant(_1);
3029
switchInt(move _6) -> [1: bb4, otherwise: bb3];
@@ -55,6 +54,7 @@ fn main() -> () {
5554
}
5655

5756
bb6: {
57+
StorageLive(_5);
5858
_5 = copy ((_1 as Some).0: u8);
5959
_0 = const ();
6060
StorageDead(_5);
@@ -63,7 +63,6 @@ fn main() -> () {
6363
}
6464

6565
bb7: {
66-
StorageDead(_5);
6766
goto -> bb1;
6867
}
6968

tests/mir-opt/building/user_type_annotations.let_else.built.after.mir

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,6 @@ fn let_else() -> () {
2121
}
2222

2323
bb0: {
24-
StorageLive(_2);
25-
StorageLive(_3);
26-
StorageLive(_4);
2724
StorageLive(_5);
2825
StorageLive(_6);
2926
StorageLive(_7);
@@ -51,26 +48,26 @@ fn let_else() -> () {
5148

5249
bb4: {
5350
AscribeUserType(_5, +, UserTypeProjection { base: UserType(1), projs: [] });
51+
StorageLive(_2);
5452
_2 = copy (_5.0: u32);
53+
StorageLive(_3);
5554
_3 = copy (_5.1: u64);
55+
StorageLive(_4);
5656
_4 = copy (_5.2: &char);
5757
StorageDead(_7);
5858
StorageDead(_5);
5959
_0 = const ();
60-
StorageDead(_8);
6160
StorageDead(_4);
6261
StorageDead(_3);
6362
StorageDead(_2);
63+
StorageDead(_8);
6464
return;
6565
}
6666

6767
bb5: {
6868
StorageDead(_7);
6969
StorageDead(_5);
7070
StorageDead(_8);
71-
StorageDead(_4);
72-
StorageDead(_3);
73-
StorageDead(_2);
7471
goto -> bb1;
7572
}
7673

tests/ui/dropck/let-else-more-permissive.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
//! The drop check is currently more permissive when `let` statements have an `else` block, due to
2-
//! scheduling drops for bindings' storage before pattern-matching (#142056).
1+
//! Regression test for #142056. The drop check used to be more permissive for `let` statements with
2+
//! `else` blocks, due to scheduling drops for bindings' storage before pattern-matching.
33
44
struct Struct<T>(T);
55
impl<T> Drop for Struct<T> {
@@ -14,10 +14,11 @@ fn main() {
1414
//~^ ERROR `short1` does not live long enough
1515
}
1616
{
17-
// This is OK: `short2`'s storage is live until after `long2`'s drop runs.
17+
// This was OK: `short2`'s storage was live until after `long2`'s drop ran.
1818
#[expect(irrefutable_let_patterns)]
1919
let (mut long2, short2) = (Struct(&0), 1) else { unreachable!() };
2020
long2.0 = &short2;
21+
//~^ ERROR `short2` does not live long enough
2122
}
2223
{
2324
// Sanity check: `short3`'s drop is significant; it's dropped before `long3`:

tests/ui/dropck/let-else-more-permissive.stderr

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,24 @@ LL | }
1414
|
1515
= note: values in a scope are dropped in the opposite order they are defined
1616

17+
error[E0597]: `short2` does not live long enough
18+
--> $DIR/let-else-more-permissive.rs:20:19
19+
|
20+
LL | let (mut long2, short2) = (Struct(&0), 1) else { unreachable!() };
21+
| ------ binding `short2` declared here
22+
LL | long2.0 = &short2;
23+
| ^^^^^^^ borrowed value does not live long enough
24+
LL |
25+
LL | }
26+
| -
27+
| |
28+
| `short2` dropped here while still borrowed
29+
| borrow might be used here, when `long2` is dropped and runs the `Drop` code for type `Struct`
30+
|
31+
= note: values in a scope are dropped in the opposite order they are defined
32+
1733
error[E0597]: `short3` does not live long enough
18-
--> $DIR/let-else-more-permissive.rs:27:19
34+
--> $DIR/let-else-more-permissive.rs:28:19
1935
|
2036
LL | let (mut long3, short3) = (Struct(&tmp), Box::new(1)) else { unreachable!() };
2137
| ------ binding `short3` declared here
@@ -30,6 +46,6 @@ LL | }
3046
|
3147
= note: values in a scope are dropped in the opposite order they are defined
3248

33-
error: aborting due to 2 previous errors
49+
error: aborting due to 3 previous errors
3450

3551
For more information about this error, try `rustc --explain E0597`.

0 commit comments

Comments
 (0)