summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_mir_build/src/thir
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:50 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:50 +0000
commit9835e2ae736235810b4ea1c162ca5e65c547e770 (patch)
tree3fcebf40ed70e581d776a8a4c65923e8ec20e026 /compiler/rustc_mir_build/src/thir
parentReleasing progress-linux version 1.70.0+dfsg2-1~progress7.99u1. (diff)
downloadrustc-9835e2ae736235810b4ea1c162ca5e65c547e770.tar.xz
rustc-9835e2ae736235810b4ea1c162ca5e65c547e770.zip
Merging upstream version 1.71.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/cx/block.rs2
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs15
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/mod.rs25
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs119
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs71
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs10
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs4
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/usefulness.rs19
-rw-r--r--compiler/rustc_mir_build/src/thir/print.rs17
9 files changed, 167 insertions, 115 deletions
diff --git a/compiler/rustc_mir_build/src/thir/cx/block.rs b/compiler/rustc_mir_build/src/thir/cx/block.rs
index 8aacec53f..a46ad6423 100644
--- a/compiler/rustc_mir_build/src/thir/cx/block.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/block.rs
@@ -5,7 +5,7 @@ use rustc_middle::middle::region;
use rustc_middle::thir::*;
use rustc_middle::ty;
-use rustc_index::vec::Idx;
+use rustc_index::Idx;
use rustc_middle::ty::CanonicalUserTypeAnnotation;
impl<'tcx> Cx<'tcx> {
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 8e2e92e6f..b20495d60 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -5,7 +5,7 @@ use crate::thir::util::UserAnnotatedTyHelpers;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
-use rustc_index::vec::Idx;
+use rustc_index::Idx;
use rustc_middle::hir::place::Place as HirPlace;
use rustc_middle::hir::place::PlaceBase as HirPlaceBase;
use rustc_middle::hir::place::ProjectionKind as HirProjectionKind;
@@ -130,6 +130,7 @@ impl<'tcx> Cx<'tcx> {
ExprKind::Pointer { cast: PointerCast::Unsize, 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) => {
adjust_span(&mut expr);
@@ -332,7 +333,7 @@ impl<'tcx> Cx<'tcx> {
} else if let Some(box_item) = tcx.lang_items().owned_box() {
if let hir::ExprKind::Path(hir::QPath::TypeRelative(ty, fn_path)) = fun.kind
&& let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = ty.kind
- && path.res.opt_def_id().map_or(false, |did| did == box_item)
+ && path.res.opt_def_id().is_some_and(|did| did == box_item)
&& fn_path.ident.name == sym::new
&& let [value] = args
{
@@ -664,6 +665,14 @@ impl<'tcx> Cx<'tcx> {
line_spans: asm.line_spans,
})),
+ hir::ExprKind::OffsetOf(_, _) => {
+ let data = self.typeck_results.offset_of_data();
+ let &(container, ref indices) = data.get(expr.hir_id).unwrap();
+ let fields = tcx.mk_fields_from_iter(indices.iter().copied());
+
+ ExprKind::OffsetOf { container, fields }
+ }
+
hir::ExprKind::ConstBlock(ref anon_const) => {
let ty = self.typeck_results().node_type(anon_const.hir_id);
let did = anon_const.def_id.to_def_id();
@@ -947,7 +956,7 @@ impl<'tcx> Cx<'tcx> {
let is_upvar = self
.tcx
.upvars_mentioned(self.body_owner)
- .map_or(false, |upvars| upvars.contains_key(&var_hir_id));
+ .is_some_and(|upvars| upvars.contains_key(&var_hir_id));
debug!(
"convert_var({:?}): is_upvar={}, body_owner={:?}",
diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs
index 070544446..463f639de 100644
--- a/compiler/rustc_mir_build/src/thir/cx/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs
@@ -20,25 +20,25 @@ use rustc_span::Span;
pub(crate) fn thir_body(
tcx: TyCtxt<'_>,
- owner_def: ty::WithOptConstParam<LocalDefId>,
+ owner_def: LocalDefId,
) -> Result<(&Steal<Thir<'_>>, ExprId), ErrorGuaranteed> {
let hir = tcx.hir();
- let body = hir.body(hir.body_owned_by(owner_def.did));
+ let body = hir.body(hir.body_owned_by(owner_def));
let mut cx = Cx::new(tcx, owner_def);
if let Some(reported) = cx.typeck_results.tainted_by_errors {
return Err(reported);
}
let expr = cx.mirror_expr(&body.value);
- let owner_id = hir.local_def_id_to_hir_id(owner_def.did);
+ let owner_id = hir.local_def_id_to_hir_id(owner_def);
if let Some(ref fn_decl) = hir.fn_decl_by_hir_id(owner_id) {
- let closure_env_param = cx.closure_env_param(owner_def.did, owner_id);
+ let closure_env_param = cx.closure_env_param(owner_def, owner_id);
let explicit_params = cx.explicit_params(owner_id, fn_decl, body);
cx.thir.params = closure_env_param.into_iter().chain(explicit_params).collect();
// The resume argument may be missing, in that case we need to provide it here.
// It will always be `()` in this case.
- if tcx.def_kind(owner_def.did) == DefKind::Generator && body.params.is_empty() {
+ if tcx.def_kind(owner_def) == DefKind::Generator && body.params.is_empty() {
cx.thir.params.push(Param {
ty: tcx.mk_unit(),
pat: None,
@@ -78,13 +78,12 @@ struct Cx<'tcx> {
}
impl<'tcx> Cx<'tcx> {
- fn new(tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam<LocalDefId>) -> Cx<'tcx> {
- let typeck_results = tcx.typeck_opt_const_arg(def);
- let did = def.did;
+ fn new(tcx: TyCtxt<'tcx>, def: LocalDefId) -> Cx<'tcx> {
+ let typeck_results = tcx.typeck(def);
let hir = tcx.hir();
- let hir_id = hir.local_def_id_to_hir_id(did);
+ let hir_id = hir.local_def_id_to_hir_id(def);
- let body_type = if hir.body_owner_kind(did).is_fn_or_closure() {
+ let body_type = if hir.body_owner_kind(def).is_fn_or_closure() {
// fetch the fully liberated fn signature (that is, all bound
// types/lifetimes replaced)
BodyTy::Fn(typeck_results.liberated_fn_sigs()[hir_id])
@@ -106,11 +105,11 @@ impl<'tcx> Cx<'tcx> {
Cx {
tcx,
thir: Thir::new(body_type),
- param_env: tcx.param_env(def.did),
- region_scope_tree: tcx.region_scope_tree(def.did),
+ param_env: tcx.param_env(def),
+ region_scope_tree: tcx.region_scope_tree(def),
typeck_results,
rvalue_scopes: &typeck_results.rvalue_scopes,
- body_owner: did.to_def_id(),
+ body_owner: def.to_def_id(),
adjustment_span: None,
apply_adjustments: hir
.attrs(hir_id)
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 8f58db504..1e51cb9aa 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -26,8 +26,8 @@ use rustc_session::Session;
use rustc_span::hygiene::DesugaringKind;
use rustc_span::Span;
-pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: LocalDefId) {
- let Ok((thir, expr)) = tcx.thir_body(ty::WithOptConstParam::unknown(def_id)) else { return };
+pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGuaranteed> {
+ let (thir, expr) = tcx.thir_body(def_id)?;
let thir = thir.borrow();
let pattern_arena = TypedArena::default();
let mut visitor = MatchVisitor {
@@ -37,13 +37,16 @@ pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: LocalDefId) {
lint_level: tcx.hir().local_def_id_to_hir_id(def_id),
let_source: LetSource::None,
pattern_arena: &pattern_arena,
+ error: Ok(()),
};
visitor.visit_expr(&thir[expr]);
+
for param in thir.params.iter() {
if let Some(box ref pattern) = param.pat {
visitor.check_irrefutable(pattern, "function argument", None);
}
}
+ visitor.error
}
fn create_e0004(
@@ -77,6 +80,7 @@ struct MatchVisitor<'a, 'p, 'tcx> {
lint_level: HirId,
let_source: LetSource,
pattern_arena: &'p TypedArena<DeconstructedPat<'p, 'tcx>>,
+ error: Result<(), ErrorGuaranteed>,
}
impl<'a, 'tcx> Visitor<'a, 'tcx> for MatchVisitor<'a, '_, 'tcx> {
@@ -86,35 +90,34 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for MatchVisitor<'a, '_, 'tcx> {
#[instrument(level = "trace", skip(self))]
fn visit_arm(&mut self, arm: &Arm<'tcx>) {
- match arm.guard {
- Some(Guard::If(expr)) => {
- self.with_let_source(LetSource::IfLetGuard, |this| {
- this.visit_expr(&this.thir[expr])
- });
- }
- Some(Guard::IfLet(ref pat, expr)) => {
- self.with_let_source(LetSource::IfLetGuard, |this| {
- this.check_let(pat, expr, LetSource::IfLetGuard, pat.span);
- this.visit_pat(pat);
- this.visit_expr(&this.thir[expr]);
- });
+ self.with_lint_level(arm.lint_level, |this| {
+ match arm.guard {
+ Some(Guard::If(expr)) => {
+ this.with_let_source(LetSource::IfLetGuard, |this| {
+ this.visit_expr(&this.thir[expr])
+ });
+ }
+ Some(Guard::IfLet(ref pat, expr)) => {
+ this.with_let_source(LetSource::IfLetGuard, |this| {
+ this.check_let(pat, expr, LetSource::IfLetGuard, pat.span);
+ this.visit_pat(pat);
+ this.visit_expr(&this.thir[expr]);
+ });
+ }
+ None => {}
}
- None => {}
- }
- self.visit_pat(&arm.pattern);
- self.visit_expr(&self.thir[arm.body]);
+ this.visit_pat(&arm.pattern);
+ this.visit_expr(&self.thir[arm.body]);
+ });
}
#[instrument(level = "trace", skip(self))]
fn visit_expr(&mut self, ex: &Expr<'tcx>) {
match ex.kind {
ExprKind::Scope { value, lint_level, .. } => {
- let old_lint_level = self.lint_level;
- if let LintLevel::Explicit(hir_id) = lint_level {
- self.lint_level = hir_id;
- }
- self.visit_expr(&self.thir[value]);
- self.lint_level = old_lint_level;
+ self.with_lint_level(lint_level, |this| {
+ this.visit_expr(&this.thir[value]);
+ });
return;
}
ExprKind::If { cond, then, else_opt, if_then_scope: _ } => {
@@ -186,6 +189,17 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
self.let_source = old_let_source;
}
+ fn with_lint_level(&mut self, new_lint_level: LintLevel, f: impl FnOnce(&mut Self)) {
+ if let LintLevel::Explicit(hir_id) = new_lint_level {
+ let old_lint_level = self.lint_level;
+ self.lint_level = hir_id;
+ f(self);
+ self.lint_level = old_lint_level;
+ } else {
+ f(self);
+ }
+ }
+
fn check_patterns(&self, pat: &Pat<'tcx>, rf: RefutableFlag) {
pat.walk_always(|pat| check_borrow_conflicts_in_at_patterns(self, pat));
check_for_bindings_named_same_as_variants(self, pat, rf);
@@ -232,7 +246,9 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
for &arm in arms {
// Check the arm for some things unrelated to exhaustiveness.
let arm = &self.thir.arms[arm];
- self.check_patterns(&arm.pattern, Refutable);
+ self.with_lint_level(arm.lint_level, |this| {
+ this.check_patterns(&arm.pattern, Refutable);
+ });
}
let tarms: Vec<_> = arms
@@ -276,9 +292,9 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
let [pat_field] = &subpatterns[..] else { bug!() };
self.check_irrefutable(&pat_field.pattern, "`for` loop binding", None);
} else {
- non_exhaustive_match(
+ self.error = Err(non_exhaustive_match(
&cx, self.thir, scrut_ty, scrut.span, witnesses, arms, expr_span,
- );
+ ));
}
}
}
@@ -406,7 +422,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
}
#[instrument(level = "trace", skip(self))]
- fn check_irrefutable(&self, pat: &Pat<'tcx>, origin: &str, sp: Option<Span>) {
+ fn check_irrefutable(&mut self, pat: &Pat<'tcx>, origin: &str, sp: Option<Span>) {
let mut cx = self.new_cx(self.lint_level, false);
let pattern = self.lower_pattern(&mut cx, pat);
@@ -475,18 +491,36 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
AdtDefinedHere { adt_def_span, ty, variants }
};
- self.tcx.sess.emit_err(PatternNotCovered {
+ // Emit an extra note if the first uncovered witness would be uninhabited
+ // if we disregard visibility.
+ let witness_1_is_privately_uninhabited =
+ if cx.tcx.features().exhaustive_patterns
+ && let Some(witness_1) = witnesses.get(0)
+ && let ty::Adt(adt, substs) = witness_1.ty().kind()
+ && adt.is_enum()
+ && let Constructor::Variant(variant_index) = witness_1.ctor()
+ {
+ let variant = adt.variant(*variant_index);
+ let inhabited = variant.inhabited_predicate(cx.tcx, *adt).subst(cx.tcx, substs);
+ assert!(inhabited.apply(cx.tcx, cx.param_env, cx.module));
+ !inhabited.apply_ignore_module(cx.tcx, cx.param_env)
+ } else {
+ false
+ };
+
+ self.error = Err(self.tcx.sess.emit_err(PatternNotCovered {
span: pat.span,
origin,
uncovered: Uncovered::new(pat.span, &cx, witnesses),
inform,
interpreted_as_const,
+ witness_1_is_privately_uninhabited: witness_1_is_privately_uninhabited.then_some(()),
_p: (),
pattern_ty,
let_suggestion,
misc_suggestion,
adt_defined_here,
- });
+ }));
}
}
@@ -628,7 +662,7 @@ fn non_exhaustive_match<'p, 'tcx>(
witnesses: Vec<DeconstructedPat<'p, 'tcx>>,
arms: &[ArmId],
expr_span: Span,
-) {
+) -> ErrorGuaranteed {
let is_empty_match = arms.is_empty();
let non_empty_enum = match scrut_ty.kind() {
ty::Adt(def, _) => def.is_enum() && !def.variants().is_empty(),
@@ -640,13 +674,12 @@ fn non_exhaustive_match<'p, 'tcx>(
let pattern;
let patterns_len;
if is_empty_match && !non_empty_enum {
- cx.tcx.sess.emit_err(NonExhaustivePatternsTypeNotEmpty {
+ return cx.tcx.sess.emit_err(NonExhaustivePatternsTypeNotEmpty {
cx,
expr_span,
span: sp,
ty: scrut_ty,
});
- return;
} else {
// FIXME: migration of this diagnostic will require list support
let joined_patterns = joined_uncovered_patterns(cx, &witnesses);
@@ -668,13 +701,11 @@ fn non_exhaustive_match<'p, 'tcx>(
};
};
- let is_variant_list_non_exhaustive = match scrut_ty.kind() {
- ty::Adt(def, _) if def.is_variant_list_non_exhaustive() && !def.did().is_local() => true,
- _ => false,
- };
+ let is_variant_list_non_exhaustive = matches!(scrut_ty.kind(),
+ ty::Adt(def, _) if def.is_variant_list_non_exhaustive() && !def.did().is_local());
adt_defined_here(cx, &mut err, scrut_ty, &witnesses);
- err.note(&format!(
+ err.note(format!(
"the matched value is of type `{}`{}",
scrut_ty,
if is_variant_list_non_exhaustive { ", which is marked as non-exhaustive" } else { "" }
@@ -684,13 +715,13 @@ fn non_exhaustive_match<'p, 'tcx>(
&& witnesses.len() == 1
&& matches!(witnesses[0].ctor(), Constructor::NonExhaustive)
{
- err.note(&format!(
+ err.note(format!(
"`{}` does not have a fixed maximum value, so a wildcard `_` is necessary to match \
exhaustively",
scrut_ty,
));
if cx.tcx.sess.is_nightly_build() {
- err.help(&format!(
+ err.help(format!(
"add `#![feature(precise_pointer_size_matching)]` to the crate attributes to \
enable precise `{}` matching",
scrut_ty,
@@ -795,11 +826,11 @@ fn non_exhaustive_match<'p, 'tcx>(
},
);
if let Some((span, sugg)) = suggestion {
- err.span_suggestion_verbose(span, &msg, sugg, Applicability::HasPlaceholders);
+ err.span_suggestion_verbose(span, msg, sugg, Applicability::HasPlaceholders);
} else {
- err.help(&msg);
+ err.help(msg);
}
- err.emit();
+ err.emit()
}
pub(crate) fn joined_uncovered_patterns<'p, 'tcx>(
@@ -859,7 +890,7 @@ fn adt_defined_here<'p, 'tcx>(
for pat in spans {
span.push_span_label(pat, "not covered");
}
- err.span_note(span, &format!("`{}` defined here", ty));
+ err.span_note(span, format!("`{}` defined here", ty));
}
}
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 32d0404bd..b243f1dc8 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,5 +1,5 @@
use rustc_hir as hir;
-use rustc_index::vec::Idx;
+use rustc_index::Idx;
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::Obligation;
use rustc_middle::mir;
@@ -62,21 +62,13 @@ struct ConstToPat<'tcx> {
treat_byte_string_as_slice: bool,
}
-mod fallback_to_const_ref {
- #[derive(Debug)]
- /// This error type signals that we encountered a non-struct-eq situation behind a reference.
- /// We bubble this up in order to get back to the reference destructuring and make that emit
- /// a const pattern instead of a deref pattern. This allows us to simply call `PartialEq::eq`
- /// on such patterns (since that function takes a reference) and not have to jump through any
- /// hoops to get a reference to the value.
- pub(super) struct FallbackToConstRef(());
-
- pub(super) fn fallback_to_const_ref(c2p: &super::ConstToPat<'_>) -> FallbackToConstRef {
- assert!(c2p.behind_reference.get());
- FallbackToConstRef(())
- }
-}
-use fallback_to_const_ref::{fallback_to_const_ref, FallbackToConstRef};
+/// This error type signals that we encountered a non-struct-eq situation.
+/// We bubble this up in order to get back to the reference destructuring and make that emit
+/// a const pattern instead of a deref pattern. This allows us to simply call `PartialEq::eq`
+/// on such patterns (since that function takes a reference) and not have to jump through any
+/// hoops to get a reference to the value.
+#[derive(Debug)]
+struct FallbackToConstRef;
impl<'tcx> ConstToPat<'tcx> {
fn new(
@@ -156,7 +148,7 @@ impl<'tcx> ConstToPat<'tcx> {
if let Some(non_sm_ty) = structural {
if !self.type_may_have_partial_eq_impl(cv.ty()) {
- // fatal avoids ICE from resolution of non-existent method (rare case).
+ // 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 });
@@ -191,7 +183,7 @@ impl<'tcx> ConstToPat<'tcx> {
self.tcx(),
ObligationCause::dummy(),
self.param_env,
- self.tcx().mk_trait_ref(partial_eq_trait_id, [ty, ty]),
+ ty::TraitRef::new(self.tcx(), partial_eq_trait_id, [ty, ty]),
);
// FIXME: should this call a `predicate_must_hold` variant instead?
@@ -236,13 +228,13 @@ impl<'tcx> ConstToPat<'tcx> {
let kind = match cv.ty().kind() {
ty::Float(_) => {
- tcx.emit_spanned_lint(
- lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
- id,
- span,
- FloatPattern,
- );
- PatKind::Constant { value: cv }
+ tcx.emit_spanned_lint(
+ lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
+ id,
+ span,
+ FloatPattern,
+ );
+ 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
@@ -289,7 +281,7 @@ impl<'tcx> ConstToPat<'tcx> {
// Since we are behind a reference, we can just bubble the error up so we get a
// constant at reference type, making it easy to let the fallback call
// `PartialEq::eq` on it.
- return Err(fallback_to_const_ref(self));
+ return Err(FallbackToConstRef);
}
ty::Adt(adt_def, _) if !self.type_marked_structural(cv.ty()) => {
debug!(
@@ -393,11 +385,11 @@ impl<'tcx> ConstToPat<'tcx> {
self.behind_reference.set(old);
val
}
- // Backwards compatibility hack: support references to non-structural types.
- // We'll lower
- // this pattern to a `PartialEq::eq` comparison and `PartialEq::eq` takes a
- // reference. This makes the rest of the matching logic simpler as it doesn't have
- // to figure out how to get a reference again.
+ // 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
+ // code to compile, as then it only goes through the future incompat lint
+ // 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()
@@ -411,7 +403,7 @@ impl<'tcx> ConstToPat<'tcx> {
IndirectStructuralMatch { non_sm_ty: *pointee_ty },
);
}
- PatKind::Constant { value: cv }
+ return Err(FallbackToConstRef);
} else {
if !self.saw_const_match_error.get() {
self.saw_const_match_error.set(true);
@@ -435,16 +427,9 @@ impl<'tcx> ConstToPat<'tcx> {
PatKind::Wild
} else {
let old = self.behind_reference.replace(true);
- // In case there are structural-match violations somewhere in this subpattern,
- // we fall back to a const pattern. If we do not do this, we may end up with
- // a !structural-match constant that is not of reference type, which makes it
- // very hard to invoke `PartialEq::eq` on it as a fallback.
- let val = match self.recur(tcx.deref_mir_constant(self.param_env.and(cv)), false) {
- Ok(subpattern) => PatKind::Deref { subpattern },
- Err(_) => PatKind::Constant { value: cv },
- };
+ let subpattern = self.recur(tcx.deref_mir_constant(self.param_env.and(cv)), false)?;
self.behind_reference.set(old);
- val
+ PatKind::Deref { subpattern }
}
}
},
@@ -452,7 +437,7 @@ impl<'tcx> ConstToPat<'tcx> {
PatKind::Constant { value: cv }
}
ty::RawPtr(pointee) if pointee.ty.is_sized(tcx, param_env) => {
- PatKind::Constant { value: cv }
+ return Err(FallbackToConstRef);
}
// FIXME: these can have very surprising behaviour where optimization levels or other
// compilation choices change the runtime behaviour of the match.
@@ -469,7 +454,7 @@ impl<'tcx> ConstToPat<'tcx> {
PointerPattern
);
}
- PatKind::Constant { value: cv }
+ return Err(FallbackToConstRef);
}
_ => {
self.saw_const_match_error.set(true);
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 7c2919644..6a7714613 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
@@ -52,7 +52,7 @@ use smallvec::{smallvec, SmallVec};
use rustc_data_structures::captures::Captures;
use rustc_hir::{HirId, RangeEnd};
-use rustc_index::vec::Idx;
+use rustc_index::Idx;
use rustc_middle::mir;
use rustc_middle::thir::{FieldPat, Pat, PatKind, PatRange};
use rustc_middle::ty::layout::IntegerExt;
@@ -844,8 +844,8 @@ impl<'tcx> Constructor<'tcx> {
}
/// Faster version of `is_covered_by` when applied to many constructors. `used_ctors` is
- /// assumed to be built from `matrix.head_ctors()` with wildcards filtered out, and `self` is
- /// assumed to have been split from a wildcard.
+ /// assumed to be built from `matrix.head_ctors()` with wildcards and opaques filtered out,
+ /// and `self` is assumed to have been split from a wildcard.
fn is_covered_by_any<'p>(
&self,
pcx: &PatCtxt<'_, 'p, 'tcx>,
@@ -894,7 +894,7 @@ impl<'tcx> Constructor<'tcx> {
/// in `to_ctors`: in some cases we only return `Missing`.
#[derive(Debug)]
pub(super) struct SplitWildcard<'tcx> {
- /// Constructors seen in the matrix.
+ /// Constructors (other than wildcards and opaques) seen in the matrix.
matrix_ctors: Vec<Constructor<'tcx>>,
/// All the constructors for this type
all_ctors: SmallVec<[Constructor<'tcx>; 1]>,
@@ -1037,7 +1037,7 @@ impl<'tcx> SplitWildcard<'tcx> {
// Since `all_ctors` never contains wildcards, this won't recurse further.
self.all_ctors =
self.all_ctors.iter().flat_map(|ctor| ctor.split(pcx, ctors.clone())).collect();
- self.matrix_ctors = ctors.filter(|c| !c.is_wildcard()).cloned().collect();
+ self.matrix_ctors = ctors.filter(|c| !matches!(c, Wildcard | Opaque)).cloned().collect();
}
/// Whether there are any value constructors for this type that are not present in the matrix.
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 70d015a39..1cf2f7ec0 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -16,7 +16,7 @@ use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::pat_util::EnumerateAndAdjustIterator;
use rustc_hir::RangeEnd;
-use rustc_index::vec::Idx;
+use rustc_index::Idx;
use rustc_middle::mir::interpret::{
ConstValue, ErrorHandled, LitToConstError, LitToConstInput, Scalar,
};
@@ -229,7 +229,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
self.lower_pattern_range(ty, lc, hc, end, lo_span, lo_expr, hi_expr)
}
None => {
- let msg = &format!(
+ let msg = format!(
"found bad range pattern `{:?}` outside of error recovery",
(&lo, &hi),
);
diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
index d8f66a175..e5b635069 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
@@ -288,6 +288,22 @@
//!
//! The details are not necessary to understand this file, so we explain them in
//! [`super::deconstruct_pat`]. Splitting is done by the [`Constructor::split`] function.
+//!
+//! # Constants in patterns
+//!
+//! There are two kinds of constants in patterns:
+//!
+//! * literals (`1`, `true`, `"foo"`)
+//! * named or inline consts (`FOO`, `const { 5 + 6 }`)
+//!
+//! The latter are converted into other patterns with literals at the leaves. For example
+//! `const_to_pat(const { [1, 2, 3] })` becomes an `Array(vec![Const(1), Const(2), Const(3)])`
+//! pattern. This gets problematic when comparing the constant via `==` would behave differently
+//! from matching on the constant converted to a pattern. Situations like that can occur, when
+//! the user implements `PartialEq` manually, and thus could make `==` behave arbitrarily different.
+//! In order to honor the `==` implementation, constants of types that implement `PartialEq` manually
+//! stay as a full constant and become an `Opaque` pattern. These `Opaque` patterns do not participate
+//! in exhaustiveness, specialization or overlap checking.
use self::ArmType::*;
use self::Usefulness::*;
@@ -685,10 +701,9 @@ enum ArmType {
/// For example, if we are constructing a witness for the match against
///
/// ```compile_fail,E0004
-/// # #![feature(type_ascription)]
/// struct Pair(Option<(u32, u32)>, bool);
/// # fn foo(p: Pair) {
-/// match (p: Pair) {
+/// match p {
/// Pair(None, _) => {}
/// Pair(_, false) => {}
/// }
diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs
index ed61d6ee7..b2f2a64e2 100644
--- a/compiler/rustc_mir_build/src/thir/print.rs
+++ b/compiler/rustc_mir_build/src/thir/print.rs
@@ -3,7 +3,7 @@ use rustc_middle::ty::{self, TyCtxt};
use rustc_span::def_id::LocalDefId;
use std::fmt::{self, Write};
-pub(crate) fn thir_tree(tcx: TyCtxt<'_>, owner_def: ty::WithOptConstParam<LocalDefId>) -> String {
+pub(crate) fn thir_tree(tcx: TyCtxt<'_>, owner_def: LocalDefId) -> String {
match super::cx::thir_body(tcx, owner_def) {
Ok((thir, _)) => {
let thir = thir.steal();
@@ -15,7 +15,7 @@ pub(crate) fn thir_tree(tcx: TyCtxt<'_>, owner_def: ty::WithOptConstParam<LocalD
}
}
-pub(crate) fn thir_flat(tcx: TyCtxt<'_>, owner_def: ty::WithOptConstParam<LocalDefId>) -> String {
+pub(crate) fn thir_flat(tcx: TyCtxt<'_>, owner_def: LocalDefId) -> String {
match super::cx::thir_body(tcx, owner_def) {
Ok((thir, _)) => format!("{:#?}", thir.steal()),
Err(_) => "error".into(),
@@ -519,6 +519,19 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
self.print_inline_asm_expr(&**expr, depth_lvl + 2);
print_indented!(self, "}", depth_lvl);
}
+ OffsetOf { container, fields } => {
+ print_indented!(self, "OffsetOf {", depth_lvl);
+ print_indented!(self, format!("container: {:?}", container), depth_lvl + 1);
+ print_indented!(self, "fields: [", depth_lvl + 1);
+
+ for field in fields.iter() {
+ print_indented!(self, format!("{:?}", field), depth_lvl + 2);
+ print_indented!(self, ",", depth_lvl + 1);
+ }
+
+ print_indented!(self, "]", depth_lvl + 1);
+ print_indented!(self, "}", depth_lvl);
+ }
ThreadLocalRef(def_id) => {
print_indented!(self, "ThreadLocalRef {", depth_lvl);
print_indented!(self, format!("def_id: {:?}", def_id), depth_lvl + 1);