From b445bf2bd1139236fd815bf93610ddaf17726111 Mon Sep 17 00:00:00 2001
From: "Felix S. Klock II" <pnkfelix@pnkfx.org>
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<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
         ast::ExprForLoop(pat, head, body, opt_ident) => {
             // to:
             //
-            //   match ::std::iter::IntoIterator::into_iter(<head>) {
-            //     mut iter => {
-            //       [opt_ident]: loop {
-            //         match ::std::iter::Iterator::next(&mut iter) {
-            //           ::std::option::Option::Some(<pat>) => <body>,
-            //           ::std::option::Option::None => break
+            //   {
+            //     let result = match ::std::iter::IntoIterator::into_iter(<head>) {
+            //       mut iter => {
+            //         [opt_ident]: loop {
+            //           match ::std::iter::Iterator::next(&mut iter) {
+            //             ::std::option::Option::Some(<pat>) => <body>,
+            //             ::std::option::Option::None => break
+            //           }
             //         }
             //       }
-            //     }
+            //     };
+            //     result
             //   }
 
             // expand <head>
@@ -319,7 +322,16 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
 
                 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);
     }
 }