Skip to content

Commit 2019147

Browse files
committed
Auto merge of rust-lang#101894 - dingxiangfei2009:let-else-avoid-duplicate-storage-live, r=oli-obk
Avoid duplicating StorageLive in let-else cc `@est31` Fix rust-lang#101867 Fix rust-lang#101932 rust-lang#101410 introduced directives to activate storages of bindings in let-else earlier. However, since it is using the machinery of `match` and friends for pattern matching and binding, those storages are activated for the second time. This PR adjusts this behavior and avoid the duplicated activation for let-else statements.
2 parents 11bb80a + eb36f5e commit 2019147

File tree

5 files changed

+136
-9
lines changed

5 files changed

+136
-9
lines changed

compiler/rustc_mir_build/src/build/block.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
232232
pattern,
233233
UserTypeProjections::none(),
234234
&mut |this, _, _, _, node, span, _, _| {
235-
this.storage_live_binding(block, node, span, OutsideGuard, false);
235+
this.storage_live_binding(block, node, span, OutsideGuard, true);
236+
this.schedule_drop_for_binding(node, span, OutsideGuard);
236237
},
237238
);
238239
let failure = unpack!(

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

+31-8
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
371371
Some(arm.span),
372372
Some(arm.scope),
373373
Some(match_scope),
374+
false,
374375
);
375376

376377
if let Some(source_scope) = scope {
@@ -416,6 +417,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
416417
arm_span: Option<Span>,
417418
arm_scope: Option<region::Scope>,
418419
match_scope: Option<region::Scope>,
420+
storages_alive: bool,
419421
) -> BasicBlock {
420422
if candidate.subcandidates.is_empty() {
421423
// Avoid generating another `BasicBlock` when we only have one
@@ -429,6 +431,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
429431
arm_span,
430432
match_scope,
431433
true,
434+
storages_alive,
432435
)
433436
} else {
434437
// It's helpful to avoid scheduling drops multiple times to save
@@ -466,6 +469,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
466469
arm_span,
467470
match_scope,
468471
schedule_drops,
472+
storages_alive,
469473
);
470474
if arm_scope.is_none() {
471475
schedule_drops = false;
@@ -641,6 +645,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
641645
None,
642646
None,
643647
None,
648+
false,
644649
)
645650
.unit()
646651
}
@@ -1813,6 +1818,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
18131818
None,
18141819
None,
18151820
None,
1821+
false,
18161822
);
18171823

18181824
post_guard_block.unit()
@@ -1836,6 +1842,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
18361842
arm_span: Option<Span>,
18371843
match_scope: Option<region::Scope>,
18381844
schedule_drops: bool,
1845+
storages_alive: bool,
18391846
) -> BasicBlock {
18401847
debug!("bind_and_guard_matched_candidate(candidate={:?})", candidate);
18411848

@@ -2051,7 +2058,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
20512058
self.cfg.push_fake_read(post_guard_block, guard_end, cause, Place::from(local_id));
20522059
}
20532060
assert!(schedule_drops, "patterns with guards must schedule drops");
2054-
self.bind_matched_candidate_for_arm_body(post_guard_block, true, by_value_bindings);
2061+
self.bind_matched_candidate_for_arm_body(
2062+
post_guard_block,
2063+
true,
2064+
by_value_bindings,
2065+
storages_alive,
2066+
);
20552067

20562068
post_guard_block
20572069
} else {
@@ -2065,6 +2077,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
20652077
.iter()
20662078
.flat_map(|(bindings, _)| bindings)
20672079
.chain(&candidate.bindings),
2080+
storages_alive,
20682081
);
20692082
block
20702083
}
@@ -2154,6 +2167,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
21542167
block: BasicBlock,
21552168
schedule_drops: bool,
21562169
bindings: impl IntoIterator<Item = &'b Binding<'tcx>>,
2170+
storages_alive: bool,
21572171
) where
21582172
'tcx: 'b,
21592173
{
@@ -2163,13 +2177,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
21632177
// Assign each of the bindings. This may trigger moves out of the candidate.
21642178
for binding in bindings {
21652179
let source_info = self.source_info(binding.span);
2166-
let local = self.storage_live_binding(
2167-
block,
2168-
binding.var_id,
2169-
binding.span,
2170-
OutsideGuard,
2171-
schedule_drops,
2172-
);
2180+
let local = if storages_alive {
2181+
// Here storages are already alive, probably because this is a binding
2182+
// from let-else.
2183+
// We just need to schedule drop for the value.
2184+
self.var_local_id(binding.var_id, OutsideGuard).into()
2185+
} else {
2186+
self.storage_live_binding(
2187+
block,
2188+
binding.var_id,
2189+
binding.span,
2190+
OutsideGuard,
2191+
schedule_drops,
2192+
)
2193+
};
21732194
if schedule_drops {
21742195
self.schedule_drop_for_binding(binding.var_id, binding.span, OutsideGuard);
21752196
}
@@ -2300,6 +2321,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
23002321
None,
23012322
None,
23022323
None,
2324+
true,
23032325
);
23042326
// This block is for the failure case
23052327
let failure = this.bind_pattern(
@@ -2311,6 +2333,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
23112333
None,
23122334
None,
23132335
None,
2336+
true,
23142337
);
23152338
this.break_for_else(failure, *let_else_scope, this.source_info(initializer_span));
23162339
matching.unit()

src/test/mir-opt/issue-101867.rs

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#![cfg_attr(bootstrap, feature(let_else))]
2+
3+
// EMIT_MIR issue_101867.main.mir_map.0.mir
4+
fn main() {
5+
let x: Option<u8> = Some(1);
6+
let Some(y) = x else {
7+
panic!();
8+
};
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// MIR for `main` 0 mir_map
2+
3+
| User Type Annotations
4+
| 0: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(std::option::Option<u8>) }, span: $DIR/issue-101867.rs:5:12: 5:22, inferred_ty: std::option::Option<u8>
5+
| 1: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(std::option::Option<u8>) }, span: $DIR/issue-101867.rs:5:12: 5:22, inferred_ty: std::option::Option<u8>
6+
|
7+
fn main() -> () {
8+
let mut _0: (); // return place in scope 0 at $DIR/issue-101867.rs:+0:11: +0:11
9+
let _1: std::option::Option<u8> as UserTypeProjection { base: UserType(0), projs: [] }; // in scope 0 at $DIR/issue-101867.rs:+1:9: +1:10
10+
let mut _2: !; // in scope 0 at $DIR/issue-101867.rs:+2:26: +4:6
11+
let _3: (); // in scope 0 at $SRC_DIR/std/src/panic.rs:LL:COL
12+
let mut _4: !; // in scope 0 at $SRC_DIR/std/src/panic.rs:LL:COL
13+
let mut _6: isize; // in scope 0 at $DIR/issue-101867.rs:+2:9: +2:16
14+
scope 1 {
15+
debug x => _1; // in scope 1 at $DIR/issue-101867.rs:+1:9: +1:10
16+
let _5: u8; // in scope 1 at $DIR/issue-101867.rs:+2:14: +2:15
17+
scope 2 {
18+
debug y => _5; // in scope 2 at $DIR/issue-101867.rs:+2:14: +2:15
19+
}
20+
}
21+
22+
bb0: {
23+
StorageLive(_1); // scope 0 at $DIR/issue-101867.rs:+1:9: +1:10
24+
_1 = Option::<u8>::Some(const 1_u8); // scope 0 at $DIR/issue-101867.rs:+1:25: +1:32
25+
FakeRead(ForLet(None), _1); // scope 0 at $DIR/issue-101867.rs:+1:9: +1:10
26+
AscribeUserType(_1, o, UserTypeProjection { base: UserType(1), projs: [] }); // scope 0 at $DIR/issue-101867.rs:+1:12: +1:22
27+
StorageLive(_5); // scope 1 at $DIR/issue-101867.rs:+2:14: +2:15
28+
FakeRead(ForMatchedPlace(None), _1); // scope 1 at $DIR/issue-101867.rs:+2:19: +2:20
29+
_6 = discriminant(_1); // scope 1 at $DIR/issue-101867.rs:+2:19: +2:20
30+
switchInt(move _6) -> [1_isize: bb4, otherwise: bb3]; // scope 1 at $DIR/issue-101867.rs:+2:9: +2:16
31+
}
32+
33+
bb1: {
34+
StorageLive(_3); // scope 1 at $SRC_DIR/std/src/panic.rs:LL:COL
35+
StorageLive(_4); // scope 1 at $SRC_DIR/std/src/panic.rs:LL:COL
36+
_4 = begin_panic::<&str>(const "explicit panic") -> bb7; // scope 1 at $SRC_DIR/std/src/panic.rs:LL:COL
37+
// mir::Constant
38+
// + span: $SRC_DIR/std/src/panic.rs:LL:COL
39+
// + literal: Const { ty: fn(&str) -> ! {begin_panic::<&str>}, val: Value(<ZST>) }
40+
// mir::Constant
41+
// + span: $SRC_DIR/std/src/panic.rs:LL:COL
42+
// + literal: Const { ty: &str, val: Value(Slice(..)) }
43+
}
44+
45+
bb2: {
46+
StorageDead(_4); // scope 1 at $SRC_DIR/std/src/panic.rs:LL:COL
47+
StorageDead(_3); // scope 1 at $DIR/issue-101867.rs:+3:16: +3:17
48+
unreachable; // scope 1 at $DIR/issue-101867.rs:+2:26: +4:6
49+
}
50+
51+
bb3: {
52+
goto -> bb6; // scope 1 at $DIR/issue-101867.rs:+2:19: +2:20
53+
}
54+
55+
bb4: {
56+
falseEdge -> [real: bb5, imaginary: bb3]; // scope 1 at $DIR/issue-101867.rs:+2:9: +2:16
57+
}
58+
59+
bb5: {
60+
_5 = ((_1 as Some).0: u8); // scope 1 at $DIR/issue-101867.rs:+2:14: +2:15
61+
_0 = const (); // scope 0 at $DIR/issue-101867.rs:+0:11: +5:2
62+
StorageDead(_5); // scope 1 at $DIR/issue-101867.rs:+5:1: +5:2
63+
StorageDead(_1); // scope 0 at $DIR/issue-101867.rs:+5:1: +5:2
64+
return; // scope 0 at $DIR/issue-101867.rs:+5:2: +5:2
65+
}
66+
67+
bb6: {
68+
StorageDead(_5); // scope 1 at $DIR/issue-101867.rs:+5:1: +5:2
69+
goto -> bb1; // scope 0 at $DIR/issue-101867.rs:+0:11: +5:2
70+
}
71+
72+
bb7 (cleanup): {
73+
resume; // scope 0 at $DIR/issue-101867.rs:+0:1: +5:2
74+
}
75+
}

src/test/ui/let-else/const-fn.rs

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// run-pass
2+
// issue #101932
3+
4+
#![cfg_attr(bootstrap, feature(let_else))]
5+
6+
const fn foo(a: Option<i32>) -> i32 {
7+
let Some(a) = a else {
8+
return 42
9+
};
10+
11+
a + 1
12+
}
13+
14+
fn main() {
15+
const A: i32 = foo(None);
16+
const B: i32 = foo(Some(1));
17+
18+
println!("{} {}", A, B);
19+
}

0 commit comments

Comments
 (0)