Change:
These currently compile, even if they can be used from compile-time code to trigger a drop: cc

Discussion:
return_qualif: Option<Qualif>, qualif: Qualif, const_fn_arg_vars: BitVector, <del> local_needs_drop: IndexVec<Local, Option<Span>>, </del> temp_promotion_state: IndexVec<Local, TempState>, promotion_candidates: Vec<Candidate> }

let mut rpo = traversal::reverse_postorder(mir); let temps = promote_consts::collect_temps(mir, &mut rpo); rpo.reset(); <ins> 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); } </ins> Qualifier { mode, span: mir.span,

mir, rpo, tcx, <del> param_env: tcx.param_env(def_id), temp_qualif: IndexVec::from_elem(None, &mir.local_decls), </del> <ins> param_env, temp_qualif, </ins> return_qualif: None, qualif: Qualif::empty(), const_fn_arg_vars: BitVector::new(mir.local_decls.len()), <del> local_needs_drop: IndexVec::from_elem(None, &mir.local_decls), </del> temp_promotion_state: temps, promotion_candidates: vec![] }

return; } <del> // 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); } } </del> match *dest { Place::Local(index) if self.mir.local_kind(index) == LocalKind::Temp => { debug!("store to temp {:?}", index);

&local: &Local, _: PlaceContext<'tcx>, _: Location) { <del> match self.mir.local_kind(local) { </del> <ins> let kind = self.mir.local_kind(local); match kind { </ins> LocalKind::ReturnPointer => { self.not_const(); } <del> LocalKind::Arg => { self.add(Qualif::FN_ARGUMENT); } </del> LocalKind::Var => { self.add(Qualif::NOT_CONST); } <ins> LocalKind::Arg | </ins> LocalKind::Temp => { <ins> if let LocalKind::Arg = kind { self.add(Qualif::FN_ARGUMENT); } </ins> if !self.temp_promotion_state[local].is_promotable() { self.add(Qualif::NOT_PROMOTABLE); }

fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) { match *operand { <del> Operand::Copy(ref place) | Operand::Move(ref place) => { </del> <ins> Operand::Copy(_) | Operand::Move(_) => { </ins> self.nest(|this| { this.super_operand(operand, location); this.try_consume(); }); // Mark the consumed locals to indicate later drops are noops. <del> if let Place::Local(local) = *place { self.local_needs_drop[local] = None; </del> <ins> if let Operand::Move(Place::Local(local)) = *operand { self.temp_qualif[local] = self.temp_qualif[local].map(|q| q - Qualif::NEEDS_DROP ); </ins> } } Operand::Constant(ref constant) => {

// HACK(eddyb) Emulate a bit of dataflow analysis, // conservatively, that drop elaboration will do. let needs_drop = if let Place::Local(local) = *place { <del> self.local_needs_drop[local] </del> <ins> 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 } </ins> } else { <del> None </del> <ins> Some(self.span) </ins> }; if let Some(span) = needs_drop {

// option. This file may not be copied, modified, or distributed // except according to those terms. <ins> #![feature(const_fn)] </ins> struct WithDtor; impl Drop for WithDtor {

const EARLY_DROP_C: i32 = (WithDtor, 0).1; //~^ ERROR destructors cannot be evaluated at compile-time <ins> 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 } </ins> fn main () {}