Skip to content

Commit 8ceb8c2

Browse files
More comments, reverse polarity of structural check
1 parent 5ab390a commit 8ceb8c2

File tree

1 file changed

+32
-14
lines changed
  • compiler/rustc_const_eval/src/check_consts

1 file changed

+32
-14
lines changed

compiler/rustc_const_eval/src/check_consts/qualifs.rs

+32-14
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)