summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_mir_build
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_mir_build')
-rw-r--r--compiler/rustc_mir_build/Cargo.toml1
-rw-r--r--compiler/rustc_mir_build/src/build/block.rs37
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_constant.rs7
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_operand.rs5
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_place.rs76
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_rvalue.rs24
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_temp.rs5
-rw-r--r--compiler/rustc_mir_build/src/build/expr/into.rs5
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs96
-rw-r--r--compiler/rustc_mir_build/src/build/matches/simplify.rs35
-rw-r--r--compiler/rustc_mir_build/src/build/matches/test.rs25
-rw-r--r--compiler/rustc_mir_build/src/build/matches/util.rs51
-rw-r--r--compiler/rustc_mir_build/src/build/mod.rs132
-rw-r--r--compiler/rustc_mir_build/src/build/scope.rs4
-rw-r--r--compiler/rustc_mir_build/src/check_unsafety.rs30
-rw-r--r--compiler/rustc_mir_build/src/lib.rs2
-rw-r--r--compiler/rustc_mir_build/src/lints.rs24
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs7
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/mod.rs2
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs117
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs57
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs20
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs8
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/usefulness.rs19
24 files changed, 402 insertions, 387 deletions
diff --git a/compiler/rustc_mir_build/Cargo.toml b/compiler/rustc_mir_build/Cargo.toml
index 30f90e383..c726fa3a3 100644
--- a/compiler/rustc_mir_build/Cargo.toml
+++ b/compiler/rustc_mir_build/Cargo.toml
@@ -4,7 +4,6 @@ version = "0.0.0"
edition = "2021"
[lib]
-doctest = false
[dependencies]
rustc_arena = { path = "../rustc_arena" }
diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs
index 784583d94..183db56d7 100644
--- a/compiler/rustc_mir_build/src/build/block.rs
+++ b/compiler/rustc_mir_build/src/build/block.rs
@@ -221,26 +221,32 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let init = &this.thir[*initializer];
let initializer_span = init.span;
- this.declare_bindings(
- visibility_scope,
- remainder_span,
- pattern,
- ArmHasGuard(false),
- Some((None, initializer_span)),
- );
- this.visit_primary_bindings(
- pattern,
- UserTypeProjections::none(),
- &mut |this, _, _, _, node, span, _, _| {
- this.storage_live_binding(block, node, span, OutsideGuard, true);
- },
- );
let failure = unpack!(
block = this.in_opt_scope(
opt_destruction_scope.map(|de| (de, source_info)),
|this| {
let scope = (*init_scope, source_info);
this.in_scope(scope, *lint_level, |this| {
+ this.declare_bindings(
+ visibility_scope,
+ remainder_span,
+ pattern,
+ ArmHasGuard(false),
+ Some((None, initializer_span)),
+ );
+ this.visit_primary_bindings(
+ pattern,
+ UserTypeProjections::none(),
+ &mut |this, _, _, _, node, span, _, _| {
+ this.storage_live_binding(
+ block,
+ node,
+ span,
+ OutsideGuard,
+ true,
+ );
+ },
+ );
this.ast_let_else(
block,
init,
@@ -305,7 +311,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
ArmHasGuard(false),
Some((None, initializer_span)),
);
- this.expr_into_pattern(block, &pattern, init) // irrefutable pattern
+ this.expr_into_pattern(block, &pattern, init)
+ // irrefutable pattern
})
},
)
diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs
index c9bec130c..37dc1ad9f 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs
@@ -2,6 +2,7 @@
use crate::build::{parse_float_into_constval, Builder};
use rustc_ast as ast;
+use rustc_middle::mir;
use rustc_middle::mir::interpret::{
Allocation, ConstValue, LitToConstError, LitToConstInput, Scalar,
};
@@ -66,7 +67,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
})
});
- let uneval = ty::Unevaluated::new(ty::WithOptConstParam::unknown(def_id), substs);
+ let uneval =
+ mir::UnevaluatedConst::new(ty::WithOptConstParam::unknown(def_id), substs);
let literal = ConstantKind::Unevaluated(uneval, ty);
Constant { user_ty, span, literal }
@@ -79,7 +81,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
Constant { user_ty: None, span, literal }
}
ExprKind::ConstBlock { did: def_id, substs } => {
- let uneval = ty::Unevaluated::new(ty::WithOptConstParam::unknown(def_id), substs);
+ let uneval =
+ mir::UnevaluatedConst::new(ty::WithOptConstParam::unknown(def_id), substs);
let literal = ConstantKind::Unevaluated(uneval, ty);
Constant { user_ty: None, span, literal }
diff --git a/compiler/rustc_mir_build/src/build/expr/as_operand.rs b/compiler/rustc_mir_build/src/build/expr/as_operand.rs
index e707c373f..c8610af70 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_operand.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_operand.rs
@@ -153,12 +153,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
if tcx.features().unsized_fn_params {
let ty = expr.ty;
- let span = expr.span;
let param_env = this.param_env;
- if !ty.is_sized(tcx.at(span), param_env) {
+ if !ty.is_sized(tcx, param_env) {
// !sized means !copy, so this is an unsized move
- assert!(!ty.is_copy_modulo_regions(tcx.at(span), param_env));
+ assert!(!ty.is_copy_modulo_regions(tcx, param_env));
// As described above, detect the case where we are passing a value of unsized
// type, and that value is coming from the deref of a box.
diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs
index ebb56e5a2..396782d45 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_place.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs
@@ -17,6 +17,7 @@ use rustc_target::abi::VariantIdx;
use rustc_index::vec::Idx;
+use std::assert_matches::assert_matches;
use std::iter;
/// The "outermost" place that holds this value.
@@ -69,7 +70,7 @@ pub(crate) enum PlaceBase {
/// This is used internally when building a place for an expression like `a.b.c`. The fields `b`
/// and `c` can be progressively pushed onto the place builder that is created when converting `a`.
#[derive(Clone, Debug, PartialEq)]
-pub(crate) struct PlaceBuilder<'tcx> {
+pub(in crate::build) struct PlaceBuilder<'tcx> {
base: PlaceBase,
projection: Vec<PlaceElem<'tcx>>,
}
@@ -102,6 +103,8 @@ fn convert_to_hir_projections_and_truncate_for_capture<'tcx>(
variant = Some(*idx);
continue;
}
+ // These do not affect anything, they just make sure we know the right type.
+ ProjectionElem::OpaqueCast(_) => continue,
ProjectionElem::Index(..)
| ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. } => {
@@ -168,22 +171,22 @@ fn find_capture_matching_projections<'a, 'tcx>(
/// `PlaceBuilder` now starts from `PlaceBase::Local`.
///
/// Returns a Result with the error being the PlaceBuilder (`from_builder`) that was not found.
-fn to_upvars_resolved_place_builder<'a, 'tcx>(
+#[instrument(level = "trace", skip(cx), ret)]
+fn to_upvars_resolved_place_builder<'tcx>(
from_builder: PlaceBuilder<'tcx>,
- tcx: TyCtxt<'tcx>,
- upvars: &'a CaptureMap<'tcx>,
+ cx: &Builder<'_, 'tcx>,
) -> Result<PlaceBuilder<'tcx>, PlaceBuilder<'tcx>> {
match from_builder.base {
PlaceBase::Local(_) => Ok(from_builder),
PlaceBase::Upvar { var_hir_id, closure_def_id } => {
let Some((capture_index, capture)) =
find_capture_matching_projections(
- upvars,
+ &cx.upvars,
var_hir_id,
&from_builder.projection,
) else {
- let closure_span = tcx.def_span(closure_def_id);
- if !enable_precise_capture(tcx, closure_span) {
+ let closure_span = cx.tcx.def_span(closure_def_id);
+ if !enable_precise_capture(cx.tcx, closure_span) {
bug!(
"No associated capture found for {:?}[{:#?}] even though \
capture_disjoint_fields isn't enabled",
@@ -200,12 +203,13 @@ fn to_upvars_resolved_place_builder<'a, 'tcx>(
};
// Access the capture by accessing the field within the Closure struct.
- let capture_info = &upvars[capture_index];
+ let capture_info = &cx.upvars[capture_index];
let mut upvar_resolved_place_builder = PlaceBuilder::from(capture_info.use_place);
// We used some of the projections to build the capture itself,
// now we apply the remaining to the upvar resolved place.
+ trace!(?capture.captured_place, ?from_builder.projection);
let remaining_projections = strip_prefix(
capture.captured_place.place.base_ty,
from_builder.projection,
@@ -229,17 +233,20 @@ fn strip_prefix<'tcx>(
projections: Vec<PlaceElem<'tcx>>,
prefix_projections: &[HirProjection<'tcx>],
) -> impl Iterator<Item = PlaceElem<'tcx>> {
- let mut iter = projections.into_iter();
+ let mut iter = projections
+ .into_iter()
+ // Filter out opaque casts, they are unnecessary in the prefix.
+ .filter(|elem| !matches!(elem, ProjectionElem::OpaqueCast(..)));
for projection in prefix_projections {
match projection.kind {
HirProjectionKind::Deref => {
- assert!(matches!(iter.next(), Some(ProjectionElem::Deref)));
+ assert_matches!(iter.next(), Some(ProjectionElem::Deref));
}
HirProjectionKind::Field(..) => {
if base_ty.is_enum() {
- assert!(matches!(iter.next(), Some(ProjectionElem::Downcast(..))));
+ assert_matches!(iter.next(), Some(ProjectionElem::Downcast(..)));
}
- assert!(matches!(iter.next(), Some(ProjectionElem::Field(..))));
+ assert_matches!(iter.next(), Some(ProjectionElem::Field(..)));
}
HirProjectionKind::Index | HirProjectionKind::Subslice => {
bug!("unexpected projection kind: {:?}", projection);
@@ -251,24 +258,16 @@ fn strip_prefix<'tcx>(
}
impl<'tcx> PlaceBuilder<'tcx> {
- pub(in crate::build) fn into_place<'a>(
- self,
- tcx: TyCtxt<'tcx>,
- upvars: &'a CaptureMap<'tcx>,
- ) -> Place<'tcx> {
+ pub(in crate::build) fn into_place(self, cx: &Builder<'_, 'tcx>) -> Place<'tcx> {
if let PlaceBase::Local(local) = self.base {
- Place { local, projection: tcx.intern_place_elems(&self.projection) }
+ Place { local, projection: cx.tcx.intern_place_elems(&self.projection) }
} else {
- self.expect_upvars_resolved(tcx, upvars).into_place(tcx, upvars)
+ self.expect_upvars_resolved(cx).into_place(cx)
}
}
- fn expect_upvars_resolved<'a>(
- self,
- tcx: TyCtxt<'tcx>,
- upvars: &'a CaptureMap<'tcx>,
- ) -> PlaceBuilder<'tcx> {
- to_upvars_resolved_place_builder(self, tcx, upvars).unwrap()
+ fn expect_upvars_resolved(self, cx: &Builder<'_, 'tcx>) -> PlaceBuilder<'tcx> {
+ to_upvars_resolved_place_builder(self, cx).unwrap()
}
/// Attempts to resolve the `PlaceBuilder`.
@@ -282,18 +281,21 @@ impl<'tcx> PlaceBuilder<'tcx> {
/// not captured. This can happen because the final mir that will be
/// generated doesn't require a read for this place. Failures will only
/// happen inside closures.
- pub(in crate::build) fn try_upvars_resolved<'a>(
+ pub(in crate::build) fn try_upvars_resolved(
self,
- tcx: TyCtxt<'tcx>,
- upvars: &'a CaptureMap<'tcx>,
+ cx: &Builder<'_, 'tcx>,
) -> Result<PlaceBuilder<'tcx>, PlaceBuilder<'tcx>> {
- to_upvars_resolved_place_builder(self, tcx, upvars)
+ to_upvars_resolved_place_builder(self, cx)
}
pub(crate) fn base(&self) -> PlaceBase {
self.base
}
+ pub(crate) fn projection(&self) -> &[PlaceElem<'tcx>] {
+ &self.projection
+ }
+
pub(crate) fn field(self, f: Field, ty: Ty<'tcx>) -> Self {
self.project(PlaceElem::Field(f, ty))
}
@@ -353,7 +355,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
expr: &Expr<'tcx>,
) -> BlockAnd<Place<'tcx>> {
let place_builder = unpack!(block = self.as_place_builder(block, expr));
- block.and(place_builder.into_place(self.tcx, &self.upvars))
+ block.and(place_builder.into_place(self))
}
/// This is used when constructing a compound `Place`, so that we can avoid creating
@@ -377,7 +379,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
expr: &Expr<'tcx>,
) -> BlockAnd<Place<'tcx>> {
let place_builder = unpack!(block = self.as_read_only_place_builder(block, expr));
- block.and(place_builder.into_place(self.tcx, &self.upvars))
+ block.and(place_builder.into_place(self))
}
/// This is used when constructing a compound `Place`, so that we can avoid creating
@@ -472,7 +474,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
inferred_ty: expr.ty,
});
- let place = place_builder.clone().into_place(this.tcx, &this.upvars);
+ let place = place_builder.clone().into_place(this);
this.cfg.push(
block,
Statement {
@@ -610,7 +612,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
if is_outermost_index {
self.read_fake_borrows(block, fake_borrow_temps, source_info)
} else {
- base_place = base_place.expect_upvars_resolved(self.tcx, &self.upvars);
+ base_place = base_place.expect_upvars_resolved(self);
self.add_fake_borrows_of_base(
&base_place,
block,
@@ -638,12 +640,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let lt = self.temp(bool_ty, expr_span);
// len = len(slice)
- self.cfg.push_assign(
- block,
- source_info,
- len,
- Rvalue::Len(slice.into_place(self.tcx, &self.upvars)),
- );
+ self.cfg.push_assign(block, source_info, len, Rvalue::Len(slice.into_place(self)));
// lt = idx < len
self.cfg.push_assign(
block,
@@ -723,6 +720,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
ProjectionElem::Field(..)
| ProjectionElem::Downcast(..)
+ | ProjectionElem::OpaqueCast(..)
| ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. } => (),
}
diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
index f88ab63f0..3dafdcb78 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
@@ -12,7 +12,7 @@ use rustc_middle::mir::AssertKind;
use rustc_middle::mir::Place;
use rustc_middle::mir::*;
use rustc_middle::thir::*;
-use rustc_middle::ty::cast::CastTy;
+use rustc_middle::ty::cast::{mir_cast_kind, CastTy};
use rustc_middle::ty::{self, Ty, UpvarSubsts};
use rustc_span::Span;
@@ -217,16 +217,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let from_ty = CastTy::from_ty(ty);
let cast_ty = CastTy::from_ty(expr.ty);
debug!("ExprKind::Cast from_ty={from_ty:?}, cast_ty={:?}/{cast_ty:?}", expr.ty,);
- let cast_kind = match (from_ty, cast_ty) {
- (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Int(_))) => {
- CastKind::PointerExposeAddress
- }
- (Some(CastTy::Int(_)), Some(CastTy::Ptr(_))) => {
- CastKind::PointerFromExposedAddress
- }
- (_, Some(CastTy::DynStar)) => CastKind::DynStar,
- (_, _) => CastKind::Misc,
- };
+ let cast_kind = mir_cast_kind(ty, expr.ty);
block.and(Rvalue::Cast(cast_kind, source, expr.ty))
}
ExprKind::Pointer { cast, source } => {
@@ -329,10 +320,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let place_builder =
unpack!(block = this.as_place_builder(block, &this.thir[*thir_place]));
- if let Ok(place_builder_resolved) =
- place_builder.try_upvars_resolved(this.tcx, &this.upvars)
- {
- let mir_place = place_builder_resolved.into_place(this.tcx, &this.upvars);
+ if let Ok(place_builder_resolved) = place_builder.try_upvars_resolved(this) {
+ let mir_place = place_builder_resolved.into_place(this);
this.cfg.push_fake_read(
block,
this.source_info(this.tcx.hir().span(*hir_id)),
@@ -623,8 +612,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// by the parent itself. The mutability of the current capture
// is same as that of the capture in the parent closure.
PlaceBase::Upvar { .. } => {
- let enclosing_upvars_resolved =
- arg_place_builder.clone().into_place(this.tcx, &this.upvars);
+ let enclosing_upvars_resolved = arg_place_builder.clone().into_place(this);
match enclosing_upvars_resolved.as_ref() {
PlaceRef {
@@ -661,7 +649,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
Mutability::Mut => BorrowKind::Mut { allow_two_phase_borrow: false },
};
- let arg_place = arg_place_builder.into_place(this.tcx, &this.upvars);
+ let arg_place = arg_place_builder.into_place(this);
this.cfg.push_assign(
block,
diff --git a/compiler/rustc_mir_build/src/build/expr/as_temp.rs b/compiler/rustc_mir_build/src/build/expr/as_temp.rs
index e5dafb820..0ca4e3745 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_temp.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_temp.rs
@@ -23,6 +23,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
ensure_sufficient_stack(|| self.as_temp_inner(block, temp_lifetime, expr, mutability))
}
+ #[instrument(skip(self), level = "debug")]
fn as_temp_inner(
&mut self,
mut block: BasicBlock,
@@ -30,10 +31,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
expr: &Expr<'tcx>,
mutability: Mutability,
) -> BlockAnd<Local> {
- debug!(
- "as_temp(block={:?}, temp_lifetime={:?}, expr={:?}, mutability={:?})",
- block, temp_lifetime, expr, mutability
- );
let this = self;
let expr_span = expr.span;
diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs
index 224a1b80f..24ecd0a53 100644
--- a/compiler/rustc_mir_build/src/build/expr/into.rs
+++ b/compiler/rustc_mir_build/src/build/expr/into.rs
@@ -15,14 +15,13 @@ use std::iter;
impl<'a, 'tcx> Builder<'a, 'tcx> {
/// Compile `expr`, storing the result into `destination`, which
/// is assumed to be uninitialized.
+ #[instrument(level = "debug", skip(self))]
pub(crate) fn expr_into_dest(
&mut self,
destination: Place<'tcx>,
mut block: BasicBlock,
expr: &Expr<'tcx>,
) -> BlockAnd<()> {
- debug!("expr_into_dest(destination={:?}, block={:?}, expr={:?})", destination, block, expr);
-
// since we frequently have to reference `self` from within a
// closure, where `self` would be shadowed, it's easier to
// just use the name `this` uniformly
@@ -366,7 +365,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
None => {
let place_builder = place_builder.clone();
this.consume_by_copy_or_move(
- place_builder.field(n, *ty).into_place(this.tcx, &this.upvars),
+ place_builder.field(n, *ty).into_place(this),
)
}
})
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index 93f382cc6..3f813e0af 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -220,10 +220,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let cause_matched_place = FakeReadCause::ForMatchedPlace(None);
let source_info = self.source_info(scrutinee_span);
- if let Ok(scrutinee_builder) =
- scrutinee_place_builder.clone().try_upvars_resolved(self.tcx, &self.upvars)
- {
- let scrutinee_place = scrutinee_builder.into_place(self.tcx, &self.upvars);
+ if let Ok(scrutinee_builder) = scrutinee_place_builder.clone().try_upvars_resolved(self) {
+ let scrutinee_place = scrutinee_builder.into_place(self);
self.cfg.push_fake_read(block, source_info, cause_matched_place, scrutinee_place);
}
@@ -246,7 +244,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
.map(|arm| {
let arm = &self.thir[arm];
let arm_has_guard = arm.guard.is_some();
- let arm_candidate = Candidate::new(scrutinee.clone(), &arm.pattern, arm_has_guard);
+ let arm_candidate =
+ Candidate::new(scrutinee.clone(), &arm.pattern, arm_has_guard, self);
(arm, arm_candidate)
})
.collect()
@@ -349,9 +348,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let mut opt_scrutinee_place: Option<(Option<&Place<'tcx>>, Span)> = None;
let scrutinee_place: Place<'tcx>;
if let Ok(scrutinee_builder) =
- scrutinee_place_builder.clone().try_upvars_resolved(this.tcx, &this.upvars)
+ scrutinee_place_builder.clone().try_upvars_resolved(this)
{
- scrutinee_place = scrutinee_builder.into_place(this.tcx, &this.upvars);
+ scrutinee_place = scrutinee_builder.into_place(this);
opt_scrutinee_place = Some((Some(&scrutinee_place), scrutinee_span));
}
let scope = this.declare_bindings(
@@ -584,7 +583,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
initializer: PlaceBuilder<'tcx>,
set_match_place: bool,
) -> BlockAnd<()> {
- let mut candidate = Candidate::new(initializer.clone(), &irrefutable_pat, false);
+ let mut candidate = Candidate::new(initializer.clone(), &irrefutable_pat, false, self);
let fake_borrow_temps = self.lower_match_tree(
block,
irrefutable_pat.span,
@@ -601,12 +600,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
while let Some(next) = {
for binding in &candidate_ref.bindings {
let local = self.var_local_id(binding.var_id, OutsideGuard);
-
- let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
- VarBindingForm { opt_match_place: Some((ref mut match_place, _)), .. },
- )))) = self.local_decls[local].local_info else {
- bug!("Let binding to non-user variable.")
- };
// `try_upvars_resolved` may fail if it is unable to resolve the given
// `PlaceBuilder` inside a closure. In this case, we don't want to include
// a scrutinee place. `scrutinee_place_builder` will fail for destructured
@@ -621,10 +614,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// let (v1, v2) = foo;
// };
// ```
- if let Ok(match_pair_resolved) =
- initializer.clone().try_upvars_resolved(self.tcx, &self.upvars)
- {
- let place = match_pair_resolved.into_place(self.tcx, &self.upvars);
+ if let Ok(match_pair_resolved) = initializer.clone().try_upvars_resolved(self) {
+ let place = match_pair_resolved.into_place(self);
+
+ let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
+ VarBindingForm { opt_match_place: Some((ref mut match_place, _)), .. },
+ )))) = self.local_decls[local].local_info else {
+ bug!("Let binding to non-user variable.")
+ };
*match_place = Some(place);
}
}
@@ -654,6 +651,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// scope for the bindings in these patterns, if such a scope had to be
/// created. NOTE: Declaring the bindings should always be done in their
/// drop scope.
+ #[instrument(skip(self), level = "debug")]
pub(crate) fn declare_bindings(
&mut self,
mut visibility_scope: Option<SourceScope>,
@@ -662,7 +660,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
has_guard: ArmHasGuard,
opt_match_place: Option<(Option<&Place<'tcx>>, Span)>,
) -> Option<SourceScope> {
- debug!("declare_bindings: pattern={:?}", pattern);
self.visit_primary_bindings(
&pattern,
UserTypeProjections::none(),
@@ -868,11 +865,16 @@ struct Candidate<'pat, 'tcx> {
}
impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
- fn new(place: PlaceBuilder<'tcx>, pattern: &'pat Pat<'tcx>, has_guard: bool) -> Self {
+ fn new(
+ place: PlaceBuilder<'tcx>,
+ pattern: &'pat Pat<'tcx>,
+ has_guard: bool,
+ cx: &Builder<'_, 'tcx>,
+ ) -> Self {
Candidate {
span: pattern.span,
has_guard,
- match_pairs: smallvec![MatchPair { place, pattern }],
+ match_pairs: smallvec![MatchPair::new(place, pattern, cx)],
bindings: Vec::new(),
ascriptions: Vec::new(),
subcandidates: Vec::new(),
@@ -1048,6 +1050,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// if `x.0` matches `false` (for the third arm). In the (impossible at
/// runtime) case when `x.0` is now `true`, we branch to
/// `otherwise_block`.
+ #[instrument(skip(self, fake_borrows), level = "debug")]
fn match_candidates<'pat>(
&mut self,
span: Span,
@@ -1057,11 +1060,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
candidates: &mut [&mut Candidate<'pat, 'tcx>],
fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>,
) {
- debug!(
- "matched_candidate(span={:?}, candidates={:?}, start_block={:?}, otherwise_block={:?})",
- span, candidates, start_block, otherwise_block,
- );
-
// Start by simplifying candidates. Once this process is complete, all
// the match pairs which remain require some form of test, whether it
// be a switch or pattern comparison.
@@ -1380,6 +1378,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
)
}
+ #[instrument(
+ skip(self, otherwise, or_span, place, fake_borrows, candidate, pats),
+ level = "debug"
+ )]
fn test_or_pattern<'pat>(
&mut self,
candidate: &mut Candidate<'pat, 'tcx>,
@@ -1389,10 +1391,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
place: PlaceBuilder<'tcx>,
fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>,
) {
- debug!("test_or_pattern:\ncandidate={:#?}\npats={:#?}", candidate, pats);
+ debug!("candidate={:#?}\npats={:#?}", candidate, pats);
let mut or_candidates: Vec<_> = pats
.iter()
- .map(|pat| Candidate::new(place.clone(), pat, candidate.has_guard))
+ .map(|pat| Candidate::new(place.clone(), pat, candidate.has_guard, self))
.collect();
let mut or_candidate_refs: Vec<_> = or_candidates.iter_mut().collect();
let otherwise = if candidate.otherwise_block.is_some() {
@@ -1605,9 +1607,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// Insert a Shallow borrow of any places that is switched on.
if let Some(fb) = fake_borrows && let Ok(match_place_resolved) =
- match_place.clone().try_upvars_resolved(self.tcx, &self.upvars)
+ match_place.clone().try_upvars_resolved(self)
{
- let resolved_place = match_place_resolved.into_place(self.tcx, &self.upvars);
+ let resolved_place = match_place_resolved.into_place(self);
fb.insert(resolved_place);
}
@@ -1634,9 +1636,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
candidates = rest;
}
// at least the first candidate ought to be tested
- assert!(total_candidate_count > candidates.len());
- debug!("test_candidates: tested_candidates: {}", total_candidate_count - candidates.len());
- debug!("test_candidates: untested_candidates: {}", candidates.len());
+ assert!(
+ total_candidate_count > candidates.len(),
+ "{}, {:#?}",
+ total_candidate_count,
+ candidates
+ );
+ debug!("tested_candidates: {}", total_candidate_count - candidates.len());
+ debug!("untested_candidates: {}", candidates.len());
// HACK(matthewjasper) This is a closure so that we can let the test
// create its blocks before the rest of the match. This currently
@@ -1783,8 +1790,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let expr_span = expr.span;
let expr_place_builder = unpack!(block = self.lower_scrutinee(block, expr, expr_span));
let wildcard = Pat::wildcard_from_ty(pat.ty);
- let mut guard_candidate = Candidate::new(expr_place_builder.clone(), &pat, false);
- let mut otherwise_candidate = Candidate::new(expr_place_builder.clone(), &wildcard, false);
+ let mut guard_candidate = Candidate::new(expr_place_builder.clone(), &pat, false, self);
+ let mut otherwise_candidate =
+ Candidate::new(expr_place_builder.clone(), &wildcard, false, self);
let fake_borrow_temps = self.lower_match_tree(
block,
pat.span,
@@ -1794,8 +1802,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
);
let mut opt_expr_place: Option<(Option<&Place<'tcx>>, Span)> = None;
let expr_place: Place<'tcx>;
- if let Ok(expr_builder) = expr_place_builder.try_upvars_resolved(self.tcx, &self.upvars) {
- expr_place = expr_builder.into_place(self.tcx, &self.upvars);
+ if let Ok(expr_builder) = expr_place_builder.try_upvars_resolved(self) {
+ expr_place = expr_builder.into_place(self);
opt_expr_place = Some((Some(&expr_place), expr_span));
}
let otherwise_post_guard_block = otherwise_candidate.pre_binding_block.unwrap();
@@ -2209,6 +2217,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// first local is a binding for occurrences of `var` in the guard, which
/// will have type `&T`. The second local is a binding for occurrences of
/// `var` in the arm body, which will have type `T`.
+ #[instrument(skip(self), level = "debug")]
fn declare_binding(
&mut self,
source_info: SourceInfo,
@@ -2223,19 +2232,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
opt_match_place: Option<(Option<Place<'tcx>>, Span)>,
pat_span: Span,
) {
- debug!(
- "declare_binding(var_id={:?}, name={:?}, mode={:?}, var_ty={:?}, \
- visibility_scope={:?}, source_info={:?})",
- var_id, name, mode, var_ty, visibility_scope, source_info
- );
-
let tcx = self.tcx;
let debug_source_info = SourceInfo { span: source_info.span, scope: visibility_scope };
let binding_mode = match mode {
BindingMode::ByValue => ty::BindingMode::BindByValue(mutability),
BindingMode::ByRef(_) => ty::BindingMode::BindByReference(mutability),
};
- debug!("declare_binding: user_ty={:?}", user_ty);
let local = LocalDecl::<'tcx> {
mutability,
ty: var_ty,
@@ -2285,7 +2287,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
} else {
LocalsForNode::One(for_arm_body)
};
- debug!("declare_binding: vars={:?}", locals);
+ debug!(?locals);
self.var_indices.insert(var_id, locals);
}
@@ -2302,8 +2304,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let (matching, failure) = self.in_if_then_scope(*let_else_scope, else_block_span, |this| {
let scrutinee = unpack!(block = this.lower_scrutinee(block, init, initializer_span));
let pat = Pat { ty: init.ty, span: else_block_span, kind: PatKind::Wild };
- let mut wildcard = Candidate::new(scrutinee.clone(), &pat, false);
- let mut candidate = Candidate::new(scrutinee.clone(), pattern, false);
+ let mut wildcard = Candidate::new(scrutinee.clone(), &pat, false, this);
+ let mut candidate = Candidate::new(scrutinee.clone(), pattern, false, this);
let fake_borrow_temps = this.lower_match_tree(
block,
initializer_span,
diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs
index df221d356..924d2f555 100644
--- a/compiler/rustc_mir_build/src/build/matches/simplify.rs
+++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs
@@ -37,12 +37,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
///
/// only generates a single switch. If this happens this method returns
/// `true`.
+ #[instrument(skip(self, candidate), level = "debug")]
pub(super) fn simplify_candidate<'pat>(
&mut self,
candidate: &mut Candidate<'pat, 'tcx>,
) -> bool {
// repeatedly simplify match pairs until fixed point is reached
- debug!(?candidate, "simplify_candidate");
+ debug!("{candidate:#?}");
// existing_bindings and new_bindings exists to keep the semantics in order.
// Reversing the binding order for bindings after `@` changes the binding order in places
@@ -131,7 +132,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
) -> Vec<Candidate<'pat, 'tcx>> {
pats.iter()
.map(|box pat| {
- let mut candidate = Candidate::new(place.clone(), pat, candidate.has_guard);
+ let mut candidate = Candidate::new(place.clone(), pat, candidate.has_guard, self);
self.simplify_candidate(&mut candidate);
candidate
})
@@ -155,17 +156,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
ascription: thir::Ascription { ref annotation, variance },
} => {
// Apply the type ascription to the value at `match_pair.place`, which is the
- if let Ok(place_resolved) =
- match_pair.place.clone().try_upvars_resolved(self.tcx, &self.upvars)
- {
+ if let Ok(place_resolved) = match_pair.place.clone().try_upvars_resolved(self) {
candidate.ascriptions.push(Ascription {
annotation: annotation.clone(),
- source: place_resolved.into_place(self.tcx, &self.upvars),
+ source: place_resolved.into_place(self),
variance,
});
}
- candidate.match_pairs.push(MatchPair::new(match_pair.place, subpattern));
+ candidate.match_pairs.push(MatchPair::new(match_pair.place, subpattern, self));
Ok(())
}
@@ -184,12 +183,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
ref subpattern,
is_primary: _,
} => {
- if let Ok(place_resolved) =
- match_pair.place.clone().try_upvars_resolved(self.tcx, &self.upvars)
- {
+ if let Ok(place_resolved) = match_pair.place.clone().try_upvars_resolved(self) {
candidate.bindings.push(Binding {
span: match_pair.pattern.span,
- source: place_resolved.into_place(self.tcx, &self.upvars),
+ source: place_resolved.into_place(self),
var_id: var,
binding_mode: mode,
});
@@ -197,7 +194,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
if let Some(subpattern) = subpattern.as_ref() {
// this is the `x @ P` case; have to keep matching against `P` now
- candidate.match_pairs.push(MatchPair::new(match_pair.place, subpattern));
+ candidate.match_pairs.push(MatchPair::new(match_pair.place, subpattern, self));
}
Ok(())
@@ -267,14 +264,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| {
i == variant_index || {
self.tcx.features().exhaustive_patterns
- && !v
- .uninhabited_from(
- self.tcx,
- substs,
- adt_def.adt_kind(),
- self.param_env,
- )
- .is_empty()
+ && v.inhabited_predicate(self.tcx, adt_def)
+ .subst(self.tcx, substs)
+ .apply_any_module(self.tcx, self.param_env)
+ != Some(true)
}
}) && (adt_def.did().is_local()
|| !adt_def.is_variant_list_non_exhaustive());
@@ -308,7 +301,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
PatKind::Deref { ref subpattern } => {
let place_builder = match_pair.place.deref();
- candidate.match_pairs.push(MatchPair::new(place_builder, subpattern));
+ candidate.match_pairs.push(MatchPair::new(place_builder, subpattern, self));
Ok(())
}
diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs
index 47d05a6e3..b597ecfaa 100644
--- a/compiler/rustc_mir_build/src/build/matches/test.rs
+++ b/compiler/rustc_mir_build/src/build/matches/test.rs
@@ -14,8 +14,8 @@ use rustc_hir::{LangItem, RangeEnd};
use rustc_index::bit_set::BitSet;
use rustc_middle::mir::*;
use rustc_middle::thir::*;
-use rustc_middle::ty::subst::{GenericArg, Subst};
use rustc_middle::ty::util::IntTypeExt;
+use rustc_middle::ty::GenericArg;
use rustc_middle::ty::{self, adjustment::PointerCast, Ty, TyCtxt};
use rustc_span::def_id::DefId;
use rustc_span::symbol::{sym, Symbol};
@@ -144,6 +144,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
}
+ #[instrument(skip(self, make_target_blocks, place_builder), level = "debug")]
pub(super) fn perform_test(
&mut self,
match_start_span: Span,
@@ -153,19 +154,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
test: &Test<'tcx>,
make_target_blocks: impl FnOnce(&mut Self) -> Vec<BasicBlock>,
) {
- let place: Place<'tcx>;
- if let Ok(test_place_builder) = place_builder.try_upvars_resolved(self.tcx, &self.upvars) {
- place = test_place_builder.into_place(self.tcx, &self.upvars);
- } else {
- return;
- }
- debug!(
- "perform_test({:?}, {:?}: {:?}, {:?})",
- block,
- place,
- place.ty(&self.local_decls, self.tcx),
- test
- );
+ let place = place_builder.into_place(self);
+ let place_ty = place.ty(&self.local_decls, self.tcx);
+ debug!(?place, ?place_ty,);
let source_info = self.source_info(test.span);
match test.kind {
@@ -733,14 +724,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// So, if we have a match-pattern like `x @ Enum::Variant(P1, P2)`,
// we want to create a set of derived match-patterns like
// `(x as Variant).0 @ P1` and `(x as Variant).1 @ P1`.
- let elem =
- ProjectionElem::Downcast(Some(adt_def.variant(variant_index).name), variant_index);
- let downcast_place = match_pair.place.project(elem); // `(x as Variant)`
+ let downcast_place = match_pair.place.downcast(adt_def, variant_index); // `(x as Variant)`
let consequent_match_pairs = subpatterns.iter().map(|subpattern| {
// e.g., `(x as Variant).0`
let place = downcast_place.clone().field(subpattern.field, subpattern.pattern.ty);
// e.g., `(x as Variant).0 @ P1`
- MatchPair::new(place, &subpattern.pattern)
+ MatchPair::new(place, &subpattern.pattern, self)
});
candidate.match_pairs.extend(consequent_match_pairs);
diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs
index b61c4fe50..b854ba47f 100644
--- a/compiler/rustc_mir_build/src/build/matches/util.rs
+++ b/compiler/rustc_mir_build/src/build/matches/util.rs
@@ -1,9 +1,11 @@
+use crate::build::expr::as_place::PlaceBase;
use crate::build::expr::as_place::PlaceBuilder;
use crate::build::matches::MatchPair;
use crate::build::Builder;
use rustc_middle::mir::*;
use rustc_middle::thir::*;
use rustc_middle::ty;
+use rustc_middle::ty::TypeVisitable;
use smallvec::SmallVec;
use std::convert::TryInto;
@@ -17,7 +19,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
.iter()
.map(|fieldpat| {
let place = place.clone().field(fieldpat.field, fieldpat.pattern.ty);
- MatchPair::new(place, &fieldpat.pattern)
+ MatchPair::new(place, &fieldpat.pattern, self)
})
.collect()
}
@@ -31,23 +33,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
suffix: &'pat [Box<Pat<'tcx>>],
) {
let tcx = self.tcx;
- let (min_length, exact_size) = if let Ok(place_resolved) =
- place.clone().try_upvars_resolved(tcx, &self.upvars)
- {
- match place_resolved.into_place(tcx, &self.upvars).ty(&self.local_decls, tcx).ty.kind()
- {
- ty::Array(_, length) => (length.eval_usize(tcx, self.param_env), true),
- _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false),
- }
- } else {
- ((prefix.len() + suffix.len()).try_into().unwrap(), false)
- };
+ let (min_length, exact_size) =
+ if let Ok(place_resolved) = place.clone().try_upvars_resolved(self) {
+ match place_resolved.into_place(self).ty(&self.local_decls, tcx).ty.kind() {
+ ty::Array(_, length) => (length.eval_usize(tcx, self.param_env), true),
+ _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false),
+ }
+ } else {
+ ((prefix.len() + suffix.len()).try_into().unwrap(), false)
+ };
match_pairs.extend(prefix.iter().enumerate().map(|(idx, subpattern)| {
let elem =
ProjectionElem::ConstantIndex { offset: idx as u64, min_length, from_end: false };
let place = place.clone().project(elem);
- MatchPair::new(place, subpattern)
+ MatchPair::new(place, subpattern, self)
}));
if let Some(subslice_pat) = opt_slice {
@@ -57,7 +57,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
to: if exact_size { min_length - suffix_len } else { suffix_len },
from_end: !exact_size,
});
- match_pairs.push(MatchPair::new(subslice, subslice_pat));
+ match_pairs.push(MatchPair::new(subslice, subslice_pat, self));
}
match_pairs.extend(suffix.iter().rev().enumerate().map(|(idx, subpattern)| {
@@ -68,7 +68,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
from_end: !exact_size,
};
let place = place.clone().project(elem);
- MatchPair::new(place, subpattern)
+ MatchPair::new(place, subpattern, self)
}));
}
@@ -96,10 +96,29 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
- pub(crate) fn new(
+ pub(in crate::build) fn new(
place: PlaceBuilder<'tcx>,
pattern: &'pat Pat<'tcx>,
+ cx: &Builder<'_, 'tcx>,
) -> MatchPair<'pat, 'tcx> {
+ // Force the place type to the pattern's type.
+ // FIXME(oli-obk): can we use this to simplify slice/array pattern hacks?
+ let mut place = match place.try_upvars_resolved(cx) {
+ Ok(val) | Err(val) => val,
+ };
+
+ // Only add the OpaqueCast projection if the given place is an opaque type and the
+ // expected type from the pattern is not.
+ let may_need_cast = match place.base() {
+ PlaceBase::Local(local) => {
+ let ty = Place::ty_from(local, place.projection(), &cx.local_decls, cx.tcx).ty;
+ ty != pattern.ty && ty.has_opaque_types()
+ }
+ _ => true,
+ };
+ if may_need_cast {
+ place = place.project(ProjectionElem::OpaqueCast(pattern.ty));
+ }
MatchPair { place, pattern }
}
}
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index 25c4e51cb..cbcf9cd12 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -157,7 +157,7 @@ struct BlockContext(Vec<BlockFrame>);
struct Builder<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
- infcx: InferCtxt<'a, 'tcx>,
+ infcx: InferCtxt<'tcx>,
typeck_results: &'tcx TypeckResults<'tcx>,
region_scope_tree: &'tcx region::ScopeTree,
param_env: ty::ParamEnv<'tcx>,
@@ -481,54 +481,49 @@ fn construct_fn<'tcx>(
(None, fn_sig.output())
};
- let mut body = tcx.infer_ctxt().enter(|infcx| {
- let mut builder = Builder::new(
- thir,
- infcx,
- fn_def,
- fn_id,
- span_with_body,
- arguments.len(),
- safety,
- return_ty,
- return_ty_span,
- generator_kind,
- );
+ let infcx = tcx.infer_ctxt().build();
+ let mut builder = Builder::new(
+ thir,
+ infcx,
+ fn_def,
+ fn_id,
+ span_with_body,
+ arguments.len(),
+ safety,
+ return_ty,
+ return_ty_span,
+ generator_kind,
+ );
- let call_site_scope =
- region::Scope { id: body_id.hir_id.local_id, data: region::ScopeData::CallSite };
- let arg_scope =
- region::Scope { id: body_id.hir_id.local_id, data: region::ScopeData::Arguments };
- let source_info = builder.source_info(span);
- let call_site_s = (call_site_scope, source_info);
- unpack!(builder.in_scope(call_site_s, LintLevel::Inherited, |builder| {
- let arg_scope_s = (arg_scope, source_info);
- // Attribute epilogue to function's closing brace
- let fn_end = span_with_body.shrink_to_hi();
- let return_block = unpack!(builder.in_breakable_scope(
- None,
- Place::return_place(),
- fn_end,
- |builder| {
- Some(builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| {
- builder.args_and_body(
- START_BLOCK,
- fn_def.did,
- arguments,
- arg_scope,
- &thir[expr],
- )
- }))
- }
- ));
- let source_info = builder.source_info(fn_end);
- builder.cfg.terminate(return_block, source_info, TerminatorKind::Return);
- builder.build_drop_trees();
- return_block.unit()
- }));
-
- builder.finish()
- });
+ let call_site_scope =
+ region::Scope { id: body_id.hir_id.local_id, data: region::ScopeData::CallSite };
+ let arg_scope =
+ region::Scope { id: body_id.hir_id.local_id, data: region::ScopeData::Arguments };
+ let source_info = builder.source_info(span);
+ let call_site_s = (call_site_scope, source_info);
+ unpack!(builder.in_scope(call_site_s, LintLevel::Inherited, |builder| {
+ let arg_scope_s = (arg_scope, source_info);
+ // Attribute epilogue to function's closing brace
+ let fn_end = span_with_body.shrink_to_hi();
+ let return_block =
+ unpack!(builder.in_breakable_scope(None, Place::return_place(), fn_end, |builder| {
+ Some(builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| {
+ builder.args_and_body(
+ START_BLOCK,
+ fn_def.did,
+ arguments,
+ arg_scope,
+ &thir[expr],
+ )
+ }))
+ }));
+ let source_info = builder.source_info(fn_end);
+ builder.cfg.terminate(return_block, source_info, TerminatorKind::Return);
+ builder.build_drop_trees();
+ return_block.unit()
+ }));
+
+ let mut body = builder.finish();
body.spread_arg = if abi == Abi::RustCall {
// RustCall pseudo-ABI untuples the last argument.
@@ -584,30 +579,29 @@ fn construct_const<'a, 'tcx>(
let typeck_results = tcx.typeck_opt_const_arg(def);
let const_ty = typeck_results.node_type(hir_id);
- tcx.infer_ctxt().enter(|infcx| {
- let mut builder = Builder::new(
- thir,
- infcx,
- def,
- hir_id,
- span,
- 0,
- Safety::Safe,
- const_ty,
- const_ty_span,
- None,
- );
+ let infcx = tcx.infer_ctxt().build();
+ let mut builder = Builder::new(
+ thir,
+ infcx,
+ def,
+ hir_id,
+ span,
+ 0,
+ Safety::Safe,
+ const_ty,
+ const_ty_span,
+ None,
+ );
- let mut block = START_BLOCK;
- unpack!(block = builder.expr_into_dest(Place::return_place(), block, &thir[expr]));
+ let mut block = START_BLOCK;
+ unpack!(block = builder.expr_into_dest(Place::return_place(), block, &thir[expr]));
- let source_info = builder.source_info(span);
- builder.cfg.terminate(block, source_info, TerminatorKind::Return);
+ let source_info = builder.source_info(span);
+ builder.cfg.terminate(block, source_info, TerminatorKind::Return);
- builder.build_drop_trees();
+ builder.build_drop_trees();
- builder.finish()
- })
+ builder.finish()
}
/// Construct MIR for an item that has had errors in type checking.
@@ -683,7 +677,7 @@ fn construct_error<'tcx>(
impl<'a, 'tcx> Builder<'a, 'tcx> {
fn new(
thir: &'a Thir<'tcx>,
- infcx: InferCtxt<'a, 'tcx>,
+ infcx: InferCtxt<'tcx>,
def: ty::WithOptConstParam<LocalDefId>,
hir_id: hir::HirId,
span: Span,
diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs
index ff66ca595..3cebd5ebe 100644
--- a/compiler/rustc_mir_build/src/build/scope.rs
+++ b/compiler/rustc_mir_build/src/build/scope.rs
@@ -555,6 +555,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// Convenience wrapper that pushes a scope and then executes `f`
/// to build its contents, popping the scope afterwards.
+ #[instrument(skip(self, f), level = "debug")]
pub(crate) fn in_scope<F, R>(
&mut self,
region_scope: (region::Scope, SourceInfo),
@@ -564,7 +565,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
where
F: FnOnce(&mut Builder<'a, 'tcx>) -> BlockAnd<R>,
{
- debug!("in_scope(region_scope={:?})", region_scope);
let source_scope = self.source_scope;
let tcx = self.tcx;
if let LintLevel::Explicit(current_hir_id) = lint_level {
@@ -591,7 +591,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let rv = unpack!(block = f(self));
unpack!(block = self.pop_scope(region_scope, block));
self.source_scope = source_scope;
- debug!("in_scope: exiting region_scope={:?} block={:?}", region_scope, block);
+ debug!(?block);
block.and(rv)
}
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index 495738ebe..fb1ea9ed3 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -89,15 +89,8 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
UNSAFE_OP_IN_UNSAFE_FN,
self.hir_context,
span,
- |lint| {
- lint.build(&format!(
- "{} is unsafe and requires unsafe block (error E0133)",
- description,
- ))
- .span_label(span, kind.simple_description())
- .note(note)
- .emit();
- },
+ format!("{} is unsafe and requires unsafe block (error E0133)", description,),
+ |lint| lint.span_label(span, kind.simple_description()).note(note),
)
}
SafetyContext::Safe => {
@@ -125,14 +118,13 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
enclosing_unsafe: Option<(Span, &'static str)>,
) {
let block_span = self.tcx.sess.source_map().guess_head_span(block_span);
- self.tcx.struct_span_lint_hir(UNUSED_UNSAFE, hir_id, block_span, |lint| {
- let msg = "unnecessary `unsafe` block";
- let mut db = lint.build(msg);
- db.span_label(block_span, msg);
+ let msg = "unnecessary `unsafe` block";
+ self.tcx.struct_span_lint_hir(UNUSED_UNSAFE, hir_id, block_span, msg, |lint| {
+ lint.span_label(block_span, msg);
if let Some((span, kind)) = enclosing_unsafe {
- db.span_label(span, format!("because it's nested under this `unsafe` {}", kind));
+ lint.span_label(span, format!("because it's nested under this `unsafe` {}", kind));
}
- db.emit();
+ lint
});
}
@@ -268,7 +260,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
};
match borrow_kind {
BorrowKind::Shallow | BorrowKind::Shared | BorrowKind::Unique => {
- if !ty.is_freeze(self.tcx.at(pat.span), self.param_env) {
+ if !ty.is_freeze(self.tcx, self.param_env) {
self.requires_unsafe(pat.span, BorrowOfLayoutConstrainedField);
}
}
@@ -364,7 +356,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
// If the called function has target features the calling function hasn't,
// the call requires `unsafe`. Don't check this on wasm
// targets, though. For more information on wasm see the
- // is_like_wasm check in typeck/src/collect.rs
+ // is_like_wasm check in hir_analysis/src/collect.rs
if !self.tcx.sess.target.options.is_like_wasm
&& !self
.tcx
@@ -465,9 +457,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
if visitor.found {
match borrow_kind {
BorrowKind::Shallow | BorrowKind::Shared | BorrowKind::Unique
- if !self.thir[arg]
- .ty
- .is_freeze(self.tcx.at(self.thir[arg].span), self.param_env) =>
+ if !self.thir[arg].ty.is_freeze(self.tcx, self.param_env) =>
{
self.requires_unsafe(expr.span, BorrowOfLayoutConstrainedField)
}
diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs
index 0c0a2fe9c..b53bd3d07 100644
--- a/compiler/rustc_mir_build/src/lib.rs
+++ b/compiler/rustc_mir_build/src/lib.rs
@@ -2,11 +2,11 @@
//!
//! This crate also contains the match exhaustiveness and usefulness checking.
#![allow(rustc::potential_query_instability)]
+#![feature(assert_matches)]
#![feature(box_patterns)]
#![feature(control_flow_enum)]
#![feature(if_let_guard)]
#![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
#![feature(min_specialization)]
#![feature(once_cell)]
#![recursion_limit = "256"]
diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs
index 54d549fd6..b21f30efc 100644
--- a/compiler/rustc_mir_build/src/lints.rs
+++ b/compiler/rustc_mir_build/src/lints.rs
@@ -36,16 +36,20 @@ pub(crate) fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
let sp = tcx.def_span(def_id);
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- tcx.struct_span_lint_hir(UNCONDITIONAL_RECURSION, hir_id, sp, |lint| {
- let mut db = lint.build("function cannot return without recursing");
- db.span_label(sp, "cannot return without recursing");
- // offer some help to the programmer.
- for call_span in vis.reachable_recursive_calls {
- db.span_label(call_span, "recursive call site");
- }
- db.help("a `loop` may express intention better if this is on purpose");
- db.emit();
- });
+ tcx.struct_span_lint_hir(
+ UNCONDITIONAL_RECURSION,
+ hir_id,
+ sp,
+ "function cannot return without recursing",
+ |lint| {
+ lint.span_label(sp, "cannot return without recursing");
+ // offer some help to the programmer.
+ for call_span in vis.reachable_recursive_calls {
+ lint.span_label(call_span, "recursive call site");
+ }
+ lint.help("a `loop` may express intention better if this is on purpose")
+ },
+ );
}
}
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index d059877f8..c7a7c3e3f 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -48,6 +48,8 @@ impl<'tcx> Cx<'tcx> {
_ => None,
};
+ trace!(?expr.ty);
+
// Now apply adjustments, if any.
for adjustment in self.typeck_results.expr_adjustments(hir_expr) {
trace!(?expr, ?adjustment);
@@ -56,6 +58,8 @@ impl<'tcx> Cx<'tcx> {
self.apply_adjustment(hir_expr, expr, adjustment, adjustment_span.unwrap_or(span));
}
+ trace!(?expr.ty, "after adjustments");
+
// Next, wrap this up in the expr's scope.
expr = Expr {
temp_lifetime,
@@ -155,6 +159,7 @@ impl<'tcx> Cx<'tcx> {
Adjust::Borrow(AutoBorrow::RawPtr(mutability)) => {
ExprKind::AddressOf { mutability, arg: self.thir.exprs.push(expr) }
}
+ Adjust::DynStar => ExprKind::Cast { source: self.thir.exprs.push(expr) },
};
Expr { temp_lifetime, ty: adjustment.target, span, kind }
@@ -994,7 +999,7 @@ impl<'tcx> Cx<'tcx> {
.temporary_scope(self.region_scope_tree, closure_expr.hir_id.local_id);
let var_ty = place.base_ty;
- // The result of capture analysis in `rustc_typeck/check/upvar.rs`represents a captured path
+ // The result of capture analysis in `rustc_hir_analysis/check/upvar.rs`represents a captured path
// as it's seen for use within the closure and not at the time of closure creation.
//
// That is we see expect to see it start from a captured upvar and not something that is local
diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs
index 3ef1b263f..1d95d6b53 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, Subst, TyCtxt};
+use rustc_middle::ty::{self, RvalueScopes, TyCtxt};
use rustc_span::Span;
pub(crate) fn thir_body<'tcx>(
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 d45b88690..858129c74 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -7,7 +7,7 @@ use super::{PatCtxt, PatternError};
use rustc_arena::TypedArena;
use rustc_ast::Mutability;
use rustc_errors::{
- error_code, pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder,
+ error_code, pluralize, struct_span_err, Applicability, DelayDm, Diagnostic, DiagnosticBuilder,
ErrorGuaranteed, MultiSpan,
};
use rustc_hir as hir;
@@ -347,27 +347,35 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
let span_end = affix.last().unwrap().unwrap().0;
let span = span_start.to(span_end);
let cnt = affix.len();
- cx.tcx.struct_span_lint_hir(IRREFUTABLE_LET_PATTERNS, top, span, |lint| {
- let s = pluralize!(cnt);
- let mut diag = lint.build(&format!("{kind} irrefutable pattern{s} in let chain"));
- diag.note(&format!(
- "{these} pattern{s} will always match",
- these = pluralize!("this", cnt),
- ));
- diag.help(&format!(
- "consider moving {} {suggestion}",
- if cnt > 1 { "them" } else { "it" }
- ));
- diag.emit()
- });
+ let s = pluralize!(cnt);
+ cx.tcx.struct_span_lint_hir(
+ IRREFUTABLE_LET_PATTERNS,
+ top,
+ span,
+ format!("{kind} irrefutable pattern{s} in let chain"),
+ |lint| {
+ lint.note(format!(
+ "{these} pattern{s} will always match",
+ these = pluralize!("this", cnt),
+ ))
+ .help(format!(
+ "consider moving {} {suggestion}",
+ if cnt > 1 { "them" } else { "it" }
+ ))
+ },
+ );
};
if let Some(until) = chain_refutabilities.iter().position(|r| !matches!(*r, Some((_, false)))) && until > 0 {
// The chain has a non-zero prefix of irrefutable `let` statements.
// Check if the let source is while, for there is no alternative place to put a prefix,
// and we shouldn't lint.
+ // For let guards inside a match, prefixes might use bindings of the match pattern,
+ // so can't always be moved out.
+ // FIXME: Add checking whether the bindings are actually used in the prefix,
+ // and lint if they are not.
let let_source = let_source_parent(self.tcx, top, None);
- if !matches!(let_source, LetSource::WhileLet) {
+ if !matches!(let_source, LetSource::WhileLet | LetSource::IfLetGuard) {
// Emit the lint
let prefix = &chain_refutabilities[..until];
lint_affix(prefix, "leading", "outside of the construct");
@@ -487,7 +495,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
],
Applicability::HasPlaceholders,
);
- if !bindings.is_empty() && cx.tcx.sess.is_nightly_build() {
+ if !bindings.is_empty() {
err.span_suggestion_verbose(
semi_span.shrink_to_lo(),
&format!(
@@ -561,26 +569,28 @@ fn check_for_bindings_named_same_as_variants(
BINDINGS_WITH_VARIANT_NAME,
p.hir_id,
p.span,
+ DelayDm(|| format!(
+ "pattern binding `{}` is named the same as one \
+ of the variants of the type `{}`",
+ ident, cx.tcx.def_path_str(edef.did())
+ )),
|lint| {
let ty_path = cx.tcx.def_path_str(edef.did());
- let mut err = lint.build(&format!(
- "pattern binding `{}` is named the same as one \
- of the variants of the type `{}`",
- ident, ty_path
- ));
- err.code(error_code!(E0170));
+ lint.code(error_code!(E0170));
+
// If this is an irrefutable pattern, and there's > 1 variant,
// then we can't actually match on this. Applying the below
// suggestion would produce code that breaks on `check_irrefutable`.
if rf == Refutable || variant_count == 1 {
- err.span_suggestion(
+ lint.span_suggestion(
p.span,
"to match on the variant, qualify the path",
format!("{}::{}", ty_path, ident),
Applicability::MachineApplicable,
);
}
- err.emit();
+
+ lint
},
)
}
@@ -598,14 +608,13 @@ fn pat_is_catchall(pat: &DeconstructedPat<'_, '_>) -> bool {
}
fn unreachable_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, catchall: Option<Span>) {
- tcx.struct_span_lint_hir(UNREACHABLE_PATTERNS, id, span, |lint| {
- let mut err = lint.build("unreachable pattern");
+ tcx.struct_span_lint_hir(UNREACHABLE_PATTERNS, id, span, "unreachable pattern", |lint| {
if let Some(catchall) = catchall {
// We had a catchall pattern, hint at that.
- err.span_label(span, "unreachable pattern");
- err.span_label(catchall, "matches any value");
+ lint.span_label(span, "unreachable pattern");
+ lint.span_label(catchall, "matches any value");
}
- err.emit();
+ lint
});
}
@@ -621,6 +630,11 @@ fn irrefutable_let_patterns(
count: usize,
span: Span,
) {
+ let span = match source {
+ LetSource::LetElse(span) => span,
+ _ => span,
+ };
+
macro_rules! emit_diag {
(
$lint:expr,
@@ -630,18 +644,23 @@ fn irrefutable_let_patterns(
) => {{
let s = pluralize!(count);
let these = pluralize!("this", count);
- let mut diag = $lint.build(&format!("irrefutable {} pattern{s}", $source_name));
- diag.note(&format!("{these} pattern{s} will always match, so the {}", $note_sufix));
- diag.help(concat!("consider ", $help_sufix));
- diag.emit()
+ tcx.struct_span_lint_hir(
+ IRREFUTABLE_LET_PATTERNS,
+ id,
+ span,
+ format!("irrefutable {} pattern{s}", $source_name),
+ |lint| {
+ lint.note(&format!(
+ "{these} pattern{s} will always match, so the {}",
+ $note_sufix
+ ))
+ .help(concat!("consider ", $help_sufix))
+ },
+ )
}};
}
- let span = match source {
- LetSource::LetElse(span) => span,
- _ => span,
- };
- tcx.struct_span_lint_hir(IRREFUTABLE_LET_PATTERNS, id, span, |lint| match source {
+ match source {
LetSource::GenericLet => {
emit_diag!(lint, "`let`", "`let` is useless", "removing `let`");
}
@@ -677,7 +696,7 @@ fn irrefutable_let_patterns(
"instead using a `loop { ... }` with a `let` inside it"
);
}
- });
+ };
}
fn is_let_irrefutable<'p, 'tcx>(
@@ -985,8 +1004,8 @@ fn maybe_point_at_variant<'a, 'p: 'a, 'tcx: 'a>(
}
/// Check if a by-value binding is by-value. That is, check if the binding's type is not `Copy`.
-fn is_binding_by_move(cx: &MatchVisitor<'_, '_, '_>, hir_id: HirId, span: Span) -> bool {
- !cx.typeck_results.node_type(hir_id).is_copy_modulo_regions(cx.tcx.at(span), cx.param_env)
+fn is_binding_by_move(cx: &MatchVisitor<'_, '_, '_>, hir_id: HirId) -> bool {
+ !cx.typeck_results.node_type(hir_id).is_copy_modulo_regions(cx.tcx, cx.param_env)
}
/// Check that there are no borrow or move conflicts in `binding @ subpat` patterns.
@@ -1012,7 +1031,7 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pa
// Get the binding move, extract the mutability if by-ref.
let mut_outer = match typeck_results.extract_binding_mode(sess, pat.hir_id, pat.span) {
- Some(ty::BindByValue(_)) if is_binding_by_move(cx, pat.hir_id, pat.span) => {
+ Some(ty::BindByValue(_)) if is_binding_by_move(cx, pat.hir_id) => {
// We have `x @ pat` where `x` is by-move. Reject all borrows in `pat`.
let mut conflicts_ref = Vec::new();
sub.each_binding(|_, hir_id, span, _| {
@@ -1051,7 +1070,7 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pa
(Mutability::Mut, Mutability::Mut) => conflicts_mut_mut.push((span, name)), // 2x `ref mut`.
_ => conflicts_mut_ref.push((span, name)), // `ref` + `ref mut` in either direction.
},
- Some(ty::BindByValue(_)) if is_binding_by_move(cx, hir_id, span) => {
+ Some(ty::BindByValue(_)) if is_binding_by_move(cx, hir_id) => {
conflicts_move.push((span, name)) // `ref mut?` + by-move conflict.
}
Some(ty::BindByValue(_)) | None => {} // `ref mut?` + by-copy is fine.
@@ -1136,10 +1155,14 @@ fn let_source_parent(tcx: TyCtxt<'_>, parent: HirId, pat_id: Option<HirId>) -> L
let parent_parent = hir.get_parent_node(parent);
let parent_parent_node = hir.get(parent_parent);
- if let hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(_), span, .. }) =
- parent_parent_node
- {
- return LetSource::LetElse(*span);
+ match parent_parent_node {
+ hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(_), span, .. }) => {
+ return LetSource::LetElse(*span);
+ }
+ hir::Node::Arm(hir::Arm { guard: Some(hir::Guard::If(_)), .. }) => {
+ return LetSource::IfLetGuard;
+ }
+ _ => {}
}
let parent_parent_parent = hir.get_parent_node(parent_parent);
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 b58685e89..ad12e0116 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,3 +1,4 @@
+use rustc_errors::DelayDm;
use rustc_hir as hir;
use rustc_index::vec::Idx;
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
@@ -27,14 +28,13 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
span: Span,
mir_structural_match_violation: bool,
) -> Box<Pat<'tcx>> {
- self.tcx.infer_ctxt().enter(|infcx| {
- let mut convert = ConstToPat::new(self, id, span, infcx);
- convert.to_pat(cv, mir_structural_match_violation)
- })
+ let infcx = self.tcx.infer_ctxt().build();
+ let mut convert = ConstToPat::new(self, id, span, infcx);
+ convert.to_pat(cv, mir_structural_match_violation)
}
}
-struct ConstToPat<'a, 'tcx> {
+struct ConstToPat<'tcx> {
id: hir::HirId,
span: Span,
param_env: ty::ParamEnv<'tcx>,
@@ -54,7 +54,7 @@ struct ConstToPat<'a, 'tcx> {
behind_reference: Cell<bool>,
// inference context used for checking `T: Structural` bounds.
- infcx: InferCtxt<'a, 'tcx>,
+ infcx: InferCtxt<'tcx>,
include_lint_checks: bool,
@@ -70,21 +70,19 @@ mod fallback_to_const_ref {
/// hoops to get a reference to the value.
pub(super) struct FallbackToConstRef(());
- pub(super) fn fallback_to_const_ref<'a, 'tcx>(
- c2p: &super::ConstToPat<'a, 'tcx>,
- ) -> FallbackToConstRef {
+ pub(super) fn fallback_to_const_ref<'tcx>(c2p: &super::ConstToPat<'tcx>) -> FallbackToConstRef {
assert!(c2p.behind_reference.get());
FallbackToConstRef(())
}
}
use fallback_to_const_ref::{fallback_to_const_ref, FallbackToConstRef};
-impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
+impl<'tcx> ConstToPat<'tcx> {
fn new(
pat_ctxt: &PatCtxt<'_, 'tcx>,
id: hir::HirId,
span: Span,
- infcx: InferCtxt<'a, 'tcx>,
+ infcx: InferCtxt<'tcx>,
) -> Self {
trace!(?pat_ctxt.typeck_results.hir_owner);
ConstToPat {
@@ -205,9 +203,8 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
lint::builtin::INDIRECT_STRUCTURAL_MATCH,
self.id,
self.span,
- |lint| {
- lint.build(&msg).emit();
- },
+ msg,
+ |lint| lint,
);
} else {
debug!(
@@ -286,9 +283,8 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
id,
span,
- |lint| {
- lint.build("floating-point types cannot be used in patterns").emit();
- },
+ "floating-point types cannot be used in patterns",
+ |lint| lint,
);
}
PatKind::Constant { value: cv }
@@ -340,15 +336,15 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
lint::builtin::INDIRECT_STRUCTURAL_MATCH,
id,
span,
- |lint| {
- let msg = format!(
+ DelayDm(|| {
+ format!(
"to use a constant of type `{}` in a pattern, \
`{}` must be annotated with `#[derive(PartialEq, Eq)]`",
cv.ty(),
cv.ty(),
- );
- lint.build(&msg).emit();
- },
+ )
+ }),
+ |lint| lint,
);
}
// Since we are behind a reference, we can just bubble the error up so we get a
@@ -488,7 +484,8 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
lint::builtin::INDIRECT_STRUCTURAL_MATCH,
self.id,
self.span,
- |lint| {lint.build(&msg).emit();},
+ msg,
+ |lint| lint,
);
}
PatKind::Constant { value: cv }
@@ -509,7 +506,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
// convert the dereferenced constant to a pattern that is the sub-pattern of the
// deref pattern.
_ => {
- if !pointee_ty.is_sized(tcx.at(span), param_env) {
+ 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).
let msg = format!("cannot use unsized non-slice type `{}` in constant patterns", pointee_ty);
@@ -537,7 +534,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::FnDef(..) => {
PatKind::Constant { value: cv }
}
- ty::RawPtr(pointee) if pointee.ty.is_sized(tcx.at(span), param_env) => {
+ ty::RawPtr(pointee) if pointee.ty.is_sized(tcx, param_env) => {
PatKind::Constant { value: cv }
}
// FIXME: these can have very surprising behaviour where optimization levels or other
@@ -556,9 +553,8 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
lint::builtin::POINTER_STRUCTURAL_MATCH,
id,
span,
- |lint| {
- lint.build(msg).emit();
- },
+ msg,
+ |lint| lint,
);
}
PatKind::Constant { value: cv }
@@ -594,9 +590,8 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
lint::builtin::NONTRIVIAL_STRUCTURAL_MATCH,
id,
span,
- |lint| {
- lint.build(&msg).emit();
- },
+ msg,
+ |lint| lint,
);
}
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 5105f059f..595abc8f6 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
@@ -299,10 +299,10 @@ impl IntRange {
lint::builtin::OVERLAPPING_RANGE_ENDPOINTS,
hir_id,
pcx.span,
+ "multiple patterns overlap on their endpoints",
|lint| {
- let mut err = lint.build("multiple patterns overlap on their endpoints");
for (int_range, span) in overlaps {
- err.span_label(
+ lint.span_label(
span,
&format!(
"this range overlaps on `{}`...",
@@ -310,9 +310,9 @@ impl IntRange {
),
);
}
- err.span_label(pcx.span, "... with this range");
- err.note("you likely meant to write mutually exclusive ranges");
- err.emit();
+ lint.span_label(pcx.span, "... with this range");
+ lint.note("you likely meant to write mutually exclusive ranges");
+ lint
},
);
}
@@ -988,10 +988,12 @@ impl<'tcx> SplitWildcard<'tcx> {
.filter(|(_, v)| {
// If `exhaustive_patterns` is enabled, we exclude variants known to be
// uninhabited.
- let is_uninhabited = is_exhaustive_pat_feature
- && v.uninhabited_from(cx.tcx, substs, def.adt_kind(), cx.param_env)
- .contains(cx.tcx, cx.module);
- !is_uninhabited
+ !is_exhaustive_pat_feature
+ || v.inhabited_predicate(cx.tcx, *def).subst(cx.tcx, substs).apply(
+ cx.tcx,
+ cx.param_env,
+ cx.module,
+ )
})
.map(|(idx, _)| Variant(idx))
.collect();
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 0edf6a983..2526522a2 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -86,7 +86,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
// ```
//
// the type assigned to `Some(n)` in `unadjusted_pat` would be `Option<i32>` (this is
- // determined in rustc_typeck::check::match). The adjustments would be
+ // determined in rustc_hir_analysis::check::match). The adjustments would be
//
// `vec![&&Option<i32>, &Option<i32>]`.
//
@@ -200,6 +200,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
}
}
+ #[instrument(skip(self), level = "debug")]
fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tcx>> {
let mut ty = self.typeck_results.node_type(pat.hir_id);
let mut span = pat.span;
@@ -432,7 +433,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
| DefKind::AssocTy,
_,
)
- | Res::SelfTy { .. }
+ | Res::SelfTyParam { .. }
+ | Res::SelfTyAlias { .. }
| Res::SelfCtor(..) => PatKind::Leaf { subpatterns },
_ => {
let pattern_error = match res {
@@ -684,7 +686,7 @@ macro_rules! ClonePatternFoldableImpls {
}
ClonePatternFoldableImpls! { <'tcx>
- Span, Field, Mutability, Symbol, LocalVarId, usize, ty::Const<'tcx>,
+ Span, Field, Mutability, Symbol, LocalVarId, usize,
Region<'tcx>, Ty<'tcx>, BindingMode, AdtDef<'tcx>,
SubstsRef<'tcx>, &'tcx GenericArg<'tcx>, UserType<'tcx>,
UserTypeProjection, CanonicalUserTypeAnnotation<'tcx>
diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
index 115d34ff8..8dc9976ea 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
@@ -746,7 +746,7 @@ impl<'p, 'tcx> Witness<'p, 'tcx> {
/// Report that a match of a `non_exhaustive` enum marked with `non_exhaustive_omitted_patterns`
/// is not exhaustive enough.
///
-/// NB: The partner lint for structs lives in `compiler/rustc_typeck/src/check/pat.rs`.
+/// NB: The partner lint for structs lives in `compiler/rustc_hir_analysis/src/check/pat.rs`.
fn lint_non_exhaustive_omitted_patterns<'p, 'tcx>(
cx: &MatchCheckCtxt<'p, 'tcx>,
scrut_ty: Ty<'tcx>,
@@ -754,9 +754,8 @@ fn lint_non_exhaustive_omitted_patterns<'p, 'tcx>(
hir_id: HirId,
witnesses: Vec<DeconstructedPat<'p, 'tcx>>,
) {
- cx.tcx.struct_span_lint_hir(NON_EXHAUSTIVE_OMITTED_PATTERNS, hir_id, sp, |build| {
+ cx.tcx.struct_span_lint_hir(NON_EXHAUSTIVE_OMITTED_PATTERNS, hir_id, sp, "some variants are not matched explicitly", |lint| {
let joined_patterns = joined_uncovered_patterns(cx, &witnesses);
- let mut lint = build.build("some variants are not matched explicitly");
lint.span_label(sp, pattern_not_covered_label(&witnesses, &joined_patterns));
lint.help(
"ensure that all variants are matched explicitly by adding the suggested match arms",
@@ -765,7 +764,7 @@ fn lint_non_exhaustive_omitted_patterns<'p, 'tcx>(
"the matched value is of type `{}` and the `non_exhaustive_omitted_patterns` attribute was found",
scrut_ty,
));
- lint.emit();
+ lint
});
}
@@ -842,7 +841,15 @@ fn is_useful<'p, 'tcx>(
}
}
} else {
- let ty = v.head().ty();
+ let mut ty = v.head().ty();
+
+ // Opaque types can't get destructured/split, but the patterns can
+ // actually hint at hidden types, so we use the patterns' types instead.
+ if let ty::Opaque(..) = ty.kind() {
+ if let Some(row) = rows.first() {
+ ty = row.head().ty();
+ }
+ }
let is_non_exhaustive = cx.is_foreign_non_exhaustive_enum(ty);
debug!("v.head: {:?}, v.span: {:?}", v.head(), v.head().span());
let pcx = &PatCtxt { cx, ty, span: v.head().span(), is_top_level, is_non_exhaustive };
@@ -878,7 +885,7 @@ fn is_useful<'p, 'tcx>(
// that has the potential to trigger the `non_exhaustive_omitted_patterns` lint.
// To understand the workings checkout `Constructor::split` and `SplitWildcard::new/into_ctors`
if is_non_exhaustive_and_wild
- // We check that the match has a wildcard pattern and that that wildcard is useful,
+ // We check that the match has a wildcard pattern and that wildcard is useful,
// meaning there are variants that are covered by the wildcard. Without the check
// for `witness_preference` the lint would trigger on `if let NonExhaustiveEnum::A = foo {}`
&& usefulness.is_useful() && matches!(witness_preference, RealArm)