From b445bf2bd1139236fd815bf93610ddaf17726111 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Wed, 4 Feb 2015 13:24:44 +0100 Subject: [PATCH] make `for PAT in ITER_EXPR { ... }` a terminating-scope for ITER_EXPR. In effect, temporary anonymous values created during the evaluation of ITER_EXPR no longer not live for the entirety of the block surrounding the for-loop; instead they only live for the extent of the for-loop itself, and no longer. ---- There is one case I know of that this breaks, demonstrated to me by niko (but it is also a corner-case that is useless in practice). Here is that case: ``` fn main() { let mut foo: Vec<&i8> = Vec::new(); for i in &[1, 2, 3] { foo.push(i) } } ``` Note that if you add any code following the for-loop above, or even a semicolon to the end of it, then the code will stop compiling (i.e., it gathers a vector of references but the gathered vector cannot actually be used.) (The above code, despite being useless, did occur in one run-pass test by accident; that test is updated here to accommodate the new striction.) ---- So, technically this is a: [breaking-change] --- src/libsyntax/ext/expand.rs | 28 ++++++++++++++++------- src/test/run-pass/loop-label-shadowing.rs | 2 +- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index eaee67f9a6174..d75766c608ba0 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -230,15 +230,18 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { ast::ExprForLoop(pat, head, body, opt_ident) => { // to: // - // match ::std::iter::IntoIterator::into_iter() { - // mut iter => { - // [opt_ident]: loop { - // match ::std::iter::Iterator::next(&mut iter) { - // ::std::option::Option::Some() => , - // ::std::option::Option::None => break + // { + // let result = match ::std::iter::IntoIterator::into_iter() { + // mut iter => { + // [opt_ident]: loop { + // match ::std::iter::Iterator::next(&mut iter) { + // ::std::option::Option::Some() => , + // ::std::option::Option::None => break + // } // } // } - // } + // }; + // result // } // expand @@ -319,7 +322,16 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { fld.cx.expr_call(span, fld.cx.expr_path(into_iter_path), vec![head]) }; - fld.cx.expr_match(span, into_iter_expr, vec![iter_arm]) + + let match_expr = fld.cx.expr_match(span, into_iter_expr, vec![iter_arm]); + + // `{ let result = ...; result }` + let result_ident = token::gensym_ident("result"); + fld.cx.expr_block( + fld.cx.block_all( + span, + vec![fld.cx.stmt_let(span, false, result_ident, match_expr)], + Some(fld.cx.expr_ident(span, result_ident)))) } ast::ExprClosure(capture_clause, fn_decl, block) => { diff --git a/src/test/run-pass/loop-label-shadowing.rs b/src/test/run-pass/loop-label-shadowing.rs index 686a9a002cebf..d96ff869fa0ab 100644 --- a/src/test/run-pass/loop-label-shadowing.rs +++ b/src/test/run-pass/loop-label-shadowing.rs @@ -13,7 +13,7 @@ fn main() { let mut foo = Vec::new(); 'foo: for i in &[1, 2, 3] { - foo.push(i); + foo.push(*i); } }