Also generate StorageDead in constants

This commit is contained in:
oli 2020-12-09 10:50:34 +00:00
parent db85512bd8
commit 84fe7cf24e
10 changed files with 92 additions and 57 deletions

View file

@ -4,7 +4,7 @@ use std::mem;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_hir::{self as hir, def::DefKind, def_id::DefId, definitions::DefPathData};
use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData};
use rustc_index::vec::IndexVec;
use rustc_macros::HashStable;
use rustc_middle::ich::StableHashingContext;
@ -700,21 +700,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let mut locals = IndexVec::from_elem(dummy, &body.local_decls);
// Now mark those locals as dead that we do not want to initialize
match self.tcx.def_kind(instance.def_id()) {
// statics and constants don't have `Storage*` statements, no need to look for them
//
// FIXME: The above is likely untrue. See
// <https://github.com/rust-lang/rust/pull/70004#issuecomment-602022110>. Is it
// okay to ignore `StorageDead`/`StorageLive` annotations during CTFE?
DefKind::Static | DefKind::Const | DefKind::AssocConst => {}
_ => {
// Mark locals that use `Storage*` annotations as dead on function entry.
let always_live = AlwaysLiveLocals::new(self.body());
for local in locals.indices() {
if !always_live.contains(local) {
locals[local].value = LocalValue::Dead;
}
}
// Mark locals that use `Storage*` annotations as dead on function entry.
let always_live = AlwaysLiveLocals::new(self.body());
for local in locals.indices() {
if !always_live.contains(local) {
locals[local].value = LocalValue::Dead;
}
}
// done

View file

@ -19,7 +19,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
M: Mirror<'tcx, Output = Expr<'tcx>>,
{
let local_scope = self.local_scope();
self.as_operand(block, local_scope, expr)
self.as_operand(block, Some(local_scope), expr)
}
/// Returns an operand suitable for use until the end of the current scope expression and
@ -79,7 +79,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
M: Mirror<'tcx, Output = Expr<'tcx>>,
{
let local_scope = self.local_scope();
self.as_call_operand(block, local_scope, expr)
self.as_call_operand(block, Some(local_scope), expr)
}
/// Compile `expr` into a value that can be used as an operand.

View file

@ -25,7 +25,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
M: Mirror<'tcx, Output = Expr<'tcx>>,
{
let local_scope = self.local_scope();
self.as_rvalue(block, local_scope, expr)
self.as_rvalue(block, Some(local_scope), expr)
}
/// Compile `expr`, yielding an rvalue.
@ -445,9 +445,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
Rvalue::Ref(this.hir.tcx().lifetimes.re_erased, borrow_kind, arg_place),
);
// In constants, temp_lifetime is None. We should not need to drop
// anything because no values with a destructor can be created in
// a constant at this time, even if the type may need dropping.
// See the comment in `expr_as_temp` and on the `rvalue_scopes` field for why
// this can be `None`.
if let Some(temp_lifetime) = temp_lifetime {
this.schedule_drop_storage_and_value(upvar_span, temp_lifetime, temp);
}

View file

@ -79,7 +79,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// (#66975) Source could be a const of type `!`, so has to
// exist in the generated MIR.
unpack!(block = this.as_temp(block, this.local_scope(), source, Mutability::Mut,));
unpack!(block = this.as_temp(block, Some(this.local_scope()), source, Mutability::Mut,));
// This is an optimization. If the expression was a call then we already have an
// unreachable block. Don't bother to terminate it and create a new one.
@ -300,7 +300,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// (evaluating them in order given by user)
let fields_map: FxHashMap<_, _> = fields
.into_iter()
.map(|f| (f.name, unpack!(block = this.as_operand(block, scope, f.expr))))
.map(|f| (f.name, unpack!(block = this.as_operand(block, Some(scope), f.expr))))
.collect();
let field_names = this.hir.all_fields(adt_def, variant_index);
@ -468,7 +468,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
ExprKind::Yield { value } => {
let scope = this.local_scope();
let value = unpack!(block = this.as_operand(block, scope, value));
let value = unpack!(block = this.as_operand(block, Some(scope), value));
let resume = this.cfg.start_new_block();
this.record_operands_moved(slice::from_ref(&value));
this.cfg.terminate(

View file

@ -85,7 +85,6 @@ use crate::build::matches::{ArmHasGuard, Candidate};
use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder, CFG};
use crate::thir::{Arm, Expr, ExprRef, LintLevel};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir as hir;
use rustc_index::vec::IndexVec;
use rustc_middle::middle::region;
use rustc_middle::mir::*;
@ -740,18 +739,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// We would allocate the box but then free it on the unwinding
/// path; we would also emit a free on the 'success' path from
/// panic, but that will turn out to be removed as dead-code.
///
/// When building statics/constants, returns `None` since
/// intermediate values do not have to be dropped in that case.
crate fn local_scope(&self) -> Option<region::Scope> {
match self.hir.body_owner_kind {
hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) =>
// No need to free storage in this context.
{
None
}
hir::BodyOwnerKind::Closure | hir::BodyOwnerKind::Fn => Some(self.scopes.topmost()),
}
crate fn local_scope(&self) -> region::Scope {
self.scopes.topmost()
}
// Scheduling drops
@ -938,23 +927,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// not the `DROP(_X)` itself, but the (spurious) unwind pathways
/// that it creates. See #64391 for an example.
crate fn record_operands_moved(&mut self, operands: &[Operand<'tcx>]) {
let scope = match self.local_scope() {
None => {
// if there is no local scope, operands won't be dropped anyway
return;
}
let local_scope = self.local_scope();
let scope = self.scopes.scopes.last_mut().unwrap();
Some(local_scope) => {
let top_scope = self.scopes.scopes.last_mut().unwrap();
assert!(
top_scope.region_scope == local_scope,
"local scope ({:?}) is not the topmost scope!",
local_scope
);
top_scope
}
};
assert_eq!(
scope.region_scope, local_scope,
"local scope is not the topmost scope!",
);
// look for moves of a local variable, like `MOVE(_X)`
let locals_moved = operands
@ -993,9 +972,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
match cond {
// Don't try to drop a constant
Operand::Constant(_) => (),
// If constants and statics, we don't generate StorageLive for this
// temporary, so don't try to generate StorageDead for it either.
_ if self.local_scope().is_none() => (),
Operand::Copy(place) | Operand::Move(place) => {
if let Some(cond_temp) = place.as_local() {
// Manually drop the condition on both branches.

View file

@ -12,4 +12,7 @@ static mut BAR: *const &i32 = [&Y].as_ptr();
// EMIT_MIR const_promotion_extern_static.FOO-promoted[0].ConstProp.after.mir
static mut FOO: *const &i32 = [unsafe { &X }].as_ptr();
// EMIT_MIR const_promotion_extern_static.BOP.mir_map.0.mir
static BOP: &i32 = &13;
fn main() {}

View file

@ -33,6 +33,8 @@
+ // + literal: Const { ty: &[&i32; 1], val: Unevaluated(WithOptConstParam { did: DefId(0:6 ~ const_promotion_extern_static[317d]::BAR), const_param_did: None }, [], Some(promoted[0])) }
+ _2 = &(*_6); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35
_1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35
- StorageDead(_4); // scope 0 at $DIR/const-promotion-extern-static.rs:9:34: 9:35
StorageDead(_2); // scope 0 at $DIR/const-promotion-extern-static.rs:9:34: 9:35
_0 = core::slice::<impl [&i32]>::as_ptr(move _1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44
// mir::Constant
// + span: $DIR/const-promotion-extern-static.rs:9:36: 9:42
@ -42,6 +44,7 @@
bb1: {
- StorageDead(_5); // scope 0 at $DIR/const-promotion-extern-static.rs:9:43: 9:44
- StorageDead(_3); // scope 0 at $DIR/const-promotion-extern-static.rs:9:43: 9:44
StorageDead(_1); // scope 0 at $DIR/const-promotion-extern-static.rs:9:43: 9:44
return; // scope 0 at $DIR/const-promotion-extern-static.rs:9:1: 9:45
}

View file

@ -0,0 +1,17 @@
// MIR for `BOP` 0 mir_map
static BOP: &i32 = {
let mut _0: &i32; // return place in scope 0 at $DIR/const-promotion-extern-static.rs:16:13: 16:17
let _1: &i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:16:20: 16:23
let _2: i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:16:21: 16:23
bb0: {
StorageLive(_1); // scope 0 at $DIR/const-promotion-extern-static.rs:16:20: 16:23
StorageLive(_2); // scope 0 at $DIR/const-promotion-extern-static.rs:16:21: 16:23
_2 = const 13_i32; // scope 0 at $DIR/const-promotion-extern-static.rs:16:21: 16:23
_1 = &_2; // scope 0 at $DIR/const-promotion-extern-static.rs:16:20: 16:23
_0 = &(*_1); // scope 0 at $DIR/const-promotion-extern-static.rs:16:20: 16:23
StorageDead(_1); // scope 0 at $DIR/const-promotion-extern-static.rs:16:22: 16:23
return; // scope 0 at $DIR/const-promotion-extern-static.rs:16:1: 16:24
}
}

View file

@ -35,6 +35,8 @@
+ // + literal: Const { ty: &[&i32; 1], val: Unevaluated(WithOptConstParam { did: DefId(0:7 ~ const_promotion_extern_static[317d]::FOO), const_param_did: None }, [], Some(promoted[0])) }
+ _2 = &(*_6); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
_1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
- StorageDead(_4); // scope 0 at $DIR/const-promotion-extern-static.rs:13:45: 13:46
StorageDead(_2); // scope 0 at $DIR/const-promotion-extern-static.rs:13:45: 13:46
_0 = core::slice::<impl [&i32]>::as_ptr(move _1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55
// mir::Constant
// + span: $DIR/const-promotion-extern-static.rs:13:47: 13:53
@ -44,6 +46,7 @@
bb1: {
- StorageDead(_5); // scope 0 at $DIR/const-promotion-extern-static.rs:13:54: 13:55
- StorageDead(_3); // scope 0 at $DIR/const-promotion-extern-static.rs:13:54: 13:55
StorageDead(_1); // scope 0 at $DIR/const-promotion-extern-static.rs:13:54: 13:55
return; // scope 0 at $DIR/const-promotion-extern-static.rs:13:1: 13:56
}

View file

@ -143,9 +143,52 @@ static XXX: &Foo = {
StorageLive(_48); // scope 0 at $DIR/storage_live_dead_in_statics.rs:21:25: 21:31
_48 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:21:25: 21:31
_6 = [move _7, move _8, move _9, move _10, move _11, move _12, move _13, move _14, move _15, move _16, move _17, move _18, move _19, move _20, move _21, move _22, move _23, move _24, move _25, move _26, move _27, move _28, move _29, move _30, move _31, move _32, move _33, move _34, move _35, move _36, move _37, move _38, move _39, move _40, move _41, move _42, move _43, move _44, move _45, move _46, move _47, move _48]; // scope 0 at $DIR/storage_live_dead_in_statics.rs:7:12: 22:6
StorageDead(_48); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6
StorageDead(_47); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6
StorageDead(_46); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6
StorageDead(_45); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6
StorageDead(_44); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6
StorageDead(_43); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6
StorageDead(_42); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6
StorageDead(_41); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6
StorageDead(_40); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6
StorageDead(_39); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6
StorageDead(_38); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6
StorageDead(_37); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6
StorageDead(_36); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6
StorageDead(_35); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6
StorageDead(_34); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6
StorageDead(_33); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6
StorageDead(_32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6
StorageDead(_31); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6
StorageDead(_30); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6
StorageDead(_29); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6
StorageDead(_28); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6
StorageDead(_27); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6
StorageDead(_26); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6
StorageDead(_25); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6
StorageDead(_24); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6
StorageDead(_23); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6
StorageDead(_22); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6
StorageDead(_21); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6
StorageDead(_20); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6
StorageDead(_19); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6
StorageDead(_18); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6
StorageDead(_17); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6
StorageDead(_16); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6
StorageDead(_15); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6
StorageDead(_14); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6
StorageDead(_13); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6
StorageDead(_12); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6
StorageDead(_11); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6
StorageDead(_10); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6
StorageDead(_9); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6
StorageDead(_8); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6
StorageDead(_7); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6
_5 = &_6; // scope 0 at $DIR/storage_live_dead_in_statics.rs:7:11: 22:6
_4 = &(*_5); // scope 0 at $DIR/storage_live_dead_in_statics.rs:7:11: 22:6
_3 = move _4 as &[(u32, u32)] (Pointer(Unsize)); // scope 0 at $DIR/storage_live_dead_in_statics.rs:7:11: 22:6
StorageDead(_4); // scope 0 at $DIR/storage_live_dead_in_statics.rs:22:5: 22:6
_2 = Foo { tup: const "hi", data: move _3 }; // scope 0 at $DIR/storage_live_dead_in_statics.rs:5:29: 23:2
// ty::Const
// + ty: &str
@ -153,6 +196,7 @@ static XXX: &Foo = {
// mir::Constant
// + span: $DIR/storage_live_dead_in_statics.rs:6:10: 6:14
// + literal: Const { ty: &str, val: Value(Slice { data: Allocation { bytes: [104, 105], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [3], len: Size { raw: 2 } }, size: Size { raw: 2 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 2 }) }
StorageDead(_3); // scope 0 at $DIR/storage_live_dead_in_statics.rs:23:1: 23:2
_1 = &_2; // scope 0 at $DIR/storage_live_dead_in_statics.rs:5:28: 23:2
_0 = &(*_1); // scope 0 at $DIR/storage_live_dead_in_statics.rs:5:28: 23:2
StorageDead(_5); // scope 0 at $DIR/storage_live_dead_in_statics.rs:23:1: 23:2