summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_mir_build/src/build/matches
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_mir_build/src/build/matches')
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs114
-rw-r--r--compiler/rustc_mir_build/src/build/matches/simplify.rs8
-rw-r--r--compiler/rustc_mir_build/src/build/matches/test.rs53
3 files changed, 94 insertions, 81 deletions
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index 304870274..487b1f44b 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -90,6 +90,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let local_scope = this.local_scope();
let (success_block, failure_block) =
this.in_if_then_scope(local_scope, expr_span, |this| {
+ // Help out coverage instrumentation by injecting a dummy statement with
+ // the original condition's span (including `!`). This fixes #115468.
+ if this.tcx.sess.instrument_coverage() {
+ this.cfg.push_coverage_span_marker(block, this.source_info(expr_span));
+ }
this.then_else_break(
block,
&this.thir[arg],
@@ -212,7 +217,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let scrutinee_place =
unpack!(block = self.lower_scrutinee(block, scrutinee, scrutinee_span,));
- let mut arm_candidates = self.create_match_candidates(&scrutinee_place, &arms);
+ let mut arm_candidates = self.create_match_candidates(&scrutinee_place, arms);
let match_has_guard = arm_candidates.iter().any(|(_, candidate)| candidate.has_guard);
let mut candidates =
@@ -424,7 +429,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
this.source_scope = source_scope;
}
- this.expr_into_dest(destination, arm_block, &&this.thir[arm.body])
+ this.expr_into_dest(destination, arm_block, &this.thir[arm.body])
})
})
.collect();
@@ -505,7 +510,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let binding_end = self.bind_and_guard_matched_candidate(
leaf_candidate,
parent_bindings,
- &fake_borrow_temps,
+ fake_borrow_temps,
scrutinee_span,
arm_match_scope,
schedule_drops,
@@ -613,7 +618,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
_ => {
let place_builder =
unpack!(block = self.lower_scrutinee(block, initializer, initializer.span));
- self.place_into_pattern(block, &irrefutable_pat, place_builder, true)
+ self.place_into_pattern(block, irrefutable_pat, place_builder, true)
}
}
}
@@ -625,7 +630,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, self);
+ let mut candidate = Candidate::new(initializer.clone(), irrefutable_pat, false, self);
let fake_borrow_temps = self.lower_match_tree(
block,
irrefutable_pat.span,
@@ -700,7 +705,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
opt_match_place: Option<(Option<&Place<'tcx>>, Span)>,
) -> Option<SourceScope> {
self.visit_primary_bindings(
- &pattern,
+ pattern,
UserTypeProjections::none(),
&mut |this, mutability, name, mode, var, span, ty, user_ty| {
if visibility_scope.is_none() {
@@ -827,6 +832,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
PatKind::Constant { .. }
| PatKind::Range { .. }
| PatKind::Wild
+ | PatKind::Never
| PatKind::Error(_) => {}
PatKind::Deref { ref subpattern } => {
@@ -1693,59 +1699,51 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
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
- // improves the speed of llvm when optimizing long string literal
- // matches
- let make_target_blocks = move |this: &mut Self| -> Vec<BasicBlock> {
- // The block that we should branch to if none of the
- // `target_candidates` match. This is either the block where we
- // start matching the untested candidates if there are any,
- // otherwise it's the `otherwise_block`.
- let remainder_start = &mut None;
- let remainder_start =
- if candidates.is_empty() { &mut *otherwise_block } else { remainder_start };
-
- // For each outcome of test, process the candidates that still
- // apply. Collect a list of blocks where control flow will
- // branch if one of the `target_candidate` sets is not
- // exhaustive.
- let target_blocks: Vec<_> = target_candidates
- .into_iter()
- .map(|mut candidates| {
- if !candidates.is_empty() {
- let candidate_start = this.cfg.start_new_block();
- this.match_candidates(
- span,
- scrutinee_span,
- candidate_start,
- remainder_start,
- &mut *candidates,
- fake_borrows,
- );
- candidate_start
- } else {
- *remainder_start.get_or_insert_with(|| this.cfg.start_new_block())
- }
- })
- .collect();
-
- if !candidates.is_empty() {
- let remainder_start = remainder_start.unwrap_or_else(|| this.cfg.start_new_block());
- this.match_candidates(
- span,
- scrutinee_span,
- remainder_start,
- otherwise_block,
- candidates,
- fake_borrows,
- );
- };
+ // The block that we should branch to if none of the
+ // `target_candidates` match. This is either the block where we
+ // start matching the untested candidates if there are any,
+ // otherwise it's the `otherwise_block`.
+ let remainder_start = &mut None;
+ let remainder_start =
+ if candidates.is_empty() { &mut *otherwise_block } else { remainder_start };
+
+ // For each outcome of test, process the candidates that still
+ // apply. Collect a list of blocks where control flow will
+ // branch if one of the `target_candidate` sets is not
+ // exhaustive.
+ let target_blocks: Vec<_> = target_candidates
+ .into_iter()
+ .map(|mut candidates| {
+ if !candidates.is_empty() {
+ let candidate_start = self.cfg.start_new_block();
+ self.match_candidates(
+ span,
+ scrutinee_span,
+ candidate_start,
+ remainder_start,
+ &mut *candidates,
+ fake_borrows,
+ );
+ candidate_start
+ } else {
+ *remainder_start.get_or_insert_with(|| self.cfg.start_new_block())
+ }
+ })
+ .collect();
- target_blocks
- };
+ if !candidates.is_empty() {
+ let remainder_start = remainder_start.unwrap_or_else(|| self.cfg.start_new_block());
+ self.match_candidates(
+ span,
+ scrutinee_span,
+ remainder_start,
+ otherwise_block,
+ candidates,
+ fake_borrows,
+ );
+ }
- self.perform_test(span, scrutinee_span, block, &match_place, &test, make_target_blocks);
+ self.perform_test(span, scrutinee_span, block, &match_place, &test, target_blocks);
}
/// Determine the fake borrows that are needed from a set of places that
@@ -1843,7 +1841,7 @@ 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, self);
+ 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(
diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs
index 6a40c8d84..a7f6f4873 100644
--- a/compiler/rustc_mir_build/src/build/matches/simplify.rs
+++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs
@@ -69,7 +69,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
{
existing_bindings.extend_from_slice(&new_bindings);
mem::swap(&mut candidate.bindings, &mut existing_bindings);
- candidate.subcandidates = self.create_or_subcandidates(candidate, &place, pats);
+ candidate.subcandidates = self.create_or_subcandidates(candidate, place, pats);
return true;
}
@@ -194,6 +194,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
Ok(())
}
+ PatKind::Never => {
+ // A never pattern acts like a load from the place.
+ // FIXME(never_patterns): load from the place
+ Ok(())
+ }
+
PatKind::Constant { .. } => {
// FIXME normalize patterns when possible
Err(match_pair)
diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs
index bdd4f2011..53e5d70f9 100644
--- a/compiler/rustc_mir_build/src/build/matches/test.rs
+++ b/compiler/rustc_mir_build/src/build/matches/test.rs
@@ -75,6 +75,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
| PatKind::Array { .. }
| PatKind::Wild
| PatKind::Binding { .. }
+ | PatKind::Never
| PatKind::Leaf { .. }
| PatKind::Deref { .. }
| PatKind::Error(_) => self.error_simplifiable(match_pair),
@@ -107,6 +108,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
PatKind::Slice { .. }
| PatKind::Array { .. }
| PatKind::Wild
+ | PatKind::Never
| PatKind::Or { .. }
| PatKind::Binding { .. }
| PatKind::AscribeUserType { .. }
@@ -145,7 +147,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
}
- #[instrument(skip(self, make_target_blocks, place_builder), level = "debug")]
+ #[instrument(skip(self, target_blocks, place_builder), level = "debug")]
pub(super) fn perform_test(
&mut self,
match_start_span: Span,
@@ -153,7 +155,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
block: BasicBlock,
place_builder: &PlaceBuilder<'tcx>,
test: &Test<'tcx>,
- make_target_blocks: impl FnOnce(&mut Self) -> Vec<BasicBlock>,
+ target_blocks: Vec<BasicBlock>,
) {
let place = place_builder.to_place(self);
let place_ty = place.ty(&self.local_decls, self.tcx);
@@ -162,7 +164,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let source_info = self.source_info(test.span);
match test.kind {
TestKind::Switch { adt_def, ref variants } => {
- let target_blocks = make_target_blocks(self);
// Variants is a BitVec of indexes into adt_def.variants.
let num_enum_variants = adt_def.variants().len();
debug_assert_eq!(target_blocks.len(), num_enum_variants + 1);
@@ -208,7 +209,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
TestKind::SwitchInt { switch_ty, ref options } => {
- let target_blocks = make_target_blocks(self);
let terminator = if *switch_ty.kind() == ty::Bool {
assert!(!options.is_empty() && options.len() <= 2);
let [first_bb, second_bb] = *target_blocks else {
@@ -238,6 +238,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
TestKind::Eq { value, ty } => {
let tcx = self.tcx;
+ let [success_block, fail_block] = *target_blocks else {
+ bug!("`TestKind::Eq` should have two target blocks")
+ };
if let ty::Adt(def, _) = ty.kind()
&& Some(def.did()) == tcx.lang_items().string()
{
@@ -278,38 +281,43 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
);
self.non_scalar_compare(
eq_block,
- make_target_blocks,
+ success_block,
+ fail_block,
source_info,
value,
ref_str,
ref_str_ty,
);
- return;
- }
- if !ty.is_scalar() {
+ } else if !ty.is_scalar() {
// Use `PartialEq::eq` instead of `BinOp::Eq`
// (the binop can only handle primitives)
self.non_scalar_compare(
block,
- make_target_blocks,
+ success_block,
+ fail_block,
source_info,
value,
place,
ty,
);
- } else if let [success, fail] = *make_target_blocks(self) {
+ } else {
assert_eq!(value.ty(), ty);
let expect = self.literal_operand(test.span, value);
let val = Operand::Copy(place);
- self.compare(block, success, fail, source_info, BinOp::Eq, expect, val);
- } else {
- bug!("`TestKind::Eq` should have two target blocks");
+ self.compare(
+ block,
+ success_block,
+ fail_block,
+ source_info,
+ BinOp::Eq,
+ expect,
+ val,
+ );
}
}
TestKind::Range(ref range) => {
let lower_bound_success = self.cfg.start_new_block();
- let target_blocks = make_target_blocks(self);
// Test `val` by computing `lo <= val && val <= hi`, using primitive comparisons.
// FIXME: skip useless comparison when the range is half-open.
@@ -339,8 +347,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
TestKind::Len { len, op } => {
- let target_blocks = make_target_blocks(self);
-
let usize_ty = self.tcx.types.usize;
let actual = self.temp(usize_ty, test.span);
@@ -404,7 +410,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
fn non_scalar_compare(
&mut self,
block: BasicBlock,
- make_target_blocks: impl FnOnce(&mut Self) -> Vec<BasicBlock>,
+ success_block: BasicBlock,
+ fail_block: BasicBlock,
source_info: SourceInfo,
value: Const<'tcx>,
mut val: Place<'tcx>,
@@ -494,7 +501,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
let eq_def_id = self.tcx.require_lang_item(LangItem::PartialEq, Some(source_info.span));
- let method = trait_method(self.tcx, eq_def_id, sym::eq, [ty, ty]);
+ let method = trait_method(
+ self.tcx,
+ eq_def_id,
+ sym::eq,
+ self.tcx.with_opt_host_effect_param(self.def_id, eq_def_id, [ty, ty]),
+ );
let bool_ty = self.tcx.types.bool;
let eq_result = self.temp(bool_ty, source_info.span);
@@ -524,9 +536,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
);
self.diverge_from(block);
- let [success_block, fail_block] = *make_target_blocks(self) else {
- bug!("`TestKind::Eq` should have two target blocks")
- };
// check the result
self.cfg.terminate(
eq_block,
@@ -736,7 +745,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// These are all binary tests.
//
// FIXME(#29623) we can be more clever here
- let pattern_test = self.test(&match_pair);
+ let pattern_test = self.test(match_pair);
if pattern_test.kind == test.kind {
self.candidate_without_match_pair(match_pair_index, candidate);
Some(0)