about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2015-10-09 08:53:45 +0000
committerbors <bors@rust-lang.org>2015-10-09 08:53:45 +0000
commitc14609035d1780d4a8a3ca7b4fdf93046299ab4a (patch)
treee2cd7e864e6d87be5ef3f9c044d0d2a510c6c96e /src/libsyntax
parent7cea9a714130b7b85caf91c2a1d126539f41c383 (diff)
parenta62a529eea3e00b3ce9e659daa4235add2cb8551 (diff)
downloadrust-c14609035d1780d4a8a3ca7b4fdf93046299ab4a.tar.gz
rust-c14609035d1780d4a8a3ca7b4fdf93046299ab4a.zip
Auto merge of #28857 - nrc:lowering, r=nikomatsakis
r? @nikomatsakis 
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ast.rs18
-rw-r--r--src/libsyntax/codemap.rs22
-rw-r--r--src/libsyntax/config.rs4
-rw-r--r--src/libsyntax/diagnostic.rs1
-rw-r--r--src/libsyntax/ext/base.rs7
-rw-r--r--src/libsyntax/ext/build.rs2
-rw-r--r--src/libsyntax/ext/expand.rs466
-rw-r--r--src/libsyntax/feature_gate.rs2
-rw-r--r--src/libsyntax/fold.rs5
-rw-r--r--src/libsyntax/parse/parser.rs4
-rw-r--r--src/libsyntax/print/pprust.rs2
-rw-r--r--src/libsyntax/visit.rs2
12 files changed, 91 insertions, 444 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index ce00505b0b4..34b99ab8cce 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -375,6 +375,11 @@ pub const CRATE_NODE_ID: NodeId = 0;
 /// small, positive ids.
 pub const DUMMY_NODE_ID: NodeId = !0;
 
+pub trait NodeIdAssigner {
+    fn next_node_id(&self) -> NodeId;
+    fn peek_node_id(&self) -> NodeId;
+}
+
 /// The AST represents all type param bounds as types.
 /// typeck::collect::compute_bounds matches these against
 /// the "special" built-in traits (see middle::lang_items) and
@@ -850,9 +855,8 @@ pub enum Expr_ {
     ///
     /// `'label: loop { block }`
     ExprLoop(P<Block>, Option<Ident>),
-    /// A `match` block, with a source that indicates whether or not it is
-    /// the result of a desugaring, and if so, which kind.
-    ExprMatch(P<Expr>, Vec<Arm>, MatchSource),
+    /// A `match` block.
+    ExprMatch(P<Expr>, Vec<Arm>),
     /// A closure (for example, `move |a, b, c| {a + b + c}`)
     ExprClosure(CaptureClause, P<FnDecl>, P<Block>),
     /// A block (`{ ... }`)
@@ -932,14 +936,6 @@ pub struct QSelf {
 }
 
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
-pub enum MatchSource {
-    Normal,
-    IfLetDesugar { contains_else_clause: bool },
-    WhileLetDesugar,
-    ForLoopDesugar,
-}
-
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
 pub enum CaptureClause {
     CaptureByValue,
     CaptureByRef,
diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs
index aa4dd1d53c5..a73fd4534c9 100644
--- a/src/libsyntax/codemap.rs
+++ b/src/libsyntax/codemap.rs
@@ -29,7 +29,6 @@ use std::io::{self, Read};
 
 use serialize::{Encodable, Decodable, Encoder, Decoder};
 
-use parse::token::intern;
 use ast::Name;
 
 // _____________________________________________________________________________
@@ -269,28 +268,8 @@ pub enum ExpnFormat {
     MacroAttribute(Name),
     /// e.g. `format!()`
     MacroBang(Name),
-    /// Syntax sugar expansion performed by the compiler (libsyntax::expand).
-    CompilerExpansion(CompilerExpansionFormat),
 }
 
-#[derive(Clone, Copy, Hash, Debug, PartialEq, Eq)]
-pub enum CompilerExpansionFormat {
-    IfLet,
-    PlacementIn,
-    WhileLet,
-    ForLoop,
-}
-
-impl CompilerExpansionFormat {
-    pub fn name(self) -> &'static str {
-        match self {
-            CompilerExpansionFormat::IfLet => "if let expansion",
-            CompilerExpansionFormat::PlacementIn => "placement-in expansion",
-            CompilerExpansionFormat::WhileLet => "while let expansion",
-            CompilerExpansionFormat::ForLoop => "for loop expansion",
-        }
-    }
-}
 #[derive(Clone, Hash, Debug)]
 pub struct NameAndSpan {
     /// The format with which the macro was invoked.
@@ -310,7 +289,6 @@ impl NameAndSpan {
         match self.format {
             ExpnFormat::MacroAttribute(s) => s,
             ExpnFormat::MacroBang(s) => s,
-            ExpnFormat::CompilerExpansion(ce) => intern(ce.name()),
         }
     }
 }
diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs
index 889a0d7e440..2d266be3242 100644
--- a/src/libsyntax/config.rs
+++ b/src/libsyntax/config.rs
@@ -225,10 +225,10 @@ fn fold_expr<F>(cx: &mut Context<F>, expr: P<ast::Expr>) -> P<ast::Expr> where
         fold::noop_fold_expr(ast::Expr {
             id: id,
             node: match node {
-                ast::ExprMatch(m, arms, source) => {
+                ast::ExprMatch(m, arms) => {
                     ast::ExprMatch(m, arms.into_iter()
                                         .filter(|a| (cx.in_cfg)(&a.attrs))
-                                        .collect(), source)
+                                        .collect())
                 }
                 _ => node
             },
diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs
index 6b4a5538501..2a8cdf138b0 100644
--- a/src/libsyntax/diagnostic.rs
+++ b/src/libsyntax/diagnostic.rs
@@ -737,7 +737,6 @@ impl EmitterWriter {
                         let (pre, post) = match ei.callee.format {
                             codemap::MacroAttribute(..) => ("#[", "]"),
                             codemap::MacroBang(..) => ("", "!"),
-                            codemap::CompilerExpansion(..) => ("", ""),
                         };
                         // Don't print recursive invocations
                         if ei.call_site != last_span {
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index 7459f8b8f24..6196062b08a 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -13,7 +13,7 @@ pub use self::SyntaxExtension::*;
 use ast;
 use ast::Name;
 use codemap;
-use codemap::{CodeMap, Span, ExpnId, ExpnInfo, NO_EXPANSION, CompilerExpansion};
+use codemap::{CodeMap, Span, ExpnId, ExpnInfo, NO_EXPANSION};
 use ext;
 use ext::expand;
 use ext::tt::macro_rules;
@@ -651,10 +651,7 @@ impl<'a> ExtCtxt<'a> {
                         return None;
                     }
                     expn_id = i.call_site.expn_id;
-                    match i.callee.format {
-                        CompilerExpansion(..) => (),
-                        _ => last_macro = Some(i.call_site),
-                    }
+                    last_macro = Some(i.call_site);
                     return Some(());
                 })
             }).is_none() {
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index a20080dcbf0..efea85f9162 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -868,7 +868,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
     }
 
     fn expr_match(&self, span: Span, arg: P<ast::Expr>, arms: Vec<ast::Arm>) -> P<Expr> {
-        self.expr(span, ast::ExprMatch(arg, arms, ast::MatchSource::Normal))
+        self.expr(span, ast::ExprMatch(arg, arms))
     }
 
     fn expr_if(&self, span: Span, cond: P<ast::Expr>,
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index b15c51490a1..b1b4605d5ec 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -20,53 +20,20 @@ use attr;
 use attr::AttrMetaMethods;
 use codemap;
 use codemap::{Span, Spanned, ExpnInfo, NameAndSpan, MacroBang, MacroAttribute};
-use codemap::{CompilerExpansion, CompilerExpansionFormat};
 use ext::base::*;
 use feature_gate::{self, Features, GatedCfg};
 use fold;
 use fold::*;
 use parse;
 use parse::token::{fresh_mark, fresh_name, intern};
-use parse::token;
 use ptr::P;
 use util::small_vector::SmallVector;
 use visit;
 use visit::Visitor;
 use std_inject;
 
-// Given suffix ["b","c","d"], returns path `::std::b::c::d` when
-// `fld.cx.use_std`, and `::core::b::c::d` otherwise.
-fn mk_core_path(fld: &mut MacroExpander,
-                span: Span,
-                suffix: &[&'static str]) -> ast::Path {
-    let idents = fld.cx.std_path(suffix);
-    fld.cx.path_global(span, idents)
-}
 
 pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
-    fn push_compiler_expansion(fld: &mut MacroExpander, span: Span,
-                               expansion_type: CompilerExpansionFormat) {
-        fld.cx.bt_push(ExpnInfo {
-            call_site: span,
-            callee: NameAndSpan {
-                format: CompilerExpansion(expansion_type),
-
-                // This does *not* mean code generated after
-                // `push_compiler_expansion` is automatically exempt
-                // from stability lints; must also tag such code with
-                // an appropriate span from `fld.cx.backtrace()`.
-                allow_internal_unstable: true,
-
-                span: None,
-            },
-        });
-    }
-
-    // Sets the expn_id so that we can use unstable methods.
-    fn allow_unstable(fld: &mut MacroExpander, span: Span) -> Span {
-        Span { expn_id: fld.cx.backtrace(), ..span }
-    }
-
     let expr_span = e.span;
     return e.and_then(|ast::Expr {id, node, span}| match node {
 
@@ -94,265 +61,39 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
             })
         }
 
-        // Desugar ExprInPlace: `in PLACE { EXPR }`
         ast::ExprInPlace(placer, value_expr) => {
-            // to:
-            //
-            // let p = PLACE;
-            // let mut place = Placer::make_place(p);
-            // let raw_place = Place::pointer(&mut place);
-            // push_unsafe!({
-            //     std::intrinsics::move_val_init(raw_place, pop_unsafe!( EXPR ));
-            //     InPlace::finalize(place)
-            // })
-
             // Ensure feature-gate is enabled
             feature_gate::check_for_placement_in(
                 fld.cx.ecfg.features,
                 &fld.cx.parse_sess.span_diagnostic,
                 expr_span);
 
-            push_compiler_expansion(fld, expr_span, CompilerExpansionFormat::PlacementIn);
-
-            let value_span = value_expr.span;
-            let placer_span = placer.span;
-
-            let placer_expr = fld.fold_expr(placer);
+            let placer = fld.fold_expr(placer);
             let value_expr = fld.fold_expr(value_expr);
-
-            let placer_ident = token::gensym_ident("placer");
-            let agent_ident = token::gensym_ident("place");
-            let p_ptr_ident = token::gensym_ident("p_ptr");
-
-            let placer = fld.cx.expr_ident(span, placer_ident);
-            let agent = fld.cx.expr_ident(span, agent_ident);
-            let p_ptr = fld.cx.expr_ident(span, p_ptr_ident);
-
-            let make_place = ["ops", "Placer", "make_place"];
-            let place_pointer = ["ops", "Place", "pointer"];
-            let move_val_init = ["intrinsics", "move_val_init"];
-            let inplace_finalize = ["ops", "InPlace", "finalize"];
-
-            let make_call = |fld: &mut MacroExpander, p, args| {
-                // We feed in the `expr_span` because codemap's span_allows_unstable
-                // allows the call_site span to inherit the `allow_internal_unstable`
-                // setting.
-                let span_unstable = allow_unstable(fld, expr_span);
-                let path = mk_core_path(fld, span_unstable, p);
-                let path = fld.cx.expr_path(path);
-                let expr_span_unstable = allow_unstable(fld, span);
-                fld.cx.expr_call(expr_span_unstable, path, args)
-            };
-
-            let stmt_let = |fld: &mut MacroExpander, bind, expr| {
-                fld.cx.stmt_let(placer_span, false, bind, expr)
-            };
-            let stmt_let_mut = |fld: &mut MacroExpander, bind, expr| {
-                fld.cx.stmt_let(placer_span, true, bind, expr)
-            };
-
-            // let placer = <placer_expr> ;
-            let s1 = stmt_let(fld, placer_ident, placer_expr);
-
-            // let mut place = Placer::make_place(placer);
-            let s2 = {
-                let call = make_call(fld, &make_place, vec![placer]);
-                stmt_let_mut(fld, agent_ident, call)
-            };
-
-            // let p_ptr = Place::pointer(&mut place);
-            let s3 = {
-                let args = vec![fld.cx.expr_mut_addr_of(placer_span, agent.clone())];
-                let call = make_call(fld, &place_pointer, args);
-                stmt_let(fld, p_ptr_ident, call)
-            };
-
-            // pop_unsafe!(EXPR));
-            let pop_unsafe_expr = pop_unsafe_expr(fld.cx, value_expr, value_span);
-
-            // push_unsafe!({
-            //     ptr::write(p_ptr, pop_unsafe!(<value_expr>));
-            //     InPlace::finalize(place)
-            // })
-            let expr = {
-                let call_move_val_init = StmtSemi(make_call(
-                    fld, &move_val_init, vec![p_ptr, pop_unsafe_expr]), ast::DUMMY_NODE_ID);
-                let call_move_val_init = codemap::respan(value_span, call_move_val_init);
-
-                let call = make_call(fld, &inplace_finalize, vec![agent]);
-                Some(push_unsafe_expr(fld.cx, vec![P(call_move_val_init)], call, span))
-            };
-
-            let block = fld.cx.block_all(span, vec![s1, s2, s3], expr);
-            let result = fld.cx.expr_block(block);
-            fld.cx.bt_pop();
-            result
+            fld.cx.expr(span, ast::ExprInPlace(placer, value_expr))
         }
 
-        // Issue #22181:
-        // Eventually a desugaring for `box EXPR`
-        // (similar to the desugaring above for `in PLACE BLOCK`)
-        // should go here, desugaring
-        //
-        // to:
-        //
-        // let mut place = BoxPlace::make_place();
-        // let raw_place = Place::pointer(&mut place);
-        // let value = $value;
-        // unsafe {
-        //     ::std::ptr::write(raw_place, value);
-        //     Boxed::finalize(place)
-        // }
-        //
-        // But for now there are type-inference issues doing that.
-
         ast::ExprWhile(cond, body, opt_ident) => {
             let cond = fld.fold_expr(cond);
             let (body, opt_ident) = expand_loop_block(body, opt_ident, fld);
             fld.cx.expr(span, ast::ExprWhile(cond, body, opt_ident))
         }
 
-        // Desugar ExprWhileLet
-        // From: `[opt_ident]: while let <pat> = <expr> <body>`
         ast::ExprWhileLet(pat, expr, body, opt_ident) => {
-            // to:
-            //
-            //   [opt_ident]: loop {
-            //     match <expr> {
-            //       <pat> => <body>,
-            //       _ => break
-            //     }
-            //   }
-
-            push_compiler_expansion(fld, span, CompilerExpansionFormat::WhileLet);
-
-            // `<pat> => <body>`
-            let pat_arm = {
-                let body_expr = fld.cx.expr_block(body);
-                fld.cx.arm(pat.span, vec![pat], body_expr)
-            };
-
-            // `_ => break`
-            let break_arm = {
-                let pat_under = fld.cx.pat_wild(span);
-                let break_expr = fld.cx.expr_break(span);
-                fld.cx.arm(span, vec![pat_under], break_expr)
-            };
-
-            // `match <expr> { ... }`
-            let arms = vec![pat_arm, break_arm];
-            let match_expr = fld.cx.expr(span,
-                                    ast::ExprMatch(expr, arms, ast::MatchSource::WhileLetDesugar));
-
-            // `[opt_ident]: loop { ... }`
-            let loop_block = fld.cx.block_expr(match_expr);
-            let (loop_block, opt_ident) = expand_loop_block(loop_block, opt_ident, fld);
-            let result = fld.cx.expr(span, ast::ExprLoop(loop_block, opt_ident));
-            fld.cx.bt_pop();
-            result
-        }
-
-        // Desugar ExprIfLet
-        // From: `if let <pat> = <expr> <body> [<elseopt>]`
-        ast::ExprIfLet(pat, expr, body, mut elseopt) => {
-            // to:
-            //
-            //   match <expr> {
-            //     <pat> => <body>,
-            //     [_ if <elseopt_if_cond> => <elseopt_if_body>,]
-            //     _ => [<elseopt> | ()]
-            //   }
-
-            push_compiler_expansion(fld, span, CompilerExpansionFormat::IfLet);
-
-            // `<pat> => <body>`
-            let pat_arm = {
-                let body_expr = fld.cx.expr_block(body);
-                fld.cx.arm(pat.span, vec![pat], body_expr)
-            };
-
-            // `[_ if <elseopt_if_cond> => <elseopt_if_body>,]`
-            let else_if_arms = {
-                let mut arms = vec![];
-                loop {
-                    let elseopt_continue = elseopt
-                        .and_then(|els| els.and_then(|els| match els.node {
-                        // else if
-                        ast::ExprIf(cond, then, elseopt) => {
-                            let pat_under = fld.cx.pat_wild(span);
-                            arms.push(ast::Arm {
-                                attrs: vec![],
-                                pats: vec![pat_under],
-                                guard: Some(cond),
-                                body: fld.cx.expr_block(then)
-                            });
-                            elseopt.map(|elseopt| (elseopt, true))
-                        }
-                        _ => Some((P(els), false))
-                    }));
-                    match elseopt_continue {
-                        Some((e, true)) => {
-                            elseopt = Some(e);
-                        }
-                        Some((e, false)) => {
-                            elseopt = Some(e);
-                            break;
-                        }
-                        None => {
-                            elseopt = None;
-                            break;
-                        }
-                    }
-                }
-                arms
-            };
-
-            let contains_else_clause = elseopt.is_some();
-
-            // `_ => [<elseopt> | ()]`
-            let else_arm = {
-                let pat_under = fld.cx.pat_wild(span);
-                let else_expr = elseopt.unwrap_or_else(|| fld.cx.expr_tuple(span, vec![]));
-                fld.cx.arm(span, vec![pat_under], else_expr)
-            };
-
-            let mut arms = Vec::with_capacity(else_if_arms.len() + 2);
-            arms.push(pat_arm);
-            arms.extend(else_if_arms);
-            arms.push(else_arm);
-
-            let match_expr = fld.cx.expr(span,
-                                         ast::ExprMatch(expr, arms,
-                                                ast::MatchSource::IfLetDesugar {
-                                                    contains_else_clause: contains_else_clause,
-                                                }));
-            let result = fld.fold_expr(match_expr);
-            fld.cx.bt_pop();
-            result
-        }
+            let pat = fld.fold_pat(pat);
+            let expr = fld.fold_expr(expr);
+
+            // Hygienic renaming of the body.
+            let ((body, opt_ident), mut rewritten_pats) =
+                rename_in_scope(vec![pat],
+                                fld,
+                                (body, opt_ident),
+                                |rename_fld, fld, (body, opt_ident)| {
+                expand_loop_block(rename_fld.fold_block(body), opt_ident, fld)
+            });
+            assert!(rewritten_pats.len() == 1);
 
-        // Desugar support for ExprIfLet in the ExprIf else position
-        ast::ExprIf(cond, blk, elseopt) => {
-            let elseopt = elseopt.map(|els| els.and_then(|els| match els.node {
-                ast::ExprIfLet(..) => {
-                    push_compiler_expansion(fld, span, CompilerExpansionFormat::IfLet);
-                    // wrap the if-let expr in a block
-                    let span = els.span;
-                    let blk = P(ast::Block {
-                        stmts: vec![],
-                        expr: Some(P(els)),
-                        id: ast::DUMMY_NODE_ID,
-                        rules: ast::DefaultBlock,
-                        span: span
-                    });
-                    let result = fld.cx.expr_block(blk);
-                    fld.cx.bt_pop();
-                    result
-                }
-                _ => P(els)
-            }));
-            let if_expr = fld.cx.expr(span, ast::ExprIf(cond, blk, elseopt));
-            if_expr.map(|e| noop_fold_expr(e, fld))
+            fld.cx.expr(span, ast::ExprWhileLet(rewritten_pats.remove(0), expr, body, opt_ident))
         }
 
         ast::ExprLoop(loop_block, opt_ident) => {
@@ -360,102 +101,39 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
             fld.cx.expr(span, ast::ExprLoop(loop_block, opt_ident))
         }
 
-        // Desugar ExprForLoop
-        // From: `[opt_ident]: for <pat> in <head> <body>`
         ast::ExprForLoop(pat, head, body, opt_ident) => {
-            // to:
-            //
-            //   {
-            //     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
-            //   }
-
-            push_compiler_expansion(fld, span, CompilerExpansionFormat::ForLoop);
-
-            let span = fld.new_span(span);
+            let pat = fld.fold_pat(pat);
+
+            // Hygienic renaming of the for loop body (for loop binds its pattern).
+            let ((body, opt_ident), mut rewritten_pats) =
+                rename_in_scope(vec![pat],
+                                fld,
+                                (body, opt_ident),
+                                |rename_fld, fld, (body, opt_ident)| {
+                expand_loop_block(rename_fld.fold_block(body), opt_ident, fld)
+            });
+            assert!(rewritten_pats.len() == 1);
 
-            // expand <head>
             let head = fld.fold_expr(head);
+            fld.cx.expr(span, ast::ExprForLoop(rewritten_pats.remove(0), head, body, opt_ident))
+        }
 
-            let iter = token::gensym_ident("iter");
-
-            let pat_span = fld.new_span(pat.span);
-            // `::std::option::Option::Some(<pat>) => <body>`
-            let pat_arm = {
-                let body_expr = fld.cx.expr_block(body);
-                let pat = fld.fold_pat(pat);
-                let some_pat = fld.cx.pat_some(pat_span, pat);
-
-                fld.cx.arm(pat_span, vec![some_pat], body_expr)
-            };
-
-            // `::std::option::Option::None => break`
-            let break_arm = {
-                let break_expr = fld.cx.expr_break(span);
-
-                fld.cx.arm(span, vec![fld.cx.pat_none(span)], break_expr)
-            };
-
-            // `match ::std::iter::Iterator::next(&mut iter) { ... }`
-            let match_expr = {
-                let next_path = {
-                    let strs = fld.cx.std_path(&["iter", "Iterator", "next"]);
-
-                    fld.cx.path_global(span, strs)
-                };
-                let ref_mut_iter = fld.cx.expr_mut_addr_of(span, fld.cx.expr_ident(span, iter));
-                let next_expr =
-                    fld.cx.expr_call(span, fld.cx.expr_path(next_path), vec![ref_mut_iter]);
-                let arms = vec![pat_arm, break_arm];
-
-                fld.cx.expr(pat_span,
-                            ast::ExprMatch(next_expr, arms, ast::MatchSource::ForLoopDesugar))
-            };
-
-            // `[opt_ident]: loop { ... }`
-            let loop_block = fld.cx.block_expr(match_expr);
-            let (loop_block, opt_ident) = expand_loop_block(loop_block, opt_ident, fld);
-            let loop_expr = fld.cx.expr(span, ast::ExprLoop(loop_block, opt_ident));
-
-            // `mut iter => { ... }`
-            let iter_arm = {
-                let iter_pat =
-                    fld.cx.pat_ident_binding_mode(span, iter, ast::BindByValue(ast::MutMutable));
-                fld.cx.arm(span, vec![iter_pat], loop_expr)
-            };
-
-            // `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
-            let into_iter_expr = {
-                let into_iter_path = {
-                    let strs = fld.cx.std_path(&["iter", "IntoIterator",
-                                                 "into_iter"]);
-
-                    fld.cx.path_global(span, strs)
-                };
-
-                fld.cx.expr_call(span, fld.cx.expr_path(into_iter_path), vec![head])
-            };
+        ast::ExprIfLet(pat, sub_expr, body, else_opt) => {
+            let pat = fld.fold_pat(pat);
 
-            let match_expr = fld.cx.expr_match(span, into_iter_expr, vec![iter_arm]);
+            // Hygienic renaming of the body.
+            let (body, mut rewritten_pats) =
+                rename_in_scope(vec![pat],
+                                fld,
+                                body,
+                                |rename_fld, fld, body| {
+                fld.fold_block(rename_fld.fold_block(body))
+            });
+            assert!(rewritten_pats.len() == 1);
 
-            // `{ let result = ...; result }`
-            let result_ident = token::gensym_ident("result");
-            let 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))));
-            fld.cx.bt_pop();
-            result
+            let else_opt = else_opt.map(|else_opt| fld.fold_expr(else_opt));
+            let sub_expr = fld.fold_expr(sub_expr);
+            fld.cx.expr(span, ast::ExprIfLet(rewritten_pats.remove(0), sub_expr, body, else_opt))
         }
 
         ast::ExprClosure(capture_clause, fn_decl, block) => {
@@ -475,25 +153,6 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
             }, fld))
         }
     });
-
-    fn push_unsafe_expr(cx: &mut ExtCtxt, stmts: Vec<P<ast::Stmt>>,
-                        expr: P<ast::Expr>, span: Span)
-                        -> P<ast::Expr> {
-        let rules = ast::PushUnsafeBlock(ast::CompilerGenerated);
-        cx.expr_block(P(ast::Block {
-            rules: rules, span: span, id: ast::DUMMY_NODE_ID,
-            stmts: stmts, expr: Some(expr),
-        }))
-    }
-
-    fn pop_unsafe_expr(cx: &mut ExtCtxt, expr: P<ast::Expr>, span: Span)
-                       -> P<ast::Expr> {
-        let rules = ast::PopUnsafeBlock(ast::CompilerGenerated);
-        cx.expr_block(P(ast::Block {
-            rules: rules, span: span, id: ast::DUMMY_NODE_ID,
-            stmts: vec![], expr: Some(expr),
-        }))
-    }
 }
 
 /// Expand a (not-ident-style) macro invocation. Returns the result
@@ -948,18 +607,18 @@ fn expand_arm(arm: ast::Arm, fld: &mut MacroExpander) -> ast::Arm {
     if expanded_pats.is_empty() {
         panic!("encountered match arm with 0 patterns");
     }
-    // all of the pats must have the same set of bindings, so use the
-    // first one to extract them and generate new names:
-    let idents = pattern_bindings(&*expanded_pats[0]);
-    let new_renames = idents.into_iter().map(|id| (id, fresh_name(id))).collect();
-    // apply the renaming, but only to the PatIdents:
-    let mut rename_pats_fld = PatIdentRenamer{renames:&new_renames};
-    let rewritten_pats = expanded_pats.move_map(|pat| rename_pats_fld.fold_pat(pat));
+
     // apply renaming and then expansion to the guard and the body:
-    let mut rename_fld = IdentRenamer{renames:&new_renames};
-    let rewritten_guard =
-        arm.guard.map(|g| fld.fold_expr(rename_fld.fold_expr(g)));
-    let rewritten_body = fld.fold_expr(rename_fld.fold_expr(arm.body));
+    let ((rewritten_guard, rewritten_body), rewritten_pats) =
+        rename_in_scope(expanded_pats,
+                        fld,
+                        (arm.guard, arm.body),
+                        |rename_fld, fld, (ag, ab)|{
+        let rewritten_guard = ag.map(|g| fld.fold_expr(rename_fld.fold_expr(g)));
+        let rewritten_body = fld.fold_expr(rename_fld.fold_expr(ab));
+        (rewritten_guard, rewritten_body)
+    });
+
     ast::Arm {
         attrs: fold::fold_attrs(arm.attrs, fld),
         pats: rewritten_pats,
@@ -968,6 +627,25 @@ fn expand_arm(arm: ast::Arm, fld: &mut MacroExpander) -> ast::Arm {
     }
 }
 
+fn rename_in_scope<X, F>(pats: Vec<P<ast::Pat>>,
+                         fld: &mut MacroExpander,
+                         x: X,
+                         f: F)
+                         -> (X, Vec<P<ast::Pat>>)
+    where F: Fn(&mut IdentRenamer, &mut MacroExpander, X) -> X
+{
+    // all of the pats must have the same set of bindings, so use the
+    // first one to extract them and generate new names:
+    let idents = pattern_bindings(&*pats[0]);
+    let new_renames = idents.into_iter().map(|id| (id, fresh_name(id))).collect();
+    // apply the renaming, but only to the PatIdents:
+    let mut rename_pats_fld = PatIdentRenamer{renames:&new_renames};
+    let rewritten_pats = pats.move_map(|pat| rename_pats_fld.fold_pat(pat));
+
+    let mut rename_fld = IdentRenamer{ renames:&new_renames };
+    (f(&mut rename_fld, fld, x), rewritten_pats)
+}
+
 /// A visitor that extracts the PatIdent (binding) paths
 /// from a given thingy and puts them in a mutable
 /// array
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 6129cddfe6d..8efeaa330c0 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -726,7 +726,7 @@ impl<'a, 'v> Visitor<'v> for MacroVisitor<'a> {
 }
 
 struct PostExpansionVisitor<'a> {
-    context: &'a Context<'a>
+    context: &'a Context<'a>,
 }
 
 impl<'a> PostExpansionVisitor<'a> {
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 914b08265fe..3c1aa992a3c 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -1256,10 +1256,9 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span}: Expr, folder: &mut T) ->
                 ExprLoop(folder.fold_block(body),
                         opt_ident.map(|i| folder.fold_ident(i)))
             }
-            ExprMatch(expr, arms, source) => {
+            ExprMatch(expr, arms) => {
                 ExprMatch(folder.fold_expr(expr),
-                        arms.move_map(|x| folder.fold_arm(x)),
-                        source)
+                          arms.move_map(|x| folder.fold_arm(x)))
             }
             ExprClosure(capture_clause, decl, body) => {
                 ExprClosure(capture_clause,
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index f47dfeb1d34..443cea696b6 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -37,7 +37,7 @@ use ast::{LifetimeDef, Lit, Lit_};
 use ast::{LitBool, LitChar, LitByte, LitByteStr};
 use ast::{LitStr, LitInt, Local};
 use ast::{MacStmtWithBraces, MacStmtWithSemicolon, MacStmtWithoutBraces};
-use ast::{MutImmutable, MutMutable, Mac_, MatchSource};
+use ast::{MutImmutable, MutMutable, Mac_};
 use ast::{MutTy, BiMul, Mutability};
 use ast::{MethodImplItem, NamedField, UnNeg, NoReturn, UnNot};
 use ast::{Pat, PatBox, PatEnum, PatIdent, PatLit, PatQPath, PatMac, PatRange};
@@ -2927,7 +2927,7 @@ impl<'a> Parser<'a> {
         }
         let hi = self.span.hi;
         try!(self.bump());
-        return Ok(self.mk_expr(lo, hi, ExprMatch(discriminant, arms, MatchSource::Normal)));
+        return Ok(self.mk_expr(lo, hi, ExprMatch(discriminant, arms)));
     }
 
     pub fn parse_arm_nopanic(&mut self) -> PResult<Arm> {
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 405fd9b8cc7..f5f3907a4e6 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -2045,7 +2045,7 @@ impl<'a> State<'a> {
                 try!(space(&mut self.s));
                 try!(self.print_block(&**blk));
             }
-            ast::ExprMatch(ref expr, ref arms, _) => {
+            ast::ExprMatch(ref expr, ref arms) => {
                 try!(self.cbox(indent_unit));
                 try!(self.ibox(4));
                 try!(self.word_nbsp("match"));
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 67e4927a52f..091580b9bd8 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -731,7 +731,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
             visitor.visit_block(block);
             walk_opt_ident(visitor, expression.span, opt_ident)
         }
-        ExprMatch(ref subexpression, ref arms, _) => {
+        ExprMatch(ref subexpression, ref arms) => {
             visitor.visit_expr(subexpression);
             walk_list!(visitor, visit_arm, arms);
         }