@@ -8,6 +8,9 @@ use super::ops;
88use super :: qualifs:: { NeedsDrop , Qualif } ;
99use super :: validation:: Qualifs ;
1010use 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 } ;
1114
1215/// Returns `true` if we should use the more precise live drop checker that runs after drop
1316/// elaboration.
@@ -31,14 +34,22 @@ pub fn check_live_drops(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &mir::Body<
3134
3235 let ccx = ConstCx { body, tcx, def_id, const_kind, param_env : tcx. param_env ( def_id) } ;
3336
34- let mut visitor = CheckLiveDrops { ccx : & ccx, qualifs : Qualifs :: default ( ) } ;
37+ let mut visitor = CheckLiveDrops { ccx : & ccx, qualifs : Qualifs :: default ( ) , maybe_inits : None } ;
3538
3639 visitor. visit_body ( body) ;
3740}
3841
42+ type MaybeInits < ' mir , ' tcx > = ResultsCursor <
43+ ' mir ,
44+ ' tcx ,
45+ dataflow:: impls:: MaybeInitializedPlaces < ' mir , ' tcx , MoveDataParamEnv < ' tcx > > ,
46+ > ;
47+
3948struct CheckLiveDrops < ' mir , ' tcx > {
4049 ccx : & ' mir ConstCx < ' mir , ' tcx > ,
4150 qualifs : Qualifs < ' mir , ' tcx > ,
51+
52+ maybe_inits : Option < MaybeInits < ' mir , ' tcx > > ,
4253}
4354
4455// So we can access `body` and `tcx`.
@@ -83,7 +94,41 @@ impl Visitor<'tcx> for CheckLiveDrops<'mir, 'tcx> {
8394 return ;
8495 }
8596
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 {
87132 // Use the span where the dropped local was declared for the error.
88133 let span = self . body . local_decls [ dropped_place. local ] . source_info . span ;
89134 self . check_live_drop ( span) ;
0 commit comments