Skip to content

Commit 2fa8d0b

Browse files
committed
Add pattern_complexity_limit to Limits.
It's similar to the other limits, e.g. obtained via `get_limit`. So it makes sense to handle it consistently with the other limits. We now use `Limit` in most places instead of `Option<usize>`, so we use `Limit::new(usize::MAX)` to emulate how `None` used to work. The commit also adds `Limit::unlimited`.
1 parent 3f33b30 commit 2fa8d0b

File tree

12 files changed

+63
-36
lines changed

12 files changed

+63
-36
lines changed

compiler/rustc_middle/src/middle/limits.rs

+11-5
Original file line numberDiff line numberDiff line change
@@ -24,30 +24,36 @@ pub fn provide(providers: &mut Providers) {
2424
tcx.hir().krate_attrs(),
2525
tcx.sess,
2626
sym::move_size_limit,
27-
tcx.sess.opts.unstable_opts.move_size_limit.unwrap_or(0),
27+
Limit::new(tcx.sess.opts.unstable_opts.move_size_limit.unwrap_or(0)),
2828
),
2929
type_length_limit: get_limit(
3030
tcx.hir().krate_attrs(),
3131
tcx.sess,
3232
sym::type_length_limit,
33-
2usize.pow(24),
33+
Limit::new(2usize.pow(24)),
34+
),
35+
pattern_complexity_limit: get_limit(
36+
tcx.hir().krate_attrs(),
37+
tcx.sess,
38+
sym::pattern_complexity,
39+
Limit::unlimited(),
3440
),
3541
}
3642
}
3743

3844
pub fn get_recursion_limit(krate_attrs: &[impl AttributeExt], sess: &Session) -> Limit {
39-
get_limit(krate_attrs, sess, sym::recursion_limit, 128)
45+
get_limit(krate_attrs, sess, sym::recursion_limit, Limit::new(128))
4046
}
4147

4248
fn get_limit(
4349
krate_attrs: &[impl AttributeExt],
4450
sess: &Session,
4551
name: Symbol,
46-
default: usize,
52+
default: Limit,
4753
) -> Limit {
4854
match get_limit_size(krate_attrs, sess, name) {
4955
Some(size) => Limit::new(size),
50-
None => Limit::new(default),
56+
None => default,
5157
}
5258
}
5359

compiler/rustc_middle/src/ty/context.rs

+4
Original file line numberDiff line numberDiff line change
@@ -2144,6 +2144,10 @@ impl<'tcx> TyCtxt<'tcx> {
21442144
self.limits(()).move_size_limit
21452145
}
21462146

2147+
pub fn pattern_complexity_limit(self) -> Limit {
2148+
self.limits(()).pattern_complexity_limit
2149+
}
2150+
21472151
/// All traits in the crate graph, including those not visible to the user.
21482152
pub fn all_traits(self) -> impl Iterator<Item = DefId> + 'tcx {
21492153
iter::once(LOCAL_CRATE)

compiler/rustc_mir_build/src/thir/pattern/check_match.rs

+6-14
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ use rustc_hir::{self as hir, BindingMode, ByRef, HirId};
1010
use rustc_infer::infer::TyCtxtInferExt;
1111
use rustc_lint::Level;
1212
use rustc_middle::bug;
13-
use rustc_middle::middle::limits::get_limit_size;
1413
use rustc_middle::thir::visit::Visitor;
1514
use rustc_middle::thir::*;
1615
use rustc_middle::ty::print::with_no_trimmed_paths;
@@ -25,7 +24,7 @@ use rustc_session::lint::builtin::{
2524
};
2625
use rustc_span::edit_distance::find_best_match_for_name;
2726
use rustc_span::hygiene::DesugaringKind;
28-
use rustc_span::{Ident, Span, sym};
27+
use rustc_span::{Ident, Span};
2928
use rustc_trait_selection::infer::InferCtxtExt;
3029
use tracing::instrument;
3130

@@ -404,18 +403,11 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
404403
arms: &[MatchArm<'p, 'tcx>],
405404
scrut_ty: Ty<'tcx>,
406405
) -> Result<UsefulnessReport<'p, 'tcx>, ErrorGuaranteed> {
407-
let pattern_complexity_limit =
408-
get_limit_size(cx.tcx.hir().krate_attrs(), cx.tcx.sess, sym::pattern_complexity);
409-
let report = rustc_pattern_analysis::rustc::analyze_match(
410-
&cx,
411-
&arms,
412-
scrut_ty,
413-
pattern_complexity_limit,
414-
)
415-
.map_err(|err| {
416-
self.error = Err(err);
417-
err
418-
})?;
406+
let report =
407+
rustc_pattern_analysis::rustc::analyze_match(&cx, &arms, scrut_ty).map_err(|err| {
408+
self.error = Err(err);
409+
err
410+
})?;
419411

420412
// Warn unreachable subpatterns.
421413
for (arm, is_useful) in report.arm_usefulness.iter() {

compiler/rustc_pattern_analysis/src/rustc.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -1084,12 +1084,16 @@ pub fn analyze_match<'p, 'tcx>(
10841084
tycx: &RustcPatCtxt<'p, 'tcx>,
10851085
arms: &[MatchArm<'p, 'tcx>],
10861086
scrut_ty: Ty<'tcx>,
1087-
pattern_complexity_limit: Option<usize>,
10881087
) -> Result<UsefulnessReport<'p, 'tcx>, ErrorGuaranteed> {
10891088
let scrut_ty = tycx.reveal_opaque_ty(scrut_ty);
10901089
let scrut_validity = PlaceValidity::from_bool(tycx.known_valid_scrutinee);
1091-
let report =
1092-
compute_match_usefulness(tycx, arms, scrut_ty, scrut_validity, pattern_complexity_limit)?;
1090+
let report = compute_match_usefulness(
1091+
tycx,
1092+
arms,
1093+
scrut_ty,
1094+
scrut_validity,
1095+
tycx.tcx.pattern_complexity_limit(),
1096+
)?;
10931097

10941098
// Run the non_exhaustive_omitted_patterns lint. Only run on refutable patterns to avoid hitting
10951099
// `if let`s. Only run if the match is exhaustive otherwise the error is redundant.

compiler/rustc_pattern_analysis/src/usefulness.rs

+7-8
Original file line numberDiff line numberDiff line change
@@ -713,6 +713,7 @@ use std::fmt;
713713
use rustc_data_structures::stack::ensure_sufficient_stack;
714714
use rustc_hash::{FxHashMap, FxHashSet};
715715
use rustc_index::bit_set::DenseBitSet;
716+
use rustc_session::Limit;
716717
use smallvec::{SmallVec, smallvec};
717718
use tracing::{debug, instrument};
718719

@@ -795,20 +796,18 @@ struct UsefulnessCtxt<'a, 'p, Cx: PatCx> {
795796
/// Track information about the usefulness of branch patterns (see definition of "branch
796797
/// pattern" at [`BranchPatUsefulness`]).
797798
branch_usefulness: FxHashMap<PatId, BranchPatUsefulness<'p, Cx>>,
798-
complexity_limit: Option<usize>,
799+
complexity_limit: Limit,
799800
complexity_level: usize,
800801
}
801802

802803
impl<'a, 'p, Cx: PatCx> UsefulnessCtxt<'a, 'p, Cx> {
803804
fn increase_complexity_level(&mut self, complexity_add: usize) -> Result<(), Cx::Error> {
804805
self.complexity_level += complexity_add;
805-
if self
806-
.complexity_limit
807-
.is_some_and(|complexity_limit| complexity_limit < self.complexity_level)
808-
{
809-
return self.tycx.complexity_exceeded();
806+
if self.complexity_limit.value_within_limit(self.complexity_level) {
807+
Ok(())
808+
} else {
809+
self.tycx.complexity_exceeded()
810810
}
811-
Ok(())
812811
}
813812
}
814813

@@ -1834,7 +1833,7 @@ pub fn compute_match_usefulness<'p, Cx: PatCx>(
18341833
arms: &[MatchArm<'p, Cx>],
18351834
scrut_ty: Cx::Ty,
18361835
scrut_validity: PlaceValidity,
1837-
complexity_limit: Option<usize>,
1836+
complexity_limit: Limit,
18381837
) -> Result<UsefulnessReport<'p, Cx>, Cx::Error> {
18391838
let mut cx = UsefulnessCtxt {
18401839
tycx,

compiler/rustc_pattern_analysis/tests/common/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use rustc_pattern_analysis::constructor::{
33
};
44
use rustc_pattern_analysis::usefulness::{PlaceValidity, UsefulnessReport};
55
use rustc_pattern_analysis::{Captures, MatchArm, PatCx, PrivateUninhabitedField};
6+
use rustc_session::Limit;
67

78
/// Sets up `tracing` for easier debugging. Tries to look like the `rustc` setup.
89
pub fn init_tracing() {
@@ -124,7 +125,7 @@ pub fn compute_match_usefulness<'p>(
124125
arms: &[MatchArm<'p, Cx>],
125126
ty: Ty,
126127
scrut_validity: PlaceValidity,
127-
complexity_limit: Option<usize>,
128+
complexity_limit: Limit,
128129
) -> Result<UsefulnessReport<'p, Cx>, ()> {
129130
init_tracing();
130131
rustc_pattern_analysis::usefulness::compute_match_usefulness(

compiler/rustc_pattern_analysis/tests/complexity.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use common::*;
44
use rustc_pattern_analysis::MatchArm;
55
use rustc_pattern_analysis::pat::DeconstructedPat;
66
use rustc_pattern_analysis::usefulness::PlaceValidity;
7+
use rustc_session::Limit;
78

89
#[macro_use]
910
mod common;
@@ -14,8 +15,13 @@ fn check(patterns: &[DeconstructedPat<Cx>], complexity_limit: usize) -> Result<(
1415
let ty = *patterns[0].ty();
1516
let arms: Vec<_> =
1617
patterns.iter().map(|pat| MatchArm { pat, has_guard: false, arm_data: () }).collect();
17-
compute_match_usefulness(arms.as_slice(), ty, PlaceValidity::ValidOnly, Some(complexity_limit))
18-
.map(|_report| ())
18+
compute_match_usefulness(
19+
arms.as_slice(),
20+
ty,
21+
PlaceValidity::ValidOnly,
22+
Limit::new(complexity_limit),
23+
)
24+
.map(|_report| ())
1925
}
2026

2127
/// Asserts that analyzing this match takes exactly `complexity` steps.

compiler/rustc_pattern_analysis/tests/exhaustiveness.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use common::*;
44
use rustc_pattern_analysis::MatchArm;
55
use rustc_pattern_analysis::pat::{DeconstructedPat, WitnessPat};
66
use rustc_pattern_analysis::usefulness::PlaceValidity;
7+
use rustc_session::Limit;
78

89
#[macro_use]
910
mod common;
@@ -14,7 +15,8 @@ fn check(patterns: Vec<DeconstructedPat<Cx>>) -> Vec<WitnessPat<Cx>> {
1415
let arms: Vec<_> =
1516
patterns.iter().map(|pat| MatchArm { pat, has_guard: false, arm_data: () }).collect();
1617
let report =
17-
compute_match_usefulness(arms.as_slice(), ty, PlaceValidity::ValidOnly, None).unwrap();
18+
compute_match_usefulness(arms.as_slice(), ty, PlaceValidity::ValidOnly, Limit::unlimited())
19+
.unwrap();
1820
report.non_exhaustiveness_witnesses
1921
}
2022

compiler/rustc_pattern_analysis/tests/intersection.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use common::*;
44
use rustc_pattern_analysis::MatchArm;
55
use rustc_pattern_analysis::pat::DeconstructedPat;
66
use rustc_pattern_analysis::usefulness::PlaceValidity;
7+
use rustc_session::Limit;
78

89
#[macro_use]
910
mod common;
@@ -14,7 +15,8 @@ fn check(patterns: Vec<DeconstructedPat<Cx>>) -> Vec<Vec<usize>> {
1415
let arms: Vec<_> =
1516
patterns.iter().map(|pat| MatchArm { pat, has_guard: false, arm_data: () }).collect();
1617
let report =
17-
compute_match_usefulness(arms.as_slice(), ty, PlaceValidity::ValidOnly, None).unwrap();
18+
compute_match_usefulness(arms.as_slice(), ty, PlaceValidity::ValidOnly, Limit::unlimited())
19+
.unwrap();
1820
report.arm_intersections.into_iter().map(|bitset| bitset.iter().collect()).collect()
1921
}
2022

compiler/rustc_session/src/session.rs

+7
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,11 @@ impl Limit {
6969
Limit(value)
7070
}
7171

72+
/// Create a new unlimited limit.
73+
pub fn unlimited() -> Self {
74+
Limit(usize::MAX)
75+
}
76+
7277
/// Check that `value` is within the limit. Ensures that the same comparisons are used
7378
/// throughout the compiler, as mismatches can cause ICEs, see #72540.
7479
#[inline]
@@ -121,6 +126,8 @@ pub struct Limits {
121126
pub move_size_limit: Limit,
122127
/// The maximum length of types during monomorphization.
123128
pub type_length_limit: Limit,
129+
/// The maximum pattern complexity allowed (internal only).
130+
pub pattern_complexity_limit: Limit,
124131
}
125132

126133
pub struct CompilerIO {

src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use rustc_pattern_analysis::{
1010
usefulness::{compute_match_usefulness, PlaceValidity, UsefulnessReport},
1111
Captures, IndexVec, PatCx, PrivateUninhabitedField,
1212
};
13+
use rustc_session::Limit;
1314
use smallvec::{smallvec, SmallVec};
1415
use stdx::never;
1516

@@ -95,7 +96,7 @@ impl<'db> MatchCheckCtx<'db> {
9596

9697
let place_validity = PlaceValidity::from_bool(known_valid_scrutinee.unwrap_or(true));
9798
// Measured to take ~100ms on modern hardware.
98-
let complexity_limit = Some(500000);
99+
let complexity_limit = Limit::new(500000);
99100
compute_match_usefulness(self, arms, scrut_ty, place_validity, complexity_limit)
100101
}
101102

src/tools/rust-analyzer/crates/hir-ty/src/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
44
#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
55

6+
#[cfg(feature = "in-rust-tree")]
7+
extern crate rustc_session;
8+
69
#[cfg(feature = "in-rust-tree")]
710
extern crate rustc_index;
811

0 commit comments

Comments
 (0)