2
2
//!
3
3
//! See the `Qualif` trait for more info.
4
4
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
+
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 , TypingMode } ;
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
@@ -125,11 +123,7 @@ impl Qualif for HasMutInterior {
125
123
!errors. is_empty ( )
126
124
}
127
125
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 {
133
127
// Exactly one type, `UnsafeCell`, has the `HasMutInterior` qualif inherently.
134
128
// It arises structurally for all other types.
135
129
adt. is_unsafe_cell ( )
@@ -140,6 +134,7 @@ impl Qualif for HasMutInterior {
140
134
}
141
135
}
142
136
137
+ // FIXME(effects): Get rid of this!
143
138
/// Constant containing an ADT that implements `Drop`.
144
139
/// This must be ruled out because implicit promotion would remove side-effects
145
140
/// that occur as part of dropping that value. N.B., the implicit promotion has
@@ -159,11 +154,7 @@ impl Qualif for NeedsDrop {
159
154
ty. needs_drop ( cx. tcx , cx. param_env )
160
155
}
161
156
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 {
167
158
adt. has_dtor ( cx. tcx )
168
159
}
169
160
@@ -192,16 +183,32 @@ impl Qualif for NeedsNonConstDrop {
192
183
return false ;
193
184
}
194
185
195
- // FIXME(const_trait_impl): Reimplement const drop checking.
196
- NeedsDrop :: in_any_value_of_ty ( cx, ty)
186
+ if cx. tcx . features ( ) . const_trait_impl ( ) {
187
+ let destruct_def_id = cx. tcx . require_lang_item ( LangItem :: Destruct , Some ( cx. body . span ) ) ;
188
+ let infcx = cx. tcx . infer_ctxt ( ) . build ( TypingMode :: from_param_env ( cx. param_env ) ) ;
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:: Binder :: dummy ( ty:: TraitRef :: new ( cx. tcx , destruct_def_id, [ ty] ) )
195
+ . to_host_effect_clause ( cx. tcx , match cx. const_kind ( ) {
196
+ rustc_hir:: ConstContext :: ConstFn => ty:: BoundConstness :: Maybe ,
197
+ rustc_hir:: ConstContext :: Static ( _)
198
+ | rustc_hir:: ConstContext :: Const { .. } => ty:: BoundConstness :: Const ,
199
+ } ) ,
200
+ ) ) ;
201
+ !ocx. select_all_or_error ( ) . is_empty ( )
202
+ } else {
203
+ NeedsDrop :: in_any_value_of_ty ( cx, ty)
204
+ }
197
205
}
198
206
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 )
207
+ fn is_non_structural < ' tcx > ( cx : & ConstCx < ' _ , ' tcx > , adt : AdtDef < ' tcx > ) -> bool {
208
+ // Even a `const` dtor may have `~const` bounds that may need to
209
+ // be satisfied, so this becomes non-structural as soon as the
210
+ // ADT gets a destructor at all.
211
+ adt. has_dtor ( cx. tcx )
205
212
}
206
213
207
214
fn deref_structural < ' tcx > ( _cx : & ConstCx < ' _ , ' tcx > ) -> bool {
@@ -257,14 +264,10 @@ where
257
264
Rvalue :: Aggregate ( kind, operands) => {
258
265
// Return early if we know that the struct or enum being constructed is always
259
266
// qualified.
260
- if let AggregateKind :: Adt ( adt_did, _ , args , ..) = * * kind {
267
+ if let AggregateKind :: Adt ( adt_did, ..) = * * kind {
261
268
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 ;
269
+ if def. is_union ( ) || Q :: is_non_structural ( cx, def) {
270
+ return Q :: in_any_value_of_ty ( cx, rvalue. ty ( cx. body , cx. tcx ) ) ;
268
271
}
269
272
}
270
273
0 commit comments