Change:
<!-- Thank you for filing a bug report! Please provide a short summary of the bug, along with any information you feel relevant to replicating the bug. If you cannot produce a minimal reproduction case (something that would work in isolation), please provide the steps or even link to a repository that causes the problematic output to occur. --Given the following code: The current output is: Ideally the output should look like: <!-- If the problem is not self-explanatory, please provide a rationale for the change. --It may not be immediately clear to a user why implicit-return/break style works for expressions, but not for . Adding a hint to explicitly break with would be helpful. <!-- If dramatically different output is caused by small changes, consider also adding them here. If you're using the stable version of the compiler, you should also check if the bug also exists in the beta or nightly versions. The output might also be different depending on the Edition. --<!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOTEND --
label +A-suggestion-diagnostics
claim

Discussion:
if let (Some((expr, _)), Some((fn_decl, _, _))) = (expression, fcx.get_node_fn_decl(parent_item)) { <del> fcx.suggest_missing_return_expr(&mut err, expr, fn_decl, expected, found, parent_id); </del> <ins> fcx.suggest_missing_break_or_return_expr( &mut err, expr, fn_decl, expected, found, id, parent_id, ); </ins> } if let (Some(sp), Some(fn_output)) = (fcx.ret_coercion_span.get(), fn_output) {

use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind}; use rustc_hir::lang_items::LangItem; <del> use rustc_hir::{ExprKind, ItemKind, Node}; </del> <ins> use rustc_hir::{Expr, ExprKind, ItemKind, Node, Stmt, StmtKind}; </ins> use rustc_infer::infer; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Binder, Ty};

pointing_at_return_type = self.suggest_missing_return_type(err, &fn_decl, expected, found, can_suggest); let fn_id = self.tcx.hir().get_return_block(blk_id).unwrap(); <del> self.suggest_missing_return_expr(err, expr, &fn_decl, expected, found, fn_id); </del> <ins> self.suggest_missing_break_or_return_expr( err, expr, &fn_decl, expected, found, blk_id, fn_id, ); </ins> } pointing_at_return_type }

} } <del> pub(in super::super) fn suggest_missing_return_expr( </del> <ins> pub(in super::super) fn suggest_missing_break_or_return_expr( </ins> &self, err: &mut DiagnosticBuilder<'_>, expr: &'tcx hir::Expr<'tcx>,

expected: Ty<'tcx>, found: Ty<'tcx>, id: hir::HirId, <ins> fn_id: hir::HirId, </ins> ) { if !expected.is_unit() { return; } let found = self.resolve_vars_with_obligations(found); <ins> let in_loop = self.is_loop(id) || self.tcx.hir().parent_iter(id).any(|(parent_id, _)| self.is_loop(parent_id)); let in_local_statement = self.is_local_statement(id) || self .tcx .hir() .parent_iter(id) .any(|(parent_id, _)| self.is_local_statement(parent_id)); if in_loop && in_local_statement { err.multipart_suggestion( "you might have meant to break the loop with this value", vec![ (expr.span.shrink_to_lo(), "break ".to_string()), (expr.span.shrink_to_hi(), ";".to_string()), ], Applicability::MaybeIncorrect, ); return; } </ins> if let hir::FnRetTy::Return(ty) = fn_decl.output { let ty = <dyn AstConv<'_>>::ast_ty_to_ty(self, ty); <del> let bound_vars = self.tcx.late_bound_vars(id); </del> <ins> let bound_vars = self.tcx.late_bound_vars(fn_id); </ins> let ty = self.tcx.erase_late_bound_regions(Binder::bind_with_vars(ty, bound_vars)); let ty = self.normalize_associated_types_in(expr.span, ty); if self.can_coerce(found, ty) {

self.tcx.sess.parse_sess.expr_parentheses_needed(err, *sp, None); } } <ins> fn is_loop(&self, id: hir::HirId) -> bool { let node = self.tcx.hir().get(id); matches!(node, Node::Expr(Expr { kind: ExprKind::Loop(..), .. })) } fn is_local_statement(&self, id: hir::HirId) -> bool { let node = self.tcx.hir().get(id); matches!(node, Node::Stmt(Stmt { kind: StmtKind::Local(..), .. })) } </ins> }

<ins> fn main() { let a: i8 = loop { 1 //~ ERROR mismatched types }; let b: i8 = loop { break 1; }; } fn foo() -> i8 { let a: i8 = loop { 1 //~ ERROR mismatched types }; let b: i8 = loop { break 1; }; loop { 1 //~ ERROR mismatched types } loop { return 1; } loop { 1 //~ ERROR mismatched types } } </ins>

<ins> error[E0308]: mismatched types --> $DIR/loop-no-implicit-break.rs:3:9 | LL |         1 |         ^ expected `()`, found integer | help: you might have meant to break the loop with this value | LL |         break 1; |         ^^^^^  ^ error[E0308]: mismatched types --> $DIR/loop-no-implicit-break.rs:13:9 | LL |         1 |         ^ expected `()`, found integer | help: you might have meant to break the loop with this value | LL |         break 1; |         ^^^^^  ^ error[E0308]: mismatched types --> $DIR/loop-no-implicit-break.rs:21:9 | LL |         1 |         ^ expected `()`, found integer | help: you might have meant to return this value | LL |         return 1; |         ^^^^^^  ^ error[E0308]: mismatched types --> $DIR/loop-no-implicit-break.rs:29:9 | LL |         1 |         ^ expected `()`, found integer | help: you might have meant to return this value | LL |         return 1; |         ^^^^^^  ^ error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0308`. </ins>