Don't track local_needs_drop separately in qualify_consts (fixes #47351).

This commit is contained in:
Alexander Regueiro 2018-01-10 02:57:50 +00:00
parent 73ac5d6a80
commit e2c1a9393b
2 changed files with 41 additions and 23 deletions

View File

@ -122,7 +122,6 @@ struct Qualifier<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
return_qualif: Option<Qualif>,
qualif: Qualif,
const_fn_arg_vars: BitVector,
local_needs_drop: IndexVec<Local, Option<Span>>,
temp_promotion_state: IndexVec<Local, TempState>,
promotion_candidates: Vec<Candidate>
}
@ -136,6 +135,16 @@ fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let mut rpo = traversal::reverse_postorder(mir);
let temps = promote_consts::collect_temps(mir, &mut rpo);
rpo.reset();
let param_env = tcx.param_env(def_id);
let mut temp_qualif = IndexVec::from_elem(None, &mir.local_decls);
for arg in mir.args_iter() {
let mut qualif = Qualif::NEEDS_DROP;
qualif.restrict(mir.local_decls[arg].ty, tcx, param_env);
temp_qualif[arg] = Some(qualif);
}
Qualifier {
mode,
span: mir.span,
@ -143,12 +152,11 @@ fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
mir,
rpo,
tcx,
param_env: tcx.param_env(def_id),
temp_qualif: IndexVec::from_elem(None, &mir.local_decls),
param_env,
temp_qualif,
return_qualif: None,
qualif: Qualif::empty(),
const_fn_arg_vars: BitVector::new(mir.local_decls.len()),
local_needs_drop: IndexVec::from_elem(None, &mir.local_decls),
temp_promotion_state: temps,
promotion_candidates: vec![]
}
@ -255,15 +263,6 @@ fn assign(&mut self, dest: &Place<'tcx>, location: Location) {
return;
}
// When initializing a local, record whether the *value* being
// stored in it needs dropping, which it may not, even if its
// type does, e.g. `None::<String>`.
if let Place::Local(local) = *dest {
if qualif.intersects(Qualif::NEEDS_DROP) {
self.local_needs_drop[local] = Some(self.span);
}
}
match *dest {
Place::Local(index) if self.mir.local_kind(index) == LocalKind::Temp => {
debug!("store to temp {:?}", index);
@ -424,17 +423,20 @@ fn visit_local(&mut self,
&local: &Local,
_: PlaceContext<'tcx>,
_: Location) {
match self.mir.local_kind(local) {
let kind = self.mir.local_kind(local);
match kind {
LocalKind::ReturnPointer => {
self.not_const();
}
LocalKind::Arg => {
self.add(Qualif::FN_ARGUMENT);
}
LocalKind::Var => {
self.add(Qualif::NOT_CONST);
}
LocalKind::Arg |
LocalKind::Temp => {
if let LocalKind::Arg = kind {
self.add(Qualif::FN_ARGUMENT);
}
if !self.temp_promotion_state[local].is_promotable() {
self.add(Qualif::NOT_PROMOTABLE);
}
@ -529,16 +531,18 @@ fn visit_place(&mut self,
fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
match *operand {
Operand::Copy(ref place) |
Operand::Move(ref place) => {
Operand::Copy(_) |
Operand::Move(_) => {
self.nest(|this| {
this.super_operand(operand, location);
this.try_consume();
});
// Mark the consumed locals to indicate later drops are noops.
if let Place::Local(local) = *place {
self.local_needs_drop[local] = None;
if let Operand::Move(Place::Local(local)) = *operand {
self.temp_qualif[local] = self.temp_qualif[local].map(|q|
q - Qualif::NEEDS_DROP
);
}
}
Operand::Constant(ref constant) => {
@ -847,9 +851,13 @@ struct and enum constructors",
// HACK(eddyb) Emulate a bit of dataflow analysis,
// conservatively, that drop elaboration will do.
let needs_drop = if let Place::Local(local) = *place {
self.local_needs_drop[local]
if self.temp_qualif[local].map_or(true, |q| q.intersects(Qualif::NEEDS_DROP)) {
Some(self.mir.local_decls[local].source_info.span)
} else {
None
}
} else {
None
Some(self.span)
};
if let Some(span) = needs_drop {

View File

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(const_fn)]
struct WithDtor;
impl Drop for WithDtor {
@ -28,4 +30,12 @@ fn drop(&mut self) {}
const EARLY_DROP_C: i32 = (WithDtor, 0).1;
//~^ ERROR destructors cannot be evaluated at compile-time
const fn const_drop<T>(_: T) {}
//~^ ERROR destructors cannot be evaluated at compile-time
const fn const_drop2<T>(x: T) {
(x, ()).1
//~^ ERROR destructors cannot be evaluated at compile-time
}
fn main () {}