diff options
| author | Oli Scherer <github333195615777966@oli-obk.de> | 2025-05-30 16:01:00 +0000 |
|---|---|---|
| committer | Oli Scherer <github333195615777966@oli-obk.de> | 2025-06-10 08:41:23 +0000 |
| commit | 1b9d38dd08d2e09b2ea6b18a0201252203f63e27 (patch) | |
| tree | 40c029201345dd40a2882efde54ee7da3ab70eb8 /compiler/rustc_passes/src/loops.rs | |
| parent | b73bf3c0b52d3fa61f0110f3fc867ca69f9f43ae (diff) | |
| download | rust-1b9d38dd08d2e09b2ea6b18a0201252203f63e27.tar.gz rust-1b9d38dd08d2e09b2ea6b18a0201252203f63e27.zip | |
Remove check_mod_loops query and run the checks per-body instead
Diffstat (limited to 'compiler/rustc_passes/src/loops.rs')
| -rw-r--r-- | compiler/rustc_passes/src/loops.rs | 402 |
1 files changed, 0 insertions, 402 deletions
diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs deleted file mode 100644 index b06f16cc7bd..00000000000 --- a/compiler/rustc_passes/src/loops.rs +++ /dev/null @@ -1,402 +0,0 @@ -use std::collections::BTreeMap; -use std::fmt; - -use Context::*; -use rustc_hir as hir; -use rustc_hir::def_id::{LocalDefId, LocalModDefId}; -use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{Destination, Node}; -use rustc_middle::hir::nested_filter; -use rustc_middle::query::Providers; -use rustc_middle::span_bug; -use rustc_middle::ty::TyCtxt; -use rustc_span::hygiene::DesugaringKind; -use rustc_span::{BytePos, Span}; - -use crate::errors::{ - BreakInsideClosure, BreakInsideCoroutine, BreakNonLoop, ContinueLabeledBlock, OutsideLoop, - OutsideLoopSuggestion, UnlabeledCfInWhileCondition, UnlabeledInLabeledBlock, -}; - -/// The context in which a block is encountered. -#[derive(Clone, Copy, Debug, PartialEq)] -enum Context { - Normal, - Fn, - Loop(hir::LoopSource), - Closure(Span), - Coroutine { - coroutine_span: Span, - kind: hir::CoroutineDesugaring, - source: hir::CoroutineSource, - }, - UnlabeledBlock(Span), - UnlabeledIfBlock(Span), - LabeledBlock, - /// E.g. The labeled block inside `['_'; 'block: { break 'block 1 + 2; }]`. - AnonConst, - /// E.g. `const { ... }`. - ConstBlock, -} - -#[derive(Clone)] -struct BlockInfo { - name: String, - spans: Vec<Span>, - suggs: Vec<Span>, -} - -#[derive(PartialEq)] -enum BreakContextKind { - Break, - Continue, -} - -impl fmt::Display for BreakContextKind { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - BreakContextKind::Break => "break", - BreakContextKind::Continue => "continue", - } - .fmt(f) - } -} - -#[derive(Clone)] -struct CheckLoopVisitor<'tcx> { - tcx: TyCtxt<'tcx>, - // Keep track of a stack of contexts, so that suggestions - // are not made for contexts where it would be incorrect, - // such as adding a label for an `if`. - // e.g. `if 'foo: {}` would be incorrect. - cx_stack: Vec<Context>, - block_breaks: BTreeMap<Span, BlockInfo>, -} - -fn check_mod_loops(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) { - let mut check = - CheckLoopVisitor { tcx, cx_stack: vec![Normal], block_breaks: Default::default() }; - tcx.hir_visit_item_likes_in_module(module_def_id, &mut check); - check.report_outside_loop_error(); -} - -pub(crate) fn provide(providers: &mut Providers) { - *providers = Providers { check_mod_loops, ..*providers }; -} - -impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> { - type NestedFilter = nested_filter::OnlyBodies; - - fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { - self.tcx - } - - fn visit_anon_const(&mut self, c: &'hir hir::AnonConst) { - self.with_context(AnonConst, |v| intravisit::walk_anon_const(v, c)); - } - - fn visit_inline_const(&mut self, c: &'hir hir::ConstBlock) { - self.with_context(ConstBlock, |v| intravisit::walk_inline_const(v, c)); - } - - fn visit_fn( - &mut self, - fk: hir::intravisit::FnKind<'hir>, - fd: &'hir hir::FnDecl<'hir>, - b: hir::BodyId, - _: Span, - id: LocalDefId, - ) { - self.with_context(Fn, |v| intravisit::walk_fn(v, fk, fd, b, id)); - } - - fn visit_trait_item(&mut self, trait_item: &'hir hir::TraitItem<'hir>) { - self.with_context(Fn, |v| intravisit::walk_trait_item(v, trait_item)); - } - - fn visit_impl_item(&mut self, impl_item: &'hir hir::ImplItem<'hir>) { - self.with_context(Fn, |v| intravisit::walk_impl_item(v, impl_item)); - } - - fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) { - match e.kind { - hir::ExprKind::If(cond, then, else_opt) => { - self.visit_expr(cond); - - let get_block = |ck_loop: &CheckLoopVisitor<'hir>, - expr: &hir::Expr<'hir>| - -> Option<&hir::Block<'hir>> { - if let hir::ExprKind::Block(b, None) = expr.kind - && matches!( - ck_loop.cx_stack.last(), - Some(&Normal) - | Some(&AnonConst) - | Some(&UnlabeledBlock(_)) - | Some(&UnlabeledIfBlock(_)) - ) - { - Some(b) - } else { - None - } - }; - - if let Some(b) = get_block(self, then) { - self.with_context(UnlabeledIfBlock(b.span.shrink_to_lo()), |v| { - v.visit_block(b) - }); - } else { - self.visit_expr(then); - } - - if let Some(else_expr) = else_opt { - if let Some(b) = get_block(self, else_expr) { - self.with_context(UnlabeledIfBlock(b.span.shrink_to_lo()), |v| { - v.visit_block(b) - }); - } else { - self.visit_expr(else_expr); - } - } - } - hir::ExprKind::Loop(ref b, _, source, _) => { - self.with_context(Loop(source), |v| v.visit_block(b)); - } - hir::ExprKind::Closure(&hir::Closure { - ref fn_decl, body, fn_decl_span, kind, .. - }) => { - let cx = match kind { - hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(kind, source)) => { - Coroutine { coroutine_span: fn_decl_span, kind, source } - } - _ => Closure(fn_decl_span), - }; - self.visit_fn_decl(fn_decl); - self.with_context(cx, |v| v.visit_nested_body(body)); - } - hir::ExprKind::Block(ref b, Some(_label)) => { - self.with_context(LabeledBlock, |v| v.visit_block(b)); - } - hir::ExprKind::Block(ref b, None) - if matches!(self.cx_stack.last(), Some(&Fn) | Some(&ConstBlock)) => - { - self.with_context(Normal, |v| v.visit_block(b)); - } - hir::ExprKind::Block( - ref b @ hir::Block { rules: hir::BlockCheckMode::DefaultBlock, .. }, - None, - ) if matches!( - self.cx_stack.last(), - Some(&Normal) | Some(&AnonConst) | Some(&UnlabeledBlock(_)) - ) => - { - self.with_context(UnlabeledBlock(b.span.shrink_to_lo()), |v| v.visit_block(b)); - } - hir::ExprKind::Break(break_label, ref opt_expr) => { - if let Some(e) = opt_expr { - self.visit_expr(e); - } - - if self.require_label_in_labeled_block(e.span, &break_label, "break") { - // If we emitted an error about an unlabeled break in a labeled - // block, we don't need any further checking for this break any more - return; - } - - let loop_id = match break_label.target_id { - Ok(loop_id) => Some(loop_id), - Err(hir::LoopIdError::OutsideLoopScope) => None, - Err(hir::LoopIdError::UnlabeledCfInWhileCondition) => { - self.tcx.dcx().emit_err(UnlabeledCfInWhileCondition { - span: e.span, - cf_type: "break", - }); - None - } - Err(hir::LoopIdError::UnresolvedLabel) => None, - }; - - if let Some(Node::Block(_)) = loop_id.map(|id| self.tcx.hir_node(id)) { - return; - } - - if let Some(break_expr) = opt_expr { - let (head, loop_label, loop_kind) = if let Some(loop_id) = loop_id { - match self.tcx.hir_expect_expr(loop_id).kind { - hir::ExprKind::Loop(_, label, source, sp) => { - (Some(sp), label, Some(source)) - } - ref r => { - span_bug!(e.span, "break label resolved to a non-loop: {:?}", r) - } - } - } else { - (None, None, None) - }; - match loop_kind { - None | Some(hir::LoopSource::Loop) => (), - Some(kind) => { - let suggestion = format!( - "break{}", - break_label - .label - .map_or_else(String::new, |l| format!(" {}", l.ident)) - ); - self.tcx.dcx().emit_err(BreakNonLoop { - span: e.span, - head, - kind: kind.name(), - suggestion, - loop_label, - break_label: break_label.label, - break_expr_kind: &break_expr.kind, - break_expr_span: break_expr.span, - }); - } - } - } - - let sp_lo = e.span.with_lo(e.span.lo() + BytePos("break".len() as u32)); - let label_sp = match break_label.label { - Some(label) => sp_lo.with_hi(label.ident.span.hi()), - None => sp_lo.shrink_to_lo(), - }; - self.require_break_cx( - BreakContextKind::Break, - e.span, - label_sp, - self.cx_stack.len() - 1, - ); - } - hir::ExprKind::Continue(destination) => { - self.require_label_in_labeled_block(e.span, &destination, "continue"); - - match destination.target_id { - Ok(loop_id) => { - if let Node::Block(block) = self.tcx.hir_node(loop_id) { - self.tcx.dcx().emit_err(ContinueLabeledBlock { - span: e.span, - block_span: block.span, - }); - } - } - Err(hir::LoopIdError::UnlabeledCfInWhileCondition) => { - self.tcx.dcx().emit_err(UnlabeledCfInWhileCondition { - span: e.span, - cf_type: "continue", - }); - } - Err(_) => {} - } - self.require_break_cx( - BreakContextKind::Continue, - e.span, - e.span, - self.cx_stack.len() - 1, - ) - } - _ => intravisit::walk_expr(self, e), - } - } -} - -impl<'hir> CheckLoopVisitor<'hir> { - fn with_context<F>(&mut self, cx: Context, f: F) - where - F: FnOnce(&mut CheckLoopVisitor<'hir>), - { - self.cx_stack.push(cx); - f(self); - self.cx_stack.pop(); - } - - fn require_break_cx( - &mut self, - br_cx_kind: BreakContextKind, - span: Span, - break_span: Span, - cx_pos: usize, - ) { - match self.cx_stack[cx_pos] { - LabeledBlock | Loop(_) => {} - Closure(closure_span) => { - self.tcx.dcx().emit_err(BreakInsideClosure { - span, - closure_span, - name: &br_cx_kind.to_string(), - }); - } - Coroutine { coroutine_span, kind, source } => { - let kind = match kind { - hir::CoroutineDesugaring::Async => "async", - hir::CoroutineDesugaring::Gen => "gen", - hir::CoroutineDesugaring::AsyncGen => "async gen", - }; - let source = match source { - hir::CoroutineSource::Block => "block", - hir::CoroutineSource::Closure => "closure", - hir::CoroutineSource::Fn => "function", - }; - self.tcx.dcx().emit_err(BreakInsideCoroutine { - span, - coroutine_span, - name: &br_cx_kind.to_string(), - kind, - source, - }); - } - UnlabeledBlock(block_span) - if br_cx_kind == BreakContextKind::Break && block_span.eq_ctxt(break_span) => - { - let block = self.block_breaks.entry(block_span).or_insert_with(|| BlockInfo { - name: br_cx_kind.to_string(), - spans: vec![], - suggs: vec![], - }); - block.spans.push(span); - block.suggs.push(break_span); - } - UnlabeledIfBlock(_) if br_cx_kind == BreakContextKind::Break => { - self.require_break_cx(br_cx_kind, span, break_span, cx_pos - 1); - } - Normal | AnonConst | Fn | UnlabeledBlock(_) | UnlabeledIfBlock(_) | ConstBlock => { - self.tcx.dcx().emit_err(OutsideLoop { - spans: vec![span], - name: &br_cx_kind.to_string(), - is_break: br_cx_kind == BreakContextKind::Break, - suggestion: None, - }); - } - } - } - - fn require_label_in_labeled_block( - &self, - span: Span, - label: &Destination, - cf_type: &str, - ) -> bool { - if !span.is_desugaring(DesugaringKind::QuestionMark) - && self.cx_stack.last() == Some(&LabeledBlock) - && label.label.is_none() - { - self.tcx.dcx().emit_err(UnlabeledInLabeledBlock { span, cf_type }); - return true; - } - false - } - - fn report_outside_loop_error(&self) { - for (s, block) in &self.block_breaks { - self.tcx.dcx().emit_err(OutsideLoop { - spans: block.spans.clone(), - name: &block.name, - is_break: true, - suggestion: Some(OutsideLoopSuggestion { - block_span: *s, - break_spans: block.suggs.clone(), - }), - }); - } - } -} |
