about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2025-06-10 23:54:45 +0000
committerbors <bors@rust-lang.org>2025-06-10 23:54:45 +0000
commit1c047506f94cd2d05228eb992b0a6bbed1942349 (patch)
tree7f0b73f2eae9b6792a19bf5fdde9d5433d6d79b8
parent1677d46cb128cc8f285dbd32b0dc4d7a46437050 (diff)
parent7f4093e78bbddae798e3eaf4d713da75c6315877 (diff)
downloadrust-1c047506f94cd2d05228eb992b0a6bbed1942349.tar.gz
rust-1c047506f94cd2d05228eb992b0a6bbed1942349.zip
Auto merge of #141883 - oli-obk:remove-check-mod-loops, r=nnethercote
Remove check_mod_loops query and run the checks per-body instead

This analysis is older than my first rustc contribution I believe. It was never querified. Ideally we'd merge it into the analysis happening within typeck anyway (typeck just uses span_delayed_bug instead of erroring), but I didn't want to do that within this PR that also moves things around and subtly changes diagnostic ordering.
-rw-r--r--compiler/rustc_hir_typeck/messages.ftl44
-rw-r--r--compiler/rustc_hir_typeck/src/errors.rs128
-rw-r--r--compiler/rustc_hir_typeck/src/lib.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/loops.rs (renamed from compiler/rustc_passes/src/loops.rs)39
-rw-r--r--compiler/rustc_interface/src/passes.rs1
-rw-r--r--compiler/rustc_middle/src/query/mod.rs5
-rw-r--r--compiler/rustc_passes/messages.ftl40
-rw-r--r--compiler/rustc_passes/src/errors.rs128
-rw-r--r--compiler/rustc_passes/src/lib.rs2
-rw-r--r--tests/ui/async-await/async-block-control-flow-static-semantics.stderr32
-rw-r--r--tests/ui/inline-const/break-inside-inline-const-issue-128604.rs6
-rw-r--r--tests/ui/inline-const/break-inside-inline-const-issue-128604.stderr32
-rw-r--r--tests/ui/inline-const/cross-const-control-flow-125846.stderr20
-rw-r--r--tests/ui/loops/issue-43162.stderr12
-rw-r--r--tests/ui/track-diagnostics/track.stderr2
-rw-r--r--tests/ui/typeck/issue-114529-illegal-break-with-value.stderr36
-rw-r--r--tests/ui/unsafe/break-inside-unsafe-block-issue-128604.stderr12
17 files changed, 272 insertions, 271 deletions
diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl
index 6c33dfb4ec0..3bdd1b48666 100644
--- a/compiler/rustc_hir_typeck/messages.ftl
+++ b/compiler/rustc_hir_typeck/messages.ftl
@@ -17,6 +17,24 @@ hir_typeck_base_expression_double_dot_enable_default_field_values =
     add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields
 hir_typeck_base_expression_double_dot_remove = remove the `..` as all the fields are already present
 
+hir_typeck_break_inside_closure =
+    `{$name}` inside of a closure
+    .label = cannot `{$name}` inside of a closure
+    .closure_label = enclosing closure
+
+hir_typeck_break_inside_coroutine =
+    `{$name}` inside `{$kind}` {$source}
+    .label = cannot `{$name}` inside `{$kind}` {$source}
+    .coroutine_label = enclosing `{$kind}` {$source}
+
+hir_typeck_break_non_loop =
+    `break` with value from a `{$kind}` loop
+    .label = can only break with a value inside `loop` or breakable block
+    .label2 = you can't `break` with a value in a `{$kind}` loop
+    .suggestion = use `break` on its own without a value inside this `{$kind}` loop
+    .break_expr_suggestion = alternatively, you might have meant to use the available loop label
+
+
 hir_typeck_candidate_trait_note = `{$trait_name}` defines an item `{$item_name}`{$action_or_ty ->
     [NONE] {""}
     [implement] , perhaps you need to implement it
@@ -64,6 +82,12 @@ hir_typeck_const_select_must_be_fn = this argument must be a function item
     .note = expected a function item, found {$ty}
     .help = consult the documentation on `const_eval_select` for more information
 
+hir_typeck_continue_labeled_block =
+    `continue` pointing to a labeled block
+    .label = labeled blocks cannot be `continue`'d
+    .block_label = labeled block the `continue` points to
+
+
 hir_typeck_convert_to_str = try converting the passed type into a `&str`
 
 hir_typeck_convert_using_method = try using `{$sugg}` to convert `{$found}` to `{$expected}`
@@ -182,6 +206,19 @@ hir_typeck_option_result_asref = use `{$def_path}::as_ref` to convert `{$expecte
 hir_typeck_option_result_cloned = use `{$def_path}::cloned` to clone the value inside the `{$def_path}`
 hir_typeck_option_result_copied = use `{$def_path}::copied` to copy the value inside the `{$def_path}`
 
+hir_typeck_outside_loop =
+    `{$name}` outside of a loop{$is_break ->
+        [true] {" or labeled block"}
+        *[false] {""}
+    }
+    .label = cannot `{$name}` outside of a loop{$is_break ->
+        [true] {" or labeled block"}
+        *[false] {""}
+    }
+
+hir_typeck_outside_loop_suggestion = consider labeling this block to be able to break within it
+
+
 hir_typeck_params_not_allowed =
     referencing function parameters is not allowed in naked functions
     .help = follow the calling convention in asm block to use parameters
@@ -254,6 +291,13 @@ hir_typeck_union_pat_dotdot = `..` cannot be used in union patterns
 
 hir_typeck_union_pat_multiple_fields = union patterns should have exactly one field
 
+hir_typeck_unlabeled_cf_in_while_condition =
+    `break` or `continue` with no label in the condition of a `while` loop
+    .label = unlabeled `{$cf_type}` in the condition of a `while` loop
+
+hir_typeck_unlabeled_in_labeled_block =
+    unlabeled `{$cf_type}` inside of a labeled block
+    .label = `{$cf_type}` statements that would diverge to or through a labeled block need to bear a label
 hir_typeck_use_is_empty =
     consider using the `is_empty` method on `{$expr_ty}` to determine if it contains anything
 
diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs
index 97a90548fc5..774815015d5 100644
--- a/compiler/rustc_hir_typeck/src/errors.rs
+++ b/compiler/rustc_hir_typeck/src/errors.rs
@@ -2,11 +2,14 @@
 
 use std::borrow::Cow;
 
+use rustc_ast::Label;
 use rustc_errors::codes::*;
 use rustc_errors::{
     Applicability, Diag, DiagArgValue, DiagCtxtHandle, DiagSymbolList, Diagnostic,
     EmissionGuarantee, IntoDiagArg, Level, MultiSpan, Subdiagnostic,
 };
+use rustc_hir as hir;
+use rustc_hir::ExprKind;
 use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
 use rustc_middle::ty::{self, Ty};
 use rustc_span::edition::{Edition, LATEST_STABLE_EDITION};
@@ -721,6 +724,131 @@ pub(crate) struct TrivialCast<'tcx> {
     pub cast_ty: Ty<'tcx>,
 }
 
+pub(crate) struct BreakNonLoop<'a> {
+    pub span: Span,
+    pub head: Option<Span>,
+    pub kind: &'a str,
+    pub suggestion: String,
+    pub loop_label: Option<Label>,
+    pub break_label: Option<Label>,
+    pub break_expr_kind: &'a ExprKind<'a>,
+    pub break_expr_span: Span,
+}
+
+impl<'a, G: EmissionGuarantee> Diagnostic<'_, G> for BreakNonLoop<'a> {
+    #[track_caller]
+    fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
+        let mut diag = Diag::new(dcx, level, fluent::hir_typeck_break_non_loop);
+        diag.span(self.span);
+        diag.code(E0571);
+        diag.arg("kind", self.kind);
+        diag.span_label(self.span, fluent::hir_typeck_label);
+        if let Some(head) = self.head {
+            diag.span_label(head, fluent::hir_typeck_label2);
+        }
+        diag.span_suggestion(
+            self.span,
+            fluent::hir_typeck_suggestion,
+            self.suggestion,
+            Applicability::MaybeIncorrect,
+        );
+        if let (Some(label), None) = (self.loop_label, self.break_label) {
+            match self.break_expr_kind {
+                ExprKind::Path(hir::QPath::Resolved(
+                    None,
+                    hir::Path { segments: [segment], res: hir::def::Res::Err, .. },
+                )) if label.ident.to_string() == format!("'{}", segment.ident) => {
+                    // This error is redundant, we will have already emitted a
+                    // suggestion to use the label when `segment` wasn't found
+                    // (hence the `Res::Err` check).
+                    diag.downgrade_to_delayed_bug();
+                }
+                _ => {
+                    diag.span_suggestion(
+                        self.break_expr_span,
+                        fluent::hir_typeck_break_expr_suggestion,
+                        label.ident,
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+            }
+        }
+        diag
+    }
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_typeck_continue_labeled_block, code = E0696)]
+pub(crate) struct ContinueLabeledBlock {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    #[label(hir_typeck_block_label)]
+    pub block_span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_typeck_break_inside_closure, code = E0267)]
+pub(crate) struct BreakInsideClosure<'a> {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    #[label(hir_typeck_closure_label)]
+    pub closure_span: Span,
+    pub name: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_typeck_break_inside_coroutine, code = E0267)]
+pub(crate) struct BreakInsideCoroutine<'a> {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    #[label(hir_typeck_coroutine_label)]
+    pub coroutine_span: Span,
+    pub name: &'a str,
+    pub kind: &'a str,
+    pub source: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_typeck_outside_loop, code = E0268)]
+pub(crate) struct OutsideLoop<'a> {
+    #[primary_span]
+    #[label]
+    pub spans: Vec<Span>,
+    pub name: &'a str,
+    pub is_break: bool,
+    #[subdiagnostic]
+    pub suggestion: Option<OutsideLoopSuggestion>,
+}
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(hir_typeck_outside_loop_suggestion, applicability = "maybe-incorrect")]
+pub(crate) struct OutsideLoopSuggestion {
+    #[suggestion_part(code = "'block: ")]
+    pub block_span: Span,
+    #[suggestion_part(code = " 'block")]
+    pub break_spans: Vec<Span>,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_typeck_unlabeled_in_labeled_block, code = E0695)]
+pub(crate) struct UnlabeledInLabeledBlock<'a> {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub cf_type: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_typeck_unlabeled_cf_in_while_condition, code = E0590)]
+pub(crate) struct UnlabeledCfInWhileCondition<'a> {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub cf_type: &'a str,
+}
+
 #[derive(Diagnostic)]
 #[diag(hir_typeck_no_associated_item, code = E0599)]
 pub(crate) struct NoAssociatedItem {
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index 741a616631a..a45a7715340 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -28,6 +28,7 @@ mod fallback;
 mod fn_ctxt;
 mod gather_locals;
 mod intrinsicck;
+mod loops;
 mod method;
 mod naked_functions;
 mod op;
@@ -149,6 +150,7 @@ fn typeck_with_inspect<'tcx>(
         };
 
         check_abi(tcx, id, span, fn_sig.abi());
+        loops::check(tcx, def_id, body);
 
         // Compute the function signature from point of view of inside the fn.
         let mut fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig);
@@ -189,6 +191,8 @@ fn typeck_with_inspect<'tcx>(
             tcx.type_of(def_id).instantiate_identity()
         };
 
+        loops::check(tcx, def_id, body);
+
         let expected_type = fcx.normalize(body.value.span, expected_type);
 
         let wf_code = ObligationCauseCode::WellFormed(Some(WellFormedLoc::Ty(def_id)));
diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_hir_typeck/src/loops.rs
index b06f16cc7bd..b06e0704b6f 100644
--- a/compiler/rustc_passes/src/loops.rs
+++ b/compiler/rustc_hir_typeck/src/loops.rs
@@ -3,11 +3,11 @@ use std::fmt;
 
 use Context::*;
 use rustc_hir as hir;
-use rustc_hir::def_id::{LocalDefId, LocalModDefId};
+use rustc_hir::def::DefKind;
+use rustc_hir::def_id::LocalDefId;
 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;
@@ -73,17 +73,17 @@ struct CheckLoopVisitor<'tcx> {
     block_breaks: BTreeMap<Span, BlockInfo>,
 }
 
-fn check_mod_loops(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
+pub(crate) fn check<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &'tcx hir::Body<'tcx>) {
     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);
+    let cx = match tcx.def_kind(def_id) {
+        DefKind::AnonConst => AnonConst,
+        _ => Fn,
+    };
+    check.with_context(cx, |v| v.visit_body(body));
     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;
 
@@ -91,33 +91,14 @@ impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> {
         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_anon_const(&mut self, _: &'hir hir::AnonConst) {
+        // Typecked on its own.
     }
 
     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) => {
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 2643e5c1926..99520a3fea3 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -954,7 +954,6 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
                 tcx.ensure_ok().exportable_items(LOCAL_CRATE);
                 tcx.ensure_ok().stable_order_of_exportable_impls(LOCAL_CRATE);
                 tcx.par_hir_for_each_module(|module| {
-                    tcx.ensure_ok().check_mod_loops(module);
                     tcx.ensure_ok().check_mod_attrs(module);
                     tcx.ensure_ok().check_mod_unstable_api_usage(module);
                 });
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index d03f01bf863..686ac54f89e 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -1115,11 +1115,6 @@ rustc_queries! {
         desc { |tcx| "checking for unstable API usage in {}", describe_as_module(key, tcx) }
     }
 
-    /// Checks the loops in the module.
-    query check_mod_loops(key: LocalModDefId) {
-        desc { |tcx| "checking loops in {}", describe_as_module(key, tcx) }
-    }
-
     query check_mod_privacy(key: LocalModDefId) {
         desc { |tcx| "checking privacy in {}", describe_as_module(key.to_local_def_id(), tcx) }
     }
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index 983e562cdf3..a4ef065ea2c 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -56,23 +56,6 @@ passes_autodiff_attr =
 passes_both_ffi_const_and_pure =
     `#[ffi_const]` function cannot be `#[ffi_pure]`
 
-passes_break_inside_closure =
-    `{$name}` inside of a closure
-    .label = cannot `{$name}` inside of a closure
-    .closure_label = enclosing closure
-
-passes_break_inside_coroutine =
-    `{$name}` inside `{$kind}` {$source}
-    .label = cannot `{$name}` inside `{$kind}` {$source}
-    .coroutine_label = enclosing `{$kind}` {$source}
-
-passes_break_non_loop =
-    `break` with value from a `{$kind}` loop
-    .label = can only break with a value inside `loop` or breakable block
-    .label2 = you can't `break` with a value in a `{$kind}` loop
-    .suggestion = use `break` on its own without a value inside this `{$kind}` loop
-    .break_expr_suggestion = alternatively, you might have meant to use the available loop label
-
 passes_cannot_stabilize_deprecated =
     an API can't be stabilized after it is deprecated
     .label = invalid version
@@ -103,10 +86,6 @@ passes_const_stable_not_stable =
     attribute `#[rustc_const_stable]` can only be applied to functions that are declared `#[stable]`
     .label = attribute specified here
 
-passes_continue_labeled_block =
-    `continue` pointing to a labeled block
-    .label = labeled blocks cannot be `continue`'d
-    .block_label = labeled block the `continue` points to
 
 passes_coroutine_on_non_closure =
     attribute should be applied to closures
@@ -574,17 +553,6 @@ passes_optimize_invalid_target =
 passes_outer_crate_level_attr =
     crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
 
-passes_outside_loop =
-    `{$name}` outside of a loop{$is_break ->
-        [true] {" or labeled block"}
-        *[false] {""}
-    }
-    .label = cannot `{$name}` outside of a loop{$is_break ->
-        [true] {" or labeled block"}
-        *[false] {""}
-    }
-
-passes_outside_loop_suggestion = consider labeling this block to be able to break within it
 
 passes_panic_unwind_without_std =
     unwinding panics are not supported without std
@@ -752,14 +720,6 @@ passes_unknown_lang_item =
     definition of an unknown lang item: `{$name}`
     .label = definition of unknown lang item `{$name}`
 
-passes_unlabeled_cf_in_while_condition =
-    `break` or `continue` with no label in the condition of a `while` loop
-    .label = unlabeled `{$cf_type}` in the condition of a `while` loop
-
-passes_unlabeled_in_labeled_block =
-    unlabeled `{$cf_type}` inside of a labeled block
-    .label = `{$cf_type}` statements that would diverge to or through a labeled block need to bear a label
-
 passes_unnecessary_partial_stable_feature = the feature `{$feature}` has been partially stabilized since {$since} and is succeeded by the feature `{$implies}`
     .suggestion = if you are using features which are still unstable, change to using `{$implies}`
     .suggestion_remove = if you are using features which are now stable, remove this line
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index b995781719b..74ce92624bd 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -1,13 +1,12 @@
 use std::io::Error;
 use std::path::{Path, PathBuf};
 
-use rustc_ast::Label;
 use rustc_errors::codes::*;
 use rustc_errors::{
     Applicability, Diag, DiagCtxtHandle, DiagSymbolList, Diagnostic, EmissionGuarantee, Level,
     MultiSpan, Subdiagnostic,
 };
-use rustc_hir::{self as hir, ExprKind, Target};
+use rustc_hir::Target;
 use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
 use rustc_middle::ty::{MainDefinition, Ty};
 use rustc_span::{DUMMY_SP, Span, Symbol};
@@ -1071,131 +1070,6 @@ pub(crate) struct FeaturePreviouslyDeclared<'a> {
     pub prev_declared: &'a str,
 }
 
-pub(crate) struct BreakNonLoop<'a> {
-    pub span: Span,
-    pub head: Option<Span>,
-    pub kind: &'a str,
-    pub suggestion: String,
-    pub loop_label: Option<Label>,
-    pub break_label: Option<Label>,
-    pub break_expr_kind: &'a ExprKind<'a>,
-    pub break_expr_span: Span,
-}
-
-impl<'a, G: EmissionGuarantee> Diagnostic<'_, G> for BreakNonLoop<'a> {
-    #[track_caller]
-    fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
-        let mut diag = Diag::new(dcx, level, fluent::passes_break_non_loop);
-        diag.span(self.span);
-        diag.code(E0571);
-        diag.arg("kind", self.kind);
-        diag.span_label(self.span, fluent::passes_label);
-        if let Some(head) = self.head {
-            diag.span_label(head, fluent::passes_label2);
-        }
-        diag.span_suggestion(
-            self.span,
-            fluent::passes_suggestion,
-            self.suggestion,
-            Applicability::MaybeIncorrect,
-        );
-        if let (Some(label), None) = (self.loop_label, self.break_label) {
-            match self.break_expr_kind {
-                ExprKind::Path(hir::QPath::Resolved(
-                    None,
-                    hir::Path { segments: [segment], res: hir::def::Res::Err, .. },
-                )) if label.ident.to_string() == format!("'{}", segment.ident) => {
-                    // This error is redundant, we will have already emitted a
-                    // suggestion to use the label when `segment` wasn't found
-                    // (hence the `Res::Err` check).
-                    diag.downgrade_to_delayed_bug();
-                }
-                _ => {
-                    diag.span_suggestion(
-                        self.break_expr_span,
-                        fluent::passes_break_expr_suggestion,
-                        label.ident,
-                        Applicability::MaybeIncorrect,
-                    );
-                }
-            }
-        }
-        diag
-    }
-}
-
-#[derive(Diagnostic)]
-#[diag(passes_continue_labeled_block, code = E0696)]
-pub(crate) struct ContinueLabeledBlock {
-    #[primary_span]
-    #[label]
-    pub span: Span,
-    #[label(passes_block_label)]
-    pub block_span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(passes_break_inside_closure, code = E0267)]
-pub(crate) struct BreakInsideClosure<'a> {
-    #[primary_span]
-    #[label]
-    pub span: Span,
-    #[label(passes_closure_label)]
-    pub closure_span: Span,
-    pub name: &'a str,
-}
-
-#[derive(Diagnostic)]
-#[diag(passes_break_inside_coroutine, code = E0267)]
-pub(crate) struct BreakInsideCoroutine<'a> {
-    #[primary_span]
-    #[label]
-    pub span: Span,
-    #[label(passes_coroutine_label)]
-    pub coroutine_span: Span,
-    pub name: &'a str,
-    pub kind: &'a str,
-    pub source: &'a str,
-}
-
-#[derive(Diagnostic)]
-#[diag(passes_outside_loop, code = E0268)]
-pub(crate) struct OutsideLoop<'a> {
-    #[primary_span]
-    #[label]
-    pub spans: Vec<Span>,
-    pub name: &'a str,
-    pub is_break: bool,
-    #[subdiagnostic]
-    pub suggestion: Option<OutsideLoopSuggestion>,
-}
-#[derive(Subdiagnostic)]
-#[multipart_suggestion(passes_outside_loop_suggestion, applicability = "maybe-incorrect")]
-pub(crate) struct OutsideLoopSuggestion {
-    #[suggestion_part(code = "'block: ")]
-    pub block_span: Span,
-    #[suggestion_part(code = " 'block")]
-    pub break_spans: Vec<Span>,
-}
-
-#[derive(Diagnostic)]
-#[diag(passes_unlabeled_in_labeled_block, code = E0695)]
-pub(crate) struct UnlabeledInLabeledBlock<'a> {
-    #[primary_span]
-    #[label]
-    pub span: Span,
-    pub cf_type: &'a str,
-}
-
-#[derive(Diagnostic)]
-#[diag(passes_unlabeled_cf_in_while_condition, code = E0590)]
-pub(crate) struct UnlabeledCfInWhileCondition<'a> {
-    #[primary_span]
-    #[label]
-    pub span: Span,
-    pub cf_type: &'a str,
-}
-
 #[derive(Diagnostic)]
 #[diag(passes_naked_functions_incompatible_attribute, code = E0736)]
 pub(crate) struct NakedFunctionIncompatibleAttribute {
diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs
index 1831f45a9ec..af7ecf0830c 100644
--- a/compiler/rustc_passes/src/lib.rs
+++ b/compiler/rustc_passes/src/lib.rs
@@ -29,7 +29,6 @@ mod lang_items;
 pub mod layout_test;
 mod lib_features;
 mod liveness;
-pub mod loops;
 mod reachable;
 pub mod stability;
 mod upvars;
@@ -45,7 +44,6 @@ pub fn provide(providers: &mut Providers) {
     entry::provide(providers);
     lang_items::provide(providers);
     lib_features::provide(providers);
-    loops::provide(providers);
     liveness::provide(providers);
     reachable::provide(providers);
     stability::provide(providers);
diff --git a/tests/ui/async-await/async-block-control-flow-static-semantics.stderr b/tests/ui/async-await/async-block-control-flow-static-semantics.stderr
index 4ed15a942c6..b64690bae6c 100644
--- a/tests/ui/async-await/async-block-control-flow-static-semantics.stderr
+++ b/tests/ui/async-await/async-block-control-flow-static-semantics.stderr
@@ -1,19 +1,3 @@
-error[E0267]: `break` inside `async` block
-  --> $DIR/async-block-control-flow-static-semantics.rs:32:9
-   |
-LL |     async {
-   |     ----- enclosing `async` block
-LL |         break 0u8;
-   |         ^^^^^^^^^ cannot `break` inside `async` block
-
-error[E0267]: `break` inside `async` block
-  --> $DIR/async-block-control-flow-static-semantics.rs:39:13
-   |
-LL |         async {
-   |         ----- enclosing `async` block
-LL |             break 0u8;
-   |             ^^^^^^^^^ cannot `break` inside `async` block
-
 error[E0308]: mismatched types
   --> $DIR/async-block-control-flow-static-semantics.rs:21:58
    |
@@ -50,6 +34,22 @@ LL |     let _: &dyn Future<Output = ()> = &block;
    |
    = note: required for the cast from `&{async block@$DIR/async-block-control-flow-static-semantics.rs:14:17: 14:22}` to `&dyn Future<Output = ()>`
 
+error[E0267]: `break` inside `async` block
+  --> $DIR/async-block-control-flow-static-semantics.rs:32:9
+   |
+LL |     async {
+   |     ----- enclosing `async` block
+LL |         break 0u8;
+   |         ^^^^^^^^^ cannot `break` inside `async` block
+
+error[E0267]: `break` inside `async` block
+  --> $DIR/async-block-control-flow-static-semantics.rs:39:13
+   |
+LL |         async {
+   |         ----- enclosing `async` block
+LL |             break 0u8;
+   |             ^^^^^^^^^ cannot `break` inside `async` block
+
 error[E0308]: mismatched types
   --> $DIR/async-block-control-flow-static-semantics.rs:49:44
    |
diff --git a/tests/ui/inline-const/break-inside-inline-const-issue-128604.rs b/tests/ui/inline-const/break-inside-inline-const-issue-128604.rs
index a9795d1569c..cc0d757885d 100644
--- a/tests/ui/inline-const/break-inside-inline-const-issue-128604.rs
+++ b/tests/ui/inline-const/break-inside-inline-const-issue-128604.rs
@@ -23,3 +23,9 @@ fn main() {
         }
     }
 }
+
+const FOO: () = break;
+//~^ ERROR: `break` outside of a loop or labeled block
+
+static BAR: () = break;
+//~^ ERROR: `break` outside of a loop or labeled block
diff --git a/tests/ui/inline-const/break-inside-inline-const-issue-128604.stderr b/tests/ui/inline-const/break-inside-inline-const-issue-128604.stderr
index 300cd45ad69..6a967c59864 100644
--- a/tests/ui/inline-const/break-inside-inline-const-issue-128604.stderr
+++ b/tests/ui/inline-const/break-inside-inline-const-issue-128604.stderr
@@ -11,6 +11,19 @@ LL |             break;
    |             ^^^^^ cannot `break` outside of a loop or labeled block
 
 error[E0268]: `break` outside of a loop or labeled block
+  --> $DIR/break-inside-inline-const-issue-128604.rs:9:13
+   |
+LL |             break;
+   |             ^^^^^ cannot `break` outside of a loop or labeled block
+   |
+help: consider labeling this block to be able to break within it
+   |
+LL ~         'block: {
+LL |
+LL ~             break 'block;
+   |
+
+error[E0268]: `break` outside of a loop or labeled block
   --> $DIR/break-inside-inline-const-issue-128604.rs:2:21
    |
 LL |     let _ = ['a'; { break 2; 1 }];
@@ -22,18 +35,17 @@ LL |     let _ = ['a'; 'block: { break 'block 2; 1 }];
    |                   +++++++         ++++++
 
 error[E0268]: `break` outside of a loop or labeled block
-  --> $DIR/break-inside-inline-const-issue-128604.rs:9:13
-   |
-LL |             break;
-   |             ^^^^^ cannot `break` outside of a loop or labeled block
-   |
-help: consider labeling this block to be able to break within it
+  --> $DIR/break-inside-inline-const-issue-128604.rs:27:17
    |
-LL ~         'block: {
-LL |
-LL ~             break 'block;
+LL | const FOO: () = break;
+   |                 ^^^^^ cannot `break` outside of a loop or labeled block
+
+error[E0268]: `break` outside of a loop or labeled block
+  --> $DIR/break-inside-inline-const-issue-128604.rs:30:18
    |
+LL | static BAR: () = break;
+   |                  ^^^^^ cannot `break` outside of a loop or labeled block
 
-error: aborting due to 4 previous errors
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0268`.
diff --git a/tests/ui/inline-const/cross-const-control-flow-125846.stderr b/tests/ui/inline-const/cross-const-control-flow-125846.stderr
index 0a910e70d09..5ea571fe98a 100644
--- a/tests/ui/inline-const/cross-const-control-flow-125846.stderr
+++ b/tests/ui/inline-const/cross-const-control-flow-125846.stderr
@@ -39,6 +39,16 @@ LL |     const { async {}.await }
    |           |          only allowed inside `async` functions and blocks
    |           this is not `async`
 
+error[E0572]: return statement outside of function body
+  --> $DIR/cross-const-control-flow-125846.rs:4:13
+   |
+LL | / fn foo() {
+LL | |     const { return }
+   | |           --^^^^^^-- the return is part of this body...
+LL | |
+LL | | }
+   | |_- ...not the enclosing function body
+
 error[E0268]: `break` outside of a loop or labeled block
   --> $DIR/cross-const-control-flow-125846.rs:9:19
    |
@@ -63,16 +73,6 @@ error[E0268]: `continue` outside of a loop
 LL |         const { continue }
    |                 ^^^^^^^^ cannot `continue` outside of a loop
 
-error[E0572]: return statement outside of function body
-  --> $DIR/cross-const-control-flow-125846.rs:4:13
-   |
-LL | / fn foo() {
-LL | |     const { return }
-   | |           --^^^^^^-- the return is part of this body...
-LL | |
-LL | | }
-   | |_- ...not the enclosing function body
-
 error: aborting due to 9 previous errors
 
 Some errors have detailed explanations: E0268, E0435, E0572, E0728, E0767.
diff --git a/tests/ui/loops/issue-43162.stderr b/tests/ui/loops/issue-43162.stderr
index 40d9200058e..f6b6bf2621c 100644
--- a/tests/ui/loops/issue-43162.stderr
+++ b/tests/ui/loops/issue-43162.stderr
@@ -4,12 +4,6 @@ error[E0268]: `break` outside of a loop or labeled block
 LL |     break true;
    |     ^^^^^^^^^^ cannot `break` outside of a loop or labeled block
 
-error[E0268]: `break` outside of a loop or labeled block
-  --> $DIR/issue-43162.rs:7:5
-   |
-LL |     break {};
-   |     ^^^^^^^^ cannot `break` outside of a loop or labeled block
-
 error[E0308]: mismatched types
   --> $DIR/issue-43162.rs:1:13
    |
@@ -18,6 +12,12 @@ LL | fn foo() -> bool {
    |    |
    |    implicitly returns `()` as its body has no tail or `return` expression
 
+error[E0268]: `break` outside of a loop or labeled block
+  --> $DIR/issue-43162.rs:7:5
+   |
+LL |     break {};
+   |     ^^^^^^^^ cannot `break` outside of a loop or labeled block
+
 error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0268, E0308.
diff --git a/tests/ui/track-diagnostics/track.stderr b/tests/ui/track-diagnostics/track.stderr
index d2908bb9177..527c0d1b898 100644
--- a/tests/ui/track-diagnostics/track.stderr
+++ b/tests/ui/track-diagnostics/track.stderr
@@ -10,7 +10,7 @@ error[E0268]: `break` outside of a loop or labeled block
    |
 LL |     break rust
    |     ^^^^^^^^^^ cannot `break` outside of a loop or labeled block
--Ztrack-diagnostics: created at compiler/rustc_passes/src/loops.rs:LL:CC
+-Ztrack-diagnostics: created at compiler/rustc_hir_typeck/src/loops.rs:LL:CC
 
 error: internal compiler error: It looks like you're trying to break rust; would you like some ICE?
   --> $DIR/track.rs:LL:CC
diff --git a/tests/ui/typeck/issue-114529-illegal-break-with-value.stderr b/tests/ui/typeck/issue-114529-illegal-break-with-value.stderr
index de993df722c..872c506c7f1 100644
--- a/tests/ui/typeck/issue-114529-illegal-break-with-value.stderr
+++ b/tests/ui/typeck/issue-114529-illegal-break-with-value.stderr
@@ -1,4 +1,22 @@
 error[E0571]: `break` with value from a `while` loop
+  --> $DIR/issue-114529-illegal-break-with-value.rs:22:9
+   |
+LL |       while true {
+   |       ---------- you can't `break` with a value in a `while` loop
+LL | /         break (|| {
+LL | |             let local = 9;
+LL | |         });
+   | |__________^ can only break with a value inside `loop` or breakable block
+   |
+help: use `break` on its own without a value inside this `while` loop
+   |
+LL -         break (|| {
+LL -             let local = 9;
+LL -         });
+LL +         break;
+   |
+
+error[E0571]: `break` with value from a `while` loop
   --> $DIR/issue-114529-illegal-break-with-value.rs:9:13
    |
 LL |         while true {
@@ -26,24 +44,6 @@ LL -             break v;
 LL +             break;
    |
 
-error[E0571]: `break` with value from a `while` loop
-  --> $DIR/issue-114529-illegal-break-with-value.rs:22:9
-   |
-LL |       while true {
-   |       ---------- you can't `break` with a value in a `while` loop
-LL | /         break (|| {
-LL | |             let local = 9;
-LL | |         });
-   | |__________^ can only break with a value inside `loop` or breakable block
-   |
-help: use `break` on its own without a value inside this `while` loop
-   |
-LL -         break (|| {
-LL -             let local = 9;
-LL -         });
-LL +         break;
-   |
-
 error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0571`.
diff --git a/tests/ui/unsafe/break-inside-unsafe-block-issue-128604.stderr b/tests/ui/unsafe/break-inside-unsafe-block-issue-128604.stderr
index b7cbe1a5cf4..2f01331db9a 100644
--- a/tests/ui/unsafe/break-inside-unsafe-block-issue-128604.stderr
+++ b/tests/ui/unsafe/break-inside-unsafe-block-issue-128604.stderr
@@ -1,10 +1,4 @@
 error[E0268]: `break` outside of a loop or labeled block
-  --> $DIR/break-inside-unsafe-block-issue-128604.rs:2:28
-   |
-LL |     let a = ["_"; unsafe { break; 1 + 2 }];
-   |                            ^^^^^ cannot `break` outside of a loop or labeled block
-
-error[E0268]: `break` outside of a loop or labeled block
   --> $DIR/break-inside-unsafe-block-issue-128604.rs:14:9
    |
 LL |         break;
@@ -37,6 +31,12 @@ LL |         unsafe {
 LL ~             break 'block;
    |
 
+error[E0268]: `break` outside of a loop or labeled block
+  --> $DIR/break-inside-unsafe-block-issue-128604.rs:2:28
+   |
+LL |     let a = ["_"; unsafe { break; 1 + 2 }];
+   |                            ^^^^^ cannot `break` outside of a loop or labeled block
+
 error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0268`.