Auto merge of #37780 - GuillaumeGomez:E0571, r=nikomatsakis
Add checkup for return statement outside of a function Fixes #37778. r? @eddyb (don't know who is in charge. Don't hesitate to set another one) cc @jonathandturner
This commit is contained in:
commit
576a361cd0
@ -376,7 +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 fcx = FnCtxt::new(&inh, tcx.types.err, impl_m_body_id);
|
||||
let fcx = FnCtxt::new(&inh, Some(tcx.types.err), impl_m_body_id);
|
||||
fcx.regionck_item(impl_m_body_id, impl_m_span, &[]);
|
||||
}
|
||||
|
||||
|
@ -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<Ty<'tcx>>,
|
||||
|
||||
ps: RefCell<UnsafetyState>,
|
||||
|
||||
@ -785,12 +785,14 @@ 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, None, 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);
|
||||
fn_sig = fcx.tcx.mk_fn_sig(fn_sig.inputs().iter().cloned(), &fcx.ret_ty, fn_sig.variadic);
|
||||
fcx.require_type_is_sized(ret_ty, decl.output.span(), traits::ReturnType);
|
||||
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, };
|
||||
@ -821,7 +823,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 +1247,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, None, expr.id);
|
||||
fcx.require_type_is_sized(expected_type, expr.span, traits::ConstSized);
|
||||
|
||||
// Gather locals in statics (because of block expressions).
|
||||
@ -1530,7 +1532,7 @@ enum TupleArgumentsFlag {
|
||||
|
||||
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
pub fn new(inh: &'a Inherited<'a, 'gcx, 'tcx>,
|
||||
rty: Ty<'tcx>,
|
||||
rty: Option<Ty<'tcx>>,
|
||||
body_id: ast::NodeId)
|
||||
-> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
FnCtxt {
|
||||
@ -3705,14 +3707,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, 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());
|
||||
} 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,
|
||||
|
@ -51,7 +51,7 @@ 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 fcx = FnCtxt::new(&inh, Some(inh.ccx.tcx.types.never), id);
|
||||
let wf_tys = f(&fcx, &mut CheckTypeWellFormedVisitor {
|
||||
ccx: fcx.ccx,
|
||||
code: code
|
||||
|
@ -4164,6 +4164,33 @@ target / ABI combination is currently unsupported by llvm.
|
||||
If necessary, you can circumvent this check using custom target specifications.
|
||||
"##,
|
||||
|
||||
E0572: r##"
|
||||
A return statement was found outside of a function body.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0572
|
||||
const FOO: u32 = return 0; // error: return statement outside of function body
|
||||
|
||||
fn main() {}
|
||||
```
|
||||
|
||||
To fix this issue, just remove the return keyword or move the expression into a
|
||||
function. Example:
|
||||
|
||||
```
|
||||
const FOO: u32 = 0;
|
||||
|
||||
fn some_fn() -> u32 {
|
||||
return FOO;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
some_fn();
|
||||
}
|
||||
```
|
||||
"##,
|
||||
|
||||
}
|
||||
|
||||
register_diagnostics! {
|
||||
|
13
src/test/compile-fail/E0572.rs
Normal file
13
src/test/compile-fail/E0572.rs
Normal file
@ -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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
const FOO: u32 = return 0; //~ ERROR E0572
|
||||
|
||||
fn main() {}
|
Loading…
Reference in New Issue
Block a user