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:
Niko Matsakis 2014-01-17 08:30:06 -05:00
parent 8f16356e5f
commit b1da8c618f
2 changed files with 82 additions and 18 deletions

View File

@ -137,15 +137,16 @@ pub fn expand_expr(e: @ast::Expr, fld: &mut MacroExpander) -> @ast::Expr {
// to:
//
// {
// let _i = &mut <src_expr>;
// ['<ident>:] loop {
// match i.next() {
// match &mut <src_expr> {
// i => {
// ['<ident>:] loop {
// match i.next() {
// None => break,
// Some(<src_pat>) => <src_loop_block>
// }
// }
// }
// }
// }
let local_ident = token::gensym_ident("i");
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 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>];`
let none_arm = {
// 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),
opt_ident));
// `{ let ... ; loop { ... } }`
let block = fld.cx.block(span,
~[iter_decl_stmt],
Some(loop_expr));
// `i => loop { ... }`
@ast::Expr {
id: ast::DUMMY_NODE_ID,
node: ast::ExprBlock(block),
span: span,
}
// `match &mut <src_expr> { i => loop { ... } }`
let discrim = fld.cx.expr_mut_addr_of(span, src_expr);
let i_pattern = fld.cx.pat_ident(span, local_ident);
let arm = fld.cx.arm(span, ~[i_pattern], loop_expr);
fld.cx.expr_match(span, discrim, ~[arm])
}
_ => noop_fold_expr(e, fld)

View 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);
}