Skip to content

Commit 163c059

Browse files
committed
Only omit StorageLive/Dead for variable that are never initialized
With `feature(never_type)`, it's not guaranteed that any variable with type `!` isn't ever assigned to.
1 parent 8918881 commit 163c059

File tree

3 files changed

+55
-25
lines changed

3 files changed

+55
-25
lines changed

src/librustc_mir/build/expr/as_temp.rs

+40-25
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
use crate::build::{BlockAnd, BlockAndExtension, Builder};
44
use crate::build::scope::DropKind;
55
use crate::hair::*;
6+
use rustc::hir;
67
use rustc::middle::region;
78
use rustc::mir::*;
89

@@ -66,32 +67,46 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
6667
};
6768
let temp_place = &Place::from(temp);
6869

69-
if !expr_ty.is_never() {
70-
this.cfg.push(
71-
block,
72-
Statement {
73-
source_info,
74-
kind: StatementKind::StorageLive(temp),
75-
},
76-
);
77-
78-
// In constants, `temp_lifetime` is `None` for temporaries that live for the
79-
// `'static` lifetime. Thus we do not drop these temporaries and simply leak them.
80-
// This is equivalent to what `let x = &foo();` does in functions. The temporary
81-
// is lifted to their surrounding scope. In a function that means the temporary lives
82-
// until just before the function returns. In constants that means it outlives the
83-
// constant's initialization value computation. Anything outliving a constant
84-
// must have the `'static` lifetime and live forever.
85-
// Anything with a shorter lifetime (e.g the `&foo()` in `bar(&foo())` or anything
86-
// within a block will keep the regular drops just like runtime code.
87-
if let Some(temp_lifetime) = temp_lifetime {
88-
this.schedule_drop(
89-
expr_span,
90-
temp_lifetime,
91-
temp,
92-
expr_ty,
93-
DropKind::Storage,
70+
match expr.kind {
71+
// Don't bother with StorageLive and Dead for these temporaries,
72+
// they are never assigned.
73+
ExprKind::Break { .. } |
74+
ExprKind::Continue { .. } |
75+
ExprKind::Return { .. } => (),
76+
ExprKind::Block {
77+
body: hir::Block { expr: None, targeted_by_break: false, .. }
78+
} if expr_ty.is_never() => (),
79+
_ => {
80+
this.cfg.push(
81+
block,
82+
Statement {
83+
source_info,
84+
kind: StatementKind::StorageLive(temp),
85+
},
9486
);
87+
88+
// In constants, `temp_lifetime` is `None` for temporaries that
89+
// live for the `'static` lifetime. Thus we do not drop these
90+
// temporaries and simply leak them.
91+
// This is equivalent to what `let x = &foo();` does in
92+
// functions. The temporary is lifted to their surrounding
93+
// scope. In a function that means the temporary lives until
94+
// just before the function returns. In constants that means it
95+
// outlives the constant's initialization value computation.
96+
// Anything outliving a constant must have the `'static`
97+
// lifetime and live forever.
98+
// Anything with a shorter lifetime (e.g the `&foo()` in
99+
// `bar(&foo())` or anything within a block will keep the
100+
// regular drops just like runtime code.
101+
if let Some(temp_lifetime) = temp_lifetime {
102+
this.schedule_drop(
103+
expr_span,
104+
temp_lifetime,
105+
temp,
106+
expr_ty,
107+
DropKind::Storage,
108+
);
109+
}
95110
}
96111
}
97112

src/test/mir-opt/loop_test.rs

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ fn main() {
2626
// _1 = ();
2727
// StorageDead(_2);
2828
// StorageDead(_1);
29+
// StorageLive(_4);
2930
// goto -> bb5;
3031
// }
3132
// ...
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Regression test for issue 62165
2+
3+
// check-pass
4+
5+
#![feature(never_type)]
6+
7+
pub fn main() {
8+
loop {
9+
match None {
10+
None => return,
11+
Some(val) => val,
12+
};
13+
};
14+
}

0 commit comments

Comments
 (0)