Skip to content

Commit b1da8c6

Browse files
committed
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
1 parent 8f16356 commit b1da8c6

File tree

2 files changed

+82
-18
lines changed

2 files changed

+82
-18
lines changed

src/libsyntax/ext/expand.rs

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -137,15 +137,16 @@ pub fn expand_expr(e: @ast::Expr, fld: &mut MacroExpander) -> @ast::Expr {
137137

138138
// to:
139139
//
140-
// {
141-
// let _i = &mut <src_expr>;
142-
// ['<ident>:] loop {
143-
// match i.next() {
140+
// match &mut <src_expr> {
141+
// i => {
142+
// ['<ident>:] loop {
143+
// match i.next() {
144144
// None => break,
145145
// Some(<src_pat>) => <src_loop_block>
146+
// }
146147
// }
148+
// }
147149
// }
148-
// }
149150

150151
let local_ident = token::gensym_ident("i");
151152
let next_ident = fld.cx.ident_of("next");
@@ -154,10 +155,6 @@ pub fn expand_expr(e: @ast::Expr, fld: &mut MacroExpander) -> @ast::Expr {
154155
let local_path = fld.cx.path_ident(span, local_ident);
155156
let some_path = fld.cx.path_ident(span, fld.cx.ident_of("Some"));
156157

157-
// `let i = &mut <src_expr>`
158-
let iter_decl_stmt = fld.cx.stmt_let(span, false, local_ident,
159-
fld.cx.expr_mut_addr_of(span, src_expr));
160-
161158
// `None => break ['<ident>];`
162159
let none_arm = {
163160
// FIXME #6993: this map goes away:
@@ -185,16 +182,13 @@ pub fn expand_expr(e: @ast::Expr, fld: &mut MacroExpander) -> @ast::Expr {
185182
ast::ExprLoop(fld.cx.block_expr(match_expr),
186183
opt_ident));
187184

188-
// `{ let ... ; loop { ... } }`
189-
let block = fld.cx.block(span,
190-
~[iter_decl_stmt],
191-
Some(loop_expr));
185+
// `i => loop { ... }`
192186

193-
@ast::Expr {
194-
id: ast::DUMMY_NODE_ID,
195-
node: ast::ExprBlock(block),
196-
span: span,
197-
}
187+
// `match &mut <src_expr> { i => loop { ... } }`
188+
let discrim = fld.cx.expr_mut_addr_of(span, src_expr);
189+
let i_pattern = fld.cx.pat_ident(span, local_ident);
190+
let arm = fld.cx.arm(span, ~[i_pattern], loop_expr);
191+
fld.cx.expr_match(span, discrim, ~[arm])
198192
}
199193

200194
_ => noop_fold_expr(e, fld)
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Test that the lifetime of rvalues in for loops is extended
12+
// to the for loop itself.
13+
14+
#[feature(macro_rules)];
15+
16+
use std::ops::Drop;
17+
18+
static mut FLAGS: u64 = 0;
19+
20+
struct Box<T> { f: T }
21+
struct AddFlags { bits: u64 }
22+
23+
fn AddFlags(bits: u64) -> AddFlags {
24+
AddFlags { bits: bits }
25+
}
26+
27+
fn arg(exp: u64, _x: &AddFlags) {
28+
check_flags(exp);
29+
}
30+
31+
fn pass<T>(v: T) -> T {
32+
v
33+
}
34+
35+
fn check_flags(exp: u64) {
36+
unsafe {
37+
let x = FLAGS;
38+
FLAGS = 0;
39+
println!("flags {}, expected {}", x, exp);
40+
assert_eq!(x, exp);
41+
}
42+
}
43+
44+
impl AddFlags {
45+
fn check_flags<'a>(&'a self, exp: u64) -> &'a AddFlags {
46+
check_flags(exp);
47+
self
48+
}
49+
50+
fn bits(&self) -> u64 {
51+
self.bits
52+
}
53+
}
54+
55+
impl Drop for AddFlags {
56+
fn drop(&mut self) {
57+
unsafe {
58+
FLAGS = FLAGS + self.bits;
59+
}
60+
}
61+
}
62+
63+
pub fn main() {
64+
// The array containing [AddFlags] should not be dropped until
65+
// after the for loop:
66+
for x in [AddFlags(1)].iter() {
67+
check_flags(0);
68+
}
69+
check_flags(1);
70+
}

0 commit comments

Comments
 (0)