]> git.lizzy.rs Git - rust.git/commitdiff
Change expansion of `for` loop to use a `match` statement
authorNiko Matsakis <niko@alum.mit.edu>
Fri, 17 Jan 2014 13:30:06 +0000 (08:30 -0500)
committerNiko Matsakis <niko@alum.mit.edu>
Fri, 17 Jan 2014 13:30:06 +0000 (08:30 -0500)
so that the "innermost enclosing statement" used for rvalue
temporaries matches up with user expectations

src/libsyntax/ext/expand.rs
src/test/run-pass/cleanup-rvalue-for-scope.rs [new file with mode: 0644]

index 303277afbe84f94dccd99ded144c26188b2df786..6ef938030ff0d757692df475bcdbf87d5c0e28f3 100644 (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)
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 (file)
index 0000000..98a0847
--- /dev/null
@@ -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);
+}