@@ -62,9 +62,12 @@ pub trait Qualif {
6262 /// It also determines the `Qualif`s for primitive types.
6363 fn in_any_value_of_ty < ' tcx > ( cx : & ConstCx < ' _ , ' tcx > , ty : Ty < ' tcx > ) -> bool ;
6464
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 ;
6871
6972 /// Returns `true` if this `Qualif` behaves sructurally for pointers and references:
7073 /// the pointer/reference qualifies if and only if the pointee qualifies.
@@ -123,18 +126,17 @@ impl Qualif for HasMutInterior {
123126 !errors. is_empty ( )
124127 }
125128
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 {
127130 // Exactly one type, `UnsafeCell`, has the `HasMutInterior` qualif inherently.
128131 // It arises structurally for all other types.
129- adt. is_unsafe_cell ( )
132+ ! adt. is_unsafe_cell ( )
130133 }
131134
132135 fn deref_structural < ' tcx > ( _cx : & ConstCx < ' _ , ' tcx > ) -> bool {
133136 false
134137 }
135138}
136139
137- // FIXME(const_trait_impl): Get rid of this!
138140/// Constant containing an ADT that implements `Drop`.
139141/// This must be ruled out because implicit promotion would remove side-effects
140142/// that occur as part of dropping that value. N.B., the implicit promotion has
@@ -154,8 +156,8 @@ impl Qualif for NeedsDrop {
154156 ty. needs_drop ( cx. tcx , cx. param_env )
155157 }
156158
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 )
159161 }
160162
161163 fn deref_structural < ' tcx > ( _cx : & ConstCx < ' _ , ' tcx > ) -> bool {
@@ -183,6 +185,11 @@ impl Qualif for NeedsNonConstDrop {
183185 return false ;
184186 }
185187
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.
186193 if cx. tcx . features ( ) . const_trait_impl ( ) {
187194 let destruct_def_id = cx. tcx . require_lang_item ( LangItem :: Destruct , Some ( cx. body . span ) ) ;
188195 let infcx = cx. tcx . infer_ctxt ( ) . build ( TypingMode :: from_param_env ( cx. param_env ) ) ;
@@ -204,11 +211,18 @@ impl Qualif for NeedsNonConstDrop {
204211 }
205212 }
206213
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 )
212226 }
213227
214228 fn deref_structural < ' tcx > ( _cx : & ConstCx < ' _ , ' tcx > ) -> bool {
@@ -266,7 +280,11 @@ where
266280 // qualified.
267281 if let AggregateKind :: Adt ( adt_did, ..) = * * kind {
268282 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) {
270288 return Q :: in_any_value_of_ty ( cx, rvalue. ty ( cx. body , cx. tcx ) ) ;
271289 }
272290 }
0 commit comments