2
2
//!
3
3
//! See the `Qualif` trait for more info.
4
4
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
+
5
8
use rustc_errors:: ErrorGuaranteed ;
6
9
use rustc_hir:: LangItem ;
7
10
use rustc_infer:: infer:: TyCtxtInferExt ;
8
11
use rustc_middle:: mir:: * ;
9
- use rustc_middle:: ty:: { self , AdtDef , GenericArgsRef , Ty } ;
12
+ use rustc_middle:: ty:: { self , AdtDef , Ty } ;
10
13
use rustc_middle:: { bug, mir} ;
11
14
use rustc_trait_selection:: traits:: { Obligation , ObligationCause , ObligationCtxt } ;
12
15
use tracing:: instrument;
@@ -59,19 +62,9 @@ pub trait Qualif {
59
62
/// It also determines the `Qualif`s for primitive types.
60
63
fn in_any_value_of_ty < ' tcx > ( cx : & ConstCx < ' _ , ' tcx > , ty : Ty < ' tcx > ) -> bool ;
61
64
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 ;
75
68
76
69
/// Returns `true` if this `Qualif` behaves sructurally for pointers and references:
77
70
/// the pointer/reference qualifies if and only if the pointee qualifies.
@@ -101,6 +94,11 @@ impl Qualif for HasMutInterior {
101
94
return false ;
102
95
}
103
96
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
+
104
102
// We do not use `ty.is_freeze` here, because that requires revealing opaque types, which
105
103
// requires borrowck, which in turn will invoke mir_const_qualifs again, causing a cycle error.
106
104
// Instead we invoke an obligation context manually, and provide the opaque type inference settings
@@ -129,11 +127,7 @@ impl Qualif for HasMutInterior {
129
127
!errors. is_empty ( )
130
128
}
131
129
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 {
137
131
// Exactly one type, `UnsafeCell`, has the `HasMutInterior` qualif inherently.
138
132
// It arises structurally for all other types.
139
133
adt. is_unsafe_cell ( )
@@ -144,6 +138,7 @@ impl Qualif for HasMutInterior {
144
138
}
145
139
}
146
140
141
+ // FIXME(const_trait_impl): Get rid of this!
147
142
/// Constant containing an ADT that implements `Drop`.
148
143
/// This must be ruled out because implicit promotion would remove side-effects
149
144
/// that occur as part of dropping that value. N.B., the implicit promotion has
@@ -163,11 +158,7 @@ impl Qualif for NeedsDrop {
163
158
ty. needs_drop ( cx. tcx , cx. typing_env )
164
159
}
165
160
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 {
171
162
adt. has_dtor ( cx. tcx )
172
163
}
173
164
@@ -196,16 +187,32 @@ impl Qualif for NeedsNonConstDrop {
196
187
return false ;
197
188
}
198
189
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
+ }
201
209
}
202
210
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 )
209
216
}
210
217
211
218
fn deref_structural < ' tcx > ( _cx : & ConstCx < ' _ , ' tcx > ) -> bool {
@@ -261,14 +268,10 @@ where
261
268
Rvalue :: Aggregate ( kind, operands) => {
262
269
// Return early if we know that the struct or enum being constructed is always
263
270
// qualified.
264
- if let AggregateKind :: Adt ( adt_did, _ , args , ..) = * * kind {
271
+ if let AggregateKind :: Adt ( adt_did, ..) = * * kind {
265
272
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 ) ) ;
272
275
}
273
276
}
274
277
0 commit comments