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

[NLL] false edges on infinite loops #46036

Closed
nikomatsakis opened this issue Nov 16, 2017 · 12 comments · Fixed by #47802
Closed

[NLL] false edges on infinite loops #46036

nikomatsakis opened this issue Nov 16, 2017 · 12 comments · Fixed by #47802
Assignees
Labels
A-NLL Area: Non-lexical lifetimes (NLL) C-enhancement Category: An issue proposing an enhancement or a PR with one. E-mentor Call for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@nikomatsakis
Copy link
Contributor

The NLL RFC specifies false edges on infinite loops, so that we get errors in some cases. This is a somewhat disputed clause (see nikomatsakis/nll-rfc#35) that we may change, but it makes sense for now. I'm filing this so we don't forget about it.

@nikomatsakis nikomatsakis added T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. WG-compiler-nll labels Nov 16, 2017
@arielb1 arielb1 added this to the NLL prototype milestone Nov 21, 2017
@nikomatsakis nikomatsakis removed this from the NLL prototype milestone Dec 12, 2017
@nikomatsakis
Copy link
Contributor Author

So @mikhail-m1 added the notion of "false edges" in #45384. This seems to be roughly what is needed here. We would want to edit the code that generates a loop construct:

ExprKind::Loop { condition: opt_cond_expr, body } => {
// [block] --> [loop_block] ~~> [loop_block_end] -1-> [exit_block]
// ^ |
// | 0
// | |
// | v
// [body_block_end] <~~~ [body_block]
//
// If `opt_cond_expr` is `None`, then the graph is somewhat simplified:
//
// [block] --> [loop_block / body_block ] ~~> [body_block_end] [exit_block]
// ^ |
// | |
// +--------------------------+
//
let loop_block = this.cfg.start_new_block();
let exit_block = this.cfg.start_new_block();
// start the loop
this.cfg.terminate(block, source_info,
TerminatorKind::Goto { target: loop_block });
this.in_breakable_scope(
Some(loop_block), exit_block, destination.clone(),
move |this| {
// conduct the test, if necessary
let body_block;
if let Some(cond_expr) = opt_cond_expr {
let loop_block_end;
let cond = unpack!(
loop_block_end = this.as_local_operand(loop_block, cond_expr));
body_block = this.cfg.start_new_block();
let term = TerminatorKind::if_(this.hir.tcx(), cond,
body_block, exit_block);
this.cfg.terminate(loop_block_end, source_info, term);
// if the test is false, there's no `break` to assign `destination`, so
// we have to do it; this overwrites any `break`-assigned value but it's
// always `()` anyway
this.cfg.push_assign_unit(exit_block, source_info, destination);
} else {
body_block = loop_block;
}
// The “return” value of the loop body must always be an unit. We therefore
// introduce a unit temporary as the destination for the loop body.
let tmp = this.get_unit_temp();
// Execute the body, branching back to the test.
let body_block_end = unpack!(this.into(&tmp, body_block, body));
this.cfg.terminate(body_block_end, source_info,
TerminatorKind::Goto { target: loop_block });
}
);
exit_block.unit()
}

and modify the graph in the case where condition is None:

body_block = loop_block;

so that we create a FalseEdges that "breaks out".

@nikomatsakis nikomatsakis added the E-mentor Call for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion. label Jan 17, 2018
@nikomatsakis
Copy link
Contributor Author

Added some mentoring instructions to this NLL issue. Can elaborate as needed!

cc nll folks:

@davidtwco
@chrisvittal
@pnkfelix
@spastorino
@Nashenas88
@gaurikholkar
@qmx
@Pulkit07
@ritiek

@Pulkit07
Copy link
Contributor

I am trying to fix this one. I have already a kind of patch ready, need to dump MIR and see if it's doing the right thing.

@nikomatsakis
Copy link
Contributor Author

@Pulkit07 nice :)

@Pulkit07
Copy link
Contributor

This might take some time, I getting core dumped error, I need to learn about what's happening before moving things here and there. If this is required to be fixed urgently, I am good with someone else fixing it.

@nikomatsakis
Copy link
Contributor Author

@Pulkit07 woah, core dumped?! When do you get the error, when bootstrapping?

@Pulkit07
Copy link
Contributor

@nikomatsakis I am getting this error when running tests like src/test/run-pass/auto-loop.rs, src/test/run-pass/break.rs and many others.

@nikomatsakis
Copy link
Contributor Author

@Pulkit07 even if you don't have time to continue working, it'd be helpful if you could post the diff somewhere of how far you got

@nikomatsakis
Copy link
Contributor Author

From gitter, here is the diff https://bpaste.net/show/ac4eab0ead8e

@sapphire-arches
Copy link
Contributor

sapphire-arches commented Jan 23, 2018

So playing with implementing this I've run in to a stumbling block. It seems like TerminatorKind::FalseEdges is mostly intended for use where control flow could sort-of follow the false edge in "normal" execution; the motivating example being things being moved in match arm guards. However in the situation mentioned here, control flow truly follows the false edge in "exceptional" circumstances (panics). The trouble is that there are a number of analysis passes that don't handle this and I'm not sure how to get that knowledge in to them. The first one I've run in to is MIR typeck:

fn oh_no1() -> i32 {
    loop {
         return 1;
    }
    // we abort here since the fake edge means MIR typeck tries to assert that () == i32
    // even though the only way we can get here is if we're unwinding and at that point the
    // return value doesn't matter
}

@nikomatsakis
Copy link
Contributor Author

@bobtwinkles

Ah, very good point! You are correct that this control flow is supposed to be like a "false unwind".

My instructions were wrong in this respect. We want the false edge not to "break out" but rather to go to an unwinding target. Basically, where we would unwind to, if we were unwinding. The method to get such a block is diverge_cleanup, iirc:

/// Creates a path that performs all required cleanup for unwinding.
///
/// This path terminates in Resume. Returns the start of the path.
/// See module comment for more details. None indicates there’s no
/// cleanup to do at this point.
pub fn diverge_cleanup(&mut self) -> BasicBlock {
self.diverge_cleanup_gen(false)
}

I'm not sure whether we will have to further modify FalseEdges to distinguish between a "false unwinding" edge and a "false normal" edge. If so, we can probably just add a boolean flag or something like that.

@nikomatsakis
Copy link
Contributor Author

Here is a test case that @bobtwinkles and I discussed on IRC:

https://play.rust-lang.org/?gist=f9b57ba12faa3e9bc8e4a4d523d58736&version=nightly

Right now, it ICEs, but it also ought to be reporting an error if this is all working correctly.

@jkordish jkordish added A-NLL Area: Non-lexical lifetimes (NLL) C-enhancement Category: An issue proposing an enhancement or a PR with one. labels Feb 7, 2018
sapphire-arches added a commit to sapphire-arches/rust that referenced this issue Feb 7, 2018
bors added a commit that referenced this issue Feb 9, 2018
[NLL] Add false edges out of infinite loops

Resolves #46036 by adding a `cleanup` member to the `FalseEdges` terminator kind. There's also a small doc fix to one of the other comments in `into.rs` which I can pull out in to another PR if desired =)

This PR should pass CI but the test suite has been relatively unstable on my system so I'm not 100% sure.

r? @nikomatsakis
JohnTitor referenced this issue in JohnTitor/rust Feb 1, 2021
…chenkov

Move some tests to more reasonable directories - 3

cc rust-lang#73494
r? `@petrochenkov`

https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-56202.rs <sup>https://github.com/rust-lang/rust/issues/56202</sup>: traits 1.008
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-69841.rs <sup>https://github.com/rust-lang/rust/issues/69841</sup>: for-loop-while 1.014
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-10763.rs <sup>https://github.com/rust-lang/rust/issues/10763</sup>: extern 1.016
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-50599.rs <sup>https://github.com/rust-lang/rust/issues/50599</sup>: resolve 1.018
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-6128.rs <sup>https://github.com/rust-lang/rust/issues/6128</sup>: traits 1.043
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-20616-8.rs <sup>https://github.com/rust-lang/rust/issues/20616</sup>: parser 1.045
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-46553.rs <sup>https://github.com/rust-lang/rust/issues/46553</sup>: consts 1.081
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-33140-hack-boundaries.rs <sup>https://github.com/rust-lang/rust/issues/33140</sup>: traits 1.101
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-25826.rs <sup>https://github.com/rust-lang/rust/issues/25826</sup>: consts 1.108
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-56488.rs <sup>https://github.com/rust-lang/rust/issues/56488</sup>: traits 1.110
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-58856-1.rs <sup>https://github.com/rust-lang/rust/issues/58856</sup>: parser 1.133
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-57819.rs <sup>https://github.com/rust-lang/rust/issues/57819</sup>: parser 1.138
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-54348.rs <sup>https://github.com/rust-lang/rust/issues/54348</sup>: consts 1.155
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-14309.rs <sup>https://github.com/rust-lang/rust/issues/14309</sup>: lint 1.160
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-4446.rs <sup>https://github.com/rust-lang/rust/issues/4446</sup>: threads-sendsync 1.203
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-53675-a-test-called-panic.rs <sup>https://github.com/rust-lang/rust/issues/53675</sup>: test-attrs 1.211
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-40231-2.rs <sup>https://github.com/rust-lang/rust/issues/40231</sup>: consts 1.213
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-22037.rs <sup>https://github.com/rust-lang/rust/issues/22037</sup>: associated-types 1.214
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-59029-2.rs <sup>https://github.com/rust-lang/rust/issues/59029</sup>: traits 1.219
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-18425.rs <sup>https://github.com/rust-lang/rust/issues/18425</sup>: consts 1.237
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-6157.rs <sup>https://github.com/rust-lang/rust/issues/6157</sup>: regions 1.238
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-33819.rs <sup>https://github.com/rust-lang/rust/issues/33819</sup>: borrowck 1.280
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-3683.rs <sup>https://github.com/rust-lang/rust/issues/3683</sup>: traits 1.283
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-8709.rs <sup>https://github.com/rust-lang/rust/issues/8709</sup>: macros 1.291
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-20616-9.rs <sup>https://github.com/rust-lang/rust/issues/20616</sup>: parser 1.293
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-64732.rs <sup>https://github.com/rust-lang/rust/issues/64732</sup>: parser 1.296
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-18655.rs <sup>https://github.com/rust-lang/rust/issues/18655</sup>: associated-types 1.305
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-32947.rs <sup>https://github.com/rust-lang/rust/issues/32947</sup>: simd 1.322
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-57198.rs <sup>https://github.com/rust-lang/rust/issues/57198</sup>: parser 1.342
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-10764-rpass.rs <sup>https://github.com/rust-lang/rust/issues/10764</sup>: extern 1.392
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-73541-2.rs <sup>https://github.com/rust-lang/rust/issues/73541</sup>: async-await 1.422
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-7970b.rs <sup>https://github.com/rust-lang/rust/issues/7970</sup>: parser 1.439
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-57684.rs <sup>https://github.com/rust-lang/rust/issues/57684</sup>: parser 1.512
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-33264.rs <sup>https://github.com/rust-lang/rust/issues/33264</sup>: llvm-asm 1.523
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-65284-suggest-generic-trait-bound.rs <sup>https://github.com/rust-lang/rust/issues/65284</sup>: suggestions 1.647
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-17458.rs <sup>https://github.com/rust-lang/rust/issues/17458</sup>: consts 1.711
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-56762.rs <sup>https://github.com/rust-lang/rust/issues/56762</sup>: consts 1.787
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-2216.rs <sup>https://github.com/rust-lang/rust/issues/2216</sup>: for-loop-while 1.856
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-45696-scribble-on-boxed-borrow.rs <sup>https://github.com/rust-lang/rust/issues/45696</sup>: nll 2.009
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-46036.rs <sup>https://github.com/rust-lang/rust/issues/46036</sup>: nll 2.059

`@petrochenkov` Can you put a place holder (like `N/A`) for tests without GitHub issues? It is a lot easier to parse fixed sized rows.
henryboisdequin referenced this issue in henryboisdequin/rust Feb 1, 2021
…chenkov

Move some tests to more reasonable directories - 3

cc rust-lang#73494
r? ``@petrochenkov``

https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-56202.rs <sup>https://github.com/rust-lang/rust/issues/56202</sup>: traits 1.008
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-69841.rs <sup>https://github.com/rust-lang/rust/issues/69841</sup>: for-loop-while 1.014
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-10763.rs <sup>https://github.com/rust-lang/rust/issues/10763</sup>: extern 1.016
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-50599.rs <sup>https://github.com/rust-lang/rust/issues/50599</sup>: resolve 1.018
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-6128.rs <sup>https://github.com/rust-lang/rust/issues/6128</sup>: traits 1.043
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-20616-8.rs <sup>https://github.com/rust-lang/rust/issues/20616</sup>: parser 1.045
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-46553.rs <sup>https://github.com/rust-lang/rust/issues/46553</sup>: consts 1.081
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-33140-hack-boundaries.rs <sup>https://github.com/rust-lang/rust/issues/33140</sup>: traits 1.101
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-25826.rs <sup>https://github.com/rust-lang/rust/issues/25826</sup>: consts 1.108
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-56488.rs <sup>https://github.com/rust-lang/rust/issues/56488</sup>: traits 1.110
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-58856-1.rs <sup>https://github.com/rust-lang/rust/issues/58856</sup>: parser 1.133
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-57819.rs <sup>https://github.com/rust-lang/rust/issues/57819</sup>: parser 1.138
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-54348.rs <sup>https://github.com/rust-lang/rust/issues/54348</sup>: consts 1.155
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-14309.rs <sup>https://github.com/rust-lang/rust/issues/14309</sup>: lint 1.160
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-4446.rs <sup>https://github.com/rust-lang/rust/issues/4446</sup>: threads-sendsync 1.203
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-53675-a-test-called-panic.rs <sup>https://github.com/rust-lang/rust/issues/53675</sup>: test-attrs 1.211
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-40231-2.rs <sup>https://github.com/rust-lang/rust/issues/40231</sup>: consts 1.213
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-22037.rs <sup>https://github.com/rust-lang/rust/issues/22037</sup>: associated-types 1.214
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-59029-2.rs <sup>https://github.com/rust-lang/rust/issues/59029</sup>: traits 1.219
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-18425.rs <sup>https://github.com/rust-lang/rust/issues/18425</sup>: consts 1.237
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-6157.rs <sup>https://github.com/rust-lang/rust/issues/6157</sup>: regions 1.238
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-33819.rs <sup>https://github.com/rust-lang/rust/issues/33819</sup>: borrowck 1.280
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-3683.rs <sup>https://github.com/rust-lang/rust/issues/3683</sup>: traits 1.283
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-8709.rs <sup>https://github.com/rust-lang/rust/issues/8709</sup>: macros 1.291
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-20616-9.rs <sup>https://github.com/rust-lang/rust/issues/20616</sup>: parser 1.293
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-64732.rs <sup>https://github.com/rust-lang/rust/issues/64732</sup>: parser 1.296
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-18655.rs <sup>https://github.com/rust-lang/rust/issues/18655</sup>: associated-types 1.305
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-32947.rs <sup>https://github.com/rust-lang/rust/issues/32947</sup>: simd 1.322
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-57198.rs <sup>https://github.com/rust-lang/rust/issues/57198</sup>: parser 1.342
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-10764-rpass.rs <sup>https://github.com/rust-lang/rust/issues/10764</sup>: extern 1.392
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-73541-2.rs <sup>https://github.com/rust-lang/rust/issues/73541</sup>: async-await 1.422
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-7970b.rs <sup>https://github.com/rust-lang/rust/issues/7970</sup>: parser 1.439
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-57684.rs <sup>https://github.com/rust-lang/rust/issues/57684</sup>: parser 1.512
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-33264.rs <sup>https://github.com/rust-lang/rust/issues/33264</sup>: llvm-asm 1.523
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-65284-suggest-generic-trait-bound.rs <sup>https://github.com/rust-lang/rust/issues/65284</sup>: suggestions 1.647
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-17458.rs <sup>https://github.com/rust-lang/rust/issues/17458</sup>: consts 1.711
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-56762.rs <sup>https://github.com/rust-lang/rust/issues/56762</sup>: consts 1.787
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-2216.rs <sup>https://github.com/rust-lang/rust/issues/2216</sup>: for-loop-while 1.856
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-45696-scribble-on-boxed-borrow.rs <sup>https://github.com/rust-lang/rust/issues/45696</sup>: nll 2.009
https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-46036.rs <sup>https://github.com/rust-lang/rust/issues/46036</sup>: nll 2.059

``@petrochenkov`` Can you put a place holder (like `N/A`) for tests without GitHub issues? It is a lot easier to parse fixed sized rows.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-NLL Area: Non-lexical lifetimes (NLL) C-enhancement Category: An issue proposing an enhancement or a PR with one. E-mentor Call for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants