@@ -8,6 +8,9 @@ use super::ops;
8
8
use super :: qualifs:: { NeedsDrop , Qualif } ;
9
9
use super :: validation:: Qualifs ;
10
10
use super :: ConstCx ;
11
+ use crate :: dataflow:: drop_flag_effects:: on_all_drop_children_bits;
12
+ use crate :: dataflow:: move_paths:: MoveData ;
13
+ use crate :: dataflow:: { self , Analysis , MoveDataParamEnv , ResultsCursor } ;
11
14
12
15
/// Returns `true` if we should use the more precise live drop checker that runs after drop
13
16
/// elaboration.
@@ -31,14 +34,22 @@ pub fn check_live_drops(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &mir::Body<
31
34
32
35
let ccx = ConstCx { body, tcx, def_id, const_kind, param_env : tcx. param_env ( def_id) } ;
33
36
34
- let mut visitor = CheckLiveDrops { ccx : & ccx, qualifs : Qualifs :: default ( ) } ;
37
+ let mut visitor = CheckLiveDrops { ccx : & ccx, qualifs : Qualifs :: default ( ) , maybe_inits : None } ;
35
38
36
39
visitor. visit_body ( body) ;
37
40
}
38
41
42
+ type MaybeInits < ' mir , ' tcx > = ResultsCursor <
43
+ ' mir ,
44
+ ' tcx ,
45
+ dataflow:: impls:: MaybeInitializedPlaces < ' mir , ' tcx , MoveDataParamEnv < ' tcx > > ,
46
+ > ;
47
+
39
48
struct CheckLiveDrops < ' mir , ' tcx > {
40
49
ccx : & ' mir ConstCx < ' mir , ' tcx > ,
41
50
qualifs : Qualifs < ' mir , ' tcx > ,
51
+
52
+ maybe_inits : Option < MaybeInits < ' mir , ' tcx > > ,
42
53
}
43
54
44
55
// So we can access `body` and `tcx`.
@@ -83,7 +94,41 @@ impl Visitor<'tcx> for CheckLiveDrops<'mir, 'tcx> {
83
94
return ;
84
95
}
85
96
86
- if self . qualifs . needs_drop ( self . ccx , dropped_place. local , location) {
97
+ if !self . qualifs . needs_drop ( self . ccx , dropped_place. local , location) {
98
+ return ;
99
+ }
100
+
101
+ let ConstCx { param_env, body, tcx, def_id, .. } = * self . ccx ;
102
+
103
+ // Replicate some logic from drop elaboration during const-checking. If we know
104
+ // that the active variant of an enum does not have drop glue, we can allow it to
105
+ // be dropped.
106
+ let maybe_inits = self . maybe_inits . get_or_insert_with ( || {
107
+ let move_data = MoveData :: gather_moves ( body, tcx, param_env) . unwrap ( ) ;
108
+ let mdpe = MoveDataParamEnv { move_data, param_env } ;
109
+ dataflow:: impls:: MaybeInitializedPlaces :: new ( tcx, body, mdpe)
110
+ . mark_inactive_variants_as_uninit ( true )
111
+ . into_engine ( tcx, body, def_id. to_def_id ( ) )
112
+ . iterate_to_fixpoint ( )
113
+ . into_results_cursor ( body)
114
+ } ) ;
115
+ maybe_inits. seek_before_primary_effect ( location) ;
116
+ let mdpe = & maybe_inits. analysis ( ) . mdpe ;
117
+
118
+ let dropped_mpi = mdpe
119
+ . move_data
120
+ . rev_lookup
121
+ . find ( dropped_place. as_ref ( ) )
122
+ . expect_exact ( "All dropped places should have a move path" ) ;
123
+
124
+ let mut is_live_drop = false ;
125
+ on_all_drop_children_bits ( tcx, body, mdpe, dropped_mpi, |mpi| {
126
+ if maybe_inits. contains ( mpi) {
127
+ is_live_drop = true ;
128
+ }
129
+ } ) ;
130
+
131
+ if is_live_drop {
87
132
// Use the span where the dropped local was declared for the error.
88
133
let span = self . body . local_decls [ dropped_place. local ] . source_info . span ;
89
134
self . check_live_drop ( span) ;
0 commit comments