diff options
| author | bors <bors@rust-lang.org> | 2024-03-06 18:51:11 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2024-03-06 18:51:11 +0000 |
| commit | 305d2b0f5c7e8081ab21f78e2d53ed8f84aebecd (patch) | |
| tree | e8c9415143a6307f929727db3da941edda124d78 /compiler/rustc_pattern_analysis/src | |
| parent | 033c1e00b0fda6616c1442ecf40bb79da8c5db20 (diff) | |
| parent | 3c2318c0b21e2f4473c2465a4d9481ccd21906dd (diff) | |
| download | rust-305d2b0f5c7e8081ab21f78e2d53ed8f84aebecd.tar.gz rust-305d2b0f5c7e8081ab21f78e2d53ed8f84aebecd.zip | |
Auto merge of #3363 - RalfJung:rustup, r=RalfJung
Rustup This should finally work again :)
Diffstat (limited to 'compiler/rustc_pattern_analysis/src')
| -rw-r--r-- | compiler/rustc_pattern_analysis/src/errors.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_pattern_analysis/src/lib.rs | 7 | ||||
| -rw-r--r-- | compiler/rustc_pattern_analysis/src/rustc.rs | 7 | ||||
| -rw-r--r-- | compiler/rustc_pattern_analysis/src/usefulness.rs | 46 |
4 files changed, 53 insertions, 11 deletions
diff --git a/compiler/rustc_pattern_analysis/src/errors.rs b/compiler/rustc_pattern_analysis/src/errors.rs index 2d592b35159..d0f56f0268d 100644 --- a/compiler/rustc_pattern_analysis/src/errors.rs +++ b/compiler/rustc_pattern_analysis/src/errors.rs @@ -1,4 +1,4 @@ -use rustc_errors::{AddToDiagnostic, Diag, EmissionGuarantee, SubdiagnosticMessageOp}; +use rustc_errors::{AddToDiagnostic, Diag, EmissionGuarantee, SubdiagMessageOp}; use rustc_macros::{LintDiagnostic, Subdiagnostic}; use rustc_middle::thir::Pat; use rustc_middle::ty::Ty; @@ -62,7 +62,7 @@ pub struct Overlap<'tcx> { } impl<'tcx> AddToDiagnostic for Overlap<'tcx> { - fn add_to_diagnostic_with<G: EmissionGuarantee, F: SubdiagnosticMessageOp<G>>( + fn add_to_diagnostic_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>( self, diag: &mut Diag<'_, G>, _: F, diff --git a/compiler/rustc_pattern_analysis/src/lib.rs b/compiler/rustc_pattern_analysis/src/lib.rs index d4b38d260e7..4b0955699fc 100644 --- a/compiler/rustc_pattern_analysis/src/lib.rs +++ b/compiler/rustc_pattern_analysis/src/lib.rs @@ -142,6 +142,9 @@ pub trait TypeCx: Sized + fmt::Debug { _overlaps_with: &[&DeconstructedPat<Self>], ) { } + + /// The maximum pattern complexity limit was reached. + fn complexity_exceeded(&self) -> Result<(), Self::Error>; } /// The arm of a match expression. @@ -167,10 +170,12 @@ pub fn analyze_match<'p, 'tcx>( tycx: &RustcMatchCheckCtxt<'p, 'tcx>, arms: &[rustc::MatchArm<'p, 'tcx>], scrut_ty: Ty<'tcx>, + pattern_complexity_limit: Option<usize>, ) -> Result<rustc::UsefulnessReport<'p, 'tcx>, ErrorGuaranteed> { let scrut_ty = tycx.reveal_opaque_ty(scrut_ty); let scrut_validity = ValidityConstraint::from_bool(tycx.known_valid_scrutinee); - let report = compute_match_usefulness(tycx, arms, scrut_ty, scrut_validity)?; + let report = + compute_match_usefulness(tycx, arms, scrut_ty, scrut_validity, pattern_complexity_limit)?; // 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/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 7a0562e12f1..5f5bfa7154a 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -604,6 +604,7 @@ impl<'p, 'tcx: 'p> RustcMatchCheckCtxt<'p, 'tcx> { let lo = lo.as_finite().map(|c| c.eval_bits(cx.tcx, cx.param_env)); let hi = hi.as_finite().map(|c| c.eval_bits(cx.tcx, cx.param_env)); match fty { + ty::FloatTy::F16 => unimplemented!("f16_f128"), ty::FloatTy::F32 => { use rustc_apfloat::ieee::Single; let lo = lo.map(Single::from_bits).unwrap_or(-Single::INFINITY); @@ -616,6 +617,7 @@ impl<'p, 'tcx: 'p> RustcMatchCheckCtxt<'p, 'tcx> { let hi = hi.map(Double::from_bits).unwrap_or(Double::INFINITY); F64Range(lo, hi, end) } + ty::FloatTy::F128 => unimplemented!("f16_f128"), } } _ => bug!("invalid type for range pattern: {}", ty.inner()), @@ -893,6 +895,11 @@ impl<'p, 'tcx: 'p> TypeCx for RustcMatchCheckCtxt<'p, 'tcx> { errors::OverlappingRangeEndpoints { overlap: overlaps, range: pat_span }, ); } + + fn complexity_exceeded(&self) -> Result<(), Self::Error> { + let span = self.whole_match_span.unwrap_or(self.scrut_span); + Err(self.tcx.dcx().span_err(span, "reached pattern complexity limit")) + } } /// Recursively expand this pattern into its subpatterns. Only useful for or-patterns. diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs index bbe02f94c0a..c518844cc5e 100644 --- a/compiler/rustc_pattern_analysis/src/usefulness.rs +++ b/compiler/rustc_pattern_analysis/src/usefulness.rs @@ -734,6 +734,21 @@ struct UsefulnessCtxt<'a, Cx: TypeCx> { /// Collect the patterns found useful during usefulness checking. This is used to lint /// unreachable (sub)patterns. useful_subpatterns: FxHashSet<PatId>, + complexity_limit: Option<usize>, + complexity_level: usize, +} + +impl<'a, Cx: TypeCx> UsefulnessCtxt<'a, 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(); + } + Ok(()) + } } /// Context that provides information local to a place under investigation. @@ -986,19 +1001,26 @@ impl<'p, Cx: TypeCx> PatStack<'p, Cx> { /// Only call if `ctor.is_covered_by(self.head().ctor())` is true. fn pop_head_constructor( &self, + cx: &Cx, ctor: &Constructor<Cx>, ctor_arity: usize, ctor_is_relevant: bool, - ) -> PatStack<'p, Cx> { + ) -> Result<PatStack<'p, Cx>, Cx::Error> { // We pop the head pattern and push the new fields extracted from the arguments of // `self.head()`. let mut new_pats = self.head().specialize(ctor, ctor_arity); + if new_pats.len() != ctor_arity { + return Err(cx.bug(format_args!( + "uncaught type error: pattern {:?} has inconsistent arity (expected arity {ctor_arity})", + self.head().as_pat().unwrap() + ))); + } new_pats.extend_from_slice(&self.pats[1..]); // `ctor` is relevant for this row if it is the actual constructor of this row, or if the // row has a wildcard and `ctor` is relevant for wildcards. let ctor_is_relevant = !matches!(self.head().ctor(), Constructor::Wildcard) || ctor_is_relevant; - PatStack { pats: new_pats, relevant: self.relevant && ctor_is_relevant } + Ok(PatStack { pats: new_pats, relevant: self.relevant && ctor_is_relevant }) } } @@ -1068,18 +1090,19 @@ impl<'p, Cx: TypeCx> MatrixRow<'p, Cx> { /// Only call if `ctor.is_covered_by(self.head().ctor())` is true. fn pop_head_constructor( &self, + cx: &Cx, ctor: &Constructor<Cx>, ctor_arity: usize, ctor_is_relevant: bool, parent_row: usize, - ) -> MatrixRow<'p, Cx> { - MatrixRow { - pats: self.pats.pop_head_constructor(ctor, ctor_arity, ctor_is_relevant), + ) -> Result<MatrixRow<'p, Cx>, Cx::Error> { + Ok(MatrixRow { + pats: self.pats.pop_head_constructor(cx, ctor, ctor_arity, ctor_is_relevant)?, parent_row, is_under_guard: self.is_under_guard, useful: false, intersects: BitSet::new_empty(0), // Initialized in `Matrix::expand_and_push`. - } + }) } } @@ -1202,7 +1225,7 @@ impl<'p, Cx: TypeCx> Matrix<'p, Cx> { }; for (i, row) in self.rows().enumerate() { if ctor.is_covered_by(pcx.cx, row.head().ctor())? { - let new_row = row.pop_head_constructor(ctor, arity, ctor_is_relevant, i); + let new_row = row.pop_head_constructor(pcx.cx, ctor, arity, ctor_is_relevant, i)?; matrix.expand_and_push(new_row); } } @@ -1552,6 +1575,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>( } let Some(place) = matrix.head_place() else { + mcx.increase_complexity_level(matrix.rows().len())?; // The base case: there are no columns in the matrix. We are morally pattern-matching on (). // A row is useful iff it has no (unguarded) rows above it. let mut useful = true; // Whether the next row is useful. @@ -1690,8 +1714,14 @@ pub fn compute_match_usefulness<'p, Cx: TypeCx>( arms: &[MatchArm<'p, Cx>], scrut_ty: Cx::Ty, scrut_validity: ValidityConstraint, + complexity_limit: Option<usize>, ) -> Result<UsefulnessReport<'p, Cx>, Cx::Error> { - let mut cx = UsefulnessCtxt { tycx, useful_subpatterns: FxHashSet::default() }; + let mut cx = UsefulnessCtxt { + tycx, + useful_subpatterns: FxHashSet::default(), + complexity_limit, + complexity_level: 0, + }; let mut matrix = Matrix::new(arms, scrut_ty, scrut_validity); let non_exhaustiveness_witnesses = compute_exhaustiveness_and_usefulness(&mut cx, &mut matrix)?; |
