From 5a065641fda719b1eeac85419981fee9d1122ded Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 15 Nov 2016 16:09:39 +0100 Subject: [PATCH 1/5] Add checkup for return statement outside of a function --- src/librustc_typeck/check/compare_method.rs | 3 ++- src/librustc_typeck/check/mod.rs | 28 +++++++++++---------- src/librustc_typeck/check/wfcheck.rs | 3 ++- src/librustc_typeck/diagnostics.rs | 28 +++++++++++++++++++++ 4 files changed, 47 insertions(+), 15 deletions(-) diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index e85dac1a44c44..21b0b5e629012 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -376,7 +376,8 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, &infcx.parameter_environment.caller_bounds); infcx.resolve_regions_and_report_errors(&free_regions, impl_m_body_id); } else { - let fcx = FnCtxt::new(&inh, tcx.types.err, impl_m_body_id); + let mut fcx = FnCtxt::new(&inh, impl_m_body_id); + fcx.ret_ty = Some(tcx.types.err); fcx.regionck_item(impl_m_body_id, impl_m_span, &[]); } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 1b35081d5241c..755ea718f8957 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -451,7 +451,7 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { // expects the types within the function to be consistent. err_count_on_creation: usize, - ret_ty: Ty<'tcx>, + ret_ty: Option>, ps: RefCell, @@ -785,11 +785,12 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, // Create the function context. This is either derived from scratch or, // in the case of function expressions, based on the outer context. - let mut fcx = FnCtxt::new(inherited, fn_sig.output(), body.id); + let mut fcx = FnCtxt::new(inherited, body.id); + let ret_ty = fn_sig.output(); *fcx.ps.borrow_mut() = UnsafetyState::function(unsafety, unsafety_id); - fcx.require_type_is_sized(fcx.ret_ty, decl.output.span(), traits::ReturnType); - fcx.ret_ty = fcx.instantiate_anon_types(&fcx.ret_ty); + fcx.require_type_is_sized(ret_ty, decl.output.span(), traits::ReturnType); + fcx.ret_ty = fcx.instantiate_anon_types(&ret_ty); fn_sig = fcx.tcx.mk_fn_sig(fn_sig.inputs().iter().cloned(), &fcx.ret_ty, fn_sig.variadic); { @@ -821,7 +822,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, inherited.tables.borrow_mut().liberated_fn_sigs.insert(fn_id, fn_sig); - fcx.check_expr_coercable_to_type(body, fcx.ret_ty); + fcx.check_expr_coercable_to_type(body, fcx.ret_ty.unwrap()); fcx } @@ -1245,7 +1246,7 @@ fn check_const_with_type<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>, expected_type: Ty<'tcx>, id: ast::NodeId) { ccx.inherited(id).enter(|inh| { - let fcx = FnCtxt::new(&inh, expected_type, expr.id); + let fcx = FnCtxt::new(&inh, expr.id); fcx.require_type_is_sized(expected_type, expr.span, traits::ConstSized); // Gather locals in statics (because of block expressions). @@ -1530,7 +1531,6 @@ enum TupleArgumentsFlag { impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn new(inh: &'a Inherited<'a, 'gcx, 'tcx>, - rty: Ty<'tcx>, body_id: ast::NodeId) -> FnCtxt<'a, 'gcx, 'tcx> { FnCtxt { @@ -1538,7 +1538,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { body_id: body_id, writeback_errors: Cell::new(false), err_count_on_creation: inh.tcx.sess.err_count(), - ret_ty: rty, + ret_ty: None, ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal, ast::CRATE_NODE_ID)), diverges: Cell::new(Diverges::Maybe), @@ -3705,14 +3705,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } hir::ExprAgain(_) => { tcx.types.never } hir::ExprRet(ref expr_opt) => { - if let Some(ref e) = *expr_opt { - self.check_expr_coercable_to_type(&e, self.ret_ty); + if self.ret_ty.is_none() { + struct_span_err!(self.tcx.sess, expr.span, E0571, + "return statement cannot be out of a function scope").emit(); + } else if let Some(ref e) = *expr_opt { + self.check_expr_coercable_to_type(&e, self.ret_ty.unwrap()); } else { match self.eq_types(false, &self.misc(expr.span), - self.ret_ty, - tcx.mk_nil()) - { + self.ret_ty.unwrap(), + tcx.mk_nil()) { Ok(ok) => self.register_infer_ok_obligations(ok), Err(_) => { struct_span_err!(tcx.sess, expr.span, E0069, diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 7f35c8efeff41..6942bb0934c4a 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -51,7 +51,8 @@ impl<'a, 'gcx, 'tcx> CheckWfFcxBuilder<'a, 'gcx, 'tcx> { let id = self.id; let span = self.span; self.inherited.enter(|inh| { - let fcx = FnCtxt::new(&inh, inh.ccx.tcx.types.never, id); + let mut fcx = FnCtxt::new(&inh, id); + fcx.ret_ty = Some(inh.ccx.tcx.types.never); let wf_tys = f(&fcx, &mut CheckTypeWellFormedVisitor { ccx: fcx.ccx, code: code diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 01e99a296e886..65b606b45823c 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4164,6 +4164,34 @@ target / ABI combination is currently unsupported by llvm. If necessary, you can circumvent this check using custom target specifications. "##, +E0571: r##" +A return statement was outside a function scope. + +Erroneous code example: + +```compile_fail,E0571 +const FOO: u32 = return 0; // error: return statement cannot be out of a + // function scope + +fn main() {} +``` + +To fix this issue, just remove the return statement or move it into a function +scope. Example: + +``` +const FOO: u32 = 0; + +fn some_fn() -> i32 { + return FOO; +} + +fn main() { + some_fn(); +} +``` +"##, + } register_diagnostics! { From 8dee5ab805298bcb095a262787ddf60cc48b10ba Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 15 Nov 2016 16:11:06 +0100 Subject: [PATCH 2/5] Add E0571 test --- src/librustc_typeck/check/mod.rs | 2 +- src/librustc_typeck/diagnostics.rs | 11 +++++------ src/test/compile-fail/E0571.rs | 13 +++++++++++++ 3 files changed, 19 insertions(+), 7 deletions(-) create mode 100644 src/test/compile-fail/E0571.rs diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 755ea718f8957..1ace79b0c55b3 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3707,7 +3707,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { hir::ExprRet(ref expr_opt) => { if self.ret_ty.is_none() { struct_span_err!(self.tcx.sess, expr.span, E0571, - "return statement cannot be out of a function scope").emit(); + "return statement outside of function body").emit(); } else if let Some(ref e) = *expr_opt { self.check_expr_coercable_to_type(&e, self.ret_ty.unwrap()); } else { diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 65b606b45823c..86220cf57c443 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4165,24 +4165,23 @@ If necessary, you can circumvent this check using custom target specifications. "##, E0571: r##" -A return statement was outside a function scope. +A return statement was found outside of a function body. Erroneous code example: ```compile_fail,E0571 -const FOO: u32 = return 0; // error: return statement cannot be out of a - // function scope +const FOO: u32 = return 0; // error: return statement outside of function body fn main() {} ``` -To fix this issue, just remove the return statement or move it into a function -scope. Example: +To fix this issue, just remove the return keyword or move the expression into a +function. Example: ``` const FOO: u32 = 0; -fn some_fn() -> i32 { +fn some_fn() -> u32 { return FOO; } diff --git a/src/test/compile-fail/E0571.rs b/src/test/compile-fail/E0571.rs new file mode 100644 index 0000000000000..d300c59700820 --- /dev/null +++ b/src/test/compile-fail/E0571.rs @@ -0,0 +1,13 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +const FOO: u32 = return 0; //~ ERROR E0571 + +fn main() {} From 64de44e0a12a1b933d8d01a9873cf030be2af214 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 17 Nov 2016 22:47:30 +0100 Subject: [PATCH 3/5] Set back Ty parameter to FnCntxt --- src/librustc_typeck/check/compare_method.rs | 3 +-- src/librustc_typeck/check/mod.rs | 7 ++++--- src/librustc_typeck/check/wfcheck.rs | 3 +-- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 21b0b5e629012..478de1673170f 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -376,8 +376,7 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, &infcx.parameter_environment.caller_bounds); infcx.resolve_regions_and_report_errors(&free_regions, impl_m_body_id); } else { - let mut fcx = FnCtxt::new(&inh, impl_m_body_id); - fcx.ret_ty = Some(tcx.types.err); + let fcx = FnCtxt::new(&inh, Some(tcx.types.err), impl_m_body_id); fcx.regionck_item(impl_m_body_id, impl_m_span, &[]); } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 1ace79b0c55b3..a43ec0aaf11f1 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -785,7 +785,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, // Create the function context. This is either derived from scratch or, // in the case of function expressions, based on the outer context. - let mut fcx = FnCtxt::new(inherited, body.id); + let mut fcx = FnCtxt::new(inherited, None, body.id); let ret_ty = fn_sig.output(); *fcx.ps.borrow_mut() = UnsafetyState::function(unsafety, unsafety_id); @@ -1246,7 +1246,7 @@ fn check_const_with_type<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>, expected_type: Ty<'tcx>, id: ast::NodeId) { ccx.inherited(id).enter(|inh| { - let fcx = FnCtxt::new(&inh, expr.id); + let fcx = FnCtxt::new(&inh, None, expr.id); fcx.require_type_is_sized(expected_type, expr.span, traits::ConstSized); // Gather locals in statics (because of block expressions). @@ -1531,6 +1531,7 @@ enum TupleArgumentsFlag { impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn new(inh: &'a Inherited<'a, 'gcx, 'tcx>, + rty: Option>, body_id: ast::NodeId) -> FnCtxt<'a, 'gcx, 'tcx> { FnCtxt { @@ -1538,7 +1539,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { body_id: body_id, writeback_errors: Cell::new(false), err_count_on_creation: inh.tcx.sess.err_count(), - ret_ty: None, + ret_ty: rty, ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal, ast::CRATE_NODE_ID)), diverges: Cell::new(Diverges::Maybe), diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 6942bb0934c4a..ffdb56753fdc1 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -51,8 +51,7 @@ impl<'a, 'gcx, 'tcx> CheckWfFcxBuilder<'a, 'gcx, 'tcx> { let id = self.id; let span = self.span; self.inherited.enter(|inh| { - let mut fcx = FnCtxt::new(&inh, id); - fcx.ret_ty = Some(inh.ccx.tcx.types.never); + let fcx = FnCtxt::new(&inh, Some(inh.ccx.tcx.types.never), id); let wf_tys = f(&fcx, &mut CheckTypeWellFormedVisitor { ccx: fcx.ccx, code: code From b1dd793acdde01f7fb50b7c29bc6519e4ce3f22a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 6 Dec 2016 15:32:30 -0800 Subject: [PATCH 4/5] Update to last master --- src/librustc_typeck/check/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index a43ec0aaf11f1..abc1c5e4b4cc9 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -790,8 +790,9 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, *fcx.ps.borrow_mut() = UnsafetyState::function(unsafety, unsafety_id); fcx.require_type_is_sized(ret_ty, decl.output.span(), traits::ReturnType); - fcx.ret_ty = fcx.instantiate_anon_types(&ret_ty); - fn_sig = fcx.tcx.mk_fn_sig(fn_sig.inputs().iter().cloned(), &fcx.ret_ty, fn_sig.variadic); + fcx.ret_ty = fcx.instantiate_anon_types(&Some(ret_ty)); + fn_sig = fcx.tcx.mk_fn_sig(fn_sig.inputs().iter().cloned(), &fcx.ret_ty.unwrap(), + fn_sig.variadic); { let mut visit = GatherLocalsVisitor { fcx: &fcx, }; From ed3c483aa8472bf791718d6f157e4e55873e7e5d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 8 Dec 2016 20:49:26 -0800 Subject: [PATCH 5/5] Change error to E0572 --- src/librustc_typeck/check/mod.rs | 2 +- src/librustc_typeck/diagnostics.rs | 4 ++-- src/test/compile-fail/{E0571.rs => E0572.rs} | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) rename src/test/compile-fail/{E0571.rs => E0572.rs} (91%) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index abc1c5e4b4cc9..9c8d7caefe5ff 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3708,7 +3708,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { hir::ExprAgain(_) => { tcx.types.never } hir::ExprRet(ref expr_opt) => { if self.ret_ty.is_none() { - struct_span_err!(self.tcx.sess, expr.span, E0571, + struct_span_err!(self.tcx.sess, expr.span, E0572, "return statement outside of function body").emit(); } else if let Some(ref e) = *expr_opt { self.check_expr_coercable_to_type(&e, self.ret_ty.unwrap()); diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 86220cf57c443..71507063ffc43 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4164,12 +4164,12 @@ target / ABI combination is currently unsupported by llvm. If necessary, you can circumvent this check using custom target specifications. "##, -E0571: r##" +E0572: r##" A return statement was found outside of a function body. Erroneous code example: -```compile_fail,E0571 +```compile_fail,E0572 const FOO: u32 = return 0; // error: return statement outside of function body fn main() {} diff --git a/src/test/compile-fail/E0571.rs b/src/test/compile-fail/E0572.rs similarity index 91% rename from src/test/compile-fail/E0571.rs rename to src/test/compile-fail/E0572.rs index d300c59700820..bbaab102de7db 100644 --- a/src/test/compile-fail/E0571.rs +++ b/src/test/compile-fail/E0572.rs @@ -8,6 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -const FOO: u32 = return 0; //~ ERROR E0571 +const FOO: u32 = return 0; //~ ERROR E0572 fn main() {}