Don't track local_needs_drop separately in qualify_consts (fixes #47351).
This commit is contained in:
parent
73ac5d6a80
commit
e2c1a9393b
@ -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 {
|
||||
|
@ -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 () {}
|
||||
|
Loading…
Reference in New Issue
Block a user