Add checkup for return statement outside of a function

This commit is contained in:
Guillaume Gomez 2016-11-15 16:09:39 +01:00
parent 7537f953e2
commit 5a065641fd
4 changed files with 47 additions and 15 deletions

View File

@ -376,7 +376,8 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
&infcx.parameter_environment.caller_bounds); &infcx.parameter_environment.caller_bounds);
infcx.resolve_regions_and_report_errors(&free_regions, impl_m_body_id); infcx.resolve_regions_and_report_errors(&free_regions, impl_m_body_id);
} else { } 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, &[]); fcx.regionck_item(impl_m_body_id, impl_m_span, &[]);
} }

View File

@ -451,7 +451,7 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
// expects the types within the function to be consistent. // expects the types within the function to be consistent.
err_count_on_creation: usize, err_count_on_creation: usize,
ret_ty: Ty<'tcx>, ret_ty: Option<Ty<'tcx>>,
ps: RefCell<UnsafetyState>, ps: RefCell<UnsafetyState>,
@ -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, // Create the function context. This is either derived from scratch or,
// in the case of function expressions, based on the outer context. // 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.ps.borrow_mut() = UnsafetyState::function(unsafety, unsafety_id);
fcx.require_type_is_sized(fcx.ret_ty, decl.output.span(), traits::ReturnType); fcx.require_type_is_sized(ret_ty, decl.output.span(), traits::ReturnType);
fcx.ret_ty = fcx.instantiate_anon_types(&fcx.ret_ty); 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); 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); 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 fcx
} }
@ -1245,7 +1246,7 @@ fn check_const_with_type<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
expected_type: Ty<'tcx>, expected_type: Ty<'tcx>,
id: ast::NodeId) { id: ast::NodeId) {
ccx.inherited(id).enter(|inh| { 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); fcx.require_type_is_sized(expected_type, expr.span, traits::ConstSized);
// Gather locals in statics (because of block expressions). // Gather locals in statics (because of block expressions).
@ -1530,7 +1531,6 @@ enum TupleArgumentsFlag {
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
pub fn new(inh: &'a Inherited<'a, 'gcx, 'tcx>, pub fn new(inh: &'a Inherited<'a, 'gcx, 'tcx>,
rty: Ty<'tcx>,
body_id: ast::NodeId) body_id: ast::NodeId)
-> FnCtxt<'a, 'gcx, 'tcx> { -> FnCtxt<'a, 'gcx, 'tcx> {
FnCtxt { FnCtxt {
@ -1538,7 +1538,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
body_id: body_id, body_id: body_id,
writeback_errors: Cell::new(false), writeback_errors: Cell::new(false),
err_count_on_creation: inh.tcx.sess.err_count(), err_count_on_creation: inh.tcx.sess.err_count(),
ret_ty: rty, ret_ty: None,
ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal, ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal,
ast::CRATE_NODE_ID)), ast::CRATE_NODE_ID)),
diverges: Cell::new(Diverges::Maybe), diverges: Cell::new(Diverges::Maybe),
@ -3705,14 +3705,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
} }
hir::ExprAgain(_) => { tcx.types.never } hir::ExprAgain(_) => { tcx.types.never }
hir::ExprRet(ref expr_opt) => { hir::ExprRet(ref expr_opt) => {
if let Some(ref e) = *expr_opt { if self.ret_ty.is_none() {
self.check_expr_coercable_to_type(&e, self.ret_ty); 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 { } else {
match self.eq_types(false, match self.eq_types(false,
&self.misc(expr.span), &self.misc(expr.span),
self.ret_ty, self.ret_ty.unwrap(),
tcx.mk_nil()) tcx.mk_nil()) {
{
Ok(ok) => self.register_infer_ok_obligations(ok), Ok(ok) => self.register_infer_ok_obligations(ok),
Err(_) => { Err(_) => {
struct_span_err!(tcx.sess, expr.span, E0069, struct_span_err!(tcx.sess, expr.span, E0069,

View File

@ -51,7 +51,8 @@ impl<'a, 'gcx, 'tcx> CheckWfFcxBuilder<'a, 'gcx, 'tcx> {
let id = self.id; let id = self.id;
let span = self.span; let span = self.span;
self.inherited.enter(|inh| { 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 { let wf_tys = f(&fcx, &mut CheckTypeWellFormedVisitor {
ccx: fcx.ccx, ccx: fcx.ccx,
code: code code: code

View File

@ -4164,6 +4164,34 @@ target / ABI combination is currently unsupported by llvm.
If necessary, you can circumvent this check using custom target specifications. 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! { register_diagnostics! {