-
Notifications
You must be signed in to change notification settings - Fork 12.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add checkup for return statement outside of a function #37780
Conversation
4a4a471
to
a519c40
Compare
Please use an informative title, the error number means nothing. |
Didn't pay attention, I thought it took first commit's message by default. My bad. |
const FOO: u32 = 0; | ||
|
||
fn main() { | ||
return FOO; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
returning a value in a function that returns ()
a519c40
to
94d21b5
Compare
@@ -759,6 +759,11 @@ impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for RegionCtxt<'a, 'gcx, 'tcx> { | |||
} | |||
|
|||
hir::ExprRet(Some(ref ret_expr)) => { | |||
if self.call_site_scope.is_none() { | |||
struct_span_err!(self.tcx.sess, expr.span, E0571, | |||
"return statement cannot be out of a function scope").emit(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about "return
can only be used inside a function body"?
It seems a bit odd to do this in regionck
... but I see that for (e.g.) a constant we use the type of the constant as the return type. That seems strange to me! I wonder how hard it would be to change that -- I'd rather have FnCtxt
have a Option<Ty<'tcx>>
as the return type, or at least do the flag in librustc_typeck/check/mod.rs
and not regionck
.
What do you think @eddyb ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm fine with banning it earlier - return for constant values only makes sense in MIR anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So I guess it's not getting merged any time soon... :-/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just have to move it to ExprRet
type-checking, should be straight-forward (except for the condition not being region-related).
const FOO: u32 = 0; | ||
|
||
fn some_fn() -> i32 { | ||
return FOO; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return type mismatch now :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
:-.
fn main() {} | ||
``` | ||
|
||
To fix this issue, just remove the return statement or move it into a function |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wording is not the best here. return foo
is an expression according to the reference, and in the example you want to remove only the return
and not the entire statement.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wut?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Considering the statement/expression grammatical categories, return is an expression according to the reference. So to say "remove the return statement" is imprecise because it's an expression, and misleading because the user might try to remove the entire expression when he should only remove the return
keyword.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I see now. I really didn't understand the first time. :-/
Thanks! :)
6442ec8
to
c843fa2
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking better! :) I left some suggestions on wording and also a request to move the ret_ty
as a parameter to new
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(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: "return statement outside of function body" feels like clearer wording to me. "cannot be out of a function scope" doesn't quite seem grammatical; also, the term "fn scope" is not (I think) quite so standard.
@@ -4163,6 +4163,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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: "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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(This would have to be updated too)
@@ -374,7 +374,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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Huh. It feels weird to me to not have the ret_ty
get passed into the constructor. I see that we (one time) reassigned it later, but now it seems like we almost always do. I think I'd rather we continue to pass in a Option<>
into new
as an argument.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It has to be computed after the fcx
is created anyway, AFAICT (not here though).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From my changes, it was always updated outside so it doesn't change much AFAICT.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The majority of cases do not need to recompute it, from what I can tell. Basically 3/4 :). In one of those cases, the default of None
suffices. So I think it's better to pass it as an argument -- harder to forget that you may want to assign it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It may well be though that in those other cases, None
would also suffice-- I suspect so.
☔ The latest upstream changes (presumably #37717) made this pull request unmergeable. Please resolve the merge conflicts. |
c843fa2
to
34fe31d
Compare
Updated. |
@@ -1195,7 +1196,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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
here it does not need to be recomputed
@@ -50,7 +50,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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
here it does not need to be recomputed
@@ -374,7 +374,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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The majority of cases do not need to recompute it, from what I can tell. Basically 3/4 :). In one of those cases, the default of None
suffices. So I think it's better to pass it as an argument -- harder to forget that you may want to assign it.
@@ -374,7 +374,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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It may well be though that in those other cases, None
would also suffice-- I suspect so.
@bors: r=nikomatsakis |
📌 Commit dd938bc has been approved by |
⌛ Testing commit dd938bc with merge f42e53f... |
💔 Test failed - auto-win-gnu-32-opt-rustbuild |
@nikomatsakis: @eddyb: We have quite a huge issue here in
|
I wonder if the MIR sanity checker should use |
@eddyb: |
@rust-lang/compiler What should we do about MIR typeck and |
@eddyb Hmm. I am not crazy about having the MIR type-checker use I am not crazy about it because my plan is to use the MIR type-checker as the basis for region checking, and I guess that in that mode, we would want to behave like the real region checker. I think we should use |
So, what should I do about this? |
☔ The latest upstream changes (presumably #38097) made this pull request unmergeable. Please resolve the merge conflicts. |
@nikomatsakis: Seems like the last master update fixed the issue. Should be ready to get merged! |
Ok, so someone added an E0571 meanwhile so I had to update mine to E0572. Should be good now. |
@GuillaumeGomez still has an X...do you see why? |
Travis is broken -- it fails this way on all PRs before running most of the tests. |
Just like @jseyfried said. New rustbuild issue if I'm not mistaken. I r+ in your name, don't hesitate to r- if you see anything. @bors: r=nikomatsakis |
📌 Commit ed3c483 has been approved by |
⌛ Testing commit ed3c483 with merge 576a361... |
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
Fixes #37778.
r? @eddyb (don't know who is in charge. Don't hesitate to set another one)
cc @jonathandturner