Skip to content

Commit

Permalink
Change expansion of for loop to use a match statement
Browse files Browse the repository at this point in the history
so that the "innermost enclosing statement" used for rvalue
temporaries matches up with user expectations
  • Loading branch information
nikomatsakis committed Jan 17, 2014
1 parent 8f16356 commit b1da8c6
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 18 deletions.
30 changes: 12 additions & 18 deletions src/libsyntax/ext/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand All @@ -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:
Expand Down Expand Up @@ -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)
Expand Down
70 changes: 70 additions & 0 deletions src/test/run-pass/cleanup-rvalue-for-scope.rs
Original file line number Diff line number Diff line change
@@ -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);
}

0 comments on commit b1da8c6

Please sign in to comment.