Skip to content

Commit 5a06564

Browse files
Add checkup for return statement outside of a function
1 parent 7537f95 commit 5a06564

File tree

4 files changed

+47
-15
lines changed

4 files changed

+47
-15
lines changed

src/librustc_typeck/check/compare_method.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,8 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
376376
&infcx.parameter_environment.caller_bounds);
377377
infcx.resolve_regions_and_report_errors(&free_regions, impl_m_body_id);
378378
} else {
379-
let fcx = FnCtxt::new(&inh, tcx.types.err, impl_m_body_id);
379+
let mut fcx = FnCtxt::new(&inh, impl_m_body_id);
380+
fcx.ret_ty = Some(tcx.types.err);
380381
fcx.regionck_item(impl_m_body_id, impl_m_span, &[]);
381382
}
382383

src/librustc_typeck/check/mod.rs

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -451,7 +451,7 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
451451
// expects the types within the function to be consistent.
452452
err_count_on_creation: usize,
453453

454-
ret_ty: Ty<'tcx>,
454+
ret_ty: Option<Ty<'tcx>>,
455455

456456
ps: RefCell<UnsafetyState>,
457457

@@ -785,11 +785,12 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
785785

786786
// Create the function context. This is either derived from scratch or,
787787
// in the case of function expressions, based on the outer context.
788-
let mut fcx = FnCtxt::new(inherited, fn_sig.output(), body.id);
788+
let mut fcx = FnCtxt::new(inherited, body.id);
789+
let ret_ty = fn_sig.output();
789790
*fcx.ps.borrow_mut() = UnsafetyState::function(unsafety, unsafety_id);
790791

791-
fcx.require_type_is_sized(fcx.ret_ty, decl.output.span(), traits::ReturnType);
792-
fcx.ret_ty = fcx.instantiate_anon_types(&fcx.ret_ty);
792+
fcx.require_type_is_sized(ret_ty, decl.output.span(), traits::ReturnType);
793+
fcx.ret_ty = fcx.instantiate_anon_types(&ret_ty);
793794
fn_sig = fcx.tcx.mk_fn_sig(fn_sig.inputs().iter().cloned(), &fcx.ret_ty, fn_sig.variadic);
794795

795796
{
@@ -821,7 +822,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
821822

822823
inherited.tables.borrow_mut().liberated_fn_sigs.insert(fn_id, fn_sig);
823824

824-
fcx.check_expr_coercable_to_type(body, fcx.ret_ty);
825+
fcx.check_expr_coercable_to_type(body, fcx.ret_ty.unwrap());
825826

826827
fcx
827828
}
@@ -1245,7 +1246,7 @@ fn check_const_with_type<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
12451246
expected_type: Ty<'tcx>,
12461247
id: ast::NodeId) {
12471248
ccx.inherited(id).enter(|inh| {
1248-
let fcx = FnCtxt::new(&inh, expected_type, expr.id);
1249+
let fcx = FnCtxt::new(&inh, expr.id);
12491250
fcx.require_type_is_sized(expected_type, expr.span, traits::ConstSized);
12501251

12511252
// Gather locals in statics (because of block expressions).
@@ -1530,15 +1531,14 @@ enum TupleArgumentsFlag {
15301531

15311532
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
15321533
pub fn new(inh: &'a Inherited<'a, 'gcx, 'tcx>,
1533-
rty: Ty<'tcx>,
15341534
body_id: ast::NodeId)
15351535
-> FnCtxt<'a, 'gcx, 'tcx> {
15361536
FnCtxt {
15371537
ast_ty_to_ty_cache: RefCell::new(NodeMap()),
15381538
body_id: body_id,
15391539
writeback_errors: Cell::new(false),
15401540
err_count_on_creation: inh.tcx.sess.err_count(),
1541-
ret_ty: rty,
1541+
ret_ty: None,
15421542
ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal,
15431543
ast::CRATE_NODE_ID)),
15441544
diverges: Cell::new(Diverges::Maybe),
@@ -3705,14 +3705,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
37053705
}
37063706
hir::ExprAgain(_) => { tcx.types.never }
37073707
hir::ExprRet(ref expr_opt) => {
3708-
if let Some(ref e) = *expr_opt {
3709-
self.check_expr_coercable_to_type(&e, self.ret_ty);
3708+
if self.ret_ty.is_none() {
3709+
struct_span_err!(self.tcx.sess, expr.span, E0571,
3710+
"return statement cannot be out of a function scope").emit();
3711+
} else if let Some(ref e) = *expr_opt {
3712+
self.check_expr_coercable_to_type(&e, self.ret_ty.unwrap());
37103713
} else {
37113714
match self.eq_types(false,
37123715
&self.misc(expr.span),
3713-
self.ret_ty,
3714-
tcx.mk_nil())
3715-
{
3716+
self.ret_ty.unwrap(),
3717+
tcx.mk_nil()) {
37163718
Ok(ok) => self.register_infer_ok_obligations(ok),
37173719
Err(_) => {
37183720
struct_span_err!(tcx.sess, expr.span, E0069,

src/librustc_typeck/check/wfcheck.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ impl<'a, 'gcx, 'tcx> CheckWfFcxBuilder<'a, 'gcx, 'tcx> {
5151
let id = self.id;
5252
let span = self.span;
5353
self.inherited.enter(|inh| {
54-
let fcx = FnCtxt::new(&inh, inh.ccx.tcx.types.never, id);
54+
let mut fcx = FnCtxt::new(&inh, id);
55+
fcx.ret_ty = Some(inh.ccx.tcx.types.never);
5556
let wf_tys = f(&fcx, &mut CheckTypeWellFormedVisitor {
5657
ccx: fcx.ccx,
5758
code: code

src/librustc_typeck/diagnostics.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4164,6 +4164,34 @@ target / ABI combination is currently unsupported by llvm.
41644164
If necessary, you can circumvent this check using custom target specifications.
41654165
"##,
41664166

4167+
E0571: r##"
4168+
A return statement was outside a function scope.
4169+
4170+
Erroneous code example:
4171+
4172+
```compile_fail,E0571
4173+
const FOO: u32 = return 0; // error: return statement cannot be out of a
4174+
// function scope
4175+
4176+
fn main() {}
4177+
```
4178+
4179+
To fix this issue, just remove the return statement or move it into a function
4180+
scope. Example:
4181+
4182+
```
4183+
const FOO: u32 = 0;
4184+
4185+
fn some_fn() -> i32 {
4186+
return FOO;
4187+
}
4188+
4189+
fn main() {
4190+
some_fn();
4191+
}
4192+
```
4193+
"##,
4194+
41674195
}
41684196

41694197
register_diagnostics! {

0 commit comments

Comments
 (0)