Skip to content
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

Merged
merged 5 commits into from
Dec 10, 2016

Conversation

GuillaumeGomez
Copy link
Member

Fixes #37778.

r? @eddyb (don't know who is in charge. Don't hesitate to set another one)

cc @jonathandturner

@eddyb
Copy link
Member

eddyb commented Nov 15, 2016

Please use an informative title, the error number means nothing.
LGTM. r? @nikomatsakis on the choice of fix.

@rust-highfive rust-highfive assigned nikomatsakis and unassigned eddyb Nov 15, 2016
@GuillaumeGomez GuillaumeGomez changed the title E0571 Add checkup for return statement outside of a function Nov 15, 2016
@GuillaumeGomez
Copy link
Member Author

GuillaumeGomez commented Nov 15, 2016

Didn't pay attention, I thought it took first commit's message by default. My bad.

const FOO: u32 = 0;

fn main() {
return FOO;
Copy link
Contributor

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 ()

@@ -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();
Copy link
Contributor

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 ?

Copy link
Member

@eddyb eddyb Nov 15, 2016

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.

Copy link
Member Author

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... :-/

Copy link
Member

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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return type mismatch now :)

Copy link
Member Author

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
Copy link
Contributor

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.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wut?

Copy link
Contributor

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.

Copy link
Member Author

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! :)

Copy link
Contributor

@nikomatsakis nikomatsakis left a 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();
Copy link
Contributor

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.
Copy link
Contributor

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
Copy link
Contributor

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);
Copy link
Contributor

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.

Copy link
Member

@eddyb eddyb Nov 16, 2016

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).

Copy link
Member Author

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.

Copy link
Contributor

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.

Copy link
Contributor

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
Copy link
Contributor

bors commented Nov 17, 2016

☔ The latest upstream changes (presumably #37717) made this pull request unmergeable. Please resolve the merge conflicts.

@GuillaumeGomez
Copy link
Member Author

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);
Copy link
Contributor

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);
Copy link
Contributor

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);
Copy link
Contributor

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);
Copy link
Contributor

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.

@GuillaumeGomez
Copy link
Member Author

@bors: r=nikomatsakis

@bors
Copy link
Contributor

bors commented Nov 17, 2016

📌 Commit dd938bc has been approved by nikomatsakis

@bors
Copy link
Contributor

bors commented Nov 19, 2016

⌛ Testing commit dd938bc with merge f42e53f...

@bors
Copy link
Contributor

bors commented Nov 19, 2016

💔 Test failed - auto-win-gnu-32-opt-rustbuild

@GuillaumeGomez
Copy link
Member Author

@nikomatsakis: @eddyb: We have quite a huge issue here in src/test/ui/span/loan-extend.rs:

warning: broken MIR (_0 = ()): bad assignment (impl std::marker::Copy = ()): Sorts(ExpectedFound { expected: impl std::marker::Copy, found: () })
  --> src/test/ui/span/loan-extend.rs:14:47
   |
14 | fn borrow<'a, T>(_: &'a mut T) -> impl Copy { () }
   |                                               ^^

@eddyb
Copy link
Member

eddyb commented Nov 19, 2016

I wonder if the MIR sanity checker should use Reveal::All for that (or just special-case impl Trait).

@GuillaumeGomez
Copy link
Member Author

@eddyb: Reveal::All? Is it something at a lower level?

@eddyb
Copy link
Member

eddyb commented Nov 24, 2016

@rust-lang/compiler What should we do about MIR typeck and impl Trait?

@eddyb eddyb added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Nov 24, 2016
@nikomatsakis
Copy link
Contributor

@eddyb Hmm. I am not crazy about having the MIR type-checker use Reveal::All, but I guess if we don't, we would need to add some sort of cast into and out of the impl Trait existential.

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 Reveal::All but add a FIXME and open an associated issue. We can fix it later.

@GuillaumeGomez
Copy link
Member Author

So, what should I do about this?

@bors
Copy link
Contributor

bors commented Dec 6, 2016

☔ The latest upstream changes (presumably #38097) made this pull request unmergeable. Please resolve the merge conflicts.

@GuillaumeGomez
Copy link
Member Author

@nikomatsakis: Seems like the last master update fixed the issue. Should be ready to get merged!

@GuillaumeGomez
Copy link
Member Author

Ok, so someone added an E0571 meanwhile so I had to update mine to E0572. Should be good now.

@GuillaumeGomez
Copy link
Member Author

cc @nikomatsakis

@nikomatsakis
Copy link
Contributor

@GuillaumeGomez still has an X...do you see why?

@jseyfried
Copy link
Contributor

Travis is broken -- it fails this way on all PRs before running most of the tests.

@GuillaumeGomez
Copy link
Member Author

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

@bors
Copy link
Contributor

bors commented Dec 10, 2016

📌 Commit ed3c483 has been approved by nikomatsakis

@bors
Copy link
Contributor

bors commented Dec 10, 2016

⌛ Testing commit ed3c483 with merge 576a361...

bors added a commit that referenced this pull request Dec 10, 2016
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
@bors bors merged commit ed3c483 into rust-lang:master Dec 10, 2016
@GuillaumeGomez GuillaumeGomez deleted the E0571 branch December 11, 2016 21:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants