Change expansion of for
loop to use a match
statement
so that the "innermost enclosing statement" used for rvalue temporaries matches up with user expectations
This commit is contained in:
parent
8f16356e5f
commit
b1da8c618f
2 changed files with 82 additions and 18 deletions
|
@ -137,15 +137,16 @@ pub fn expand_expr(e: @ast::Expr, fld: &mut MacroExpander) -> @ast::Expr {
|
||||||
|
|
||||||
// to:
|
// to:
|
||||||
//
|
//
|
||||||
// {
|
// match &mut <src_expr> {
|
||||||
// let _i = &mut <src_expr>;
|
// i => {
|
||||||
// ['<ident>:] loop {
|
// ['<ident>:] loop {
|
||||||
// match i.next() {
|
// match i.next() {
|
||||||
// None => break,
|
// None => break,
|
||||||
// Some(<src_pat>) => <src_loop_block>
|
// Some(<src_pat>) => <src_loop_block>
|
||||||
|
// }
|
||||||
// }
|
// }
|
||||||
|
// }
|
||||||
// }
|
// }
|
||||||
// }
|
|
||||||
|
|
||||||
let local_ident = token::gensym_ident("i");
|
let local_ident = token::gensym_ident("i");
|
||||||
let next_ident = fld.cx.ident_of("next");
|
let next_ident = fld.cx.ident_of("next");
|
||||||
|
@ -154,10 +155,6 @@ pub fn expand_expr(e: @ast::Expr, fld: &mut MacroExpander) -> @ast::Expr {
|
||||||
let local_path = fld.cx.path_ident(span, local_ident);
|
let local_path = fld.cx.path_ident(span, local_ident);
|
||||||
let some_path = fld.cx.path_ident(span, fld.cx.ident_of("Some"));
|
let some_path = fld.cx.path_ident(span, fld.cx.ident_of("Some"));
|
||||||
|
|
||||||
// `let i = &mut <src_expr>`
|
|
||||||
let iter_decl_stmt = fld.cx.stmt_let(span, false, local_ident,
|
|
||||||
fld.cx.expr_mut_addr_of(span, src_expr));
|
|
||||||
|
|
||||||
// `None => break ['<ident>];`
|
// `None => break ['<ident>];`
|
||||||
let none_arm = {
|
let none_arm = {
|
||||||
// FIXME #6993: this map goes away:
|
// FIXME #6993: this map goes away:
|
||||||
|
@ -185,16 +182,13 @@ pub fn expand_expr(e: @ast::Expr, fld: &mut MacroExpander) -> @ast::Expr {
|
||||||
ast::ExprLoop(fld.cx.block_expr(match_expr),
|
ast::ExprLoop(fld.cx.block_expr(match_expr),
|
||||||
opt_ident));
|
opt_ident));
|
||||||
|
|
||||||
// `{ let ... ; loop { ... } }`
|
// `i => loop { ... }`
|
||||||
let block = fld.cx.block(span,
|
|
||||||
~[iter_decl_stmt],
|
|
||||||
Some(loop_expr));
|
|
||||||
|
|
||||||
@ast::Expr {
|
// `match &mut <src_expr> { i => loop { ... } }`
|
||||||
id: ast::DUMMY_NODE_ID,
|
let discrim = fld.cx.expr_mut_addr_of(span, src_expr);
|
||||||
node: ast::ExprBlock(block),
|
let i_pattern = fld.cx.pat_ident(span, local_ident);
|
||||||
span: span,
|
let arm = fld.cx.arm(span, ~[i_pattern], loop_expr);
|
||||||
}
|
fld.cx.expr_match(span, discrim, ~[arm])
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => noop_fold_expr(e, fld)
|
_ => noop_fold_expr(e, fld)
|
||||||
|
|
70
src/test/run-pass/cleanup-rvalue-for-scope.rs
Normal file
70
src/test/run-pass/cleanup-rvalue-for-scope.rs
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
// Copyright 2012 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.
|
||||||
|
|
||||||
|
// Test that the lifetime of rvalues in for loops is extended
|
||||||
|
// to the for loop itself.
|
||||||
|
|
||||||
|
#[feature(macro_rules)];
|
||||||
|
|
||||||
|
use std::ops::Drop;
|
||||||
|
|
||||||
|
static mut FLAGS: u64 = 0;
|
||||||
|
|
||||||
|
struct Box<T> { f: T }
|
||||||
|
struct AddFlags { bits: u64 }
|
||||||
|
|
||||||
|
fn AddFlags(bits: u64) -> AddFlags {
|
||||||
|
AddFlags { bits: bits }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn arg(exp: u64, _x: &AddFlags) {
|
||||||
|
check_flags(exp);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pass<T>(v: T) -> T {
|
||||||
|
v
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_flags(exp: u64) {
|
||||||
|
unsafe {
|
||||||
|
let x = FLAGS;
|
||||||
|
FLAGS = 0;
|
||||||
|
println!("flags {}, expected {}", x, exp);
|
||||||
|
assert_eq!(x, exp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AddFlags {
|
||||||
|
fn check_flags<'a>(&'a self, exp: u64) -> &'a AddFlags {
|
||||||
|
check_flags(exp);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bits(&self) -> u64 {
|
||||||
|
self.bits
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for AddFlags {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
FLAGS = FLAGS + self.bits;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main() {
|
||||||
|
// The array containing [AddFlags] should not be dropped until
|
||||||
|
// after the for loop:
|
||||||
|
for x in [AddFlags(1)].iter() {
|
||||||
|
check_flags(0);
|
||||||
|
}
|
||||||
|
check_flags(1);
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue