22//!
33//! See the `Qualif` trait for more info.
44
5+ // FIXME(effects): This API should be really reworked. It's dangerously general for
6+ // having basically only two use-cases that act in different ways.
7+
58use rustc_errors:: ErrorGuaranteed ;
69use rustc_hir:: LangItem ;
710use rustc_infer:: infer:: TyCtxtInferExt ;
811use rustc_middle:: mir:: * ;
9- use rustc_middle:: ty:: { self , AdtDef , GenericArgsRef , Ty } ;
12+ use rustc_middle:: ty:: { self , AdtDef , Ty } ;
1013use rustc_middle:: { bug, mir} ;
1114use rustc_trait_selection:: traits:: { Obligation , ObligationCause , ObligationCtxt } ;
1215use tracing:: instrument;
@@ -59,19 +62,9 @@ pub trait Qualif {
5962 /// It also determines the `Qualif`s for primitive types.
6063 fn in_any_value_of_ty < ' tcx > ( cx : & ConstCx < ' _ , ' tcx > , ty : Ty < ' tcx > ) -> bool ;
6164
62- /// Returns `true` if this `Qualif` is inherent to the given struct or enum.
63- ///
64- /// By default, `Qualif`s propagate into ADTs in a structural way: An ADT only becomes
65- /// qualified if part of it is assigned a value with that `Qualif`. However, some ADTs *always*
66- /// have a certain `Qualif`, regardless of whether their fields have it. For example, a type
67- /// with a custom `Drop` impl is inherently `NeedsDrop`.
68- ///
69- /// Returning `true` for `in_adt_inherently` but `false` for `in_any_value_of_ty` is unsound.
70- fn in_adt_inherently < ' tcx > (
71- cx : & ConstCx < ' _ , ' tcx > ,
72- adt : AdtDef < ' tcx > ,
73- args : GenericArgsRef < ' tcx > ,
74- ) -> bool ;
65+ /// Returns `true` if the `Qualif` is not structural, i.e. that we should not recurse
66+ /// into the operand.
67+ fn is_non_structural < ' tcx > ( cx : & ConstCx < ' _ , ' tcx > , adt : AdtDef < ' tcx > ) -> bool ;
7568
7669 /// Returns `true` if this `Qualif` behaves sructurally for pointers and references:
7770 /// the pointer/reference qualifies if and only if the pointee qualifies.
@@ -101,6 +94,11 @@ impl Qualif for HasMutInterior {
10194 return false ;
10295 }
10396
97+ // Avoid selecting for `UnsafeCell` either.
98+ if ty. ty_adt_def ( ) . is_some_and ( |adt| adt. is_unsafe_cell ( ) ) {
99+ return true ;
100+ }
101+
104102 // We do not use `ty.is_freeze` here, because that requires revealing opaque types, which
105103 // requires borrowck, which in turn will invoke mir_const_qualifs again, causing a cycle error.
106104 // Instead we invoke an obligation context manually, and provide the opaque type inference settings
@@ -125,11 +123,7 @@ impl Qualif for HasMutInterior {
125123 !errors. is_empty ( )
126124 }
127125
128- fn in_adt_inherently < ' tcx > (
129- _cx : & ConstCx < ' _ , ' tcx > ,
130- adt : AdtDef < ' tcx > ,
131- _: GenericArgsRef < ' tcx > ,
132- ) -> bool {
126+ fn is_non_structural < ' tcx > ( _cx : & ConstCx < ' _ , ' tcx > , adt : AdtDef < ' tcx > ) -> bool {
133127 // Exactly one type, `UnsafeCell`, has the `HasMutInterior` qualif inherently.
134128 // It arises structurally for all other types.
135129 adt. is_unsafe_cell ( )
@@ -140,6 +134,7 @@ impl Qualif for HasMutInterior {
140134 }
141135}
142136
137+ // FIXME(effects): Get rid of this!
143138/// Constant containing an ADT that implements `Drop`.
144139/// This must be ruled out because implicit promotion would remove side-effects
145140/// that occur as part of dropping that value. N.B., the implicit promotion has
@@ -159,11 +154,7 @@ impl Qualif for NeedsDrop {
159154 ty. needs_drop ( cx. tcx , cx. param_env )
160155 }
161156
162- fn in_adt_inherently < ' tcx > (
163- cx : & ConstCx < ' _ , ' tcx > ,
164- adt : AdtDef < ' tcx > ,
165- _: GenericArgsRef < ' tcx > ,
166- ) -> bool {
157+ fn is_non_structural < ' tcx > ( cx : & ConstCx < ' _ , ' tcx > , adt : AdtDef < ' tcx > ) -> bool {
167158 adt. has_dtor ( cx. tcx )
168159 }
169160
@@ -192,16 +183,34 @@ impl Qualif for NeedsNonConstDrop {
192183 return false ;
193184 }
194185
195- // FIXME(effects): Reimplement const drop checking.
196- NeedsDrop :: in_any_value_of_ty ( cx, ty)
186+ if cx. tcx . features ( ) . effects ( ) {
187+ let destruct_def_id = cx. tcx . require_lang_item ( LangItem :: Destruct , Some ( cx. body . span ) ) ;
188+ let infcx = cx. tcx . infer_ctxt ( ) . build ( ) ;
189+ let ocx = ObligationCtxt :: new ( & infcx) ;
190+ ocx. register_obligation ( Obligation :: new (
191+ cx. tcx ,
192+ ObligationCause :: misc ( cx. body . span , cx. def_id ( ) ) ,
193+ cx. param_env ,
194+ ty:: ClauseKind :: HostEffect ( ty:: HostEffectPredicate {
195+ trait_ref : ty:: TraitRef :: new ( cx. tcx , destruct_def_id, [ ty] ) ,
196+ host : match cx. const_kind ( ) {
197+ rustc_hir:: ConstContext :: ConstFn => ty:: HostPolarity :: Maybe ,
198+ rustc_hir:: ConstContext :: Static ( _)
199+ | rustc_hir:: ConstContext :: Const { .. } => ty:: HostPolarity :: Const ,
200+ } ,
201+ } ) ,
202+ ) ) ;
203+ !ocx. select_all_or_error ( ) . is_empty ( )
204+ } else {
205+ NeedsDrop :: in_any_value_of_ty ( cx, ty)
206+ }
197207 }
198208
199- fn in_adt_inherently < ' tcx > (
200- cx : & ConstCx < ' _ , ' tcx > ,
201- adt : AdtDef < ' tcx > ,
202- _: GenericArgsRef < ' tcx > ,
203- ) -> bool {
204- adt. has_non_const_dtor ( cx. tcx )
209+ fn is_non_structural < ' tcx > ( cx : & ConstCx < ' _ , ' tcx > , adt : AdtDef < ' tcx > ) -> bool {
210+ // Even a `const` dtor may have `~const` bounds that may need to
211+ // be satisfied, so this becomes non-structural as soon as the
212+ // ADT gets a destructor at all.
213+ adt. has_dtor ( cx. tcx )
205214 }
206215
207216 fn deref_structural < ' tcx > ( _cx : & ConstCx < ' _ , ' tcx > ) -> bool {
@@ -257,14 +266,10 @@ where
257266 Rvalue :: Aggregate ( kind, operands) => {
258267 // Return early if we know that the struct or enum being constructed is always
259268 // qualified.
260- if let AggregateKind :: Adt ( adt_did, _ , args , ..) = * * kind {
269+ if let AggregateKind :: Adt ( adt_did, ..) = * * kind {
261270 let def = cx. tcx . adt_def ( adt_did) ;
262- if Q :: in_adt_inherently ( cx, def, args) {
263- return true ;
264- }
265- // Don't do any value-based reasoning for unions.
266- if def. is_union ( ) && Q :: in_any_value_of_ty ( cx, rvalue. ty ( cx. body , cx. tcx ) ) {
267- return true ;
271+ if def. is_union ( ) || Q :: is_non_structural ( cx, def) {
272+ return Q :: in_any_value_of_ty ( cx, rvalue. ty ( cx. body , cx. tcx ) ) ;
268273 }
269274 }
270275
0 commit comments