Skip to content

Commit f2c8628

Browse files
committed
rustc_mir: use the new validator's Qualif in promotion.
1 parent 6c55fb8 commit f2c8628

File tree

6 files changed

+120
-49
lines changed

6 files changed

+120
-49
lines changed

src/librustc_mir/transform/check_consts/mod.rs

+24-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use rustc::ty::{self, TyCtxt};
1111
pub use self::qualifs::Qualif;
1212

1313
pub mod ops;
14-
mod qualifs;
14+
pub mod qualifs;
1515
mod resolver;
1616
pub mod validation;
1717

@@ -23,6 +23,7 @@ pub struct Item<'mir, 'tcx> {
2323
def_id: DefId,
2424
param_env: ty::ParamEnv<'tcx>,
2525
mode: validation::Mode,
26+
for_promotion: bool,
2627
}
2728

2829
impl Item<'mir, 'tcx> {
@@ -41,6 +42,28 @@ impl Item<'mir, 'tcx> {
4142
def_id,
4243
param_env,
4344
mode,
45+
for_promotion: false,
46+
}
47+
}
48+
49+
// HACK(eddyb) this is to get around the panic for a runtime fn from `Item::new`.
50+
// Also, it allows promoting `&mut []`.
51+
pub fn for_promotion(
52+
tcx: TyCtxt<'tcx>,
53+
def_id: DefId,
54+
body: &'mir mir::Body<'tcx>,
55+
) -> Self {
56+
let param_env = tcx.param_env(def_id);
57+
let mode = validation::Mode::for_item(tcx, def_id)
58+
.unwrap_or(validation::Mode::ConstFn);
59+
60+
Item {
61+
body,
62+
tcx,
63+
def_id,
64+
param_env,
65+
mode,
66+
for_promotion: true,
4467
}
4568
}
4669
}

src/librustc_mir/transform/check_consts/qualifs.rs

+28-18
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
use rustc::mir::*;
44
use rustc::mir::interpret::ConstValue;
55
use rustc::ty::{self, Ty};
6-
use rustc_index::bit_set::BitSet;
76
use syntax_pos::DUMMY_SP;
87

98
use super::Item as ConstCx;
@@ -44,7 +43,7 @@ pub trait Qualif {
4443

4544
fn in_projection_structurally(
4645
cx: &ConstCx<'_, 'tcx>,
47-
per_local: &BitSet<Local>,
46+
per_local: &impl Fn(Local) -> bool,
4847
place: PlaceRef<'_, 'tcx>,
4948
) -> bool {
5049
if let [proj_base @ .., elem] = place.projection {
@@ -65,7 +64,7 @@ pub trait Qualif {
6564
ProjectionElem::ConstantIndex { .. } |
6665
ProjectionElem::Downcast(..) => qualif,
6766

68-
ProjectionElem::Index(local) => qualif || per_local.contains(*local),
67+
ProjectionElem::Index(local) => qualif || per_local(*local),
6968
}
7069
} else {
7170
bug!("This should be called if projection is not empty");
@@ -74,22 +73,22 @@ pub trait Qualif {
7473

7574
fn in_projection(
7675
cx: &ConstCx<'_, 'tcx>,
77-
per_local: &BitSet<Local>,
76+
per_local: &impl Fn(Local) -> bool,
7877
place: PlaceRef<'_, 'tcx>,
7978
) -> bool {
8079
Self::in_projection_structurally(cx, per_local, place)
8180
}
8281

8382
fn in_place(
8483
cx: &ConstCx<'_, 'tcx>,
85-
per_local: &BitSet<Local>,
84+
per_local: &impl Fn(Local) -> bool,
8685
place: PlaceRef<'_, 'tcx>,
8786
) -> bool {
8887
match place {
8988
PlaceRef {
9089
base: PlaceBase::Local(local),
9190
projection: [],
92-
} => per_local.contains(*local),
91+
} => per_local(*local),
9392
PlaceRef {
9493
base: PlaceBase::Static(box Static {
9594
kind: StaticKind::Promoted(..),
@@ -112,7 +111,7 @@ pub trait Qualif {
112111

113112
fn in_operand(
114113
cx: &ConstCx<'_, 'tcx>,
115-
per_local: &BitSet<Local>,
114+
per_local: &impl Fn(Local) -> bool,
116115
operand: &Operand<'tcx>,
117116
) -> bool {
118117
match *operand {
@@ -143,7 +142,7 @@ pub trait Qualif {
143142

144143
fn in_rvalue_structurally(
145144
cx: &ConstCx<'_, 'tcx>,
146-
per_local: &BitSet<Local>,
145+
per_local: &impl Fn(Local) -> bool,
147146
rvalue: &Rvalue<'tcx>,
148147
) -> bool {
149148
match *rvalue {
@@ -185,13 +184,17 @@ pub trait Qualif {
185184
}
186185
}
187186

188-
fn in_rvalue(cx: &ConstCx<'_, 'tcx>, per_local: &BitSet<Local>, rvalue: &Rvalue<'tcx>) -> bool {
187+
fn in_rvalue(
188+
cx: &ConstCx<'_, 'tcx>,
189+
per_local: &impl Fn(Local) -> bool,
190+
rvalue: &Rvalue<'tcx>,
191+
) -> bool {
189192
Self::in_rvalue_structurally(cx, per_local, rvalue)
190193
}
191194

192195
fn in_call(
193196
cx: &ConstCx<'_, 'tcx>,
194-
_per_local: &BitSet<Local>,
197+
_per_local: &impl Fn(Local) -> bool,
195198
_callee: &Operand<'tcx>,
196199
_args: &[Operand<'tcx>],
197200
return_ty: Ty<'tcx>,
@@ -216,7 +219,11 @@ impl Qualif for HasMutInterior {
216219
!ty.is_freeze(cx.tcx, cx.param_env, DUMMY_SP)
217220
}
218221

219-
fn in_rvalue(cx: &ConstCx<'_, 'tcx>, per_local: &BitSet<Local>, rvalue: &Rvalue<'tcx>) -> bool {
222+
fn in_rvalue(
223+
cx: &ConstCx<'_, 'tcx>,
224+
per_local: &impl Fn(Local) -> bool,
225+
rvalue: &Rvalue<'tcx>,
226+
) -> bool {
220227
match *rvalue {
221228
// Returning `true` for `Rvalue::Ref` indicates the borrow isn't
222229
// allowed in constants (and the `Checker` will error), and/or it
@@ -231,12 +238,11 @@ impl Qualif for HasMutInterior {
231238
// Inside a `static mut`, &mut [...] is also allowed.
232239
ty::Array(..) | ty::Slice(_) if cx.mode == Mode::StaticMut => {},
233240

234-
// FIXME(ecstaticmorse): uncomment the following match arm to stop marking
235-
// `&mut []` as `HasMutInterior`.
236-
/*
237-
ty::Array(_, len) if len.try_eval_usize(cx.tcx, cx.param_env) == Some(0)
238-
=> {},
239-
*/
241+
// FIXME(eddyb) the `cx.for_promotion` condition
242+
// seems unnecessary, given that this is merely a ZST.
243+
ty::Array(_, len)
244+
if len.try_eval_usize(cx.tcx, cx.param_env) == Some(0)
245+
&& cx.for_promotion => {},
240246

241247
_ => return true,
242248
}
@@ -275,7 +281,11 @@ impl Qualif for NeedsDrop {
275281
ty.needs_drop(cx.tcx, cx.param_env)
276282
}
277283

278-
fn in_rvalue(cx: &ConstCx<'_, 'tcx>, per_local: &BitSet<Local>, rvalue: &Rvalue<'tcx>) -> bool {
284+
fn in_rvalue(
285+
cx: &ConstCx<'_, 'tcx>,
286+
per_local: &impl Fn(Local) -> bool,
287+
rvalue: &Rvalue<'tcx>,
288+
) -> bool {
279289
if let Rvalue::Aggregate(ref kind, _) = *rvalue {
280290
if let AggregateKind::Adt(def, ..) = **kind {
281291
if def.has_dtor(cx.tcx) {

src/librustc_mir/transform/check_consts/resolver.rs

+9-3
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,13 @@ where
8181
return_place: &mir::Place<'tcx>,
8282
) {
8383
let return_ty = return_place.ty(self.item.body, self.item.tcx).ty;
84-
let qualif = Q::in_call(self.item, &mut self.qualifs_per_local, func, args, return_ty);
84+
let qualif = Q::in_call(
85+
self.item,
86+
&|l| self.qualifs_per_local.contains(l),
87+
func,
88+
args,
89+
return_ty,
90+
);
8591
if !return_place.is_indirect() {
8692
self.assign_qualif_direct(return_place, qualif);
8793
}
@@ -114,7 +120,7 @@ where
114120
rvalue: &mir::Rvalue<'tcx>,
115121
location: Location,
116122
) {
117-
let qualif = Q::in_rvalue(self.item, self.qualifs_per_local, rvalue);
123+
let qualif = Q::in_rvalue(self.item, &|l| self.qualifs_per_local.contains(l), rvalue);
118124
if !place.is_indirect() {
119125
self.assign_qualif_direct(place, qualif);
120126
}
@@ -129,7 +135,7 @@ where
129135
// here; that occurs in `apply_call_return_effect`.
130136

131137
if let mir::TerminatorKind::DropAndReplace { value, location: dest, .. } = kind {
132-
let qualif = Q::in_operand(self.item, self.qualifs_per_local, value);
138+
let qualif = Q::in_operand(self.item, &|l| self.qualifs_per_local.contains(l), value);
133139
if !dest.is_indirect() {
134140
self.assign_qualif_direct(dest, qualif);
135141
}

src/librustc_mir/transform/check_consts/validation.rs

+4-5
Original file line numberDiff line numberDiff line change
@@ -369,11 +369,10 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
369369
// it depends on `HasMutInterior` being set for mutable borrows as well as values with
370370
// interior mutability.
371371
if let Rvalue::Ref(_, kind, ref borrowed_place) = *rvalue {
372-
let rvalue_has_mut_interior = HasMutInterior::in_rvalue(
373-
&self.item,
374-
self.qualifs.has_mut_interior.get(),
375-
rvalue,
376-
);
372+
let rvalue_has_mut_interior = {
373+
let has_mut_interior = self.qualifs.has_mut_interior.get();
374+
HasMutInterior::in_rvalue(&self.item, &|l| has_mut_interior.contains(l), rvalue)
375+
};
377376

378377
if rvalue_has_mut_interior {
379378
let is_derived_from_illegal_borrow = match borrowed_place.as_local() {

src/librustc_mir/transform/promote_consts.rs

+55-20
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,13 @@ use syntax::ast::LitKind;
2525
use syntax::symbol::sym;
2626
use syntax_pos::{Span, DUMMY_SP};
2727

28-
use rustc_index::bit_set::BitSet;
2928
use rustc_index::vec::{IndexVec, Idx};
3029
use rustc_target::spec::abi::Abi;
3130

3231
use std::{iter, mem, usize};
3332

33+
use crate::transform::check_consts::{qualifs, Item as ConstCx};
34+
3435
/// State of a temporary during collection and promotion.
3536
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
3637
pub enum TempState {
@@ -231,9 +232,9 @@ struct Validator<'a, 'tcx> {
231232
is_static_mut: bool,
232233
is_non_const_fn: bool,
233234
temps: &'a IndexVec<Local, TempState>,
234-
// FIXME(eddyb) compute these 2 on the fly.
235-
has_mut_interior: &'a BitSet<Local>,
236-
needs_drop: &'a BitSet<Local>,
235+
236+
// FIXME(eddyb) deduplicate the data in this vs other fields.
237+
const_cx: ConstCx<'a, 'tcx>,
237238

238239
/// Explicit promotion happens e.g. for constant arguments declared via
239240
/// `rustc_args_required_const`.
@@ -276,15 +277,17 @@ impl<'tcx> Validator<'_, 'tcx> {
276277
PlaceBase::Local(local) => local,
277278
_ => return Err(Unpromotable),
278279
};
280+
self.validate_local(base)?;
281+
279282
if place.projection.contains(&ProjectionElem::Deref) {
280283
return Err(Unpromotable);
281284
}
282285

283-
// FIXME(eddyb) compute this on the fly.
284-
let mut has_mut_interior = self.has_mut_interior.contains(base);
286+
let mut has_mut_interior =
287+
self.qualif_local::<qualifs::HasMutInterior>(base);
285288
// HACK(eddyb) this should compute the same thing as
286289
// `<HasMutInterior as Qualif>::in_projection` from
287-
// `qualify_consts` but without recursion.
290+
// `check_consts::qualifs` but without recursion.
288291
if has_mut_interior {
289292
// This allows borrowing fields which don't have
290293
// `HasMutInterior`, from a type that does, e.g.:
@@ -311,8 +314,7 @@ impl<'tcx> Validator<'_, 'tcx> {
311314
if has_mut_interior {
312315
return Err(Unpromotable);
313316
}
314-
// FIXME(eddyb) compute this on the fly.
315-
if self.needs_drop.contains(base) {
317+
if self.qualif_local::<qualifs::NeedsDrop>(base) {
316318
return Err(Unpromotable);
317319
}
318320
if let BorrowKind::Mut { .. } = kind {
@@ -339,7 +341,7 @@ impl<'tcx> Validator<'_, 'tcx> {
339341
}
340342
}
341343

342-
self.validate_local(base)
344+
Ok(())
343345
}
344346
_ => bug!()
345347
}
@@ -373,6 +375,42 @@ impl<'tcx> Validator<'_, 'tcx> {
373375
}
374376
}
375377

378+
// FIXME(eddyb) maybe cache this?
379+
fn qualif_local<Q: qualifs::Qualif>(&self, local: Local) -> bool {
380+
let per_local = &|l| self.qualif_local::<Q>(l);
381+
382+
if let TempState::Defined { location: loc, .. } = self.temps[local] {
383+
let num_stmts = self.body[loc.block].statements.len();
384+
385+
if loc.statement_index < num_stmts {
386+
let statement = &self.body[loc.block].statements[loc.statement_index];
387+
match &statement.kind {
388+
StatementKind::Assign(box(_, rhs)) => {
389+
Q::in_rvalue(&self.const_cx, per_local, rhs)
390+
}
391+
_ => {
392+
span_bug!(statement.source_info.span, "{:?} is not an assignment",
393+
statement);
394+
}
395+
}
396+
} else {
397+
let terminator = self.body[loc.block].terminator();
398+
match &terminator.kind {
399+
TerminatorKind::Call { func, args, .. } => {
400+
let return_ty = self.body.local_decls[local].ty;
401+
Q::in_call(&self.const_cx, per_local, func, args, return_ty)
402+
}
403+
kind => {
404+
span_bug!(terminator.source_info.span, "{:?} not promotable", kind);
405+
}
406+
}
407+
}
408+
} else {
409+
let span = self.body.local_decls[local].source_info.span;
410+
span_bug!(span, "{:?} not promotable, qualif_local shouldn't have been called", local);
411+
}
412+
}
413+
376414
// FIXME(eddyb) maybe cache this?
377415
fn validate_local(&self, local: Local) -> Result<(), Unpromotable> {
378416
if let TempState::Defined { location: loc, .. } = self.temps[local] {
@@ -593,13 +631,14 @@ impl<'tcx> Validator<'_, 'tcx> {
593631
}
594632
}
595633

634+
self.validate_place(place)?;
635+
596636
// HACK(eddyb) this should compute the same thing as
597637
// `<HasMutInterior as Qualif>::in_projection` from
598-
// `qualify_consts` but without recursion.
638+
// `check_consts::qualifs` but without recursion.
599639
let mut has_mut_interior = match place.base {
600640
PlaceBase::Local(local) => {
601-
// FIXME(eddyb) compute this on the fly.
602-
self.has_mut_interior.contains(*local)
641+
self.qualif_local::<qualifs::HasMutInterior>(*local)
603642
}
604643
PlaceBase::Static(_) => false,
605644
};
@@ -624,7 +663,7 @@ impl<'tcx> Validator<'_, 'tcx> {
624663
return Err(Unpromotable);
625664
}
626665

627-
self.validate_place(place)
666+
Ok(())
628667
}
629668

630669
Rvalue::Aggregate(_, ref operands) => {
@@ -680,9 +719,6 @@ pub fn validate_candidates(
680719
body: &Body<'tcx>,
681720
def_id: DefId,
682721
temps: &IndexVec<Local, TempState>,
683-
// FIXME(eddyb) compute these 2 on the fly.
684-
has_mut_interior: &BitSet<Local>,
685-
needs_drop: &BitSet<Local>,
686722
candidates: &[Candidate],
687723
) -> Vec<Candidate> {
688724
let mut validator = Validator {
@@ -693,9 +729,8 @@ pub fn validate_candidates(
693729
is_static_mut: false,
694730
is_non_const_fn: false,
695731
temps,
696-
// FIXME(eddyb) compute these 2 on the fly.
697-
has_mut_interior,
698-
needs_drop,
732+
733+
const_cx: ConstCx::for_promotion(tcx, def_id, body),
699734

700735
explicit: false,
701736
};

src/librustc_mir/transform/qualify_consts.rs

-2
Original file line numberDiff line numberDiff line change
@@ -1118,8 +1118,6 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
11181118
self.body,
11191119
self.def_id,
11201120
&self.temp_promotion_state,
1121-
&self.per_local.0[HasMutInterior::IDX],
1122-
&self.per_local.0[NeedsDrop::IDX],
11231121
&self.unchecked_promotion_candidates,
11241122
);
11251123

0 commit comments

Comments
 (0)