From b1da8c618fb49d8a42270454ea1bf5ddca426683 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 17 Jan 2014 08:30:06 -0500 Subject: [PATCH] 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 --- src/libsyntax/ext/expand.rs | 30 ++++---- src/test/run-pass/cleanup-rvalue-for-scope.rs | 70 +++++++++++++++++++ 2 files changed, 82 insertions(+), 18 deletions(-) create mode 100644 src/test/run-pass/cleanup-rvalue-for-scope.rs diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 303277afbe84..6ef938030ff0 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -137,15 +137,16 @@ pub fn expand_expr(e: @ast::Expr, fld: &mut MacroExpander) -> @ast::Expr { // to: // - // { - // let _i = &mut ; - // [':] loop { - // match i.next() { + // match &mut { + // i => { + // [':] loop { + // match i.next() { // None => break, // Some() => + // } // } + // } // } - // } 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 ` - let iter_decl_stmt = fld.cx.stmt_let(span, false, local_ident, - fld.cx.expr_mut_addr_of(span, src_expr)); - // `None => break ['];` 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 { 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) diff --git a/src/test/run-pass/cleanup-rvalue-for-scope.rs b/src/test/run-pass/cleanup-rvalue-for-scope.rs new file mode 100644 index 000000000000..98a084790985 --- /dev/null +++ b/src/test/run-pass/cleanup-rvalue-for-scope.rs @@ -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 or the MIT license +// , 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 { 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(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); +}