diff options
| author | Michael Goulet <michael@errs.io> | 2025-04-07 22:32:49 +0000 |
|---|---|---|
| committer | Michael Goulet <michael@errs.io> | 2025-04-07 22:41:48 +0000 |
| commit | b08e9c2a60f4dbab4bdaa733727947b3395de329 (patch) | |
| tree | 925acaaac24899583917174cecea483ac7f3dc52 /compiler/rustc_pattern_analysis | |
| parent | e643f59f6da3a84f43e75dea99afaa5b041ea6bf (diff) | |
| download | rust-b08e9c2a60f4dbab4bdaa733727947b3395de329.tar.gz rust-b08e9c2a60f4dbab4bdaa733727947b3395de329.zip | |
Fix stack overflow in exhaustiveness due to recursive HIR opaque type values
Diffstat (limited to 'compiler/rustc_pattern_analysis')
| -rw-r--r-- | compiler/rustc_pattern_analysis/src/rustc.rs | 40 |
1 files changed, 35 insertions, 5 deletions
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 88d45ead295..7c12f69f14c 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -1,5 +1,6 @@ use std::fmt; use std::iter::once; +use std::ops::ControlFlow; use rustc_abi::{FIRST_VARIANT, FieldIdx, Integer, VariantIdx}; use rustc_arena::DroplessArena; @@ -11,7 +12,8 @@ use rustc_middle::mir::{self, Const}; use rustc_middle::thir::{self, Pat, PatKind, PatRange, PatRangeBoundary}; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::{ - self, FieldDef, OpaqueTypeKey, ScalarInt, Ty, TyCtxt, TypeVisitableExt, VariantDef, + self, FieldDef, OpaqueTypeKey, ScalarInt, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, + TypeVisitableExt, TypeVisitor, VariantDef, }; use rustc_middle::{bug, span_bug}; use rustc_session::lint; @@ -135,11 +137,22 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { /// Returns the hidden type corresponding to this key if the body under analysis is allowed to /// know it. fn reveal_opaque_key(&self, key: OpaqueTypeKey<'tcx>) -> Option<Ty<'tcx>> { - self.typeck_results - .concrete_opaque_types - .get(&key.def_id) - .map(|x| ty::EarlyBinder::bind(x.ty).instantiate(self.tcx, key.args)) + if let Some(hidden_ty) = self.typeck_results.concrete_opaque_types.get(&key.def_id) { + let ty = ty::EarlyBinder::bind(hidden_ty.ty).instantiate(self.tcx, key.args); + if ty.visit_with(&mut RecursiveOpaque { def_id: key.def_id.into() }).is_continue() { + Some(ty) + } else { + // HACK: We skip revealing opaque types which recursively expand + // to themselves. This is because we may infer hidden types like + // `Opaque<T> = Opaque<Opaque<T>>` or `Opaque<T> = Opaque<(T,)>` + // in hir typeck. + None + } + } else { + None + } } + // This can take a non-revealed `Ty` because it reveals opaques itself. pub fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool { !ty.inhabited_predicate(self.tcx).apply_revealing_opaque( @@ -1105,3 +1118,20 @@ pub fn analyze_match<'p, 'tcx>( Ok(report) } + +struct RecursiveOpaque { + def_id: DefId, +} +impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for RecursiveOpaque { + type Result = ControlFlow<()>; + + fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result { + if let ty::Alias(ty::Opaque, alias_ty) = t.kind() { + if alias_ty.def_id == self.def_id { + return ControlFlow::Break(()); + } + } + + if t.has_opaque_types() { t.super_visit_with(self) } else { ControlFlow::Continue(()) } + } +} |
