Skip to content

Commit 23ade23

Browse files
committed
Auto merge of #44252 - eddyb:what-is-dead-may-never-die, r=nikomatsakis
Better StorageLive / StorageDead placement for constants. Fixes problems in miri (see rust-lang/miri#324 (comment)) caused by the new scope rules in #43932. What I've tried to do here is always have a `StorageLive` but no `StorageDead` for `'static` slots. It might not work perfectly in all cases, but it should unblock miri. r? @nikomatsakis cc @oli-obk
2 parents fc54bf9 + 02ec0ae commit 23ade23

File tree

6 files changed

+94
-35
lines changed

6 files changed

+94
-35
lines changed

src/librustc/ty/maps.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ use ty::fast_reject::SimplifiedType;
3131
use util::nodemap::{DefIdSet, NodeSet};
3232
use util::common::{profq_msg, ProfileQueriesMsg};
3333

34+
use rustc_data_structures::indexed_set::IdxSetBuf;
3435
use rustc_data_structures::indexed_vec::IndexVec;
3536
use rustc_data_structures::fx::FxHashMap;
3637
use std::cell::{RefCell, RefMut, Cell};
@@ -1019,7 +1020,7 @@ define_maps! { <'tcx>
10191020
/// Maps DefId's that have an associated Mir to the result
10201021
/// of the MIR qualify_consts pass. The actual meaning of
10211022
/// the value isn't known except to the pass itself.
1022-
[] fn mir_const_qualif: MirConstQualif(DefId) -> u8,
1023+
[] fn mir_const_qualif: MirConstQualif(DefId) -> (u8, Rc<IdxSetBuf<mir::Local>>),
10231024

10241025
/// Fetch the MIR for a given def-id up till the point where it is
10251026
/// ready for const evaluation.

src/librustc_metadata/cstore_impl.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ use syntax::ext::base::SyntaxExtension;
3838
use syntax::parse::filemap_to_stream;
3939
use syntax::symbol::Symbol;
4040
use syntax_pos::{Span, NO_EXPANSION};
41+
use rustc_data_structures::indexed_set::IdxSetBuf;
4142
use rustc::hir::svh::Svh;
4243
use rustc::hir;
4344

@@ -106,7 +107,9 @@ provide! { <'tcx> tcx, def_id, cdata,
106107
mir
107108
}
108109
generator_sig => { cdata.generator_sig(def_id.index, tcx) }
109-
mir_const_qualif => { cdata.mir_const_qualif(def_id.index) }
110+
mir_const_qualif => {
111+
(cdata.mir_const_qualif(def_id.index), Rc::new(IdxSetBuf::new_empty(0)))
112+
}
110113
typeck_tables_of => { cdata.item_body_tables(def_id.index, tcx) }
111114
closure_kind => { cdata.closure_kind(def_id.index) }
112115
fn_sig => { cdata.fn_sig(def_id.index, tcx) }

src/librustc_metadata/encoder.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -793,7 +793,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
793793
let kind = match impl_item.kind {
794794
ty::AssociatedKind::Const => {
795795
EntryKind::AssociatedConst(container,
796-
self.tcx.at(ast_item.span).mir_const_qualif(def_id))
796+
self.tcx.at(ast_item.span).mir_const_qualif(def_id).0)
797797
}
798798
ty::AssociatedKind::Method => {
799799
let fn_data = if let hir::ImplItemKind::Method(ref sig, body) = ast_item.node {
@@ -912,7 +912,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
912912
hir::ItemStatic(_, hir::MutMutable, _) => EntryKind::MutStatic,
913913
hir::ItemStatic(_, hir::MutImmutable, _) => EntryKind::ImmStatic,
914914
hir::ItemConst(..) => {
915-
EntryKind::Const(tcx.at(item.span).mir_const_qualif(def_id))
915+
EntryKind::Const(tcx.at(item.span).mir_const_qualif(def_id).0)
916916
}
917917
hir::ItemFn(_, _, constness, .., body) => {
918918
let data = FnData {
@@ -1256,7 +1256,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
12561256
let body = tcx.hir.body_owned_by(id);
12571257

12581258
Entry {
1259-
kind: EntryKind::Const(tcx.mir_const_qualif(def_id)),
1259+
kind: EntryKind::Const(tcx.mir_const_qualif(def_id).0),
12601260
visibility: self.lazy(&ty::Visibility::Public),
12611261
span: self.lazy(&tcx.def_span(def_id)),
12621262
attributes: LazySeq::empty(),

src/librustc_mir/build/expr/as_rvalue.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -97,12 +97,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
9797
ExprKind::Box { value } => {
9898
let value = this.hir.mirror(value);
9999
let result = this.temp(expr.ty, expr_span);
100+
this.cfg.push(block, Statement {
101+
source_info,
102+
kind: StatementKind::StorageLive(result.clone())
103+
});
100104
if let Some(scope) = scope {
101105
// schedule a shallow free of that memory, lest we unwind:
102-
this.cfg.push(block, Statement {
103-
source_info,
104-
kind: StatementKind::StorageLive(result.clone())
105-
});
106106
this.schedule_drop(expr_span, scope, &result, value.ty);
107107
}
108108

src/librustc_mir/build/expr/as_temp.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
5050
let expr_ty = expr.ty.clone();
5151
let temp = this.temp(expr_ty.clone(), expr_span);
5252

53-
if !expr_ty.is_never() && temp_lifetime.is_some() {
53+
if !expr_ty.is_never() {
5454
this.cfg.push(block, Statement {
5555
source_info,
5656
kind: StatementKind::StorageLive(temp.clone())

src/librustc_mir/transform/qualify_consts.rs

+80-25
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
//! diagnostics as to why a constant rvalue wasn't promoted.
1616
1717
use rustc_data_structures::bitvec::BitVector;
18+
use rustc_data_structures::indexed_set::IdxSetBuf;
1819
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
1920
use rustc::hir;
2021
use rustc::hir::map as hir_map;
@@ -33,6 +34,7 @@ use syntax::feature_gate::UnstableFeatures;
3334
use syntax_pos::{Span, DUMMY_SP};
3435

3536
use std::fmt;
37+
use std::rc::Rc;
3638
use std::usize;
3739

3840
use super::promote_consts::{self, Candidate, TempState};
@@ -127,7 +129,6 @@ struct Qualifier<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
127129

128130
impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
129131
fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
130-
param_env: ty::ParamEnv<'tcx>,
131132
def_id: DefId,
132133
mir: &'a Mir<'tcx>,
133134
mode: Mode)
@@ -142,7 +143,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
142143
mir,
143144
rpo,
144145
tcx,
145-
param_env,
146+
param_env: tcx.param_env(def_id),
146147
temp_qualif: IndexVec::from_elem(None, &mir.local_decls),
147148
return_qualif: None,
148149
qualif: Qualif::empty(),
@@ -368,7 +369,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
368369
}
369370

370371
/// Qualify a whole const, static initializer or const fn.
371-
fn qualify_const(&mut self) -> Qualif {
372+
fn qualify_const(&mut self) -> (Qualif, Rc<IdxSetBuf<Local>>) {
372373
debug!("qualifying {} {:?}", self.mode, self.def_id);
373374

374375
let mir = self.mir;
@@ -390,7 +391,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
390391

391392
// Non-terminating calls cannot produce any value.
392393
TerminatorKind::Call { destination: None, .. } => {
393-
return Qualif::empty();
394+
break;
394395
}
395396

396397
TerminatorKind::SwitchInt {..} |
@@ -472,7 +473,25 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
472473
}
473474
}
474475
}
475-
self.qualif
476+
477+
// Collect all the temps we need to promote.
478+
let mut promoted_temps = IdxSetBuf::new_empty(self.temp_promotion_state.len());
479+
480+
for candidate in &self.promotion_candidates {
481+
match *candidate {
482+
Candidate::Ref(Location { block: bb, statement_index: stmt_idx }) => {
483+
match self.mir[bb].statements[stmt_idx].kind {
484+
StatementKind::Assign(_, Rvalue::Ref(_, _, Lvalue::Local(index))) => {
485+
promoted_temps.add(&index);
486+
}
487+
_ => {}
488+
}
489+
}
490+
Candidate::ShuffleIndices(_) => {}
491+
}
492+
}
493+
494+
(self.qualif, Rc::new(promoted_temps))
476495
}
477496
}
478497

@@ -516,6 +535,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
516535
span_err!(self.tcx.sess, self.span, E0625,
517536
"thread-local statics cannot be \
518537
accessed at compile-time");
538+
self.add(Qualif::NOT_CONST);
519539
return;
520540
}
521541
}
@@ -598,7 +618,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
598618
if self.tcx.trait_of_item(def_id).is_some() {
599619
self.add_type(constant.ty);
600620
} else {
601-
let bits = self.tcx.at(constant.span).mir_const_qualif(def_id);
621+
let (bits, _) = self.tcx.at(constant.span).mir_const_qualif(def_id);
602622

603623
let qualif = Qualif::from_bits(bits).expect("invalid mir_const_qualif");
604624
self.add(qualif);
@@ -702,13 +722,11 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
702722

703723
// We might have a candidate for promotion.
704724
let candidate = Candidate::Ref(location);
705-
if self.mode == Mode::Fn || self.mode == Mode::ConstFn {
706-
if !self.qualif.intersects(Qualif::NEVER_PROMOTE) {
707-
// We can only promote direct borrows of temps.
708-
if let Lvalue::Local(local) = *lvalue {
709-
if self.mir.local_kind(local) == LocalKind::Temp {
710-
self.promotion_candidates.push(candidate);
711-
}
725+
if !self.qualif.intersects(Qualif::NEVER_PROMOTE) {
726+
// We can only promote direct borrows of temps.
727+
if let Lvalue::Local(local) = *lvalue {
728+
if self.mir.local_kind(local) == LocalKind::Temp {
729+
self.promotion_candidates.push(candidate);
712730
}
713731
}
714732
}
@@ -999,21 +1017,21 @@ pub fn provide(providers: &mut Providers) {
9991017

10001018
fn mir_const_qualif<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
10011019
def_id: DefId)
1002-
-> u8 {
1020+
-> (u8, Rc<IdxSetBuf<Local>>) {
10031021
// NB: This `borrow()` is guaranteed to be valid (i.e., the value
10041022
// cannot yet be stolen), because `mir_validated()`, which steals
10051023
// from `mir_const(), forces this query to execute before
10061024
// performing the steal.
10071025
let mir = &tcx.mir_const(def_id).borrow();
10081026

10091027
if mir.return_ty.references_error() {
1010-
return Qualif::NOT_CONST.bits();
1028+
tcx.sess.delay_span_bug(mir.span, "mir_const_qualif: Mir had errors");
1029+
return (Qualif::NOT_CONST.bits(), Rc::new(IdxSetBuf::new_empty(0)));
10111030
}
10121031

1013-
let param_env = tcx.param_env(def_id);
1014-
1015-
let mut qualifier = Qualifier::new(tcx, param_env, def_id, mir, Mode::Const);
1016-
qualifier.qualify_const().bits()
1032+
let mut qualifier = Qualifier::new(tcx, def_id, mir, Mode::Const);
1033+
let (qualif, promoted_temps) = qualifier.qualify_const();
1034+
(qualif.bits(), promoted_temps)
10171035
}
10181036

10191037
pub struct QualifyAndPromoteConstants;
@@ -1023,8 +1041,15 @@ impl MirPass for QualifyAndPromoteConstants {
10231041
tcx: TyCtxt<'a, 'tcx, 'tcx>,
10241042
src: MirSource,
10251043
mir: &mut Mir<'tcx>) {
1044+
// There's not really any point in promoting errorful MIR.
1045+
if mir.return_ty.references_error() {
1046+
tcx.sess.delay_span_bug(mir.span, "QualifyAndPromoteConstants: Mir had errors");
1047+
return;
1048+
}
1049+
10261050
let id = src.item_id();
10271051
let def_id = tcx.hir.local_def_id(id);
1052+
let mut const_promoted_temps = None;
10281053
let mode = match src {
10291054
MirSource::Fn(_) => {
10301055
if tcx.is_const_fn(def_id) {
@@ -1033,20 +1058,21 @@ impl MirPass for QualifyAndPromoteConstants {
10331058
Mode::Fn
10341059
}
10351060
}
1061+
MirSource::Const(_) => {
1062+
const_promoted_temps = Some(tcx.mir_const_qualif(def_id).1);
1063+
Mode::Const
1064+
}
10361065
MirSource::Static(_, hir::MutImmutable) => Mode::Static,
10371066
MirSource::Static(_, hir::MutMutable) => Mode::StaticMut,
10381067
MirSource::GeneratorDrop(_) |
1039-
MirSource::Const(_) |
10401068
MirSource::Promoted(..) => return
10411069
};
1042-
let param_env = tcx.param_env(def_id);
10431070

10441071
if mode == Mode::Fn || mode == Mode::ConstFn {
10451072
// This is ugly because Qualifier holds onto mir,
10461073
// which can't be mutated until its scope ends.
10471074
let (temps, candidates) = {
1048-
let mut qualifier = Qualifier::new(tcx, param_env,
1049-
def_id, mir, mode);
1075+
let mut qualifier = Qualifier::new(tcx, def_id, mir, mode);
10501076
if mode == Mode::ConstFn {
10511077
// Enforce a constant-like CFG for `const fn`.
10521078
qualifier.qualify_const();
@@ -1062,8 +1088,37 @@ impl MirPass for QualifyAndPromoteConstants {
10621088
// Do the actual promotion, now that we know what's viable.
10631089
promote_consts::promote_candidates(mir, tcx, temps, candidates);
10641090
} else {
1065-
let mut qualifier = Qualifier::new(tcx, param_env, def_id, mir, mode);
1066-
qualifier.qualify_const();
1091+
let promoted_temps = if mode == Mode::Const {
1092+
// Already computed by `mir_const_qualif`.
1093+
const_promoted_temps.unwrap()
1094+
} else {
1095+
Qualifier::new(tcx, def_id, mir, mode).qualify_const().1
1096+
};
1097+
1098+
// In `const` and `static` everything without `StorageDead`
1099+
// is `'static`, we don't have to create promoted MIR fragments,
1100+
// just remove `Drop` and `StorageDead` on "promoted" locals.
1101+
for block in mir.basic_blocks_mut() {
1102+
block.statements.retain(|statement| {
1103+
match statement.kind {
1104+
StatementKind::StorageDead(Lvalue::Local(index)) => {
1105+
!promoted_temps.contains(&index)
1106+
}
1107+
_ => true
1108+
}
1109+
});
1110+
let terminator = block.terminator_mut();
1111+
match terminator.kind {
1112+
TerminatorKind::Drop { location: Lvalue::Local(index), target, .. } => {
1113+
if promoted_temps.contains(&index) {
1114+
terminator.kind = TerminatorKind::Goto {
1115+
target,
1116+
};
1117+
}
1118+
}
1119+
_ => {}
1120+
}
1121+
}
10671122
}
10681123

10691124
// Statics must be Sync.

0 commit comments

Comments
 (0)