@@ -120,6 +120,7 @@ struct Qualifier<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
120120 return_qualif : Option < Qualif > ,
121121 qualif : Qualif ,
122122 const_fn_arg_vars : BitVector ,
123+ local_needs_drop : IndexVec < Local , Option < Span > > ,
123124 temp_promotion_state : IndexVec < Local , TempState > ,
124125 promotion_candidates : Vec < Candidate >
125126}
@@ -146,6 +147,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
146147 return_qualif : None ,
147148 qualif : Qualif :: empty ( ) ,
148149 const_fn_arg_vars : BitVector :: new ( mir. local_decls . len ( ) ) ,
150+ local_needs_drop : IndexVec :: from_elem ( None , & mir. local_decls ) ,
149151 temp_promotion_state : temps,
150152 promotion_candidates : vec ! [ ]
151153 }
@@ -193,16 +195,26 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
193195 self . add ( original) ;
194196 }
195197
198+ /// Check for NEEDS_DROP (from an ADT or const fn call) and
199+ /// error, unless we're in a function.
200+ fn always_deny_drop ( & self ) {
201+ self . deny_drop_with_feature_gate_override ( false ) ;
202+ }
203+
196204 /// Check for NEEDS_DROP (from an ADT or const fn call) and
197205 /// error, unless we're in a function, or the feature-gate
198206 /// for globals with destructors is enabled.
199207 fn deny_drop ( & self ) {
208+ self . deny_drop_with_feature_gate_override ( true ) ;
209+ }
210+
211+ fn deny_drop_with_feature_gate_override ( & self , allow_gate : bool ) {
200212 if self . mode == Mode :: Fn || !self . qualif . intersects ( Qualif :: NEEDS_DROP ) {
201213 return ;
202214 }
203215
204216 // Static and const fn's allow destructors, but they're feature-gated.
205- let msg = if self . mode != Mode :: Const {
217+ let msg = if allow_gate && self . mode != Mode :: Const {
206218 // Feature-gate for globals with destructors is enabled.
207219 if self . tcx . sess . features . borrow ( ) . drop_types_in_const {
208220 return ;
@@ -223,15 +235,16 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
223235 let mut err =
224236 struct_span_err ! ( self . tcx. sess, self . span, E0493 , "{}" , msg) ;
225237
226- if self . mode != Mode :: Const {
238+ if allow_gate && self . mode != Mode :: Const {
227239 help ! ( & mut err,
228240 "in Nightly builds, add `#![feature(drop_types_in_const)]` \
229241 to the crate attributes to enable") ;
230242 } else {
231243 self . find_drop_implementation_method_span ( )
232244 . map ( |span| err. span_label ( span, "destructor defined here" ) ) ;
233245
234- err. span_label ( self . span , "constants cannot have destructors" ) ;
246+ err. span_label ( self . span ,
247+ format ! ( "{}s cannot have destructors" , self . mode) ) ;
235248 }
236249
237250 err. emit ( ) ;
@@ -314,6 +327,15 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
314327 return ;
315328 }
316329
330+ // When initializing a local, record whether the *value* being
331+ // stored in it needs dropping, which it may not, even if its
332+ // type does, e.g. `None::<String>`.
333+ if let Lvalue :: Local ( local) = * dest {
334+ if qualif. intersects ( Qualif :: NEEDS_DROP ) {
335+ self . local_needs_drop [ local] = Some ( self . span ) ;
336+ }
337+ }
338+
317339 match * dest {
318340 Lvalue :: Local ( index) if self . mir . local_kind ( index) == LocalKind :: Temp => {
319341 debug ! ( "store to temp {:?}" , index) ;
@@ -360,7 +382,6 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
360382
361383 let target = match mir[ bb] . terminator ( ) . kind {
362384 TerminatorKind :: Goto { target } |
363- // Drops are considered noops.
364385 TerminatorKind :: Drop { target, .. } |
365386 TerminatorKind :: Assert { target, .. } |
366387 TerminatorKind :: Call { destination : Some ( ( _, target) ) , .. } => {
@@ -558,11 +579,16 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
558579
559580 fn visit_operand ( & mut self , operand : & Operand < ' tcx > , location : Location ) {
560581 match * operand {
561- Operand :: Consume ( _ ) => {
582+ Operand :: Consume ( ref lvalue ) => {
562583 self . nest ( |this| {
563584 this. super_operand ( operand, location) ;
564585 this. try_consume ( ) ;
565586 } ) ;
587+
588+ // Mark the consumed locals to indicate later drops are noops.
589+ if let Lvalue :: Local ( local) = * lvalue {
590+ self . local_needs_drop [ local] = None ;
591+ }
566592 }
567593 Operand :: Constant ( ref constant) => {
568594 if let Literal :: Item { def_id, substs } = constant. literal {
@@ -864,6 +890,30 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
864890 }
865891 self . assign ( dest, location) ;
866892 }
893+ } else if let TerminatorKind :: Drop { location : ref lvalue, .. } = * kind {
894+ self . super_terminator_kind ( bb, kind, location) ;
895+
896+ // Deny *any* live drops anywhere other than functions.
897+ if self . mode != Mode :: Fn {
898+ // HACK(eddyb) Emulate a bit of dataflow analysis,
899+ // conservatively, that drop elaboration will do.
900+ let needs_drop = if let Lvalue :: Local ( local) = * lvalue {
901+ self . local_needs_drop [ local]
902+ } else {
903+ None
904+ } ;
905+
906+ if let Some ( span) = needs_drop {
907+ let ty = lvalue. ty ( self . mir , self . tcx ) . to_ty ( self . tcx ) ;
908+ self . add_type ( ty) ;
909+
910+ // Use the original assignment span to be more precise.
911+ let old_span = self . span ;
912+ self . span = span;
913+ self . always_deny_drop ( ) ;
914+ self . span = old_span;
915+ }
916+ }
867917 } else {
868918 // Qualify any operands inside other terminators.
869919 self . super_terminator_kind ( bb, kind, location) ;
0 commit comments