summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_mir_build/src/thir
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:57:31 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:57:31 +0000
commitdc0db358abe19481e475e10c32149b53370f1a1c (patch)
treeab8ce99c4b255ce46f99ef402c27916055b899ee /compiler/rustc_mir_build/src/thir
parentReleasing progress-linux version 1.71.1+dfsg1-2~progress7.99u1. (diff)
downloadrustc-dc0db358abe19481e475e10c32149b53370f1a1c.tar.xz
rustc-dc0db358abe19481e475e10c32149b53370f1a1c.zip
Merging upstream version 1.72.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_mir_build/src/thir')
-rw-r--r--compiler/rustc_mir_build/src/thir/constant.rs20
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs101
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/mod.rs6
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs12
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs380
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs33
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs127
-rw-r--r--compiler/rustc_mir_build/src/thir/print.rs8
8 files changed, 393 insertions, 294 deletions
diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs
index 57ae6a365..fbb74650f 100644
--- a/compiler/rustc_mir_build/src/thir/constant.rs
+++ b/compiler/rustc_mir_build/src/thir/constant.rs
@@ -3,6 +3,8 @@ use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
use rustc_middle::ty::{self, ParamEnv, ScalarInt, TyCtxt};
use rustc_span::DUMMY_SP;
+use crate::build::parse_float_into_scalar;
+
pub(crate) fn lit_to_const<'tcx>(
tcx: TyCtxt<'tcx>,
lit_input: LitToConstInput<'tcx>,
@@ -46,12 +48,28 @@ pub(crate) fn lit_to_const<'tcx>(
(ast::LitKind::Byte(n), ty::Uint(ty::UintTy::U8)) => {
ty::ValTree::from_scalar_int((*n).into())
}
+ (ast::LitKind::CStr(data, _), ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Adt(def, _) if Some(def.did()) == tcx.lang_items().c_str()) =>
+ {
+ let bytes = data as &[u8];
+ ty::ValTree::from_raw_bytes(tcx, bytes)
+ }
(ast::LitKind::Int(n, _), ty::Uint(_)) | (ast::LitKind::Int(n, _), ty::Int(_)) => {
let scalar_int =
trunc(if neg { (*n as i128).overflowing_neg().0 as u128 } else { *n })?;
ty::ValTree::from_scalar_int(scalar_int)
}
(ast::LitKind::Bool(b), ty::Bool) => ty::ValTree::from_scalar_int((*b).into()),
+ (ast::LitKind::Float(n, _), ty::Float(fty)) => {
+ let bits = parse_float_into_scalar(*n, *fty, neg)
+ .ok_or_else(|| {
+ LitToConstError::Reported(tcx.sess.delay_span_bug(
+ DUMMY_SP,
+ format!("couldn't parse float literal: {:?}", lit_input.lit),
+ ))
+ })?
+ .assert_int();
+ ty::ValTree::from_scalar_int(bits)
+ }
(ast::LitKind::Char(c), ty::Char) => ty::ValTree::from_scalar_int((*c).into()),
(ast::LitKind::Err, _) => {
return Err(LitToConstError::Reported(
@@ -61,5 +79,5 @@ pub(crate) fn lit_to_const<'tcx>(
_ => return Err(LitToConstError::TypeError),
};
- Ok(tcx.mk_const(valtree, ty))
+ Ok(ty::Const::new_value(tcx, valtree, ty))
}
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index b20495d60..37537683f 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -13,7 +13,7 @@ use rustc_middle::middle::region;
use rustc_middle::mir::{self, BinOp, BorrowKind, UnOp};
use rustc_middle::thir::*;
use rustc_middle::ty::adjustment::{
- Adjust, Adjustment, AutoBorrow, AutoBorrowMutability, PointerCast,
+ Adjust, Adjustment, AutoBorrow, AutoBorrowMutability, PointerCoercion,
};
use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::{
@@ -125,11 +125,16 @@ impl<'tcx> Cx<'tcx> {
};
let kind = match adjustment.kind {
- Adjust::Pointer(PointerCast::Unsize) => {
+ Adjust::Pointer(PointerCoercion::Unsize) => {
adjust_span(&mut expr);
- ExprKind::Pointer { cast: PointerCast::Unsize, source: self.thir.exprs.push(expr) }
+ ExprKind::PointerCoercion {
+ cast: PointerCoercion::Unsize,
+ source: self.thir.exprs.push(expr),
+ }
+ }
+ Adjust::Pointer(cast) => {
+ ExprKind::PointerCoercion { cast, source: self.thir.exprs.push(expr) }
}
- Adjust::Pointer(cast) => ExprKind::Pointer { cast, source: self.thir.exprs.push(expr) },
Adjust::NeverToAny if adjustment.target.is_never() => return expr,
Adjust::NeverToAny => ExprKind::NeverToAny { source: self.thir.exprs.push(expr) },
Adjust::Deref(None) => {
@@ -143,9 +148,11 @@ impl<'tcx> Cx<'tcx> {
expr = Expr {
temp_lifetime,
- ty: self
- .tcx
- .mk_ref(deref.region, ty::TypeAndMut { ty: expr.ty, mutbl: deref.mutbl }),
+ ty: Ty::new_ref(
+ self.tcx,
+ deref.region,
+ ty::TypeAndMut { ty: expr.ty, mutbl: deref.mutbl },
+ ),
span,
kind: ExprKind::Borrow {
borrow_kind: deref.mutbl.to_borrow_kind(),
@@ -190,9 +197,9 @@ impl<'tcx> Cx<'tcx> {
// Special cased so that we can type check that the element
// type of the source matches the pointed to type of the
// destination.
- ExprKind::Pointer {
+ ExprKind::PointerCoercion {
source: self.mirror_expr(source),
- cast: PointerCast::ArrayToPointer,
+ cast: PointerCoercion::ArrayToPointer,
}
} else {
// check whether this is casting an enum variant discriminant
@@ -208,17 +215,18 @@ impl<'tcx> Cx<'tcx> {
// so we wouldn't have to compute and store the actual value
let hir::ExprKind::Path(ref qpath) = source.kind else {
- return ExprKind::Cast { source: self.mirror_expr(source)};
+ return ExprKind::Cast { source: self.mirror_expr(source) };
};
let res = self.typeck_results().qpath_res(qpath, source.hir_id);
let ty = self.typeck_results().node_type(source.hir_id);
let ty::Adt(adt_def, substs) = ty.kind() else {
- return ExprKind::Cast { source: self.mirror_expr(source)};
+ return ExprKind::Cast { source: self.mirror_expr(source) };
};
- let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Const), variant_ctor_id) = res else {
- return ExprKind::Cast { source: self.mirror_expr(source)};
+ let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Const), variant_ctor_id) = res
+ else {
+ return ExprKind::Cast { source: self.mirror_expr(source) };
};
let idx = adt_def.variant_index_with_ctor_id(variant_ctor_id);
@@ -308,7 +316,7 @@ impl<'tcx> Cx<'tcx> {
let arg_tys = args.iter().map(|e| self.typeck_results().expr_ty_adjusted(e));
let tupled_args = Expr {
- ty: tcx.mk_tup_from_iter(arg_tys),
+ ty: Ty::new_tup_from_iter(tcx, arg_tys),
temp_lifetime,
span: expr.span,
kind: ExprKind::Tuple { fields: self.mirror_exprs(args) },
@@ -351,19 +359,35 @@ impl<'tcx> Cx<'tcx> {
});
}
}
- let adt_data =
- if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = fun.kind {
- // Tuple-like ADTs are represented as ExprKind::Call. We convert them here.
- expr_ty.ty_adt_def().and_then(|adt_def| match path.res {
- Res::Def(DefKind::Ctor(_, CtorKind::Fn), ctor_id) => {
+
+ // Tuple-like ADTs are represented as ExprKind::Call. We convert them here.
+ let adt_data = if let hir::ExprKind::Path(ref qpath) = fun.kind
+ && let Some(adt_def) = expr_ty.ty_adt_def() {
+ match qpath {
+ hir::QPath::Resolved(_, ref path) => {
+ match path.res {
+ Res::Def(DefKind::Ctor(_, CtorKind::Fn), ctor_id) => {
+ Some((adt_def, adt_def.variant_index_with_ctor_id(ctor_id)))
+ }
+ Res::SelfCtor(..) => Some((adt_def, FIRST_VARIANT)),
+ _ => None,
+ }
+ }
+ hir::QPath::TypeRelative(_ty, _) => {
+ if let Some((DefKind::Ctor(_, CtorKind::Fn), ctor_id)) =
+ self.typeck_results().type_dependent_def(fun.hir_id)
+ {
Some((adt_def, adt_def.variant_index_with_ctor_id(ctor_id)))
+ } else {
+ None
}
- Res::SelfCtor(..) => Some((adt_def, FIRST_VARIANT)),
- _ => None,
- })
- } else {
- None
- };
+
+ }
+ _ => None,
+ }
+ } else {
+ None
+ };
if let Some((adt_def, index)) = adt_data {
let substs = self.typeck_results().node_substs(fun.hir_id);
let user_provided_types = self.typeck_results().user_provided_types();
@@ -694,7 +718,8 @@ impl<'tcx> Cx<'tcx> {
ExprKind::Repeat { value: self.mirror_expr(v), count: *count }
}
- hir::ExprKind::Ret(ref v) => ExprKind::Return { value: v.map(|v| self.mirror_expr(v)) },
+ hir::ExprKind::Ret(v) => ExprKind::Return { value: v.map(|v| self.mirror_expr(v)) },
+ hir::ExprKind::Become(call) => ExprKind::Become { value: self.mirror_expr(call) },
hir::ExprKind::Break(dest, ref value) => match dest.target_id {
Ok(target_id) => ExprKind::Break {
label: region::Scope { id: target_id.local_id, data: region::ScopeData::Node },
@@ -854,7 +879,11 @@ impl<'tcx> Cx<'tcx> {
let user_ty = self.user_substs_applied_to_res(expr.hir_id, Res::Def(kind, def_id));
debug!("method_callee: user_ty={:?}", user_ty);
(
- self.tcx().mk_fn_def(def_id, self.typeck_results().node_substs(expr.hir_id)),
+ Ty::new_fn_def(
+ self.tcx(),
+ def_id,
+ self.typeck_results().node_substs(expr.hir_id),
+ ),
user_ty,
)
}
@@ -1007,7 +1036,7 @@ impl<'tcx> Cx<'tcx> {
let ty::Ref(region, _, mutbl) = *self.thir[args[0]].ty.kind() else {
span_bug!(span, "overloaded_place: receiver is not a reference");
};
- let ref_ty = self.tcx.mk_ref(region, ty::TypeAndMut { ty: place_ty, mutbl });
+ let ref_ty = Ty::new_ref(self.tcx, region, ty::TypeAndMut { ty: place_ty, mutbl });
// construct the complete expression `foo()` for the overloaded call,
// which will yield the &T type
@@ -1095,8 +1124,12 @@ impl<'tcx> Cx<'tcx> {
ty::UpvarCapture::ByRef(upvar_borrow) => {
let borrow_kind = match upvar_borrow {
ty::BorrowKind::ImmBorrow => BorrowKind::Shared,
- ty::BorrowKind::UniqueImmBorrow => BorrowKind::Unique,
- ty::BorrowKind::MutBorrow => BorrowKind::Mut { allow_two_phase_borrow: false },
+ ty::BorrowKind::UniqueImmBorrow => {
+ BorrowKind::Mut { kind: mir::MutBorrowKind::ClosureCapture }
+ }
+ ty::BorrowKind::MutBorrow => {
+ BorrowKind::Mut { kind: mir::MutBorrowKind::Default }
+ }
};
Expr {
temp_lifetime,
@@ -1132,9 +1165,9 @@ impl ToBorrowKind for AutoBorrowMutability {
use rustc_middle::ty::adjustment::AllowTwoPhase;
match *self {
AutoBorrowMutability::Mut { allow_two_phase_borrow } => BorrowKind::Mut {
- allow_two_phase_borrow: match allow_two_phase_borrow {
- AllowTwoPhase::Yes => true,
- AllowTwoPhase::No => false,
+ kind: match allow_two_phase_borrow {
+ AllowTwoPhase::Yes => mir::MutBorrowKind::TwoPhaseBorrow,
+ AllowTwoPhase::No => mir::MutBorrowKind::Default,
},
},
AutoBorrowMutability::Not => BorrowKind::Shared,
@@ -1145,7 +1178,7 @@ impl ToBorrowKind for AutoBorrowMutability {
impl ToBorrowKind for hir::Mutability {
fn to_borrow_kind(&self) -> BorrowKind {
match *self {
- hir::Mutability::Mut => BorrowKind::Mut { allow_two_phase_borrow: false },
+ hir::Mutability::Mut => BorrowKind::Mut { kind: mir::MutBorrowKind::Default },
hir::Mutability::Not => BorrowKind::Shared,
}
}
diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs
index 463f639de..e6a98d1aa 100644
--- a/compiler/rustc_mir_build/src/thir/cx/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs
@@ -15,7 +15,7 @@ use rustc_hir::HirId;
use rustc_hir::Node;
use rustc_middle::middle::region;
use rustc_middle::thir::*;
-use rustc_middle::ty::{self, RvalueScopes, TyCtxt};
+use rustc_middle::ty::{self, RvalueScopes, Ty, TyCtxt};
use rustc_span::Span;
pub(crate) fn thir_body(
@@ -40,7 +40,7 @@ pub(crate) fn thir_body(
// It will always be `()` in this case.
if tcx.def_kind(owner_def) == DefKind::Generator && body.params.is_empty() {
cx.thir.params.push(Param {
- ty: tcx.mk_unit(),
+ ty: Ty::new_unit(tcx),
pat: None,
ty_span: None,
self_kind: None,
@@ -142,7 +142,7 @@ impl<'tcx> Cx<'tcx> {
var: ty::BoundVar::from_usize(bound_vars.len() - 1),
kind: ty::BrEnv,
};
- let env_region = self.tcx.mk_re_late_bound(ty::INNERMOST, br);
+ let env_region = ty::Region::new_late_bound(self.tcx, ty::INNERMOST, br);
let closure_env_ty =
self.tcx.closure_env_ty(closure_def_id, closure_substs, env_region).unwrap();
let liberated_closure_env_ty = self.tcx.erase_late_bound_regions(
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index 1e51cb9aa..ef60f08bf 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -443,7 +443,12 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
let mut let_suggestion = None;
let mut misc_suggestion = None;
let mut interpreted_as_const = None;
- if let PatKind::Constant { .. } = pat.kind
+
+ if let PatKind::Constant { .. }
+ | PatKind::AscribeUserType {
+ subpattern: box Pat { kind: PatKind::Constant { .. }, .. },
+ ..
+ } = pat.kind
&& let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(pat.span)
{
// If the pattern to match is an integer literal:
@@ -825,6 +830,11 @@ fn non_exhaustive_match<'p, 'tcx>(
_ => " or multiple match arms",
},
);
+
+ let all_arms_have_guards = arms.iter().all(|arm_id| thir[*arm_id].guard.is_some());
+ if !is_empty_match && all_arms_have_guards {
+ err.subdiagnostic(NonExhaustiveMatchAllArmsGuarded);
+ }
if let Some((span, sugg)) = suggestion {
err.span_suggestion_verbose(span, msg, sugg, Applicability::HasPlaceholders);
} else {
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index b243f1dc8..050b01294 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -1,13 +1,14 @@
use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
use rustc_index::Idx;
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::Obligation;
use rustc_middle::mir;
use rustc_middle::thir::{FieldPat, Pat, PatKind};
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt, ValTree};
use rustc_session::lint;
use rustc_span::Span;
-use rustc_target::abi::FieldIdx;
+use rustc_target::abi::{FieldIdx, VariantIdx};
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
use rustc_trait_selection::traits::{self, ObligationCause};
@@ -29,11 +30,11 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
cv: mir::ConstantKind<'tcx>,
id: hir::HirId,
span: Span,
- mir_structural_match_violation: bool,
+ check_body_for_struct_match_violation: Option<DefId>,
) -> Box<Pat<'tcx>> {
let infcx = self.tcx.infer_ctxt().build();
let mut convert = ConstToPat::new(self, id, span, infcx);
- convert.to_pat(cv, mir_structural_match_violation)
+ convert.to_pat(cv, check_body_for_struct_match_violation)
}
}
@@ -104,7 +105,7 @@ impl<'tcx> ConstToPat<'tcx> {
fn to_pat(
&mut self,
cv: mir::ConstantKind<'tcx>,
- mir_structural_match_violation: bool,
+ check_body_for_struct_match_violation: Option<DefId>,
) -> Box<Pat<'tcx>> {
trace!(self.treat_byte_string_as_slice);
// This method is just a wrapper handling a validity check; the heavy lifting is
@@ -114,14 +115,44 @@ impl<'tcx> ConstToPat<'tcx> {
// once indirect_structural_match is a full fledged error, this
// level of indirection can be eliminated
- let inlined_const_as_pat =
- self.recur(cv, mir_structural_match_violation).unwrap_or_else(|_| {
- Box::new(Pat {
- span: self.span,
- ty: cv.ty(),
- kind: PatKind::Constant { value: cv },
- })
- });
+ let mir_structural_match_violation = check_body_for_struct_match_violation.map(|def_id| {
+ // `mir_const_qualif` must be called with the `DefId` of the item where the const is
+ // defined, not where it is declared. The difference is significant for associated
+ // constants.
+ self.tcx().mir_const_qualif(def_id).custom_eq
+ });
+ debug!(?check_body_for_struct_match_violation, ?mir_structural_match_violation);
+
+ let inlined_const_as_pat = match cv {
+ mir::ConstantKind::Ty(c) => match c.kind() {
+ ty::ConstKind::Param(_)
+ | ty::ConstKind::Infer(_)
+ | ty::ConstKind::Bound(_, _)
+ | ty::ConstKind::Placeholder(_)
+ | ty::ConstKind::Unevaluated(_)
+ | ty::ConstKind::Error(_)
+ | ty::ConstKind::Expr(_) => {
+ span_bug!(self.span, "unexpected const in `to_pat`: {:?}", c.kind())
+ }
+ ty::ConstKind::Value(valtree) => self
+ .recur(valtree, cv.ty(), mir_structural_match_violation.unwrap_or(false))
+ .unwrap_or_else(|_| {
+ Box::new(Pat {
+ span: self.span,
+ ty: cv.ty(),
+ kind: PatKind::Constant { value: cv },
+ })
+ }),
+ },
+ mir::ConstantKind::Unevaluated(_, _) => {
+ span_bug!(self.span, "unevaluated const in `to_pat`: {cv:?}")
+ }
+ mir::ConstantKind::Val(_, _) => Box::new(Pat {
+ span: self.span,
+ ty: cv.ty(),
+ kind: PatKind::Constant { value: cv },
+ }),
+ };
if !self.saw_const_match_error.get() {
// If we were able to successfully convert the const to some pat,
@@ -141,29 +172,70 @@ impl<'tcx> ConstToPat<'tcx> {
//
// FIXME(#73448): Find a way to bring const qualification into parity with
// `search_for_structural_match_violation`.
- if structural.is_none() && mir_structural_match_violation {
+ if structural.is_none() && mir_structural_match_violation.unwrap_or(false) {
warn!("MIR const-checker found novel structural match violation. See #73448.");
return inlined_const_as_pat;
}
if let Some(non_sm_ty) = structural {
if !self.type_may_have_partial_eq_impl(cv.ty()) {
- // fatal avoids ICE from resolution of nonexistent method (rare case).
- self.tcx()
- .sess
- .emit_fatal(TypeNotStructural { span: self.span, non_sm_ty: non_sm_ty });
- } else if mir_structural_match_violation && !self.saw_const_match_lint.get() {
- self.tcx().emit_spanned_lint(
- lint::builtin::INDIRECT_STRUCTURAL_MATCH,
- self.id,
- self.span,
- IndirectStructuralMatch { non_sm_ty },
- );
- } else {
- debug!(
- "`search_for_structural_match_violation` found one, but `CustomEq` was \
- not in the qualifs for that `const`"
- );
+ if let ty::Adt(def, ..) = non_sm_ty.kind() {
+ if def.is_union() {
+ let err = UnionPattern { span: self.span };
+ self.tcx().sess.emit_err(err);
+ } else {
+ // fatal avoids ICE from resolution of nonexistent method (rare case).
+ self.tcx()
+ .sess
+ .emit_fatal(TypeNotStructural { span: self.span, non_sm_ty });
+ }
+ } else {
+ let err = InvalidPattern { span: self.span, non_sm_ty };
+ self.tcx().sess.emit_err(err);
+ return Box::new(Pat { span: self.span, ty: cv.ty(), kind: PatKind::Wild });
+ }
+ } else if !self.saw_const_match_lint.get() {
+ if let Some(mir_structural_match_violation) = mir_structural_match_violation {
+ match non_sm_ty.kind() {
+ ty::RawPtr(pointee)
+ if pointee.ty.is_sized(self.tcx(), self.param_env) => {}
+ ty::FnPtr(..) | ty::RawPtr(..) => {
+ self.tcx().emit_spanned_lint(
+ lint::builtin::POINTER_STRUCTURAL_MATCH,
+ self.id,
+ self.span,
+ PointerPattern,
+ );
+ }
+ ty::Adt(..) if mir_structural_match_violation => {
+ self.tcx().emit_spanned_lint(
+ lint::builtin::INDIRECT_STRUCTURAL_MATCH,
+ self.id,
+ self.span,
+ IndirectStructuralMatch { non_sm_ty },
+ );
+ }
+ _ => {
+ debug!(
+ "`search_for_structural_match_violation` found one, but `CustomEq` was \
+ not in the qualifs for that `const`"
+ );
+ }
+ }
+ }
+ }
+ } else if !self.saw_const_match_lint.get() {
+ match cv.ty().kind() {
+ ty::RawPtr(pointee) if pointee.ty.is_sized(self.tcx(), self.param_env) => {}
+ ty::FnPtr(..) | ty::RawPtr(..) => {
+ self.tcx().emit_spanned_lint(
+ lint::builtin::POINTER_STRUCTURAL_MATCH,
+ self.id,
+ self.span,
+ PointerPattern,
+ );
+ }
+ _ => {}
}
}
}
@@ -171,6 +243,7 @@ impl<'tcx> ConstToPat<'tcx> {
inlined_const_as_pat
}
+ #[instrument(level = "trace", skip(self), ret)]
fn type_may_have_partial_eq_impl(&self, ty: Ty<'tcx>) -> bool {
// double-check there even *is* a semantic `PartialEq` to dispatch to.
//
@@ -187,29 +260,19 @@ impl<'tcx> ConstToPat<'tcx> {
);
// FIXME: should this call a `predicate_must_hold` variant instead?
- let has_impl = self.infcx.predicate_may_hold(&partial_eq_obligation);
-
- // Note: To fix rust-lang/rust#65466, we could just remove this type
- // walk hack for function pointers, and unconditionally error
- // if `PartialEq` is not implemented. However, that breaks stable
- // code at the moment, because types like `for <'a> fn(&'a ())` do
- // not *yet* implement `PartialEq`. So for now we leave this here.
- has_impl
- || ty.walk().any(|t| match t.unpack() {
- ty::subst::GenericArgKind::Lifetime(_) => false,
- ty::subst::GenericArgKind::Type(t) => t.is_fn_ptr(),
- ty::subst::GenericArgKind::Const(_) => false,
- })
+ self.infcx.predicate_may_hold(&partial_eq_obligation)
}
fn field_pats(
&self,
- vals: impl Iterator<Item = mir::ConstantKind<'tcx>>,
+ vals: impl Iterator<Item = (ValTree<'tcx>, Ty<'tcx>)>,
) -> Result<Vec<FieldPat<'tcx>>, FallbackToConstRef> {
vals.enumerate()
- .map(|(idx, val)| {
+ .map(|(idx, (val, ty))| {
let field = FieldIdx::new(idx);
- Ok(FieldPat { field, pattern: self.recur(val, false)? })
+ // Patterns can only use monomorphic types.
+ let ty = self.tcx().normalize_erasing_regions(self.param_env, ty);
+ Ok(FieldPat { field, pattern: self.recur(val, ty, false)? })
})
.collect()
}
@@ -218,7 +281,8 @@ impl<'tcx> ConstToPat<'tcx> {
#[instrument(skip(self), level = "debug")]
fn recur(
&self,
- cv: mir::ConstantKind<'tcx>,
+ cv: ValTree<'tcx>,
+ ty: Ty<'tcx>,
mir_structural_match_violation: bool,
) -> Result<Box<Pat<'tcx>>, FallbackToConstRef> {
let id = self.id;
@@ -226,8 +290,9 @@ impl<'tcx> ConstToPat<'tcx> {
let tcx = self.tcx();
let param_env = self.param_env;
- let kind = match cv.ty().kind() {
+ let kind = match ty.kind() {
ty::Float(_) => {
+ self.saw_const_match_lint.set(true);
tcx.emit_spanned_lint(
lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
id,
@@ -236,27 +301,6 @@ impl<'tcx> ConstToPat<'tcx> {
);
return Err(FallbackToConstRef);
}
- ty::Adt(adt_def, _) if adt_def.is_union() => {
- // Matching on union fields is unsafe, we can't hide it in constants
- self.saw_const_match_error.set(true);
- let err = UnionPattern { span };
- tcx.sess.emit_err(err);
- PatKind::Wild
- }
- ty::Adt(..)
- if !self.type_may_have_partial_eq_impl(cv.ty())
- // FIXME(#73448): Find a way to bring const qualification into parity with
- // `search_for_structural_match_violation` and then remove this condition.
-
- // Obtain the actual type that isn't annotated. If we just looked at `cv.ty` we
- // could get `Option<NonStructEq>`, even though `Option` is annotated with derive.
- && let Some(non_sm_ty) = traits::search_for_structural_match_violation(span, tcx, cv.ty()) =>
- {
- self.saw_const_match_error.set(true);
- let err = TypeNotStructural { span, non_sm_ty };
- tcx.sess.emit_err(err);
- PatKind::Wild
- }
// If the type is not structurally comparable, just emit the constant directly,
// causing the pattern match code to treat it opaquely.
// FIXME: This code doesn't emit errors itself, the caller emits the errors.
@@ -266,16 +310,14 @@ impl<'tcx> ConstToPat<'tcx> {
// details.
// Backwards compatibility hack because we can't cause hard errors on these
// types, so we compare them via `PartialEq::eq` at runtime.
- ty::Adt(..) if !self.type_marked_structural(cv.ty()) && self.behind_reference.get() => {
- if !self.saw_const_match_error.get()
- && !self.saw_const_match_lint.get()
- {
+ ty::Adt(..) if !self.type_marked_structural(ty) && self.behind_reference.get() => {
+ if !self.saw_const_match_error.get() && !self.saw_const_match_lint.get() {
self.saw_const_match_lint.set(true);
tcx.emit_spanned_lint(
lint::builtin::INDIRECT_STRUCTURAL_MATCH,
id,
span,
- IndirectStructuralMatch { non_sm_ty: cv.ty() },
+ IndirectStructuralMatch { non_sm_ty: ty },
);
}
// Since we are behind a reference, we can just bubble the error up so we get a
@@ -283,108 +325,64 @@ impl<'tcx> ConstToPat<'tcx> {
// `PartialEq::eq` on it.
return Err(FallbackToConstRef);
}
- ty::Adt(adt_def, _) if !self.type_marked_structural(cv.ty()) => {
- debug!(
- "adt_def {:?} has !type_marked_structural for cv.ty: {:?}",
- adt_def,
- cv.ty()
- );
+ ty::Adt(adt_def, _) if !self.type_marked_structural(ty) => {
+ debug!("adt_def {:?} has !type_marked_structural for cv.ty: {:?}", adt_def, ty,);
self.saw_const_match_error.set(true);
- let err = TypeNotStructural { span, non_sm_ty: cv.ty() };
+ let err = TypeNotStructural { span, non_sm_ty: ty };
tcx.sess.emit_err(err);
PatKind::Wild
}
ty::Adt(adt_def, substs) if adt_def.is_enum() => {
- let destructured = tcx.destructure_mir_constant(param_env, cv);
-
+ let (&variant_index, fields) = cv.unwrap_branch().split_first().unwrap();
+ let variant_index =
+ VariantIdx::from_u32(variant_index.unwrap_leaf().try_to_u32().ok().unwrap());
PatKind::Variant {
adt_def: *adt_def,
substs,
- variant_index: destructured
- .variant
- .expect("destructed const of adt without variant id"),
- subpatterns: self.field_pats(destructured.fields.iter().copied())?,
+ variant_index,
+ subpatterns: self.field_pats(
+ fields.iter().copied().zip(
+ adt_def.variants()[variant_index]
+ .fields
+ .iter()
+ .map(|field| field.ty(self.tcx(), substs)),
+ ),
+ )?,
}
}
- ty::Tuple(_) | ty::Adt(_, _) => {
- let destructured = tcx.destructure_mir_constant(param_env, cv);
- PatKind::Leaf { subpatterns: self.field_pats(destructured.fields.iter().copied())? }
- }
- ty::Array(..) => PatKind::Array {
- prefix: tcx
- .destructure_mir_constant(param_env, cv)
- .fields
+ ty::Tuple(fields) => PatKind::Leaf {
+ subpatterns: self
+ .field_pats(cv.unwrap_branch().iter().copied().zip(fields.iter()))?,
+ },
+ ty::Adt(def, substs) => PatKind::Leaf {
+ subpatterns: self.field_pats(cv.unwrap_branch().iter().copied().zip(
+ def.non_enum_variant().fields.iter().map(|field| field.ty(self.tcx(), substs)),
+ ))?,
+ },
+ ty::Slice(elem_ty) => PatKind::Slice {
+ prefix: cv
+ .unwrap_branch()
+ .iter()
+ .map(|val| self.recur(*val, *elem_ty, false))
+ .collect::<Result<_, _>>()?,
+ slice: None,
+ suffix: Box::new([]),
+ },
+ ty::Array(elem_ty, _) => PatKind::Array {
+ prefix: cv
+ .unwrap_branch()
.iter()
- .map(|val| self.recur(*val, false))
+ .map(|val| self.recur(*val, *elem_ty, false))
.collect::<Result<_, _>>()?,
slice: None,
suffix: Box::new([]),
},
ty::Ref(_, pointee_ty, ..) => match *pointee_ty.kind() {
- // These are not allowed and will error elsewhere anyway.
- ty::Dynamic(..) => {
- self.saw_const_match_error.set(true);
- let err = InvalidPattern { span, non_sm_ty: cv.ty() };
- tcx.sess.emit_err(err);
- PatKind::Wild
- }
- // `&str` is represented as `ConstValue::Slice`, let's keep using this
+ // `&str` is represented as a valtree, let's keep using this
// optimization for now.
- ty::Str => PatKind::Constant { value: cv },
- // `b"foo"` produces a `&[u8; 3]`, but you can't use constants of array type when
- // matching against references, you can only use byte string literals.
- // The typechecker has a special case for byte string literals, by treating them
- // as slices. This means we turn `&[T; N]` constants into slice patterns, which
- // has no negative effects on pattern matching, even if we're actually matching on
- // arrays.
- ty::Array(..) if !self.treat_byte_string_as_slice => {
- let old = self.behind_reference.replace(true);
- let array = tcx.deref_mir_constant(self.param_env.and(cv));
- let val = PatKind::Deref {
- subpattern: Box::new(Pat {
- kind: PatKind::Array {
- prefix: tcx
- .destructure_mir_constant(param_env, array)
- .fields
- .iter()
- .map(|val| self.recur(*val, false))
- .collect::<Result<_, _>>()?,
- slice: None,
- suffix: Box::new([]),
- },
- span,
- ty: *pointee_ty,
- }),
- };
- self.behind_reference.set(old);
- val
- }
- ty::Array(elem_ty, _) |
- // Cannot merge this with the catch all branch below, because the `const_deref`
- // changes the type from slice to array, we need to keep the original type in the
- // pattern.
- ty::Slice(elem_ty) => {
- let old = self.behind_reference.replace(true);
- let array = tcx.deref_mir_constant(self.param_env.and(cv));
- let val = PatKind::Deref {
- subpattern: Box::new(Pat {
- kind: PatKind::Slice {
- prefix: tcx
- .destructure_mir_constant(param_env, array)
- .fields
- .iter()
- .map(|val| self.recur(*val, false))
- .collect::<Result<_, _>>()?,
- slice: None,
- suffix: Box::new([]),
- },
- span,
- ty: tcx.mk_slice(elem_ty),
- }),
- };
- self.behind_reference.set(old);
- val
- }
+ ty::Str => PatKind::Constant {
+ value: mir::ConstantKind::Ty(ty::Const::new_value(tcx, cv, ty)),
+ },
// Backwards compatibility hack: support references to non-structural types,
// but hard error if we aren't behind a double reference. We could just use
// the fallback code path below, but that would allow *more* of this fishy
@@ -392,11 +390,9 @@ impl<'tcx> ConstToPat<'tcx> {
// instead of a hard error.
ty::Adt(_, _) if !self.type_marked_structural(*pointee_ty) => {
if self.behind_reference.get() {
- if !self.saw_const_match_error.get()
- && !self.saw_const_match_lint.get()
- {
- self.saw_const_match_lint.set(true);
- tcx.emit_spanned_lint(
+ if !self.saw_const_match_error.get() && !self.saw_const_match_lint.get() {
+ self.saw_const_match_lint.set(true);
+ tcx.emit_spanned_lint(
lint::builtin::INDIRECT_STRUCTURAL_MATCH,
self.id,
span,
@@ -417,49 +413,41 @@ impl<'tcx> ConstToPat<'tcx> {
// convert the dereferenced constant to a pattern that is the sub-pattern of the
// deref pattern.
_ => {
- if !pointee_ty.is_sized(tcx, param_env) {
- // `tcx.deref_mir_constant()` below will ICE with an unsized type
- // (except slices, which are handled in a separate arm above).
-
+ if !pointee_ty.is_sized(tcx, param_env) && !pointee_ty.is_slice() {
let err = UnsizedPattern { span, non_sm_ty: *pointee_ty };
tcx.sess.emit_err(err);
+ // FIXME: introduce PatKind::Error to silence follow up diagnostics due to unreachable patterns.
PatKind::Wild
} else {
let old = self.behind_reference.replace(true);
- let subpattern = self.recur(tcx.deref_mir_constant(self.param_env.and(cv)), false)?;
+ // `b"foo"` produces a `&[u8; 3]`, but you can't use constants of array type when
+ // matching against references, you can only use byte string literals.
+ // The typechecker has a special case for byte string literals, by treating them
+ // as slices. This means we turn `&[T; N]` constants into slice patterns, which
+ // has no negative effects on pattern matching, even if we're actually matching on
+ // arrays.
+ let pointee_ty = match *pointee_ty.kind() {
+ ty::Array(elem_ty, _) if self.treat_byte_string_as_slice => {
+ Ty::new_slice(tcx, elem_ty)
+ }
+ _ => *pointee_ty,
+ };
+ // References have the same valtree representation as their pointee.
+ let subpattern = self.recur(cv, pointee_ty, false)?;
self.behind_reference.set(old);
PatKind::Deref { subpattern }
}
}
},
- ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::FnDef(..) => {
- PatKind::Constant { value: cv }
- }
- ty::RawPtr(pointee) if pointee.ty.is_sized(tcx, param_env) => {
- return Err(FallbackToConstRef);
- }
- // FIXME: these can have very surprising behaviour where optimization levels or other
- // compilation choices change the runtime behaviour of the match.
- // See https://github.com/rust-lang/rust/issues/70861 for examples.
- ty::FnPtr(..) | ty::RawPtr(..) => {
- if !self.saw_const_match_error.get()
- && !self.saw_const_match_lint.get()
- {
- self.saw_const_match_lint.set(true);
- tcx.emit_spanned_lint(
- lint::builtin::POINTER_STRUCTURAL_MATCH,
- id,
- span,
- PointerPattern
- );
- }
- return Err(FallbackToConstRef);
- }
+ ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::FnDef(..) => PatKind::Constant {
+ value: mir::ConstantKind::Ty(ty::Const::new_value(tcx, cv, ty)),
+ },
+ ty::FnPtr(..) | ty::RawPtr(..) => unreachable!(),
_ => {
self.saw_const_match_error.set(true);
- let err = InvalidPattern { span, non_sm_ty: cv.ty() };
- tcx.sess.emit_err(err);
+ let err = InvalidPattern { span, non_sm_ty: ty };
+ tcx.sess.emit_err(err);
PatKind::Wild
}
};
@@ -472,7 +460,7 @@ impl<'tcx> ConstToPat<'tcx> {
// Obtain the actual type that isn't annotated. If we just looked at `cv.ty` we
// could get `Option<NonStructEq>`, even though `Option` is annotated with derive.
- && let Some(non_sm_ty) = traits::search_for_structural_match_violation(span, tcx, cv.ty())
+ && let Some(non_sm_ty) = traits::search_for_structural_match_violation(span, tcx, ty)
{
self.saw_const_match_lint.set(true);
tcx.emit_spanned_lint(
@@ -483,6 +471,6 @@ impl<'tcx> ConstToPat<'tcx> {
);
}
- Ok(Box::new(Pat { span, ty: cv.ty(), kind }))
+ Ok(Box::new(Pat { span, ty, kind }))
}
}
diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
index 6a7714613..9df6d2f43 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
@@ -53,11 +53,11 @@ use smallvec::{smallvec, SmallVec};
use rustc_data_structures::captures::Captures;
use rustc_hir::{HirId, RangeEnd};
use rustc_index::Idx;
+use rustc_middle::middle::stability::EvalResult;
use rustc_middle::mir;
use rustc_middle::thir::{FieldPat, Pat, PatKind, PatRange};
use rustc_middle::ty::layout::IntegerExt;
use rustc_middle::ty::{self, Ty, TyCtxt, VariantDef};
-use rustc_middle::{middle::stability::EvalResult, mir::interpret::ConstValue};
use rustc_session::lint;
use rustc_span::{Span, DUMMY_SP};
use rustc_target::abi::{FieldIdx, Integer, Size, VariantIdx, FIRST_VARIANT};
@@ -140,28 +140,17 @@ impl IntRange {
value: mir::ConstantKind<'tcx>,
) -> Option<IntRange> {
let ty = value.ty();
- if let Some((target_size, bias)) = Self::integral_size_and_signed_bias(tcx, ty) {
- let val = if let mir::ConstantKind::Val(ConstValue::Scalar(scalar), _) = value {
- // For this specific pattern we can skip a lot of effort and go
- // straight to the result, after doing a bit of checking. (We
- // could remove this branch and just fall through, which
- // is more general but much slower.)
- scalar.to_bits_or_ptr_internal(target_size).unwrap().left()?
- } else {
- if let mir::ConstantKind::Ty(c) = value
- && let ty::ConstKind::Value(_) = c.kind()
- {
- bug!("encountered ConstValue in mir::ConstantKind::Ty, whereas this is expected to be in ConstantKind::Val");
- }
+ let (target_size, bias) = Self::integral_size_and_signed_bias(tcx, ty)?;
+ let val = match value {
+ mir::ConstantKind::Ty(c) if let ty::ConstKind::Value(valtree) = c.kind() => {
+ valtree.unwrap_leaf().to_bits(target_size).ok()
+ },
+ // This is a more general form of the previous case.
+ _ => value.try_eval_bits(tcx, param_env, ty),
+ }?;
- // This is a more general form of the previous case.
- value.try_eval_bits(tcx, param_env, ty)?
- };
- let val = val ^ bias;
- Some(IntRange { range: val..=val, bias })
- } else {
- None
- }
+ let val = val ^ bias;
+ Some(IntRange { range: val..=val, bias })
}
#[inline]
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 1cf2f7ec0..600995927 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -18,14 +18,15 @@ use rustc_hir::pat_util::EnumerateAndAdjustIterator;
use rustc_hir::RangeEnd;
use rustc_index::Idx;
use rustc_middle::mir::interpret::{
- ConstValue, ErrorHandled, LitToConstError, LitToConstInput, Scalar,
+ ConstValue, ErrorHandled, GlobalId, LitToConstError, LitToConstInput, Scalar,
};
-use rustc_middle::mir::{self, UserTypeProjection};
+use rustc_middle::mir::{self, ConstantKind, UserTypeProjection};
use rustc_middle::mir::{BorrowKind, Mutability};
use rustc_middle::thir::{Ascription, BindingMode, FieldPat, LocalVarId, Pat, PatKind, PatRange};
use rustc_middle::ty::subst::{GenericArg, SubstsRef};
use rustc_middle::ty::CanonicalUserTypeAnnotation;
-use rustc_middle::ty::{self, AdtDef, ConstKind, Region, Ty, TyCtxt, UserType};
+use rustc_middle::ty::TypeVisitableExt;
+use rustc_middle::ty::{self, AdtDef, Region, Ty, TyCtxt, UserType};
use rustc_span::{Span, Symbol};
use rustc_target::abi::FieldIdx;
@@ -286,7 +287,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
ty::BindByValue(mutbl) => (mutbl, BindingMode::ByValue),
ty::BindByReference(hir::Mutability::Mut) => (
Mutability::Not,
- BindingMode::ByRef(BorrowKind::Mut { allow_two_phase_borrow: false }),
+ BindingMode::ByRef(BorrowKind::Mut { kind: mir::MutBorrowKind::Default }),
),
ty::BindByReference(hir::Mutability::Not) => {
(Mutability::Not, BindingMode::ByRef(BorrowKind::Shared))
@@ -518,16 +519,24 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
}
};
- // `mir_const_qualif` must be called with the `DefId` of the item where the const is
- // defined, not where it is declared. The difference is significant for associated
- // constants.
- let mir_structural_match_violation = self.tcx.mir_const_qualif(instance.def_id()).custom_eq;
- debug!("mir_structural_match_violation({:?}) -> {}", qpath, mir_structural_match_violation);
-
- match self.tcx.const_eval_instance(param_env_reveal_all, instance, Some(span)) {
- Ok(literal) => {
- let const_ = mir::ConstantKind::Val(literal, ty);
- let pattern = self.const_to_pat(const_, id, span, mir_structural_match_violation);
+ let cid = GlobalId { instance, promoted: None };
+ // Prefer valtrees over opaque constants.
+ let const_value = self
+ .tcx
+ .const_eval_global_id_for_typeck(param_env_reveal_all, cid, Some(span))
+ .map(|val| match val {
+ Some(valtree) => mir::ConstantKind::Ty(ty::Const::new_value(self.tcx, valtree, ty)),
+ None => mir::ConstantKind::Val(
+ self.tcx
+ .const_eval_global_id(param_env_reveal_all, cid, Some(span))
+ .expect("const_eval_global_id_for_typeck should have already failed"),
+ ty,
+ ),
+ });
+
+ match const_value {
+ Ok(const_) => {
+ let pattern = self.const_to_pat(const_, id, span, Some(instance.def_id()));
if !is_associated_const {
return pattern;
@@ -573,31 +582,72 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
/// Converts inline const patterns.
fn lower_inline_const(
&mut self,
- anon_const: &'tcx hir::AnonConst,
+ block: &'tcx hir::ConstBlock,
id: hir::HirId,
span: Span,
) -> PatKind<'tcx> {
- let value = mir::ConstantKind::from_inline_const(self.tcx, anon_const.def_id);
-
- // Evaluate early like we do in `lower_path`.
- let value = value.eval(self.tcx, self.param_env);
-
- match value {
- mir::ConstantKind::Ty(c) => match c.kind() {
- ConstKind::Param(_) => {
- self.tcx.sess.emit_err(ConstParamInPattern { span });
- return PatKind::Wild;
+ let tcx = self.tcx;
+ let def_id = block.def_id;
+ let body_id = block.body;
+ let expr = &tcx.hir().body(body_id).value;
+ let ty = tcx.typeck(def_id).node_type(block.hir_id);
+
+ // Special case inline consts that are just literals. This is solely
+ // a performance optimization, as we could also just go through the regular
+ // const eval path below.
+ // FIXME: investigate the performance impact of removing this.
+ let lit_input = match expr.kind {
+ hir::ExprKind::Lit(ref lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }),
+ hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => match expr.kind {
+ hir::ExprKind::Lit(ref lit) => {
+ Some(LitToConstInput { lit: &lit.node, ty, neg: true })
}
- ConstKind::Error(_) => {
- return PatKind::Wild;
- }
- _ => bug!("Expected ConstKind::Param"),
+ _ => None,
},
- mir::ConstantKind::Val(_, _) => self.const_to_pat(value, id, span, false).kind,
- mir::ConstantKind::Unevaluated(..) => {
- // If we land here it means the const can't be evaluated because it's `TooGeneric`.
- self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span });
- return PatKind::Wild;
+ _ => None,
+ };
+ if let Some(lit_input) = lit_input {
+ match tcx.at(expr.span).lit_to_const(lit_input) {
+ Ok(c) => return self.const_to_pat(ConstantKind::Ty(c), id, span, None).kind,
+ // If an error occurred, ignore that it's a literal
+ // and leave reporting the error up to const eval of
+ // the unevaluated constant below.
+ Err(_) => {}
+ }
+ }
+
+ let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id());
+ let parent_substs =
+ tcx.erase_regions(ty::InternalSubsts::identity_for_item(tcx, typeck_root_def_id));
+ let substs =
+ ty::InlineConstSubsts::new(tcx, ty::InlineConstSubstsParts { parent_substs, ty })
+ .substs;
+
+ let uneval = mir::UnevaluatedConst { def: def_id.to_def_id(), substs, promoted: None };
+ debug_assert!(!substs.has_free_regions());
+
+ let ct = ty::UnevaluatedConst { def: def_id.to_def_id(), substs: substs };
+ // First try using a valtree in order to destructure the constant into a pattern.
+ if let Ok(Some(valtree)) =
+ self.tcx.const_eval_resolve_for_typeck(self.param_env, ct, Some(span))
+ {
+ self.const_to_pat(
+ ConstantKind::Ty(ty::Const::new_value(self.tcx, valtree, ty)),
+ id,
+ span,
+ None,
+ )
+ .kind
+ } else {
+ // If that fails, convert it to an opaque constant pattern.
+ match tcx.const_eval_resolve(self.param_env, uneval, None) {
+ Ok(val) => self.const_to_pat(mir::ConstantKind::Val(val, ty), id, span, None).kind,
+ Err(ErrorHandled::TooGeneric) => {
+ // If we land here it means the const can't be evaluated because it's `TooGeneric`.
+ self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span });
+ PatKind::Wild
+ }
+ Err(ErrorHandled::Reported(_)) => PatKind::Wild,
}
}
}
@@ -626,8 +676,10 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
let lit_input =
LitToConstInput { lit: &lit.node, ty: self.typeck_results.expr_ty(expr), neg };
- match self.tcx.at(expr.span).lit_to_mir_constant(lit_input) {
- Ok(constant) => self.const_to_pat(constant, expr.hir_id, lit.span, false).kind,
+ match self.tcx.at(expr.span).lit_to_const(lit_input) {
+ Ok(constant) => {
+ self.const_to_pat(ConstantKind::Ty(constant), expr.hir_id, lit.span, None).kind
+ }
Err(LitToConstError::Reported(_)) => PatKind::Wild,
Err(LitToConstError::TypeError) => bug!("lower_lit: had type error"),
}
@@ -806,6 +858,9 @@ pub(crate) fn compare_const_vals<'tcx>(
mir::ConstantKind::Val(ConstValue::Scalar(Scalar::Int(a)), _a_ty),
mir::ConstantKind::Val(ConstValue::Scalar(Scalar::Int(b)), _b_ty),
) => return Some(a.cmp(&b)),
+ (mir::ConstantKind::Ty(a), mir::ConstantKind::Ty(b)) => {
+ return Some(a.kind().cmp(&b.kind()));
+ }
_ => {}
},
}
diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs
index b2f2a64e2..8d7c624a8 100644
--- a/compiler/rustc_mir_build/src/thir/print.rs
+++ b/compiler/rustc_mir_build/src/thir/print.rs
@@ -301,7 +301,7 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
self.print_expr(*source, depth_lvl + 2);
print_indented!(self, "}", depth_lvl);
}
- Pointer { cast, source } => {
+ PointerCoercion { cast, source } => {
print_indented!(self, "Pointer {", depth_lvl);
print_indented!(self, format!("cast: {:?}", cast), depth_lvl + 1);
print_indented!(self, "source:", depth_lvl + 1);
@@ -421,6 +421,12 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
print_indented!(self, "}", depth_lvl);
}
+ Become { value } => {
+ print_indented!(self, "Become {", depth_lvl);
+ print_indented!(self, "value:", depth_lvl + 1);
+ self.print_expr(*value, depth_lvl + 2);
+ print_indented!(self, "}", depth_lvl);
+ }
ConstBlock { did, substs } => {
print_indented!(self, "ConstBlock {", depth_lvl);
print_indented!(self, format!("did: {:?}", did), depth_lvl + 1);