@@ -120,6 +120,7 @@ struct Qualifier<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
120
120
return_qualif : Option < Qualif > ,
121
121
qualif : Qualif ,
122
122
const_fn_arg_vars : BitVector ,
123
+ local_needs_drop : IndexVec < Local , Option < Span > > ,
123
124
temp_promotion_state : IndexVec < Local , TempState > ,
124
125
promotion_candidates : Vec < Candidate >
125
126
}
@@ -146,6 +147,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
146
147
return_qualif : None ,
147
148
qualif : Qualif :: empty ( ) ,
148
149
const_fn_arg_vars : BitVector :: new ( mir. local_decls . len ( ) ) ,
150
+ local_needs_drop : IndexVec :: from_elem ( None , & mir. local_decls ) ,
149
151
temp_promotion_state : temps,
150
152
promotion_candidates : vec ! [ ]
151
153
}
@@ -193,16 +195,26 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
193
195
self . add ( original) ;
194
196
}
195
197
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
+
196
204
/// Check for NEEDS_DROP (from an ADT or const fn call) and
197
205
/// error, unless we're in a function, or the feature-gate
198
206
/// for globals with destructors is enabled.
199
207
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 ) {
200
212
if self . mode == Mode :: Fn || !self . qualif . intersects ( Qualif :: NEEDS_DROP ) {
201
213
return ;
202
214
}
203
215
204
216
// 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 {
206
218
// Feature-gate for globals with destructors is enabled.
207
219
if self . tcx . sess . features . borrow ( ) . drop_types_in_const {
208
220
return ;
@@ -223,15 +235,16 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
223
235
let mut err =
224
236
struct_span_err ! ( self . tcx. sess, self . span, E0493 , "{}" , msg) ;
225
237
226
- if self . mode != Mode :: Const {
238
+ if allow_gate && self . mode != Mode :: Const {
227
239
help ! ( & mut err,
228
240
"in Nightly builds, add `#![feature(drop_types_in_const)]` \
229
241
to the crate attributes to enable") ;
230
242
} else {
231
243
self . find_drop_implementation_method_span ( )
232
244
. map ( |span| err. span_label ( span, "destructor defined here" ) ) ;
233
245
234
- err. span_label ( self . span , "constants cannot have destructors" ) ;
246
+ err. span_label ( self . span ,
247
+ format ! ( "{}s cannot have destructors" , self . mode) ) ;
235
248
}
236
249
237
250
err. emit ( ) ;
@@ -314,6 +327,15 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
314
327
return ;
315
328
}
316
329
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
+
317
339
match * dest {
318
340
Lvalue :: Local ( index) if self . mir . local_kind ( index) == LocalKind :: Temp => {
319
341
debug ! ( "store to temp {:?}" , index) ;
@@ -360,7 +382,6 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
360
382
361
383
let target = match mir[ bb] . terminator ( ) . kind {
362
384
TerminatorKind :: Goto { target } |
363
- // Drops are considered noops.
364
385
TerminatorKind :: Drop { target, .. } |
365
386
TerminatorKind :: Assert { target, .. } |
366
387
TerminatorKind :: Call { destination : Some ( ( _, target) ) , .. } => {
@@ -558,11 +579,16 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
558
579
559
580
fn visit_operand ( & mut self , operand : & Operand < ' tcx > , location : Location ) {
560
581
match * operand {
561
- Operand :: Consume ( _ ) => {
582
+ Operand :: Consume ( ref lvalue ) => {
562
583
self . nest ( |this| {
563
584
this. super_operand ( operand, location) ;
564
585
this. try_consume ( ) ;
565
586
} ) ;
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
+ }
566
592
}
567
593
Operand :: Constant ( ref constant) => {
568
594
if let Literal :: Item { def_id, substs } = constant. literal {
@@ -864,6 +890,30 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
864
890
}
865
891
self . assign ( dest, location) ;
866
892
}
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
+ }
867
917
} else {
868
918
// Qualify any operands inside other terminators.
869
919
self . super_terminator_kind ( bb, kind, location) ;
0 commit comments