diff --git a/compiler/rustc_middle/src/middle/limits.rs b/compiler/rustc_middle/src/middle/limits.rs index 8a367a947d16..7dc1db5a22df 100644 --- a/compiler/rustc_middle/src/middle/limits.rs +++ b/compiler/rustc_middle/src/middle/limits.rs @@ -24,30 +24,36 @@ pub fn provide(providers: &mut Providers) { tcx.hir().krate_attrs(), tcx.sess, sym::move_size_limit, - tcx.sess.opts.unstable_opts.move_size_limit.unwrap_or(0), + Limit::new(tcx.sess.opts.unstable_opts.move_size_limit.unwrap_or(0)), ), type_length_limit: get_limit( tcx.hir().krate_attrs(), tcx.sess, sym::type_length_limit, - 2usize.pow(24), + Limit::new(2usize.pow(24)), + ), + pattern_complexity_limit: get_limit( + tcx.hir().krate_attrs(), + tcx.sess, + sym::pattern_complexity, + Limit::unlimited(), ), } } pub fn get_recursion_limit(krate_attrs: &[impl AttributeExt], sess: &Session) -> Limit { - get_limit(krate_attrs, sess, sym::recursion_limit, 128) + get_limit(krate_attrs, sess, sym::recursion_limit, Limit::new(128)) } fn get_limit( krate_attrs: &[impl AttributeExt], sess: &Session, name: Symbol, - default: usize, + default: Limit, ) -> Limit { match get_limit_size(krate_attrs, sess, name) { Some(size) => Limit::new(size), - None => Limit::new(default), + None => default, } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index cb8dc6921487..ea2b610a727b 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2168,6 +2168,10 @@ impl<'tcx> TyCtxt<'tcx> { self.limits(()).move_size_limit } + pub fn pattern_complexity_limit(self) -> Limit { + self.limits(()).pattern_complexity_limit + } + /// All traits in the crate graph, including those not visible to the user. pub fn all_traits(self) -> impl Iterator + 'tcx { iter::once(LOCAL_CRATE) 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 697cb7cf37a3..7dd2ed7bbdf6 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -10,7 +10,6 @@ use rustc_hir::{self as hir, BindingMode, ByRef, HirId}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::Level; use rustc_middle::bug; -use rustc_middle::middle::limits::get_limit_size; use rustc_middle::thir::visit::Visitor; use rustc_middle::thir::*; use rustc_middle::ty::print::with_no_trimmed_paths; @@ -25,7 +24,7 @@ use rustc_session::lint::builtin::{ }; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::hygiene::DesugaringKind; -use rustc_span::{Ident, Span, sym}; +use rustc_span::{Ident, Span}; use rustc_trait_selection::infer::InferCtxtExt; use tracing::instrument; @@ -404,18 +403,11 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { arms: &[MatchArm<'p, 'tcx>], scrut_ty: Ty<'tcx>, ) -> Result, ErrorGuaranteed> { - let pattern_complexity_limit = - get_limit_size(cx.tcx.hir().krate_attrs(), cx.tcx.sess, sym::pattern_complexity); - let report = rustc_pattern_analysis::rustc::analyze_match( - &cx, - &arms, - scrut_ty, - pattern_complexity_limit, - ) - .map_err(|err| { - self.error = Err(err); - err - })?; + let report = + rustc_pattern_analysis::rustc::analyze_match(&cx, &arms, scrut_ty).map_err(|err| { + self.error = Err(err); + err + })?; // Warn unreachable subpatterns. for (arm, is_useful) in report.arm_usefulness.iter() { diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 2694cf472f48..0b1e954d64d4 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -1084,12 +1084,16 @@ pub fn analyze_match<'p, 'tcx>( tycx: &RustcPatCtxt<'p, 'tcx>, arms: &[MatchArm<'p, 'tcx>], scrut_ty: Ty<'tcx>, - pattern_complexity_limit: Option, ) -> Result, ErrorGuaranteed> { let scrut_ty = tycx.reveal_opaque_ty(scrut_ty); let scrut_validity = PlaceValidity::from_bool(tycx.known_valid_scrutinee); - let report = - compute_match_usefulness(tycx, arms, scrut_ty, scrut_validity, pattern_complexity_limit)?; + let report = compute_match_usefulness( + tycx, + arms, + scrut_ty, + scrut_validity, + tycx.tcx.pattern_complexity_limit().0, + )?; // Run the non_exhaustive_omitted_patterns lint. Only run on refutable patterns to avoid hitting // `if let`s. Only run if the match is exhaustive otherwise the error is redundant. diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs index cc09cd491af1..1dff76141da5 100644 --- a/compiler/rustc_pattern_analysis/src/usefulness.rs +++ b/compiler/rustc_pattern_analysis/src/usefulness.rs @@ -795,20 +795,21 @@ struct UsefulnessCtxt<'a, 'p, Cx: PatCx> { /// Track information about the usefulness of branch patterns (see definition of "branch /// pattern" at [`BranchPatUsefulness`]). branch_usefulness: FxHashMap>, - complexity_limit: Option, + // Ideally this field would have type `Limit`, but this crate is used by + // rust-analyzer which cannot have a dependency on `Limit`, because `Limit` + // is from crate `rustc_session` which uses unstable Rust features. + complexity_limit: usize, complexity_level: usize, } impl<'a, 'p, Cx: PatCx> UsefulnessCtxt<'a, 'p, Cx> { fn increase_complexity_level(&mut self, complexity_add: usize) -> Result<(), Cx::Error> { self.complexity_level += complexity_add; - if self - .complexity_limit - .is_some_and(|complexity_limit| complexity_limit < self.complexity_level) - { - return self.tycx.complexity_exceeded(); + if self.complexity_level <= self.complexity_limit { + Ok(()) + } else { + self.tycx.complexity_exceeded() } - Ok(()) } } @@ -1834,7 +1835,7 @@ pub fn compute_match_usefulness<'p, Cx: PatCx>( arms: &[MatchArm<'p, Cx>], scrut_ty: Cx::Ty, scrut_validity: PlaceValidity, - complexity_limit: Option, + complexity_limit: usize, ) -> Result, Cx::Error> { let mut cx = UsefulnessCtxt { tycx, diff --git a/compiler/rustc_pattern_analysis/tests/common/mod.rs b/compiler/rustc_pattern_analysis/tests/common/mod.rs index cd697632d1b1..23560ad64190 100644 --- a/compiler/rustc_pattern_analysis/tests/common/mod.rs +++ b/compiler/rustc_pattern_analysis/tests/common/mod.rs @@ -124,7 +124,7 @@ pub fn compute_match_usefulness<'p>( arms: &[MatchArm<'p, Cx>], ty: Ty, scrut_validity: PlaceValidity, - complexity_limit: Option, + complexity_limit: usize, ) -> Result, ()> { init_tracing(); rustc_pattern_analysis::usefulness::compute_match_usefulness( diff --git a/compiler/rustc_pattern_analysis/tests/complexity.rs b/compiler/rustc_pattern_analysis/tests/complexity.rs index 43b585bc533a..abd1ec24d938 100644 --- a/compiler/rustc_pattern_analysis/tests/complexity.rs +++ b/compiler/rustc_pattern_analysis/tests/complexity.rs @@ -14,7 +14,7 @@ fn check(patterns: &[DeconstructedPat], complexity_limit: usize) -> Result<( let ty = *patterns[0].ty(); let arms: Vec<_> = patterns.iter().map(|pat| MatchArm { pat, has_guard: false, arm_data: () }).collect(); - compute_match_usefulness(arms.as_slice(), ty, PlaceValidity::ValidOnly, Some(complexity_limit)) + compute_match_usefulness(arms.as_slice(), ty, PlaceValidity::ValidOnly, complexity_limit) .map(|_report| ()) } diff --git a/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs b/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs index 0d80042a850f..61ce0fd11e77 100644 --- a/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs +++ b/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs @@ -14,7 +14,8 @@ fn check(patterns: Vec>) -> Vec> { let arms: Vec<_> = patterns.iter().map(|pat| MatchArm { pat, has_guard: false, arm_data: () }).collect(); let report = - compute_match_usefulness(arms.as_slice(), ty, PlaceValidity::ValidOnly, None).unwrap(); + compute_match_usefulness(arms.as_slice(), ty, PlaceValidity::ValidOnly, usize::MAX) + .unwrap(); report.non_exhaustiveness_witnesses } diff --git a/compiler/rustc_pattern_analysis/tests/intersection.rs b/compiler/rustc_pattern_analysis/tests/intersection.rs index a852056b6a6c..45674338efd4 100644 --- a/compiler/rustc_pattern_analysis/tests/intersection.rs +++ b/compiler/rustc_pattern_analysis/tests/intersection.rs @@ -14,7 +14,8 @@ fn check(patterns: Vec>) -> Vec> { let arms: Vec<_> = patterns.iter().map(|pat| MatchArm { pat, has_guard: false, arm_data: () }).collect(); let report = - compute_match_usefulness(arms.as_slice(), ty, PlaceValidity::ValidOnly, None).unwrap(); + compute_match_usefulness(arms.as_slice(), ty, PlaceValidity::ValidOnly, usize::MAX) + .unwrap(); report.arm_intersections.into_iter().map(|bitset| bitset.iter().collect()).collect() } diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index f795ad1ee17d..c4d45ee02eea 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -67,6 +67,11 @@ impl Limit { Limit(value) } + /// Create a new unlimited limit. + pub fn unlimited() -> Self { + Limit(usize::MAX) + } + /// Check that `value` is within the limit. Ensures that the same comparisons are used /// throughout the compiler, as mismatches can cause ICEs, see #72540. #[inline] @@ -119,6 +124,8 @@ pub struct Limits { pub move_size_limit: Limit, /// The maximum length of types during monomorphization. pub type_length_limit: Limit, + /// The maximum pattern complexity allowed (internal only). + pub pattern_complexity_limit: Limit, } pub struct CompilerIO { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs index 2b854310a15e..3312da470c03 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs @@ -95,7 +95,7 @@ impl<'db> MatchCheckCtx<'db> { let place_validity = PlaceValidity::from_bool(known_valid_scrutinee.unwrap_or(true)); // Measured to take ~100ms on modern hardware. - let complexity_limit = Some(500000); + let complexity_limit = 500000; compute_match_usefulness(self, arms, scrut_ty, place_validity, complexity_limit) }