@@ -62,9 +62,12 @@ pub trait Qualif {
62
62
/// It also determines the `Qualif`s for primitive types.
63
63
fn in_any_value_of_ty < ' tcx > ( cx : & ConstCx < ' _ , ' tcx > , ty : Ty < ' tcx > ) -> bool ;
64
64
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 ;
65
+ /// Returns `true` if the `Qualif` is structural in its operand, i.e. that we may
66
+ /// recurse into the operand.
67
+ ///
68
+ /// If this returns false, `in_any_value_of_ty` will be invoked to determine the
69
+ /// final qualif for this operand.
70
+ fn is_structural_in_operand < ' tcx > ( cx : & ConstCx < ' _ , ' tcx > , adt : AdtDef < ' tcx > ) -> bool ;
68
71
69
72
/// Returns `true` if this `Qualif` behaves sructurally for pointers and references:
70
73
/// the pointer/reference qualifies if and only if the pointee qualifies.
@@ -123,18 +126,17 @@ impl Qualif for HasMutInterior {
123
126
!errors. is_empty ( )
124
127
}
125
128
126
- fn is_non_structural < ' tcx > ( _cx : & ConstCx < ' _ , ' tcx > , adt : AdtDef < ' tcx > ) -> bool {
129
+ fn is_structural_in_operand < ' tcx > ( _cx : & ConstCx < ' _ , ' tcx > , adt : AdtDef < ' tcx > ) -> bool {
127
130
// Exactly one type, `UnsafeCell`, has the `HasMutInterior` qualif inherently.
128
131
// It arises structurally for all other types.
129
- adt. is_unsafe_cell ( )
132
+ ! adt. is_unsafe_cell ( )
130
133
}
131
134
132
135
fn deref_structural < ' tcx > ( _cx : & ConstCx < ' _ , ' tcx > ) -> bool {
133
136
false
134
137
}
135
138
}
136
139
137
- // FIXME(const_trait_impl): Get rid of this!
138
140
/// Constant containing an ADT that implements `Drop`.
139
141
/// This must be ruled out because implicit promotion would remove side-effects
140
142
/// that occur as part of dropping that value. N.B., the implicit promotion has
@@ -154,8 +156,8 @@ impl Qualif for NeedsDrop {
154
156
ty. needs_drop ( cx. tcx , cx. param_env )
155
157
}
156
158
157
- fn is_non_structural < ' tcx > ( cx : & ConstCx < ' _ , ' tcx > , adt : AdtDef < ' tcx > ) -> bool {
158
- adt. has_dtor ( cx. tcx )
159
+ fn is_structural_in_operand < ' tcx > ( cx : & ConstCx < ' _ , ' tcx > , adt : AdtDef < ' tcx > ) -> bool {
160
+ ! adt. has_dtor ( cx. tcx )
159
161
}
160
162
161
163
fn deref_structural < ' tcx > ( _cx : & ConstCx < ' _ , ' tcx > ) -> bool {
@@ -183,6 +185,11 @@ impl Qualif for NeedsNonConstDrop {
183
185
return false ;
184
186
}
185
187
188
+ // We check that the type is `~const Destruct` since that will verify that
189
+ // the type is both `~const Drop` (if a drop impl exists for the adt), *and*
190
+ // that the components of this type are also `~const Destruct`. This
191
+ // amounts to verifying that there are no values in this ADT that may have
192
+ // a non-const drop.
186
193
if cx. tcx . features ( ) . const_trait_impl ( ) {
187
194
let destruct_def_id = cx. tcx . require_lang_item ( LangItem :: Destruct , Some ( cx. body . span ) ) ;
188
195
let infcx = cx. tcx . infer_ctxt ( ) . build ( TypingMode :: from_param_env ( cx. param_env ) ) ;
@@ -204,11 +211,18 @@ impl Qualif for NeedsNonConstDrop {
204
211
}
205
212
}
206
213
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 )
214
+ fn is_structural_in_operand < ' tcx > ( cx : & ConstCx < ' _ , ' tcx > , adt : AdtDef < ' tcx > ) -> bool {
215
+ // As soon as an ADT has a destructor, then the drop becomes non-structural
216
+ // in its value since:
217
+ // 1. The destructor may have `~const` bounds that need to be satisfied on
218
+ // top of checking that the components of a specific operand are const-drop.
219
+ // While this could be instead satisfied by checking that the `~const Drop`
220
+ // impl holds (i.e. replicating part of the `in_any_value_of_ty` logic above),
221
+ // even in this case, we have another problem, which is,
222
+ // 2. The destructor may *modify* the operand being dropped, so even if we
223
+ // did recurse on the components of the operand, we may not be even dropping
224
+ // the same values that were present before the custom destructor was invoked.
225
+ !adt. has_dtor ( cx. tcx )
212
226
}
213
227
214
228
fn deref_structural < ' tcx > ( _cx : & ConstCx < ' _ , ' tcx > ) -> bool {
@@ -266,7 +280,11 @@ where
266
280
// qualified.
267
281
if let AggregateKind :: Adt ( adt_did, ..) = * * kind {
268
282
let def = cx. tcx . adt_def ( adt_did) ;
269
- if def. is_union ( ) || Q :: is_non_structural ( cx, def) {
283
+ // Don't do any value-based reasoning for unions.
284
+ // Also, if the ADT is not structural in its operand,
285
+ // then we cannot recurse on its components. Instead,
286
+ // we fall back to checking the qualif for *any* value.
287
+ if def. is_union ( ) || !Q :: is_structural_in_operand ( cx, def) {
270
288
return Q :: in_any_value_of_ty ( cx, rvalue. ty ( cx. body , cx. tcx ) ) ;
271
289
}
272
290
}
0 commit comments