-
Notifications
You must be signed in to change notification settings - Fork 13.4k
[MIR] Reintroduce the unit temporary #30945
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -103,31 +103,41 @@ pub struct Scope<'tcx> { | |
|
||
#[derive(Clone, Debug)] | ||
pub struct LoopScope { | ||
pub extent: CodeExtent, // extent of the loop | ||
pub continue_block: BasicBlock, // where to go on a `loop` | ||
/// Extent of the loop | ||
pub extent: CodeExtent, | ||
/// Where the body of the loop begins | ||
pub continue_block: BasicBlock, | ||
/// Block to branch into when the loop terminates (either by being `break`-en out from, or by | ||
/// having its condition to become false) | ||
pub break_block: BasicBlock, // where to go on a `break | ||
/// Indicates the reachability of the break_block for this loop | ||
pub might_break: bool | ||
} | ||
|
||
impl<'a,'tcx> Builder<'a,'tcx> { | ||
/// Start a loop scope, which tracks where `continue` and `break` | ||
/// should branch to. See module comment for more details. | ||
pub fn in_loop_scope<F, R>(&mut self, | ||
/// | ||
/// Returns the might_break attribute of the LoopScope used. | ||
pub fn in_loop_scope<F>(&mut self, | ||
loop_block: BasicBlock, | ||
break_block: BasicBlock, | ||
f: F) | ||
-> BlockAnd<R> | ||
where F: FnOnce(&mut Builder<'a, 'tcx>) -> BlockAnd<R> | ||
-> bool | ||
where F: FnOnce(&mut Builder<'a, 'tcx>) | ||
{ | ||
let extent = self.extent_of_innermost_scope(); | ||
let loop_scope = LoopScope { | ||
extent: extent.clone(), | ||
continue_block: loop_block, | ||
break_block: break_block, | ||
might_break: false | ||
}; | ||
self.loop_scopes.push(loop_scope); | ||
let r = f(self); | ||
assert!(self.loop_scopes.pop().unwrap().extent == extent); | ||
r | ||
f(self); | ||
let loop_scope = self.loop_scopes.pop().unwrap(); | ||
assert!(loop_scope.extent == extent); | ||
loop_scope.might_break | ||
} | ||
|
||
/// Convenience wrapper that pushes a scope and then executes `f` | ||
|
@@ -181,28 +191,21 @@ impl<'a,'tcx> Builder<'a,'tcx> { | |
pub fn find_loop_scope(&mut self, | ||
span: Span, | ||
label: Option<CodeExtent>) | ||
-> LoopScope { | ||
let loop_scope = | ||
match label { | ||
None => { | ||
// no label? return the innermost loop scope | ||
self.loop_scopes.iter() | ||
.rev() | ||
.next() | ||
} | ||
Some(label) => { | ||
// otherwise, find the loop-scope with the correct id | ||
self.loop_scopes.iter() | ||
.rev() | ||
.filter(|loop_scope| loop_scope.extent == label) | ||
.next() | ||
} | ||
}; | ||
|
||
match loop_scope { | ||
Some(loop_scope) => loop_scope.clone(), | ||
None => self.hir.span_bug(span, "no enclosing loop scope found?"), | ||
} | ||
-> &mut LoopScope { | ||
let Builder { ref mut loop_scopes, ref mut hir, .. } = *self; | ||
match label { | ||
None => { | ||
// no label? return the innermost loop scope | ||
loop_scopes.iter_mut().rev().next() | ||
} | ||
Some(label) => { | ||
// otherwise, find the loop-scope with the correct id | ||
loop_scopes.iter_mut() | ||
.rev() | ||
.filter(|loop_scope| loop_scope.extent == label) | ||
.next() | ||
} | ||
}.unwrap_or_else(|| hir.span_bug(span, "no enclosing loop scope found?")) | ||
} | ||
|
||
/// Branch out of `block` to `target`, exiting all scopes up to | ||
|
@@ -214,20 +217,19 @@ impl<'a,'tcx> Builder<'a,'tcx> { | |
extent: CodeExtent, | ||
block: BasicBlock, | ||
target: BasicBlock) { | ||
let popped_scopes = | ||
match self.scopes.iter().rev().position(|scope| scope.extent == extent) { | ||
Some(p) => p + 1, | ||
None => self.hir.span_bug(span, &format!("extent {:?} does not enclose", | ||
extent)), | ||
}; | ||
|
||
for scope in self.scopes.iter_mut().rev().take(popped_scopes) { | ||
let Builder { ref mut scopes, ref mut cfg, ref mut hir, .. } = *self; | ||
|
||
let scope_count = 1 + scopes.iter().rev().position(|scope| scope.extent == extent) | ||
.unwrap_or_else(||{ | ||
hir.span_bug(span, &format!("extent {:?} does not enclose", extent)) | ||
}); | ||
|
||
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. no particular reason to rewrite this fn, right? just thought it seemed cleaner this way? 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. Yes to both. I had already rewritten this function in a previous iteration of the PR, so I thought I would keep it. |
||
for scope in scopes.iter_mut().rev().take(scope_count) { | ||
for &(kind, drop_span, ref lvalue) in &scope.drops { | ||
self.cfg.push_drop(block, drop_span, kind, lvalue); | ||
cfg.push_drop(block, drop_span, kind, lvalue); | ||
} | ||
} | ||
|
||
self.cfg.terminate(block, Terminator::Goto { target: target }); | ||
cfg.terminate(block, Terminator::Goto { target: target }); | ||
} | ||
|
||
/// Creates a path that performs all required cleanup for unwinding. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,5 +18,4 @@ fn forever() -> ! { | |
} | ||
|
||
fn main() { | ||
if 1 == 2 { forever(); } | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT | ||
// file at the top-level directory of this distribution and at | ||
// http://rust-lang.org/COPYRIGHT. | ||
// | ||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | ||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | ||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | ||
// option. This file may not be copied, modified, or distributed | ||
// except according to those terms. | ||
|
||
fn test1() { | ||
// In this test the outer 'a loop may terminate without `x` getting initialised. Although the | ||
// `x = loop { ... }` statement is reached, the value itself ends up never being computed and | ||
// thus leaving `x` uninit. | ||
let x: i32; | ||
'a: loop { | ||
x = loop { break 'a }; | ||
} | ||
println!("{:?}", x); //~ ERROR use of possibly uninitialized variable | ||
} | ||
|
||
// test2 and test3 should not fail. | ||
fn test2() { | ||
// In this test the `'a` loop will never terminate thus making the use of `x` unreachable. | ||
let x: i32; | ||
'a: loop { | ||
x = loop { continue 'a }; | ||
} | ||
println!("{:?}", x); | ||
} | ||
|
||
fn test3() { | ||
let x: i32; | ||
// Similarly, the use of variable `x` is unreachable. | ||
'a: loop { | ||
x = loop { return }; | ||
} | ||
println!("{:?}", x); | ||
} | ||
|
||
fn main() { | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT | ||
// file at the top-level directory of this distribution and at | ||
// http://rust-lang.org/COPYRIGHT. | ||
// | ||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | ||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | ||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | ||
// option. This file may not be copied, modified, or distributed | ||
// except according to those terms. | ||
|
||
fn forever2() -> i32 { | ||
let x: i32 = loop { break }; //~ ERROR mismatched types | ||
x | ||
} | ||
|
||
fn main() {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT | ||
// file at the top-level directory of this distribution and at | ||
// http://rust-lang.org/COPYRIGHT. | ||
// | ||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | ||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | ||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | ||
// option. This file may not be copied, modified, or distributed | ||
// except according to those terms. | ||
|
||
fn forever2() -> ! { //~ ERROR computation may converge in a function marked as diverging | ||
loop { break } | ||
} | ||
|
||
fn main() {} |
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 seems fine; we could also check in the
if
below and sayif may_break or opt_cond_expr.is_some()
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.
To me it sounds like it is better to keep state consistent in case somebody else wants to use it later for whatever reasons.