11//! Check whether a type has (potentially) non-trivial drop glue.
22
33use rustc_data_structures:: fx:: FxHashSet ;
4+ use rustc_hir as hir;
45use rustc_hir:: def_id:: DefId ;
6+ use rustc_infer:: infer:: TyCtxtInferExt ;
57use rustc_middle:: ty:: subst:: Subst ;
68use rustc_middle:: ty:: util:: { needs_drop_components, AlwaysRequiresDrop } ;
79use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
810use rustc_session:: Limit ;
911use rustc_span:: { sym, DUMMY_SP } ;
12+ use rustc_trait_selection:: traits:: { Obligation , ObligationCause , SelectionContext } ;
1013
1114type NeedsDropResult < T > = Result < T , AlwaysRequiresDrop > ;
1215
13- fn needs_drop_raw < ' tcx > ( tcx : TyCtxt < ' tcx > , query : ty:: ParamEnvAnd < ' tcx , Ty < ' tcx > > ) -> bool {
14- let adt_fields =
15- move |adt_def : & ty:: AdtDef | tcx. adt_drop_tys ( adt_def. did ) . map ( |tys| tys. iter ( ) ) ;
16+ fn needs_drop_raw < ' tcx > (
17+ tcx : TyCtxt < ' tcx > ,
18+ query : ty:: ParamEnvAnd < ' tcx , Ty < ' tcx > > ,
19+ needs_non_const_drop : bool ,
20+ ) -> bool {
1621 // If we don't know a type doesn't need drop, for example if it's a type
1722 // parameter without a `Copy` bound, then we conservatively return that it
1823 // needs drop.
19- let res = NeedsDropTypes :: new ( tcx, query. param_env , query. value , adt_fields) . next ( ) . is_some ( ) ;
24+ let res = if needs_non_const_drop {
25+ let adt_components = move |adt_def : & ty:: AdtDef | {
26+ tcx. adt_drop_tys_non_const ( adt_def. did ) . map ( |tys| tys. iter ( ) )
27+ } ;
28+ NeedsDropTypes :: new ( tcx, query. param_env , query. value , adt_components, needs_non_const_drop)
29+ . next ( )
30+ . is_some ( )
31+ } else {
32+ let adt_components =
33+ move |adt_def : & ty:: AdtDef | tcx. adt_drop_tys ( adt_def. did ) . map ( |tys| tys. iter ( ) ) ;
34+ NeedsDropTypes :: new ( tcx, query. param_env , query. value , adt_components, needs_non_const_drop)
35+ . next ( )
36+ . is_some ( )
37+ } ;
38+
2039 debug ! ( "needs_drop_raw({:?}) = {:?}" , query, res) ;
2140 res
2241}
@@ -27,9 +46,10 @@ fn has_significant_drop_raw<'tcx>(
2746) -> bool {
2847 let significant_drop_fields =
2948 move |adt_def : & ty:: AdtDef | tcx. adt_significant_drop_tys ( adt_def. did ) . map ( |tys| tys. iter ( ) ) ;
30- let res = NeedsDropTypes :: new ( tcx, query. param_env , query. value , significant_drop_fields)
31- . next ( )
32- . is_some ( ) ;
49+ let res =
50+ NeedsDropTypes :: new ( tcx, query. param_env , query. value , significant_drop_fields, false )
51+ . next ( )
52+ . is_some ( ) ;
3353 debug ! ( "has_significant_drop_raw({:?}) = {:?}" , query, res) ;
3454 res
3555}
@@ -46,6 +66,7 @@ struct NeedsDropTypes<'tcx, F> {
4666 unchecked_tys : Vec < ( Ty < ' tcx > , usize ) > ,
4767 recursion_limit : Limit ,
4868 adt_components : F ,
69+ needs_non_const_drop : bool ,
4970}
5071
5172impl < ' tcx , F > NeedsDropTypes < ' tcx , F > {
@@ -54,6 +75,7 @@ impl<'tcx, F> NeedsDropTypes<'tcx, F> {
5475 param_env : ty:: ParamEnv < ' tcx > ,
5576 ty : Ty < ' tcx > ,
5677 adt_components : F ,
78+ needs_non_const_drop : bool ,
5779 ) -> Self {
5880 let mut seen_tys = FxHashSet :: default ( ) ;
5981 seen_tys. insert ( ty) ;
@@ -65,6 +87,7 @@ impl<'tcx, F> NeedsDropTypes<'tcx, F> {
6587 unchecked_tys : vec ! [ ( ty, 0 ) ] ,
6688 recursion_limit : tcx. recursion_limit ( ) ,
6789 adt_components,
90+ needs_non_const_drop,
6891 }
6992 }
7093}
@@ -147,6 +170,35 @@ where
147170 queue_type ( self , subst_ty) ;
148171 }
149172 }
173+ ty:: Param ( _)
174+ if self . needs_non_const_drop && self . tcx . features ( ) . const_trait_impl =>
175+ {
176+ // Check if the param is bounded to have a `~const Drop` impl.
177+ let drop_trait = self . tcx . require_lang_item ( hir:: LangItem :: Drop , None ) ;
178+ let trait_ref = ty:: TraitRef {
179+ def_id : drop_trait,
180+ substs : self . tcx . mk_substs_trait ( component, & [ ] ) ,
181+ } ;
182+
183+ let obligation = Obligation :: new (
184+ ObligationCause :: dummy ( ) ,
185+ self . param_env ,
186+ ty:: Binder :: dummy ( ty:: TraitPredicate {
187+ trait_ref,
188+ constness : ty:: BoundConstness :: ConstIfConst ,
189+ } ) ,
190+ ) ;
191+
192+ let implsrc = tcx. infer_ctxt ( ) . enter ( |infcx| {
193+ let mut selcx =
194+ SelectionContext :: with_constness ( & infcx, hir:: Constness :: Const ) ;
195+ selcx. select ( & obligation)
196+ } ) ;
197+
198+ if let Ok ( Some ( _) ) = implsrc {
199+ return None ;
200+ }
201+ }
150202 ty:: Array ( ..) | ty:: Opaque ( ..) | ty:: Projection ( ..) | ty:: Param ( _) => {
151203 if ty == component {
152204 // Return the type to the caller: they may be able
@@ -176,6 +228,7 @@ fn adt_drop_tys_helper(
176228 tcx : TyCtxt < ' _ > ,
177229 def_id : DefId ,
178230 adt_has_dtor : impl Fn ( & ty:: AdtDef ) -> bool ,
231+ needs_non_const_drop : bool ,
179232) -> Result < & ty:: List < Ty < ' _ > > , AlwaysRequiresDrop > {
180233 let adt_components = move |adt_def : & ty:: AdtDef | {
181234 if adt_def. is_manually_drop ( ) {
@@ -194,15 +247,25 @@ fn adt_drop_tys_helper(
194247 let adt_ty = tcx. type_of ( def_id) ;
195248 let param_env = tcx. param_env ( def_id) ;
196249 let res: Result < Vec < _ > , _ > =
197- NeedsDropTypes :: new ( tcx, param_env, adt_ty, adt_components) . collect ( ) ;
250+ NeedsDropTypes :: new ( tcx, param_env, adt_ty, adt_components, needs_non_const_drop ) . collect ( ) ;
198251
199252 debug ! ( "adt_drop_tys(`{}`) = `{:?}`" , tcx. def_path_str( def_id) , res) ;
200253 res. map ( |components| tcx. intern_type_list ( & components) )
201254}
202255
203256fn adt_drop_tys ( tcx : TyCtxt < ' _ > , def_id : DefId ) -> Result < & ty:: List < Ty < ' _ > > , AlwaysRequiresDrop > {
204257 let adt_has_dtor = |adt_def : & ty:: AdtDef | adt_def. destructor ( tcx) . is_some ( ) ;
205- adt_drop_tys_helper ( tcx, def_id, adt_has_dtor)
258+ adt_drop_tys_helper ( tcx, def_id, adt_has_dtor, false )
259+ }
260+
261+ fn adt_drop_tys_non_const (
262+ tcx : TyCtxt < ' _ > ,
263+ def_id : DefId ,
264+ ) -> Result < & ty:: List < Ty < ' _ > > , AlwaysRequiresDrop > {
265+ let adt_has_dtor = |adt_def : & ty:: AdtDef | {
266+ adt_def. destructor ( tcx) . map ( |d| d. constness ) == Some ( hir:: Constness :: NotConst )
267+ } ;
268+ adt_drop_tys_helper ( tcx, def_id, adt_has_dtor, true )
206269}
207270
208271fn adt_significant_drop_tys (
@@ -215,14 +278,16 @@ fn adt_significant_drop_tys(
215278 . map ( |dtor| !tcx. has_attr ( dtor. did , sym:: rustc_insignificant_dtor) )
216279 . unwrap_or ( false )
217280 } ;
218- adt_drop_tys_helper ( tcx, def_id, adt_has_dtor)
281+ adt_drop_tys_helper ( tcx, def_id, adt_has_dtor, false )
219282}
220283
221284pub ( crate ) fn provide ( providers : & mut ty:: query:: Providers ) {
222285 * providers = ty:: query:: Providers {
223- needs_drop_raw,
286+ needs_drop_raw : |tcx, query| needs_drop_raw ( tcx, query, false ) ,
287+ needs_non_const_drop_raw : |tcx, query| needs_drop_raw ( tcx, query, true ) ,
224288 has_significant_drop_raw,
225289 adt_drop_tys,
290+ adt_drop_tys_non_const,
226291 adt_significant_drop_tys,
227292 ..* providers
228293 } ;
0 commit comments