diff options
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_mir_build/src/build/matches/mod.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/item.rs | 5 | ||||
| -rw-r--r-- | compiler/rustc_span/src/symbol.rs | 1 | ||||
| -rw-r--r-- | compiler/rustc_typeck/src/check/coercion.rs | 49 |
4 files changed, 54 insertions, 3 deletions
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 58b1564cc5d..cefb5f36b6a 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -2334,7 +2334,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // This place is not really used because this destination place // should never be used to take values at the end of the failure // block. - let dummy_place = Place { local: RETURN_PLACE, projection: ty::List::empty() }; + let dummy_place = self.temp(self.tcx.types.never, else_block.span); let failure_block; unpack!( failure_block = self.ast_block( diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index fb92ce41252..72c23776d33 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -271,7 +271,10 @@ impl<'a> Parser<'a> { // MACRO_RULES ITEM self.parse_item_macro_rules(vis, has_bang)? } else if self.isnt_macro_invocation() - && (self.token.is_ident_named(sym::import) || self.token.is_ident_named(sym::using)) + && (self.token.is_ident_named(sym::import) + || self.token.is_ident_named(sym::using) + || self.token.is_ident_named(sym::include) + || self.token.is_ident_named(sym::require)) { return self.recover_import_as_use(); } else if self.isnt_macro_invocation() && vis.kind.is_pub() { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 791160ff694..f81a69c1cce 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1170,6 +1170,7 @@ symbols! { repr_packed, repr_simd, repr_transparent, + require, residual, result, rhs, diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs index 2ed5f569b4f..0b63b4a63c9 100644 --- a/compiler/rustc_typeck/src/check/coercion.rs +++ b/compiler/rustc_typeck/src/check/coercion.rs @@ -38,10 +38,12 @@ use crate::astconv::AstConv; use crate::check::FnCtxt; use rustc_errors::{ - struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, + struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, }; use rustc_hir as hir; use rustc_hir::def_id::DefId; +use rustc_hir::intravisit::{self, Visitor}; +use rustc_hir::Expr; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{Coercion, InferOk, InferResult}; use rustc_infer::traits::{Obligation, TraitEngine, TraitEngineExt}; @@ -87,6 +89,19 @@ impl<'a, 'tcx> Deref for Coerce<'a, 'tcx> { type CoerceResult<'tcx> = InferResult<'tcx, (Vec<Adjustment<'tcx>>, Ty<'tcx>)>; +struct CollectRetsVisitor<'tcx> { + ret_exprs: Vec<&'tcx hir::Expr<'tcx>>, +} + +impl<'tcx> Visitor<'tcx> for CollectRetsVisitor<'tcx> { + fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { + if let hir::ExprKind::Ret(_) = expr.kind { + self.ret_exprs.push(expr); + } + intravisit::walk_expr(self, expr); + } +} + /// Coercing a mutable reference to an immutable works, while /// coercing `&T` to `&mut T` should be forbidden. fn coerce_mutbls<'tcx>( @@ -1481,6 +1496,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { let mut err; let mut unsized_return = false; + let mut visitor = CollectRetsVisitor { ret_exprs: vec![] }; match *cause.code() { ObligationCauseCode::ReturnNoExpression => { err = struct_span_err!( @@ -1506,6 +1522,10 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { if !fcx.tcx.features().unsized_locals { unsized_return = self.is_return_ty_unsized(fcx, blk_id); } + if let Some(expression) = expression + && let hir::ExprKind::Loop(loop_blk, ..) = expression.kind { + intravisit::walk_block(& mut visitor, loop_blk); + } } ObligationCauseCode::ReturnValue(id) => { err = self.report_return_mismatched_types( @@ -1551,12 +1571,39 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { ); } + if visitor.ret_exprs.len() > 0 && let Some(expr) = expression { + self.note_unreachable_loop_return(&mut err, &expr, &visitor.ret_exprs); + } err.emit_unless(unsized_return); self.final_ty = Some(fcx.tcx.ty_error()); } } } + fn note_unreachable_loop_return<'a>( + &self, + err: &mut DiagnosticBuilder<'a, ErrorGuaranteed>, + expr: &hir::Expr<'tcx>, + ret_exprs: &Vec<&'tcx hir::Expr<'tcx>>, + ) { + let hir::ExprKind::Loop(_, _, _, loop_span) = expr.kind else { return;}; + let mut span: MultiSpan = vec![loop_span].into(); + span.push_span_label(loop_span, "this might have zero elements to iterate on".to_string()); + for ret_expr in ret_exprs { + span.push_span_label( + ret_expr.span, + "if the loop doesn't execute, this value would never get returned".to_string(), + ); + } + err.span_note( + span, + "the function expects a value to always be returned, but loops might run zero times", + ); + err.help( + "return a value for the case when the loop has zero elements to iterate on, or \ + consider changing the return type to account for that possibility", + ); + } fn report_return_mismatched_types<'a>( &self, |
