Skip to content

Commit 61626b3

Browse files
committed
Auto merge of #21984 - pnkfelix:make-for-loops-a-terminating-scope, r=nikomatsakis
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 @nikomatsakis (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]
2 parents ce5aad2 + b445bf2 commit 61626b3

File tree

2 files changed

+21
-9
lines changed

2 files changed

+21
-9
lines changed

src/libsyntax/ext/expand.rs

+20-8
Original file line numberDiff line numberDiff line change
@@ -230,15 +230,18 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
230230
ast::ExprForLoop(pat, head, body, opt_ident) => {
231231
// to:
232232
//
233-
// match ::std::iter::IntoIterator::into_iter(<head>) {
234-
// mut iter => {
235-
// [opt_ident]: loop {
236-
// match ::std::iter::Iterator::next(&mut iter) {
237-
// ::std::option::Option::Some(<pat>) => <body>,
238-
// ::std::option::Option::None => break
233+
// {
234+
// let result = match ::std::iter::IntoIterator::into_iter(<head>) {
235+
// mut iter => {
236+
// [opt_ident]: loop {
237+
// match ::std::iter::Iterator::next(&mut iter) {
238+
// ::std::option::Option::Some(<pat>) => <body>,
239+
// ::std::option::Option::None => break
240+
// }
239241
// }
240242
// }
241-
// }
243+
// };
244+
// result
242245
// }
243246

244247
// expand <head>
@@ -319,7 +322,16 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
319322

320323
fld.cx.expr_call(span, fld.cx.expr_path(into_iter_path), vec![head])
321324
};
322-
fld.cx.expr_match(span, into_iter_expr, vec![iter_arm])
325+
326+
let match_expr = fld.cx.expr_match(span, into_iter_expr, vec![iter_arm]);
327+
328+
// `{ let result = ...; result }`
329+
let result_ident = token::gensym_ident("result");
330+
fld.cx.expr_block(
331+
fld.cx.block_all(
332+
span,
333+
vec![fld.cx.stmt_let(span, false, result_ident, match_expr)],
334+
Some(fld.cx.expr_ident(span, result_ident))))
323335
}
324336

325337
ast::ExprClosure(capture_clause, fn_decl, block) => {

src/test/run-pass/loop-label-shadowing.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
fn main() {
1414
let mut foo = Vec::new();
1515
'foo: for i in &[1, 2, 3] {
16-
foo.push(i);
16+
foo.push(*i);
1717
}
1818
}
1919

0 commit comments

Comments
 (0)