summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_passes/src/loops.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-07 05:48:48 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-07 05:48:48 +0000
commitef24de24a82fe681581cc130f342363c47c0969a (patch)
tree0d494f7e1a38b95c92426f58fe6eaa877303a86c /compiler/rustc_passes/src/loops.rs
parentReleasing progress-linux version 1.74.1+dfsg1-1~progress7.99u1. (diff)
downloadrustc-ef24de24a82fe681581cc130f342363c47c0969a.tar.xz
rustc-ef24de24a82fe681581cc130f342363c47c0969a.zip
Merging upstream version 1.75.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_passes/src/loops.rs')
-rw-r--r--compiler/rustc_passes/src/loops.rs55
1 files changed, 47 insertions, 8 deletions
diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs
index 0aaf85086..25e131d74 100644
--- a/compiler/rustc_passes/src/loops.rs
+++ b/compiler/rustc_passes/src/loops.rs
@@ -1,7 +1,7 @@
use Context::*;
use rustc_hir as hir;
-use rustc_hir::def_id::LocalModDefId;
+use rustc_hir::def_id::{LocalDefId, LocalModDefId};
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{Destination, Movability, Node};
use rustc_middle::hir::map::Map;
@@ -10,19 +10,21 @@ use rustc_middle::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_session::Session;
use rustc_span::hygiene::DesugaringKind;
-use rustc_span::Span;
+use rustc_span::{BytePos, Span};
use crate::errors::{
BreakInsideAsyncBlock, BreakInsideClosure, BreakNonLoop, ContinueLabeledBlock, OutsideLoop,
- UnlabeledCfInWhileCondition, UnlabeledInLabeledBlock,
+ OutsideLoopSuggestion, UnlabeledCfInWhileCondition, UnlabeledInLabeledBlock,
};
#[derive(Clone, Copy, Debug, PartialEq)]
enum Context {
Normal,
+ Fn,
Loop(hir::LoopSource),
Closure(Span),
AsyncClosure(Span),
+ UnlabeledBlock(Span),
LabeledBlock,
Constant,
}
@@ -60,6 +62,25 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
self.with_context(Constant, |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::Loop(ref b, _, source, _) => {
@@ -83,6 +104,14 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
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, Fn) => {
+ self.with_context(Normal, |v| v.visit_block(&b));
+ }
+ hir::ExprKind::Block(ref b, None)
+ if matches!(self.cx, Normal | Constant | 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);
@@ -147,7 +176,12 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
}
}
- self.require_break_cx("break", e.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("break", e.span, label_sp);
}
hir::ExprKind::Continue(destination) => {
self.require_label_in_labeled_block(e.span, &destination, "continue");
@@ -169,7 +203,7 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
}
Err(_) => {}
}
- self.require_break_cx("continue", e.span)
+ self.require_break_cx("continue", e.span, e.span)
}
_ => intravisit::walk_expr(self, e),
}
@@ -187,7 +221,8 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
self.cx = old_cx;
}
- fn require_break_cx(&self, name: &str, span: Span) {
+ fn require_break_cx(&self, name: &str, span: Span, break_span: Span) {
+ let is_break = name == "break";
match self.cx {
LabeledBlock | Loop(_) => {}
Closure(closure_span) => {
@@ -196,8 +231,12 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
AsyncClosure(closure_span) => {
self.sess.emit_err(BreakInsideAsyncBlock { span, closure_span, name });
}
- Normal | Constant => {
- self.sess.emit_err(OutsideLoop { span, name, is_break: name == "break" });
+ UnlabeledBlock(block_span) if is_break && block_span.eq_ctxt(break_span) => {
+ let suggestion = Some(OutsideLoopSuggestion { block_span, break_span });
+ self.sess.emit_err(OutsideLoop { span, name, is_break, suggestion });
+ }
+ Normal | Constant | Fn | UnlabeledBlock(_) => {
+ self.sess.emit_err(OutsideLoop { span, name, is_break, suggestion: None });
}
}
}