Skip to content

Commit 6b54829

Browse files
Add CustomEq qualif
1 parent 0850c3b commit 6b54829

File tree

3 files changed

+64
-1
lines changed

3 files changed

+64
-1
lines changed

src/librustc_middle/mir/query.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ pub struct BorrowCheckResult<'tcx> {
8080
pub struct ConstQualifs {
8181
pub has_mut_interior: bool,
8282
pub needs_drop: bool,
83+
pub custom_eq: bool,
8384
}
8485

8586
/// After we borrow check a closure, we are left with various

src/librustc_mir/transform/check_consts/qualifs.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,19 @@
22
//!
33
//! See the `Qualif` trait for more info.
44
5+
use rustc_infer::infer::TyCtxtInferExt;
56
use rustc_middle::mir::*;
67
use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty};
78
use rustc_span::DUMMY_SP;
9+
use rustc_trait_selection::traits;
810

911
use super::ConstCx;
1012

1113
pub fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> ConstQualifs {
1214
ConstQualifs {
1315
has_mut_interior: HasMutInterior::in_any_value_of_ty(cx, ty),
1416
needs_drop: NeedsDrop::in_any_value_of_ty(cx, ty),
17+
custom_eq: CustomEq::in_any_value_of_ty(cx, ty),
1518
}
1619
}
1720

@@ -108,6 +111,39 @@ impl Qualif for NeedsDrop {
108111
}
109112
}
110113

114+
/// A constant that cannot be used as part of a pattern in a `match` expression.
115+
pub struct CustomEq;
116+
117+
impl Qualif for CustomEq {
118+
const ANALYSIS_NAME: &'static str = "flow_custom_eq";
119+
120+
fn in_qualifs(qualifs: &ConstQualifs) -> bool {
121+
qualifs.custom_eq
122+
}
123+
124+
fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool {
125+
// If *any* component of a composite data type does not implement `Structural{Partial,}Eq`,
126+
// we know that at least some values of that type are not structural-match. I say "some"
127+
// because that component may be part of an enum variant (e.g.,
128+
// `Option::<NonStructuralMatchTy>::Some`), in which case some values of this type may be
129+
// structural-match (`Option::None`).
130+
let id = cx.tcx.hir().local_def_id_to_hir_id(cx.def_id.as_local().unwrap());
131+
traits::search_for_structural_match_violation(id, cx.body.span, cx.tcx, ty).is_some()
132+
}
133+
134+
fn in_adt_inherently(
135+
cx: &ConstCx<'_, 'tcx>,
136+
adt: &'tcx AdtDef,
137+
substs: SubstsRef<'tcx>,
138+
) -> bool {
139+
let ty = cx.tcx.mk_ty(ty::Adt(adt, substs));
140+
let id = cx.tcx.hir().local_def_id_to_hir_id(cx.def_id.as_local().unwrap());
141+
cx.tcx
142+
.infer_ctxt()
143+
.enter(|infcx| !traits::type_marked_structural(id, cx.body.span, &infcx, ty))
144+
}
145+
}
146+
111147
// FIXME: Use `mir::visit::Visitor` for the `in_*` functions if/when it supports early return.
112148

113149
/// Returns `true` if this `Rvalue` contains qualif `Q`.

src/librustc_mir/transform/check_consts/validation.rs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use std::borrow::Cow;
1717
use std::ops::Deref;
1818

1919
use super::ops::{self, NonConstOp};
20-
use super::qualifs::{self, HasMutInterior, NeedsDrop};
20+
use super::qualifs::{self, CustomEq, HasMutInterior, NeedsDrop};
2121
use super::resolver::FlowSensitiveAnalysis;
2222
use super::{is_lang_panic_fn, ConstCx, ConstKind, Qualif};
2323
use crate::const_eval::{is_const_fn, is_unstable_const_fn};
@@ -142,9 +142,35 @@ impl Qualifs<'mir, 'tcx> {
142142

143143
let return_loc = ccx.body.terminator_loc(return_block);
144144

145+
let custom_eq = match ccx.const_kind() {
146+
// We don't care whether a `const fn` returns a value that is not structurally
147+
// matchable. Functions calls are opaque and always use type-based qualification, so
148+
// this value should never be used.
149+
ConstKind::ConstFn => true,
150+
151+
// If we know that all values of the return type are structurally matchable, there's no
152+
// need to run dataflow.
153+
ConstKind::Const | ConstKind::Static | ConstKind::StaticMut
154+
if !CustomEq::in_any_value_of_ty(ccx, ccx.body.return_ty()) =>
155+
{
156+
false
157+
}
158+
159+
ConstKind::Const | ConstKind::Static | ConstKind::StaticMut => {
160+
let mut cursor = FlowSensitiveAnalysis::new(CustomEq, ccx)
161+
.into_engine(ccx.tcx, &ccx.body, ccx.def_id)
162+
.iterate_to_fixpoint()
163+
.into_results_cursor(&ccx.body);
164+
165+
cursor.seek_after(return_loc);
166+
cursor.contains(RETURN_PLACE)
167+
}
168+
};
169+
145170
ConstQualifs {
146171
needs_drop: self.needs_drop(ccx, RETURN_PLACE, return_loc),
147172
has_mut_interior: self.has_mut_interior(ccx, RETURN_PLACE, return_loc),
173+
custom_eq,
148174
}
149175
}
150176
}

0 commit comments

Comments
 (0)