Skip to content

Commit 75c9e38

Browse files
More comments, reverse polarity of structural check
1 parent 7d660a2 commit 75c9e38

File tree

1 file changed

+41
-35
lines changed
  • compiler/rustc_const_eval/src/check_consts

1 file changed

+41
-35
lines changed

compiler/rustc_const_eval/src/check_consts/qualifs.rs

+41-35
Original file line numberDiff line numberDiff line change
@@ -62,16 +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;
68-
69-
/// Returns `true` if this `Qualif` behaves sructurally for pointers and references:
70-
/// the pointer/reference qualifies if and only if the pointee qualifies.
65+
/// Returns `true` if the `Qualif` is structural in an ADT's fields, i.e. that we may
66+
/// recurse into an operand if we know what it is.
7167
///
72-
/// (This is currently `false` for all our instances, but that may change in the future. Also,
73-
/// by keeping it abstract, the handling of `Deref` in `in_place` becomes more clear.)
74-
fn deref_structural<'tcx>(cx: &ConstCx<'_, 'tcx>) -> bool;
68+
/// If this returns false, `in_any_value_of_ty` will be invoked to determine the
69+
/// final qualif for this ADT.
70+
fn is_structural_in_adt<'tcx>(cx: &ConstCx<'_, 'tcx>, adt: AdtDef<'tcx>) -> bool;
7571
}
7672

7773
/// Constant containing interior mutability (`UnsafeCell<T>`).
@@ -127,18 +123,13 @@ impl Qualif for HasMutInterior {
127123
!errors.is_empty()
128124
}
129125

130-
fn is_non_structural<'tcx>(_cx: &ConstCx<'_, 'tcx>, adt: AdtDef<'tcx>) -> bool {
126+
fn is_structural_in_adt<'tcx>(_cx: &ConstCx<'_, 'tcx>, adt: AdtDef<'tcx>) -> bool {
131127
// Exactly one type, `UnsafeCell`, has the `HasMutInterior` qualif inherently.
132128
// It arises structurally for all other types.
133-
adt.is_unsafe_cell()
134-
}
135-
136-
fn deref_structural<'tcx>(_cx: &ConstCx<'_, 'tcx>) -> bool {
137-
false
129+
!adt.is_unsafe_cell()
138130
}
139131
}
140132

141-
// FIXME(const_trait_impl): Get rid of this!
142133
/// Constant containing an ADT that implements `Drop`.
143134
/// This must be ruled out because implicit promotion would remove side-effects
144135
/// that occur as part of dropping that value. N.B., the implicit promotion has
@@ -158,12 +149,8 @@ impl Qualif for NeedsDrop {
158149
ty.needs_drop(cx.tcx, cx.typing_env)
159150
}
160151

161-
fn is_non_structural<'tcx>(cx: &ConstCx<'_, 'tcx>, adt: AdtDef<'tcx>) -> bool {
162-
adt.has_dtor(cx.tcx)
163-
}
164-
165-
fn deref_structural<'tcx>(_cx: &ConstCx<'_, 'tcx>) -> bool {
166-
false
152+
fn is_structural_in_adt<'tcx>(cx: &ConstCx<'_, 'tcx>, adt: AdtDef<'tcx>) -> bool {
153+
!adt.has_dtor(cx.tcx)
167154
}
168155
}
169156

@@ -187,14 +174,20 @@ impl Qualif for NeedsNonConstDrop {
187174
return false;
188175
}
189176

177+
// We check that the type is `~const Destruct` since that will verify that
178+
// the type is both `~const Drop` (if a drop impl exists for the adt), *and*
179+
// that the components of this type are also `~const Destruct`. This
180+
// amounts to verifying that there are no values in this ADT that may have
181+
// a non-const drop.
190182
if cx.tcx.features().const_trait_impl() {
191183
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));
184+
let infcx =
185+
cx.tcx.infer_ctxt().build(TypingMode::from_param_env(cx.typing_env.param_env));
193186
let ocx = ObligationCtxt::new(&infcx);
194187
ocx.register_obligation(Obligation::new(
195188
cx.tcx,
196189
ObligationCause::misc(cx.body.span, cx.def_id()),
197-
cx.param_env,
190+
cx.typing_env.param_env,
198191
ty::Binder::dummy(ty::TraitRef::new(cx.tcx, destruct_def_id, [ty]))
199192
.to_host_effect_clause(cx.tcx, match cx.const_kind() {
200193
rustc_hir::ConstContext::ConstFn => ty::BoundConstness::Maybe,
@@ -208,15 +201,18 @@ impl Qualif for NeedsNonConstDrop {
208201
}
209202
}
210203

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)
216-
}
217-
218-
fn deref_structural<'tcx>(_cx: &ConstCx<'_, 'tcx>) -> bool {
219-
false
204+
fn is_structural_in_adt<'tcx>(cx: &ConstCx<'_, 'tcx>, adt: AdtDef<'tcx>) -> bool {
205+
// As soon as an ADT has a destructor, then the drop becomes non-structural
206+
// in its value since:
207+
// 1. The destructor may have `~const` bounds that need to be satisfied on
208+
// top of checking that the components of a specific operand are const-drop.
209+
// While this could be instead satisfied by checking that the `~const Drop`
210+
// impl holds (i.e. replicating part of the `in_any_value_of_ty` logic above),
211+
// even in this case, we have another problem, which is,
212+
// 2. The destructor may *modify* the operand being dropped, so even if we
213+
// did recurse on the components of the operand, we may not be even dropping
214+
// the same values that were present before the custom destructor was invoked.
215+
!adt.has_dtor(cx.tcx)
220216
}
221217
}
222218

@@ -270,7 +266,12 @@ where
270266
// qualified.
271267
if let AggregateKind::Adt(adt_did, ..) = **kind {
272268
let def = cx.tcx.adt_def(adt_did);
273-
if def.is_union() || Q::is_non_structural(cx, def) {
269+
// Don't do any value-based reasoning for unions.
270+
// Also, if the ADT is not structural in its fields,
271+
// then we cannot recurse on its fields. Instead,
272+
// we fall back to checking the qualif for *any* value
273+
// of the ADT.
274+
if def.is_union() || !Q::is_structural_in_adt(cx, def) {
274275
return Q::in_any_value_of_ty(cx, rvalue.ty(cx.body, cx.tcx));
275276
}
276277
}
@@ -308,7 +309,12 @@ where
308309
return false;
309310
}
310311

311-
if matches!(elem, ProjectionElem::Deref) && !Q::deref_structural(cx) {
312+
// This is currently unconditionally true for all qualifs, since we do
313+
// not recurse into the pointer of a deref projection, but that may change
314+
// in the future. If that changes, each qualif should be required to
315+
// specify whether it operates structurally for deref projections, just like
316+
// we do for `Qualif::is_structural_in_adt`.
317+
if matches!(elem, ProjectionElem::Deref) {
312318
// We have to assume that this qualifies.
313319
return true;
314320
}

0 commit comments

Comments
 (0)