-
Notifications
You must be signed in to change notification settings - Fork 13k
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] Add false edges out of infinite loops #47802
Changes from 1 commit
5ca88ae
bdc37aa
ed6a2eb
eae1a35
8e0c3f5
85dfa9d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
Fixes #46036
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -156,11 +156,15 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { | |
// | ||
// If `opt_cond_expr` is `None`, then the graph is somewhat simplified: | ||
// | ||
// [block] --> [loop_block / body_block ] ~~> [body_block_end] [exit_block] | ||
// ^ | | ||
// | | | ||
// +--------------------------+ | ||
// [block] --> [loop_block] ~~> [loop_block_end] | ||
// | ^ | | ||
// false link | | | ||
// | +-------------------+ | ||
// v | ||
// [cleanup_block] | ||
// | ||
// The false link is required in case something results in | ||
// unwinding through the body. | ||
|
||
let loop_block = this.cfg.start_new_block(); | ||
let exit_block = this.cfg.start_new_block(); | ||
|
@@ -174,6 +178,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { | |
move |this| { | ||
// conduct the test, if necessary | ||
let body_block; | ||
let out_terminator; | ||
if let Some(cond_expr) = opt_cond_expr { | ||
let loop_block_end; | ||
let cond = unpack!( | ||
|
@@ -187,8 +192,15 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { | |
// 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); | ||
|
||
out_terminator = TerminatorKind::Goto { target: loop_block }; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it would be nice if we indicated what |
||
} else { | ||
body_block = loop_block; | ||
let diverge_cleanup = this.diverge_cleanup(); | ||
out_terminator = TerminatorKind::FalseUnwind { | ||
real_target: loop_block, | ||
unwind: Some(diverge_cleanup) | ||
} | ||
} | ||
|
||
// The “return” value of the loop body must always be an unit. We therefore | ||
|
@@ -197,7 +209,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { | |
// 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, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So, in the new diagram above, if let Some(cond_expr) = opt_cond_expr {
... // as before
} else {
body_block = this.cfg.start_new_block();
let diverge_cleanup = this.diverge_cleanup();
this.cfg.terminate(
loop_block,
TerminatorKind::FalseUnwind { real_target: body_block, unwind: Some(diverge_cleanup) }
);
} then there is no need for the In particular I think that will be important for this test case, which would be good to add: struct Foo { x: &'static u32 }
fn foo() {
let a = 3;
let foo = Foo { x: &a }; //~ ERROR E0597
loop { continue; } // <-- note the continue here =)
}
fn main() { } |
||
TerminatorKind::Goto { target: loop_block }); | ||
out_terminator); | ||
} | ||
); | ||
exit_block.unit() | ||
|
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 picture looks right, but I'm not sure that the code below is doing that...