22//!
33//! See the `Qualif` trait for more info.
44
5+ // FIXME(const_trait_impl): 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 , TypingMode } ;
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
@@ -129,11 +127,7 @@ impl Qualif for HasMutInterior {
129127 !errors. is_empty ( )
130128 }
131129
132- fn in_adt_inherently < ' tcx > (
133- _cx : & ConstCx < ' _ , ' tcx > ,
134- adt : AdtDef < ' tcx > ,
135- _: GenericArgsRef < ' tcx > ,
136- ) -> bool {
130+ fn is_non_structural < ' tcx > ( _cx : & ConstCx < ' _ , ' tcx > , adt : AdtDef < ' tcx > ) -> bool {
137131 // Exactly one type, `UnsafeCell`, has the `HasMutInterior` qualif inherently.
138132 // It arises structurally for all other types.
139133 adt. is_unsafe_cell ( )
@@ -144,6 +138,7 @@ impl Qualif for HasMutInterior {
144138 }
145139}
146140
141+ // FIXME(const_trait_impl): Get rid of this!
147142/// Constant containing an ADT that implements `Drop`.
148143/// This must be ruled out because implicit promotion would remove side-effects
149144/// that occur as part of dropping that value. N.B., the implicit promotion has
@@ -163,11 +158,7 @@ impl Qualif for NeedsDrop {
163158 ty. needs_drop ( cx. tcx , cx. typing_env )
164159 }
165160
166- fn in_adt_inherently < ' tcx > (
167- cx : & ConstCx < ' _ , ' tcx > ,
168- adt : AdtDef < ' tcx > ,
169- _: GenericArgsRef < ' tcx > ,
170- ) -> bool {
161+ fn is_non_structural < ' tcx > ( cx : & ConstCx < ' _ , ' tcx > , adt : AdtDef < ' tcx > ) -> bool {
171162 adt. has_dtor ( cx. tcx )
172163 }
173164
@@ -196,16 +187,32 @@ impl Qualif for NeedsNonConstDrop {
196187 return false ;
197188 }
198189
199- // FIXME(const_trait_impl): Reimplement const drop checking.
200- NeedsDrop :: in_any_value_of_ty ( cx, ty)
190+ if cx. tcx . features ( ) . const_trait_impl ( ) {
191+ let destruct_def_id = cx. tcx . require_lang_item ( LangItem :: Destruct , Some ( cx. body . span ) ) ;
192+ let infcx = cx. tcx . infer_ctxt ( ) . build ( TypingMode :: from_param_env ( cx. param_env ) ) ;
193+ let ocx = ObligationCtxt :: new ( & infcx) ;
194+ ocx. register_obligation ( Obligation :: new (
195+ cx. tcx ,
196+ ObligationCause :: misc ( cx. body . span , cx. def_id ( ) ) ,
197+ cx. param_env ,
198+ ty:: Binder :: dummy ( ty:: TraitRef :: new ( cx. tcx , destruct_def_id, [ ty] ) )
199+ . to_host_effect_clause ( cx. tcx , match cx. const_kind ( ) {
200+ rustc_hir:: ConstContext :: ConstFn => ty:: BoundConstness :: Maybe ,
201+ rustc_hir:: ConstContext :: Static ( _)
202+ | rustc_hir:: ConstContext :: Const { .. } => ty:: BoundConstness :: Const ,
203+ } ) ,
204+ ) ) ;
205+ !ocx. select_all_or_error ( ) . is_empty ( )
206+ } else {
207+ NeedsDrop :: in_any_value_of_ty ( cx, ty)
208+ }
201209 }
202210
203- fn in_adt_inherently < ' tcx > (
204- cx : & ConstCx < ' _ , ' tcx > ,
205- adt : AdtDef < ' tcx > ,
206- _: GenericArgsRef < ' tcx > ,
207- ) -> bool {
208- adt. has_non_const_dtor ( cx. tcx )
211+ fn is_non_structural < ' tcx > ( cx : & ConstCx < ' _ , ' tcx > , adt : AdtDef < ' tcx > ) -> bool {
212+ // Even a `const` dtor may have `~const` bounds that may need to
213+ // be satisfied, so this becomes non-structural as soon as the
214+ // ADT gets a destructor at all.
215+ adt. has_dtor ( cx. tcx )
209216 }
210217
211218 fn deref_structural < ' tcx > ( _cx : & ConstCx < ' _ , ' tcx > ) -> bool {
@@ -261,14 +268,10 @@ where
261268 Rvalue :: Aggregate ( kind, operands) => {
262269 // Return early if we know that the struct or enum being constructed is always
263270 // qualified.
264- if let AggregateKind :: Adt ( adt_did, _ , args , ..) = * * kind {
271+ if let AggregateKind :: Adt ( adt_did, ..) = * * kind {
265272 let def = cx. tcx . adt_def ( adt_did) ;
266- if Q :: in_adt_inherently ( cx, def, args) {
267- return true ;
268- }
269- // Don't do any value-based reasoning for unions.
270- if def. is_union ( ) && Q :: in_any_value_of_ty ( cx, rvalue. ty ( cx. body , cx. tcx ) ) {
271- return true ;
273+ if def. is_union ( ) || Q :: is_non_structural ( cx, def) {
274+ return Q :: in_any_value_of_ty ( cx, rvalue. ty ( cx. body , cx. tcx ) ) ;
272275 }
273276 }
274277
0 commit comments