Skip to content

Commit 796c0ca

Browse files
Incorporate MIR const-checker into Pat lowering
1 parent 6b54829 commit 796c0ca

File tree

2 files changed

+89
-63
lines changed

2 files changed

+89
-63
lines changed

src/librustc_mir_build/hair/pattern/const_to_pat.rs

+18-3
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,14 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
2222
cv: &'tcx ty::Const<'tcx>,
2323
id: hir::HirId,
2424
span: Span,
25+
mir_structural_match_violation: bool,
2526
) -> Pat<'tcx> {
2627
debug!("const_to_pat: cv={:#?} id={:?}", cv, id);
2728
debug!("const_to_pat: cv.ty={:?} span={:?}", cv.ty, span);
2829

2930
self.tcx.infer_ctxt().enter(|infcx| {
3031
let mut convert = ConstToPat::new(self, id, span, infcx);
31-
convert.to_pat(cv)
32+
convert.to_pat(cv, mir_structural_match_violation)
3233
})
3334
}
3435
}
@@ -81,7 +82,11 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
8182
traits::type_marked_structural(self.id, self.span, &self.infcx, ty)
8283
}
8384

84-
fn to_pat(&mut self, cv: &'tcx ty::Const<'tcx>) -> Pat<'tcx> {
85+
fn to_pat(
86+
&mut self,
87+
cv: &'tcx ty::Const<'tcx>,
88+
mir_structural_match_violation: bool,
89+
) -> Pat<'tcx> {
8590
// This method is just a wrapper handling a validity check; the heavy lifting is
8691
// performed by the recursive `recur` method, which is not meant to be
8792
// invoked except by this method.
@@ -100,6 +105,11 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
100105
"search_for_structural_match_violation cv.ty: {:?} returned: {:?}",
101106
cv.ty, structural
102107
);
108+
109+
if structural.is_none() && mir_structural_match_violation {
110+
bug!("MIR const-checker found novel structural match violation");
111+
}
112+
103113
if let Some(non_sm_ty) = structural {
104114
let adt_def = match non_sm_ty {
105115
traits::NonStructuralMatchTy::Adt(adt_def) => adt_def,
@@ -146,13 +156,18 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
146156
if !ty_is_partial_eq {
147157
// span_fatal avoids ICE from resolution of non-existent method (rare case).
148158
self.tcx().sess.span_fatal(self.span, &make_msg());
149-
} else {
159+
} else if mir_structural_match_violation {
150160
self.tcx().struct_span_lint_hir(
151161
lint::builtin::INDIRECT_STRUCTURAL_MATCH,
152162
self.id,
153163
self.span,
154164
|lint| lint.build(&make_msg()).emit(),
155165
);
166+
} else {
167+
debug!(
168+
"`search_for_structural_match_violation` found one, but `CustomEq` was \
169+
not in the qualifs for that `const`"
170+
);
156171
}
157172
}
158173
}

src/librustc_mir_build/hair/pattern/mod.rs

+71-60
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
1515
use rustc_hir::pat_util::EnumerateAndAdjustIterator;
1616
use rustc_hir::RangeEnd;
1717
use rustc_index::vec::Idx;
18-
use rustc_middle::mir::interpret::{get_slice_bytes, sign_extend, ConstValue, ErrorHandled};
18+
use rustc_middle::mir::interpret::{get_slice_bytes, sign_extend, ConstValue};
1919
use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
2020
use rustc_middle::mir::UserTypeProjection;
2121
use rustc_middle::mir::{BorrowKind, Field, Mutability};
@@ -762,69 +762,80 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
762762
fn lower_path(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) -> Pat<'tcx> {
763763
let ty = self.tables.node_type(id);
764764
let res = self.tables.qpath_res(qpath, id);
765-
let is_associated_const = match res {
766-
Res::Def(DefKind::AssocConst, _) => true,
767-
_ => false,
765+
766+
let pat_from_kind = |kind| Pat { span, ty, kind: Box::new(kind) };
767+
768+
let (def_id, is_associated_const) = match res {
769+
Res::Def(DefKind::Const, def_id) => (def_id, false),
770+
Res::Def(DefKind::AssocConst, def_id) => (def_id, true),
771+
772+
_ => return pat_from_kind(self.lower_variant_or_leaf(res, id, span, ty, vec![])),
768773
};
769-
let kind = match res {
770-
Res::Def(DefKind::Const | DefKind::AssocConst, def_id) => {
771-
let substs = self.tables.node_substs(id);
772-
// Use `Reveal::All` here because patterns are always monomorphic even if their function isn't.
773-
match self.tcx.const_eval_resolve(
774-
self.param_env.with_reveal_all(),
775-
def_id,
776-
substs,
777-
None,
778-
Some(span),
779-
) {
780-
Ok(value) => {
781-
let const_ =
782-
ty::Const::from_value(self.tcx, value, self.tables.node_type(id));
783-
784-
let pattern = self.const_to_pat(&const_, id, span);
785-
if !is_associated_const {
786-
return pattern;
787-
}
788774

789-
let user_provided_types = self.tables().user_provided_types();
790-
return if let Some(u_ty) = user_provided_types.get(id) {
791-
let user_ty = PatTyProj::from_user_type(*u_ty);
792-
Pat {
793-
span,
794-
kind: Box::new(PatKind::AscribeUserType {
795-
subpattern: pattern,
796-
ascription: Ascription {
797-
/// Note that use `Contravariant` here. See the
798-
/// `variance` field documentation for details.
799-
variance: ty::Variance::Contravariant,
800-
user_ty,
801-
user_ty_span: span,
802-
},
803-
}),
804-
ty: const_.ty,
805-
}
806-
} else {
807-
pattern
808-
};
809-
}
810-
Err(ErrorHandled::TooGeneric) => {
811-
self.errors.push(if is_associated_const {
812-
PatternError::AssocConstInPattern(span)
813-
} else {
814-
PatternError::StaticInPattern(span)
815-
});
816-
PatKind::Wild
817-
}
818-
Err(_) => {
819-
self.tcx.sess.span_err(span, "could not evaluate constant pattern");
820-
PatKind::Wild
821-
}
822-
}
775+
// Use `Reveal::All` here because patterns are always monomorphic even if their function
776+
// isn't.
777+
let param_env_reveal_all = self.param_env.with_reveal_all();
778+
let substs = self.tables.node_substs(id);
779+
let instance = match ty::Instance::resolve(self.tcx, param_env_reveal_all, def_id, substs) {
780+
Ok(Some(i)) => i,
781+
Ok(None) => {
782+
self.errors.push(if is_associated_const {
783+
PatternError::AssocConstInPattern(span)
784+
} else {
785+
PatternError::StaticInPattern(span)
786+
});
787+
788+
return pat_from_kind(PatKind::Wild);
789+
}
790+
791+
Err(_) => {
792+
self.tcx.sess.span_err(span, "could not evaluate constant pattern");
793+
return pat_from_kind(PatKind::Wild);
823794
}
824-
_ => self.lower_variant_or_leaf(res, id, span, ty, vec![]),
825795
};
826796

827-
Pat { span, ty, kind: Box::new(kind) }
797+
// `mir_const_qualif` must be called with the `DefId` of the item where the const is
798+
// defined, not where it is declared. The difference is significant for associated
799+
// constants.
800+
let mir_structural_match_violation = self.tcx.mir_const_qualif(instance.def_id()).custom_eq;
801+
debug!("mir_structural_match_violation({:?}) -> {}", qpath, mir_structural_match_violation);
802+
803+
match self.tcx.const_eval_instance(param_env_reveal_all, instance, Some(span)) {
804+
Ok(value) => {
805+
let const_ = ty::Const::from_value(self.tcx, value, self.tables.node_type(id));
806+
807+
let pattern = self.const_to_pat(&const_, id, span, mir_structural_match_violation);
808+
809+
if !is_associated_const {
810+
return pattern;
811+
}
812+
813+
let user_provided_types = self.tables().user_provided_types();
814+
if let Some(u_ty) = user_provided_types.get(id) {
815+
let user_ty = PatTyProj::from_user_type(*u_ty);
816+
Pat {
817+
span,
818+
kind: Box::new(PatKind::AscribeUserType {
819+
subpattern: pattern,
820+
ascription: Ascription {
821+
/// Note that use `Contravariant` here. See the
822+
/// `variance` field documentation for details.
823+
variance: ty::Variance::Contravariant,
824+
user_ty,
825+
user_ty_span: span,
826+
},
827+
}),
828+
ty: const_.ty,
829+
}
830+
} else {
831+
pattern
832+
}
833+
}
834+
Err(_) => {
835+
self.tcx.sess.span_err(span, "could not evaluate constant pattern");
836+
pat_from_kind(PatKind::Wild)
837+
}
838+
}
828839
}
829840

830841
/// Converts literals, paths and negation of literals to patterns.
@@ -849,7 +860,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
849860

850861
let lit_input = LitToConstInput { lit: &lit.node, ty: self.tables.expr_ty(expr), neg };
851862
match self.tcx.at(expr.span).lit_to_const(lit_input) {
852-
Ok(val) => *self.const_to_pat(val, expr.hir_id, lit.span).kind,
863+
Ok(val) => *self.const_to_pat(val, expr.hir_id, lit.span, false).kind,
853864
Err(LitToConstError::UnparseableFloat) => {
854865
self.errors.push(PatternError::FloatBug);
855866
PatKind::Wild

0 commit comments

Comments
 (0)