about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorFabian Wolff <fabian.wolff@alumni.ethz.ch>2021-06-11 01:20:00 +0200
committerFabian Wolff <fabian.wolff@alumni.ethz.ch>2021-06-11 01:20:00 +0200
commitbdddaebd76cba207b67141e2c362a4fe117bbd34 (patch)
tree1ecd5fe6a4cffb808b9a7256c00e058f48477301 /compiler
parent40c1623b16fb28f7625cab13570752d04513815c (diff)
downloadrust-bdddaebd76cba207b67141e2c362a4fe117bbd34.tar.gz
rust-bdddaebd76cba207b67141e2c362a4fe117bbd34.zip
Fix type checking of return expressions outside fn bodies
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_typeck/src/check/expr.rs34
-rw-r--r--compiler/rustc_typeck/src/errors.rs4
2 files changed, 37 insertions, 1 deletions
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index d0cbb58fb10..e9bb2b1c914 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -674,7 +674,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expr: &'tcx hir::Expr<'tcx>,
     ) -> Ty<'tcx> {
         if self.ret_coercion.is_none() {
-            self.tcx.sess.emit_err(ReturnStmtOutsideOfFnBody { span: expr.span });
+            let mut err = ReturnStmtOutsideOfFnBody {
+                span: expr.span,
+                encl_body_span: None,
+                encl_fn_span: None,
+            };
+
+            let encl_item_id = self.tcx.hir().get_parent_item(expr.hir_id);
+            let encl_item = self.tcx.hir().expect_item(encl_item_id);
+
+            if let hir::ItemKind::Fn(..) = encl_item.kind {
+                // We are inside a function body, so reporting "return statement
+                // outside of function body" needs an explanation.
+
+                let encl_body_owner_id = self.tcx.hir().enclosing_body_owner(expr.hir_id);
+
+                // If this didn't hold, we would not have to report an error in
+                // the first place.
+                assert_ne!(encl_item_id, encl_body_owner_id);
+
+                let encl_body_id = self.tcx.hir().body_owned_by(encl_body_owner_id);
+                let encl_body = self.tcx.hir().body(encl_body_id);
+
+                err.encl_body_span = Some(encl_body.value.span);
+                err.encl_fn_span = Some(encl_item.span);
+            }
+
+            self.tcx.sess.emit_err(err);
+
+            if let Some(e) = expr_opt {
+                // We still have to type-check `e` (issue #86188), but calling
+                // `check_return_expr` only works inside fn bodies.
+                self.check_expr(e);
+            }
         } else if let Some(e) = expr_opt {
             if self.ret_coercion_span.get().is_none() {
                 self.ret_coercion_span.set(Some(e.span));
diff --git a/compiler/rustc_typeck/src/errors.rs b/compiler/rustc_typeck/src/errors.rs
index 5068242692a..1a21c085d53 100644
--- a/compiler/rustc_typeck/src/errors.rs
+++ b/compiler/rustc_typeck/src/errors.rs
@@ -147,6 +147,10 @@ pub struct TypeofReservedKeywordUsed {
 pub struct ReturnStmtOutsideOfFnBody {
     #[message = "return statement outside of function body"]
     pub span: Span,
+    #[label = "the return is part of this body..."]
+    pub encl_body_span: Option<Span>,
+    #[label = "...not the enclosing function body"]
+    pub encl_fn_span: Option<Span>,
 }
 
 #[derive(SessionDiagnostic)]