diff --git a/src/libcore/char.rs b/src/libcore/char.rs
index 99c5722699e8d..26baf96a8bc86 100644
--- a/src/libcore/char.rs
+++ b/src/libcore/char.rs
@@ -17,7 +17,10 @@
 
 use mem::transmute;
 use option::{None, Option, Some};
-use iter::{Iterator, range_step};
+use iter::range_step;
+
+#[cfg(stage0)]
+use iter::Iterator; // NOTE(stage0): Remove after snapshot.
 
 // UTF-8 ranges and tags for encoding characters
 static TAG_CONT: u8    = 0b1000_0000u8;
diff --git a/src/libcore/fmt/float.rs b/src/libcore/fmt/float.rs
index ef5b51fd00b3f..386fc28119a3e 100644
--- a/src/libcore/fmt/float.rs
+++ b/src/libcore/fmt/float.rs
@@ -13,15 +13,19 @@
 use char;
 use collections::Collection;
 use fmt;
-use iter::{Iterator, range, DoubleEndedIterator};
+use iter::{range, DoubleEndedIterator};
 use num::{Float, FPNaN, FPInfinite, ToPrimitive, Primitive};
 use num::{Zero, One, cast};
-use option::{None, Some};
 use result::Ok;
 use slice::{ImmutableVector, MutableVector};
 use slice;
 use str::StrSlice;
 
+#[cfg(stage0)]
+use iter::Iterator;         // NOTE(stage0): Remove after snapshot.
+#[cfg(stage0)]
+use option::{Some, None};   // NOTE(stage0): Remove after snapshot.
+
 /// A flag that specifies whether to use exponential (scientific) notation.
 pub enum ExponentFormat {
     /// Do not use exponential notation.
diff --git a/src/libcore/fmt/num.rs b/src/libcore/fmt/num.rs
index d52791f6b0ea2..81e84c447e796 100644
--- a/src/libcore/fmt/num.rs
+++ b/src/libcore/fmt/num.rs
@@ -16,11 +16,15 @@
 
 use collections::Collection;
 use fmt;
-use iter::{Iterator, DoubleEndedIterator};
+use iter::DoubleEndedIterator;
 use num::{Int, cast, zero};
-use option::{Some, None};
 use slice::{ImmutableVector, MutableVector};
 
+#[cfg(stage0)]
+use iter::Iterator;         // NOTE(stage0): Remove after snapshot.
+#[cfg(stage0)]
+use option::{Some, None};   // NOTE(stage0): Remove after snapshot.
+
 /// A type that represents a specific radix
 trait GenericRadix {
     /// The number of digits.
diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs
index 7706d01cbaed6..b0660230c2ce6 100644
--- a/src/libcore/iter.rs
+++ b/src/libcore/iter.rs
@@ -95,6 +95,7 @@ pub trait Extendable<A>: FromIterator<A> {
 /// is returned. A concrete Iterator implementation may choose to behave however
 /// it wishes, either by returning `None` infinitely, or by doing something
 /// else.
+#[lang="iterator"]
 pub trait Iterator<A> {
     /// Advance the iterator and return the next value. Return `None` when the end is reached.
     fn next(&mut self) -> Option<A>;
diff --git a/src/libcore/option.rs b/src/libcore/option.rs
index b8612ed93e02d..84b402a68dd12 100644
--- a/src/libcore/option.rs
+++ b/src/libcore/option.rs
@@ -147,7 +147,12 @@ use iter::{Iterator, DoubleEndedIterator, FromIterator, ExactSize};
 use mem;
 use slice;
 
-/// The `Option`
+// Note that this is not a lang item per se, but it has a hidden dependency on
+// `Iterator`, which is one. The compiler assumes that the `next` method of
+// `Iterator` is an enumeration with one type parameter and two variants,
+// which basically means it must be `Option`.
+
+/// The `Option` type.
 #[deriving(Clone, PartialEq, PartialOrd, Eq, Ord, Show)]
 pub enum Option<T> {
     /// No value
diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs
index ed1d4d481100b..4921802ba732e 100644
--- a/src/libcore/ptr.rs
+++ b/src/libcore/ptr.rs
@@ -90,11 +90,14 @@
 use mem;
 use clone::Clone;
 use intrinsics;
-use iter::{range, Iterator};
+use iter::range;
 use option::{Some, None, Option};
 
 use cmp::{PartialEq, Eq, PartialOrd, Equiv, Ordering, Less, Equal, Greater};
 
+#[cfg(stage0)]
+use iter::Iterator; // NOTE(stage0): Remove after snapshot.
+
 pub use intrinsics::copy_memory;
 pub use intrinsics::copy_nonoverlapping_memory;
 pub use intrinsics::set_memory;
diff --git a/src/libcore/str.rs b/src/libcore/str.rs
index 37af64d74d414..2ba51eb98fca0 100644
--- a/src/libcore/str.rs
+++ b/src/libcore/str.rs
@@ -28,7 +28,7 @@ use iter::{Map, Iterator};
 use iter::{DoubleEndedIterator, ExactSize};
 use iter::range;
 use num::{CheckedMul, Saturating};
-use option::{None, Option, Some};
+use option::{Option, None, Some};
 use raw::Repr;
 use slice::ImmutableVector;
 use slice;
@@ -1027,9 +1027,12 @@ pub mod traits {
     use cmp::{Ord, Ordering, Less, Equal, Greater, PartialEq, PartialOrd, Equiv, Eq};
     use collections::Collection;
     use iter::Iterator;
-    use option::{Option, Some, None};
+    use option::{Option, Some};
     use str::{Str, StrSlice, eq_slice};
 
+    #[cfg(stage0)]
+    use option::None;   // NOTE(stage0): Remove after snapshot.
+
     impl<'a> Ord for &'a str {
         #[inline]
         fn cmp(&self, other: & &'a str) -> Ordering {
diff --git a/src/libcoretest/iter.rs b/src/libcoretest/iter.rs
index 64c336093996d..cadbc238e679a 100644
--- a/src/libcoretest/iter.rs
+++ b/src/libcoretest/iter.rs
@@ -137,8 +137,8 @@ fn test_iterator_take_while() {
     let ys = [0u, 1, 2, 3, 5, 13];
     let mut it = xs.iter().take_while(|&x| *x < 15u);
     let mut i = 0;
-    for &x in it {
-        assert_eq!(x, ys[i]);
+    for x in it {
+        assert_eq!(*x, ys[i]);
         i += 1;
     }
     assert_eq!(i, ys.len());
@@ -150,8 +150,8 @@ fn test_iterator_skip_while() {
     let ys = [15, 16, 17, 19];
     let mut it = xs.iter().skip_while(|&x| *x < 15u);
     let mut i = 0;
-    for &x in it {
-        assert_eq!(x, ys[i]);
+    for x in it {
+        assert_eq!(*x, ys[i]);
         i += 1;
     }
     assert_eq!(i, ys.len());
diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs
index 2aa0818b177cf..b570cb43f164e 100644
--- a/src/librustc/middle/borrowck/check_loans.rs
+++ b/src/librustc/middle/borrowck/check_loans.rs
@@ -440,6 +440,7 @@ impl<'a> CheckLoanCtxt<'a> {
                 euv::AddrOf(..) |
                 euv::AutoRef(..) |
                 euv::ClosureInvocation(..) |
+                euv::ForLoop(..) |
                 euv::RefBinding(..) => {
                     format!("previous borrow of `{}` occurs here",
                             self.bccx.loan_path_to_string(&*old_loan.loan_path))
@@ -668,6 +669,11 @@ impl<'a> CheckLoanCtxt<'a> {
             return;
         }
 
+        // Initializations are OK.
+        if mode == euv::Init {
+            return
+        }
+
         // For immutable local variables, assignments are legal
         // if they cannot already have been assigned
         if self.is_local_variable_or_arg(assignee_cmt.clone()) {
diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs
index 5604d33496d9d..3ed0f61a8f064 100644
--- a/src/librustc/middle/borrowck/mod.rs
+++ b/src/librustc/middle/borrowck/mod.rs
@@ -651,7 +651,8 @@ impl<'a> BorrowckCtxt<'a> {
                     euv::OverloadedOperator |
                     euv::AddrOf |
                     euv::RefBinding |
-                    euv::AutoRef => {
+                    euv::AutoRef |
+                    euv::ForLoop => {
                         format!("cannot borrow {} as mutable", descr)
                     }
                     euv::ClosureInvocation => {
@@ -712,6 +713,10 @@ impl<'a> BorrowckCtxt<'a> {
             BorrowViolation(euv::ClosureInvocation) => {
                 "closure invocation"
             }
+
+            BorrowViolation(euv::ForLoop) => {
+                "`for` loop"
+            }
         };
 
         match cause {
diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs
index 208a9d057166e..4f6885f05ed16 100644
--- a/src/librustc/middle/cfg/construct.rs
+++ b/src/librustc/middle/cfg/construct.rs
@@ -240,7 +240,7 @@ impl<'a> CFGBuilder<'a> {
                 //   v 3
                 // [expr]
                 //
-                // Note that `break` and `loop` statements
+                // Note that `break` and `continue` statements
                 // may cause additional edges.
 
                 // Is the condition considered part of the loop?
@@ -258,7 +258,44 @@ impl<'a> CFGBuilder<'a> {
                 expr_exit
             }
 
-            ast::ExprForLoop(..) => fail!("non-desugared expr_for_loop"),
+            ast::ExprForLoop(ref pat, ref head, ref body, _) => {
+                //
+                //          [pred]
+                //            |
+                //            v 1
+                //          [head]
+                //            |
+                //            v 2
+                //        [loopback] <--+ 7
+                //            |         |
+                //            v 3       |
+                //   +------[cond]      |
+                //   |        |         |
+                //   |        v 5       |
+                //   |       [pat]      |
+                //   |        |         |
+                //   |        v 6       |
+                //   v 4    [body] -----+
+                // [expr]
+                //
+                // Note that `break` and `continue` statements
+                // may cause additional edges.
+
+                let head = self.expr(head.clone(), pred);       // 1
+                let loopback = self.add_dummy_node([head]);     // 2
+                let cond = self.add_dummy_node([loopback]);     // 3
+                let expr_exit = self.add_node(expr.id, [cond]); // 4
+                self.loop_scopes.push(LoopScope {
+                    loop_id: expr.id,
+                    continue_index: loopback,
+                    break_index: expr_exit,
+                });
+                let pat = self.pat(&**pat, cond);               // 5
+                let body = self.block(&**body, pat);            // 6
+                self.add_contained_edge(body, loopback);        // 7
+                self.loop_scopes.pop();
+                expr_exit
+            }
 
             ast::ExprLoop(ref body, _) => {
                 //
diff --git a/src/librustc/middle/check_loop.rs b/src/librustc/middle/check_loop.rs
index ac8faaa6c6db5..61a2e8407303b 100644
--- a/src/librustc/middle/check_loop.rs
+++ b/src/librustc/middle/check_loop.rs
@@ -42,6 +42,10 @@ impl<'a> Visitor<Context> for CheckLoopVisitor<'a> {
             ast::ExprLoop(ref b, _) => {
                 self.visit_block(&**b, Loop);
             }
+            ast::ExprForLoop(_, ref e, ref b, _) => {
+                self.visit_expr(&**e, cx);
+                self.visit_block(&**b, Loop);
+            }
             ast::ExprFnBlock(_, ref b) |
             ast::ExprProc(_, ref b) |
             ast::ExprUnboxedFn(_, ref b) => {
diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs
index 67208e3337286..e458b82f03634 100644
--- a/src/librustc/middle/check_match.rs
+++ b/src/librustc/middle/check_match.rs
@@ -170,6 +170,24 @@ fn check_expr(cx: &mut MatchCheckCtxt, ex: &Expr) {
                 .collect();
             check_exhaustive(cx, ex.span, &matrix);
         },
+        ExprForLoop(ref pat, _, _, _) => {
+            let mut static_inliner = StaticInliner {
+                tcx: cx.tcx
+            };
+            match is_refutable(cx, static_inliner.fold_pat(*pat)) {
+                Some(uncovered_pat) => {
+                    cx.tcx.sess.span_err(
+                        pat.span,
+                        format!("refutable pattern in `for` loop binding: \
+                                 `{}` not covered",
+                                pat_to_string(&*uncovered_pat)).as_slice());
+                },
+                None => {}
+            }
+
+            // Check legality of move bindings.
+            check_legality_of_move_bindings(cx, false, [ *pat ]);
+        }
         _ => ()
     }
 }
diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs
index 9fc589ddf59eb..108bd35424aec 100644
--- a/src/librustc/middle/dead.rs
+++ b/src/librustc/middle/dead.rs
@@ -354,11 +354,11 @@ fn create_and_seed_worklist(tcx: &ty::ctxt,
     // depending on whether a crate is built as bin or lib, and we want
     // the warning to be consistent, we also seed the worklist with
     // exported symbols.
-    for &id in exported_items.iter() {
-        worklist.push(id);
+    for id in exported_items.iter() {
+        worklist.push(*id);
     }
-    for &id in reachable_symbols.iter() {
-        worklist.push(id);
+    for id in reachable_symbols.iter() {
+        worklist.push(*id);
     }
 
     // Seed entry point
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index b911e636da091..7995317d49fd1 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -79,7 +79,8 @@ pub enum LoanCause {
     AutoRef,
     RefBinding,
     OverloadedOperator,
-    ClosureInvocation
+    ClosureInvocation,
+    ForLoop,
 }
 
 #[deriving(PartialEq,Show)]
@@ -395,7 +396,16 @@ impl<'d,'t,TYPER:mc::Typer> ExprUseVisitor<'d,'t,TYPER> {
                 self.walk_block(&**blk);
             }
 
-            ast::ExprForLoop(..) => fail!("non-desugared expr_for_loop"),
+            ast::ExprForLoop(ref pat, ref head, ref blk, _) => {
+                // The pattern lives as long as the block.
+                debug!("walk_expr for loop case: blk id={}", blk.id);
+                self.walk_expr(&**head);
+
+                let head_cmt = return_if_err!(self.mc.cat_expr(&**head));
+                self.walk_pat(head_cmt, pat.clone());
+
+                self.walk_block(&**blk);
+            }
 
             ast::ExprUnary(_, ref lhs) => {
                 if !self.walk_overloaded_operator(expr, &**lhs, []) {
diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs
index 9abc9226c1364..f59909bd138b2 100644
--- a/src/librustc/middle/lang_items.rs
+++ b/src/librustc/middle/lang_items.rs
@@ -299,5 +299,7 @@ lets_do_this! {
     NoShareItem,                     "no_share_bound",          no_share_bound;
     ManagedItem,                     "managed_bound",           managed_bound;
 
+    IteratorItem,                    "iterator",                iterator;
+
     StackExhaustedLangItem,          "stack_exhausted",         stack_exhausted;
 }
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index 737b952151b67..1c31b671a947b 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -125,6 +125,17 @@ use syntax::print::pprust::{expr_to_string, block_to_string};
 use syntax::{visit, ast_util};
 use syntax::visit::{Visitor, FnKind};
 
+/// For use with `propagate_through_loop`.
+#[deriving(PartialEq, Eq)]
+enum LoopKind {
+    /// An endless `loop` loop.
+    LoopLoop,
+    /// A `while` loop, with the given expression as condition.
+    WhileLoop(Gc<Expr>),
+    /// A `for` loop.
+    ForLoop,
+}
+
 #[deriving(PartialEq)]
 struct Variable(uint);
 #[deriving(PartialEq)]
@@ -480,7 +491,20 @@ fn visit_expr(ir: &mut IrMaps, expr: &Expr) {
         ir.add_live_node_for_node(expr.id, ExprNode(expr.span));
         visit::walk_expr(ir, expr, ());
       }
-      ExprForLoop(..) => fail!("non-desugared expr_for_loop"),
+      ExprForLoop(ref pat, _, _, _) => {
+        pat_util::pat_bindings(&ir.tcx.def_map, &**pat, |bm, p_id, sp, path1| {
+            debug!("adding local variable {} from for loop with bm {:?}",
+                   p_id, bm);
+            let name = path1.node;
+            ir.add_live_node_for_node(p_id, VarDefNode(sp));
+            ir.add_variable(Local(LocalInfo {
+                id: p_id,
+                ident: name
+            }));
+        });
+        ir.add_live_node_for_node(expr.id, ExprNode(expr.span));
+        visit::walk_expr(ir, expr, ());
+      }
       ExprBinary(op, _, _) if ast_util::lazy_binop(op) => {
         ir.add_live_node_for_node(expr.id, ExprNode(expr.span));
         visit::walk_expr(ir, expr, ());
@@ -994,15 +1018,21 @@ impl<'a> Liveness<'a> {
           }
 
           ExprWhile(ref cond, ref blk) => {
-            self.propagate_through_loop(expr, Some(cond.clone()), &**blk, succ)
+            self.propagate_through_loop(expr,
+                                        WhileLoop(cond.clone()),
+                                        &**blk,
+                                        succ)
           }
 
-          ExprForLoop(..) => fail!("non-desugared expr_for_loop"),
+          ExprForLoop(_, ref head, ref blk, _) => {
+            let ln = self.propagate_through_loop(expr, ForLoop, &**blk, succ);
+            self.propagate_through_expr(&**head, ln)
+          }
 
           // Note that labels have been resolved, so we don't need to look
           // at the label ident
           ExprLoop(ref blk, _) => {
-            self.propagate_through_loop(expr, None, &**blk, succ)
+            self.propagate_through_loop(expr, LoopLoop, &**blk, succ)
           }
 
           ExprMatch(ref e, ref arms) => {
@@ -1281,7 +1311,7 @@ impl<'a> Liveness<'a> {
 
     fn propagate_through_loop(&mut self,
                               expr: &Expr,
-                              cond: Option<Gc<Expr>>,
+                              kind: LoopKind,
                               body: &Block,
                               succ: LiveNode)
                               -> LiveNode {
@@ -1309,17 +1339,20 @@ impl<'a> Liveness<'a> {
         let mut first_merge = true;
         let ln = self.live_node(expr.id, expr.span);
         self.init_empty(ln, succ);
-        if cond.is_some() {
-            // if there is a condition, then it's possible we bypass
-            // the body altogether.  otherwise, the only way is via a
-            // break in the loop body.
+        if kind != LoopLoop {
+            // If this is not a `loop` loop, then it's possible we bypass
+            // the body altogether. Otherwise, the only way is via a `break`
+            // in the loop body.
             self.merge_from_succ(ln, succ, first_merge);
             first_merge = false;
         }
         debug!("propagate_through_loop: using id for loop body {} {}",
                expr.id, block_to_string(body));
 
-        let cond_ln = self.propagate_through_opt_expr(cond, ln);
+        let cond_ln = match kind {
+            LoopLoop | ForLoop => ln,
+            WhileLoop(ref cond) => self.propagate_through_expr(&**cond, ln),
+        };
         let body_ln = self.with_loop_nodes(expr.id, succ, ln, |this| {
             this.propagate_through_block(body, cond_ln)
         });
@@ -1327,8 +1360,14 @@ impl<'a> Liveness<'a> {
         // repeat until fixed point is reached:
         while self.merge_from_succ(ln, body_ln, first_merge) {
             first_merge = false;
-            assert!(cond_ln == self.propagate_through_opt_expr(cond,
-                                                                    ln));
+
+            let new_cond_ln = match kind {
+                LoopLoop | ForLoop => ln,
+                WhileLoop(ref cond) => {
+                    self.propagate_through_expr(&**cond, ln)
+                }
+            };
+            assert!(cond_ln == new_cond_ln);
             assert!(body_ln == self.with_loop_nodes(expr.id, succ, ln,
             |this| this.propagate_through_block(body, cond_ln)));
         }
@@ -1415,10 +1454,9 @@ fn check_expr(this: &mut Liveness, expr: &Expr) {
       ExprAgain(..) | ExprLit(_) | ExprBlock(..) |
       ExprMac(..) | ExprAddrOf(..) | ExprStruct(..) | ExprRepeat(..) |
       ExprParen(..) | ExprFnBlock(..) | ExprProc(..) | ExprUnboxedFn(..) |
-      ExprPath(..) | ExprBox(..) => {
+      ExprPath(..) | ExprBox(..) | ExprForLoop(..) => {
         visit::walk_expr(this, expr, ());
       }
-      ExprForLoop(..) => fail!("non-desugared expr_for_loop")
     }
 }
 
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index baf7f2dd77650..317fdb5c387e2 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -482,11 +482,10 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
           ast::ExprBlock(..) | ast::ExprLoop(..) | ast::ExprMatch(..) |
           ast::ExprLit(..) | ast::ExprBreak(..) | ast::ExprMac(..) |
           ast::ExprAgain(..) | ast::ExprStruct(..) | ast::ExprRepeat(..) |
-          ast::ExprInlineAsm(..) | ast::ExprBox(..) => {
+          ast::ExprInlineAsm(..) | ast::ExprBox(..) |
+          ast::ExprForLoop(..) => {
             Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty))
           }
-
-          ast::ExprForLoop(..) => fail!("non-desugared expr_for_loop")
         }
     }
 
@@ -1113,7 +1112,7 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
           }
 
           ast::PatBox(ref subpat) | ast::PatRegion(ref subpat) => {
-            // @p1, ~p1
+            // @p1, ~p1, ref p1
             let subcmt = self.cat_deref(pat, cmt, 0, false);
             if_ok!(self.cat_pattern(subcmt, &**subpat, op));
           }
diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs
index e404ce8566375..7ed1209bdf750 100644
--- a/src/librustc/middle/reachable.rs
+++ b/src/librustc/middle/reachable.rs
@@ -365,8 +365,8 @@ pub fn find_reachable(tcx: &ty::ctxt,
     //         other crates link to us, they're going to expect to be able to
     //         use the lang items, so we need to be sure to mark them as
     //         exported.
-    for &id in exported_items.iter() {
-        reachable_context.worklist.push(id);
+    for id in exported_items.iter() {
+        reachable_context.worklist.push(*id);
     }
     for (_, item) in tcx.lang_items.items() {
         match *item {
diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs
index 822a43f2619dc..5f5a324857ab9 100644
--- a/src/librustc/middle/region.rs
+++ b/src/librustc/middle/region.rs
@@ -208,7 +208,9 @@ impl RegionMaps {
     pub fn var_region(&self, id: ast::NodeId) -> ty::Region {
         //! Returns the lifetime of the variable `id`.
 
-        ty::ReScope(self.var_scope(id))
+        let scope = ty::ReScope(self.var_scope(id));
+        debug!("var_region({}) = {:?}", id, scope);
+        scope
     }
 
     pub fn scopes_intersect(&self, scope1: ast::NodeId, scope2: ast::NodeId)
@@ -524,6 +526,14 @@ fn resolve_expr(visitor: &mut RegionResolutionVisitor,
             visitor.region_maps.mark_as_terminating_scope(body.id);
         }
 
+        ast::ExprForLoop(ref _pat, ref _head, ref body, _) => {
+            visitor.region_maps.mark_as_terminating_scope(body.id);
+
+            // The variable parent of everything inside (most importantly, the
+            // pattern) is the body.
+            new_cx.var_parent = Some(body.id);
+        }
+
         ast::ExprMatch(..) => {
             new_cx.var_parent = Some(expr.id);
         }
diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs
index 0fb377838feb1..95c04ad6607d6 100644
--- a/src/librustc/middle/resolve.rs
+++ b/src/librustc/middle/resolve.rs
@@ -5329,7 +5329,42 @@ impl<'a> Resolver<'a> {
                 })
             }
 
-            ExprForLoop(..) => fail!("non-desugared expr_for_loop"),
+            ExprForLoop(ref pattern, ref head, ref body, optional_label) => {
+                self.resolve_expr(&**head);
+
+                self.value_ribs.borrow_mut().push(Rib::new(NormalRibKind));
+
+                self.resolve_pattern(&**pattern,
+                                     LocalIrrefutableMode,
+                                     &mut HashMap::new());
+
+                match optional_label {
+                    None => {}
+                    Some(label) => {
+                        self.label_ribs
+                            .borrow_mut()
+                            .push(Rib::new(NormalRibKind));
+                        let def_like = DlDef(DefLabel(expr.id));
+
+                        {
+                            let label_ribs = self.label_ribs.borrow();
+                            let length = label_ribs.len();
+                            let rib = label_ribs.get(length - 1);
+                            let renamed = mtwt::resolve(label);
+                            rib.bindings.borrow_mut().insert(renamed,
+                                                             def_like);
+                        }
+                    }
+                }
+
+                self.resolve_block(&**body);
+
+                if optional_label.is_some() {
+                    drop(self.label_ribs.borrow_mut().pop())
+                }
+
+                self.value_ribs.borrow_mut().pop();
+            }
 
             ExprBreak(Some(label)) | ExprAgain(Some(label)) => {
                 let renamed = mtwt::resolve(label);
diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs
index 419fcffba3686..0b181d2cf367a 100644
--- a/src/librustc/middle/trans/_match.rs
+++ b/src/librustc/middle/trans/_match.rs
@@ -1543,6 +1543,31 @@ pub fn store_arg<'a>(mut bcx: &'a Block<'a>,
     }
 }
 
+/// Generates code for the pattern binding in a `for` loop like
+/// `for <pat> in <expr> { ... }`.
+pub fn store_for_loop_binding<'a>(
+                              bcx: &'a Block<'a>,
+                              pat: Gc<ast::Pat>,
+                              llvalue: ValueRef,
+                              body_scope: cleanup::ScopeId)
+                              -> &'a Block<'a> {
+    let _icx = push_ctxt("match::store_for_loop_binding");
+
+    if simple_identifier(&*pat).is_some() {
+        // Generate nicer LLVM for the common case of a `for` loop pattern
+        // like `for x in blahblah { ... }`.
+        let binding_type = node_id_type(bcx, pat.id);
+        bcx.fcx.lllocals.borrow_mut().insert(pat.id,
+                                             Datum::new(llvalue,
+                                                        binding_type,
+                                                        Lvalue));
+        return bcx
+    }
+
+    // General path. Copy out the values that are used in the pattern.
+    bind_irrefutable_pat(bcx, pat, llvalue, BindLocal, body_scope)
+}
+
 fn mk_binding_alloca<'a,A>(bcx: &'a Block<'a>,
                            p_id: ast::NodeId,
                            ident: &ast::Ident,
diff --git a/src/librustc/middle/trans/controlflow.rs b/src/librustc/middle/trans/controlflow.rs
index 845684bb037a9..d8a8cc1c561a9 100644
--- a/src/librustc/middle/trans/controlflow.rs
+++ b/src/librustc/middle/trans/controlflow.rs
@@ -12,16 +12,23 @@ use llvm::*;
 use driver::config::FullDebugInfo;
 use middle::def;
 use middle::lang_items::{FailFnLangItem, FailBoundsCheckFnLangItem};
+use middle::trans::_match;
+use middle::trans::adt;
 use middle::trans::base::*;
 use middle::trans::build::*;
 use middle::trans::callee;
 use middle::trans::cleanup::CleanupMethods;
 use middle::trans::cleanup;
 use middle::trans::common::*;
+use middle::trans::datum;
 use middle::trans::debuginfo;
 use middle::trans::expr;
+use middle::trans::meth;
+use middle::trans::type_::Type;
 use middle::ty;
+use middle::typeck::MethodCall;
 use util::ppaux::Repr;
+use util::ppaux;
 
 use syntax::ast;
 use syntax::ast::Ident;
@@ -237,6 +244,129 @@ pub fn trans_while<'a>(bcx: &'a Block<'a>,
     return next_bcx_in;
 }
 
+/// Translates a `for` loop.
+pub fn trans_for<'a>(
+                 mut bcx: &'a Block<'a>,
+                 loop_info: NodeInfo,
+                 pat: Gc<ast::Pat>,
+                 head: &ast::Expr,
+                 body: &ast::Block)
+                 -> &'a Block<'a> {
+    let _icx = push_ctxt("trans_for");
+
+    //            bcx
+    //             |
+    //      loopback_bcx_in  <-------+
+    //             |                 |
+    //      loopback_bcx_out         |
+    //           |      |            |
+    //           |    body_bcx_in    |
+    // cleanup_blk      |            |
+    //    |           body_bcx_out --+
+    // next_bcx_in
+
+    // Codegen the head to create the iterator value.
+    let iterator_datum =
+        unpack_datum!(bcx, expr::trans_to_lvalue(bcx, head, "for_head"));
+    let iterator_type = node_id_type(bcx, head.id);
+    debug!("iterator type is {}, datum type is {}",
+           ppaux::ty_to_string(bcx.tcx(), iterator_type),
+           ppaux::ty_to_string(bcx.tcx(), iterator_datum.ty));
+    let lliterator = load_ty(bcx, iterator_datum.val, iterator_datum.ty);
+
+    // Create our basic blocks and set up our loop cleanups.
+    let next_bcx_in = bcx.fcx.new_id_block("for_exit", loop_info.id);
+    let loopback_bcx_in = bcx.fcx.new_id_block("for_loopback", head.id);
+    let body_bcx_in = bcx.fcx.new_id_block("for_body", body.id);
+    bcx.fcx.push_loop_cleanup_scope(loop_info.id,
+                                    [next_bcx_in, loopback_bcx_in]);
+    Br(bcx, loopback_bcx_in.llbb);
+    let cleanup_llbb = bcx.fcx.normal_exit_block(loop_info.id,
+                                                 cleanup::EXIT_BREAK);
+
+    // Set up the method call (to `.next()`).
+    let method_call = MethodCall::expr(loop_info.id);
+    let method_type = loopback_bcx_in.tcx()
+                                     .method_map
+                                     .borrow()
+                                     .get(&method_call)
+                                     .ty;
+    let method_type = monomorphize_type(loopback_bcx_in, method_type);
+    let method_result_type = ty::ty_fn_ret(method_type);
+    let option_cleanup_scope = body_bcx_in.fcx.push_custom_cleanup_scope();
+    let option_cleanup_scope_id = cleanup::CustomScope(option_cleanup_scope);
+
+    // Compile the method call (to `.next()`).
+    let mut loopback_bcx_out = loopback_bcx_in;
+    let option_datum =
+        unpack_datum!(loopback_bcx_out,
+                      datum::lvalue_scratch_datum(loopback_bcx_out,
+                                                  method_result_type,
+                                                  "loop_option",
+                                                  false,
+                                                  option_cleanup_scope_id,
+                                                  (),
+                                                  |(), bcx, lloption| {
+        let Result {
+            bcx: bcx,
+            val: _
+        } = callee::trans_call_inner(bcx,
+                                     Some(loop_info),
+                                     method_type,
+                                     |bcx, arg_cleanup_scope| {
+                                         meth::trans_method_callee(
+                                             bcx,
+                                             method_call,
+                                             None,
+                                             arg_cleanup_scope)
+                                     },
+                                     callee::ArgVals([lliterator]),
+                                     Some(expr::SaveIn(lloption)));
+        bcx
+    }));
+
+    // Check the discriminant; if the `None` case, exit the loop.
+    let option_representation = adt::represent_type(loopback_bcx_out.ccx(),
+                                                    method_result_type);
+    let i8_type = Type::i8(loopback_bcx_out.ccx());
+    let lldiscriminant = adt::trans_get_discr(loopback_bcx_out,
+                                              &*option_representation,
+                                              option_datum.val,
+                                              Some(i8_type));
+    let llzero = C_u8(loopback_bcx_out.ccx(), 0);
+    let llcondition = ICmp(loopback_bcx_out, IntNE, lldiscriminant, llzero);
+    CondBr(loopback_bcx_out, llcondition, body_bcx_in.llbb, cleanup_llbb);
+
+    // Now we're in the body. Unpack the `Option` value into the programmer-
+    // supplied pattern.
+    let llpayload = adt::trans_field_ptr(body_bcx_in,
+                                         &*option_representation,
+                                         option_datum.val,
+                                         1,
+                                         0);
+    let binding_cleanup_scope = body_bcx_in.fcx.push_custom_cleanup_scope();
+    let binding_cleanup_scope_id =
+        cleanup::CustomScope(binding_cleanup_scope);
+    let mut body_bcx_out =
+        _match::store_for_loop_binding(body_bcx_in,
+                                       pat,
+                                       llpayload,
+                                       binding_cleanup_scope_id);
+
+    // Codegen the body.
+    body_bcx_out = trans_block(body_bcx_out, body, expr::Ignore);
+    body_bcx_out.fcx.pop_custom_cleanup_scope(binding_cleanup_scope);
+    body_bcx_out =
+        body_bcx_out.fcx
+                    .pop_and_trans_custom_cleanup_scope(body_bcx_out,
+                                                        option_cleanup_scope);
+    Br(body_bcx_out, loopback_bcx_in.llbb);
+
+    // Codegen cleanups and leave.
+    next_bcx_in.fcx.pop_loop_cleanup_scope(loop_info.id);
+    next_bcx_in
+}
+
 pub fn trans_loop<'a>(bcx:&'a Block<'a>,
                       loop_id: ast::NodeId,
                       body: &ast::Block)
diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs
index 66722b2c4dbda..6fe3ee5d29b58 100644
--- a/src/librustc/middle/trans/debuginfo.rs
+++ b/src/librustc/middle/trans/debuginfo.rs
@@ -3582,9 +3582,24 @@ fn populate_scope_map(cx: &CrateContext,
                 })
             }
 
-            ast::ExprForLoop(_, _, _, _) => {
-                cx.sess().span_bug(exp.span, "debuginfo::populate_scope_map() - \
-                                              Found unexpanded for-loop.");
+            ast::ExprForLoop(ref pattern, ref head, ref body, _) => {
+                walk_expr(cx, &**head, scope_stack, scope_map);
+
+                with_new_scope(cx,
+                               exp.span,
+                               scope_stack,
+                               scope_map,
+                               |cx, scope_stack, scope_map| {
+                    scope_map.insert(exp.id,
+                                     scope_stack.last()
+                                                .unwrap()
+                                                .scope_metadata);
+                    walk_pattern(cx,
+                                 *pattern,
+                                 scope_stack,
+                                 scope_map);
+                    walk_block(cx, &**body, scope_stack, scope_map);
+                })
             }
 
             ast::ExprMac(_) => {
diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs
index 4cb1edbe1e77f..9d970b1a393c5 100644
--- a/src/librustc/middle/trans/expr.rs
+++ b/src/librustc/middle/trans/expr.rs
@@ -665,6 +665,13 @@ fn trans_rvalue_stmt_unadjusted<'a>(bcx: &'a Block<'a>,
         ast::ExprWhile(ref cond, ref body) => {
             controlflow::trans_while(bcx, expr.id, &**cond, &**body)
         }
+        ast::ExprForLoop(ref pat, ref head, ref body, _) => {
+            controlflow::trans_for(bcx,
+                                   expr_info(expr),
+                                   *pat,
+                                   &**head,
+                                   &**body)
+        }
         ast::ExprLoop(ref body, _) => {
             controlflow::trans_loop(bcx, expr.id, &**body)
         }
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 4dfd15fe13619..8f60fe340e4d6 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -3090,7 +3090,7 @@ pub enum ExprKind {
 pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind {
     if tcx.method_map.borrow().contains_key(&typeck::MethodCall::expr(expr.id)) {
         // Overloaded operations are generally calls, and hence they are
-        // generated via DPS, but there are two exceptions:
+        // generated via DPS, but there are a few exceptions:
         return match expr.node {
             // `a += b` has a unit result.
             ast::ExprAssignOp(..) => RvalueStmtExpr,
@@ -3101,6 +3101,9 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind {
             // the index method invoked for `a[i]` always yields an `&T`
             ast::ExprIndex(..) => LvalueExpr,
 
+            // `for` loops are statements
+            ast::ExprForLoop(..) => RvalueStmtExpr,
+
             // in the general case, result could be any type, use DPS
             _ => RvalueDpsExpr
         };
@@ -3209,12 +3212,11 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind {
         ast::ExprLoop(..) |
         ast::ExprAssign(..) |
         ast::ExprInlineAsm(..) |
-        ast::ExprAssignOp(..) => {
+        ast::ExprAssignOp(..) |
+        ast::ExprForLoop(..) => {
             RvalueStmtExpr
         }
 
-        ast::ExprForLoop(..) => fail!("non-desugared expr_for_loop"),
-
         ast::ExprLit(_) | // Note: LitStr is carved out above
         ast::ExprUnary(..) |
         ast::ExprAddrOf(..) |
diff --git a/src/librustc/middle/typeck/check/_match.rs b/src/librustc/middle/typeck/check/_match.rs
index be01643e22a58..3f54677c08b24 100644
--- a/src/librustc/middle/typeck/check/_match.rs
+++ b/src/librustc/middle/typeck/check/_match.rs
@@ -21,6 +21,7 @@ use middle::typeck::check::{instantiate_path, lookup_def};
 use middle::typeck::check::{structure_of, valid_range_bounds};
 use middle::typeck::infer;
 use middle::typeck::require_same_types;
+use util::ppaux;
 
 use std::collections::{HashMap, HashSet};
 use std::gc::Gc;
@@ -484,7 +485,10 @@ pub fn check_pat(pcx: &pat_ctxt, pat: &ast::Pat, expected: ty::t) {
         }
         fcx.write_ty(pat.id, typ);
 
-        debug!("(checking match) writing type for pat id {}", pat.id);
+        debug!("(checking match) writing type {} (expected {}) for pat id {}",
+               ppaux::ty_to_string(tcx, typ),
+               ppaux::ty_to_string(tcx, expected),
+               pat.id);
 
         match sub {
           Some(ref p) => check_pat(pcx, &**p, expected),
diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs
index 747ba26f5909f..fd6b3a20a1936 100644
--- a/src/librustc/middle/typeck/check/mod.rs
+++ b/src/librustc/middle/typeck/check/mod.rs
@@ -79,6 +79,7 @@ type parameter).
 
 use middle::const_eval;
 use middle::def;
+use middle::lang_items::IteratorItem;
 use middle::pat_util::pat_id_map;
 use middle::pat_util;
 use middle::subst;
@@ -1708,6 +1709,80 @@ fn try_overloaded_index(fcx: &FnCtxt,
     }
 }
 
+/// Given the head of a `for` expression, looks up the `next` method in the
+/// `Iterator` trait. Fails if the expression does not implement `next`.
+///
+/// The return type of this function represents the concrete element type
+/// `A` in the type `Iterator<A>` that the method returns.
+fn lookup_method_for_for_loop(fcx: &FnCtxt,
+                              iterator_expr: Gc<ast::Expr>,
+                              loop_id: ast::NodeId)
+                              -> ty::t {
+    let trait_did = match fcx.tcx().lang_items.require(IteratorItem) {
+        Ok(trait_did) => trait_did,
+        Err(ref err_string) => {
+            fcx.tcx().sess.span_err(iterator_expr.span,
+                                    err_string.as_slice());
+            return ty::mk_err()
+        }
+    };
+
+    let method = method::lookup_in_trait(fcx,
+                                         iterator_expr.span,
+                                         Some(&*iterator_expr),
+                                         token::intern("next"),
+                                         trait_did,
+                                         fcx.expr_ty(&*iterator_expr),
+                                         [],
+                                         DontAutoderefReceiver,
+                                         IgnoreStaticMethods);
+
+    // Regardless of whether the lookup succeeds, check the method arguments
+    // so that we have *some* type for each argument.
+    let method_type = match method {
+        Some(ref method) => method.ty,
+        None => {
+            fcx.tcx().sess.span_err(iterator_expr.span,
+                                    "`for` loop expression does not \
+                                     implement the `Iterator` trait");
+            ty::mk_err()
+        }
+    };
+    let return_type = check_method_argument_types(fcx,
+                                                  iterator_expr.span,
+                                                  method_type,
+                                                  &*iterator_expr,
+                                                  [iterator_expr],
+                                                  DontDerefArgs,
+                                                  DontTupleArguments);
+
+    match method {
+        Some(method) => {
+            fcx.inh.method_map.borrow_mut().insert(MethodCall::expr(loop_id),
+                                                   method);
+
+            // We expect the return type to be `Option` or something like it.
+            // Grab the first parameter of its type substitution.
+            let return_type = structurally_resolved_type(fcx,
+                                                         iterator_expr.span,
+                                                         return_type);
+            match ty::get(return_type).sty {
+                ty::ty_enum(_, ref substs)
+                        if !substs.types.is_empty_in(subst::TypeSpace) => {
+                    *substs.types.get(subst::TypeSpace, 0)
+                }
+                _ => {
+                    fcx.tcx().sess.span_err(iterator_expr.span,
+                                            "`next` method of the `Iterator` \
+                                             trait has an unexpected type");
+                    ty::mk_err()
+                }
+            }
+        }
+        None => ty::mk_err()
+    }
+}
+
 fn check_method_argument_types(fcx: &FnCtxt,
                                sp: Span,
                                method_fn_ty: ty::t,
@@ -3273,8 +3348,20 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
             fcx.write_nil(id);
         }
       }
-      ast::ExprForLoop(..) =>
-          fail!("non-desugared expr_for_loop"),
+      ast::ExprForLoop(ref pat, ref head, ref block, _) => {
+        check_expr(fcx, &**head);
+        let typ = lookup_method_for_for_loop(fcx, *head, expr.id);
+        vtable::early_resolve_expr(expr, fcx, true);
+
+        let pcx = pat_ctxt {
+            fcx: fcx,
+            map: pat_id_map(&tcx.def_map, &**pat),
+        };
+        _match::check_pat(&pcx, &**pat, typ);
+
+        check_block_no_value(fcx, &**block);
+        fcx.write_nil(id);
+      }
       ast::ExprLoop(ref body, _) => {
         check_block_no_value(fcx, &**body);
         if !may_break(tcx, expr.id, body.clone()) {
diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs
index 22d52d0b7d2a0..d0431de81a359 100644
--- a/src/librustc/middle/typeck/check/regionck.rs
+++ b/src/librustc/middle/typeck/check/regionck.rs
@@ -609,6 +609,22 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
             rcx.set_repeating_scope(repeating_scope);
         }
 
+        ast::ExprForLoop(ref pat, ref head, ref body, _) => {
+            constrain_bindings_in_pat(&**pat, rcx);
+
+            {
+                let mc = mc::MemCategorizationContext::new(rcx);
+                let head_cmt = ignore_err!(mc.cat_expr(&**head));
+                link_pattern(rcx, mc, head_cmt, &**pat);
+            }
+
+            rcx.visit_expr(&**head, ());
+
+            let repeating_scope = rcx.set_repeating_scope(body.id);
+            rcx.visit_block(&**body, ());
+            rcx.set_repeating_scope(repeating_scope);
+        }
+
         _ => {
             visit::walk_expr(rcx, expr, ());
         }
diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs
index c176054b3aed0..565b88b74939b 100644
--- a/src/librustc/middle/typeck/check/vtable.rs
+++ b/src/librustc/middle/typeck/check/vtable.rs
@@ -756,7 +756,8 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) {
       ast::ExprUnary(_, _) |
       ast::ExprAssignOp(_, _, _) |
       ast::ExprIndex(_, _) |
-      ast::ExprMethodCall(_, _, _) => {
+      ast::ExprMethodCall(_, _, _) |
+      ast::ExprForLoop(..) => {
         match fcx.inh.method_map.borrow().find(&MethodCall::expr(ex.id)) {
           Some(method) => {
               debug!("vtable resolution on parameter bounds for method call {}",
diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs
index fe140cf2c97c2..dc0f2a9ffff73 100644
--- a/src/librustc/middle/typeck/coherence.rs
+++ b/src/librustc/middle/typeck/coherence.rs
@@ -419,8 +419,8 @@ impl<'a> CoherenceChecker<'a> {
     }
 
     fn check_implementation_coherence(&self) {
-        for &trait_id in self.crate_context.tcx.trait_impls.borrow().keys() {
-            self.check_implementation_coherence_of(trait_id);
+        for trait_id in self.crate_context.tcx.trait_impls.borrow().keys() {
+            self.check_implementation_coherence_of(*trait_id);
         }
     }
 
diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs
index 3dd056969d665..9c9942d2628eb 100644
--- a/src/librustc/util/common.rs
+++ b/src/librustc/util/common.rs
@@ -66,7 +66,7 @@ impl<'a> Visitor<()> for LoopQueryVisitor<'a> {
         match e.node {
           // Skip inner loops, since a break in the inner loop isn't a
           // break inside the outer loop
-          ast::ExprLoop(..) | ast::ExprWhile(..) => {}
+          ast::ExprLoop(..) | ast::ExprWhile(..) | ast::ExprForLoop(..) => {}
           _ => visit::walk_expr(self, e, ())
         }
     }
diff --git a/src/librustc_back/svh.rs b/src/librustc_back/svh.rs
index cb9519b1eb815..94dea6cb540e3 100644
--- a/src/librustc_back/svh.rs
+++ b/src/librustc_back/svh.rs
@@ -252,6 +252,7 @@ mod svh_visitor {
         SawExprStruct,
         SawExprRepeat,
         SawExprParen,
+        SawExprForLoop,
     }
 
     fn saw_expr<'a>(node: &'a Expr_) -> SawExprComponent<'a> {
@@ -287,9 +288,9 @@ mod svh_visitor {
             ExprStruct(..)           => SawExprStruct,
             ExprRepeat(..)           => SawExprRepeat,
             ExprParen(..)            => SawExprParen,
+            ExprForLoop(..)          => SawExprForLoop,
 
             // just syntactic artifacts, expanded away by time of SVH.
-            ExprForLoop(..)          => unreachable!(),
             ExprMac(..)              => unreachable!(),
         }
     }
diff --git a/src/libstd/io/tempfile.rs b/src/libstd/io/tempfile.rs
index 5ca7e417af695..f580dfd80f0ce 100644
--- a/src/libstd/io/tempfile.rs
+++ b/src/libstd/io/tempfile.rs
@@ -12,7 +12,7 @@
 
 use io::{fs, IoResult};
 use io;
-use iter::{Iterator, range};
+use iter::range;
 use libc;
 use ops::Drop;
 use option::{Option, None, Some};
@@ -21,6 +21,9 @@ use path::{Path, GenericPath};
 use result::{Ok, Err};
 use sync::atomics;
 
+#[cfg(stage0)]
+use iter::Iterator; // NOTE(stage0): Remove after snapshot.
+
 /// A wrapper for a path to temporary directory implementing automatic
 /// scope-based deletion.
 pub struct TempDir {
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 123dcf366f440..f82796b480a4e 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -62,108 +62,18 @@ fn expand_expr(e: Gc<ast::Expr>, fld: &mut MacroExpander) -> Gc<ast::Expr> {
             }
         }
 
-        // Desugar expr_for_loop
-        // From: `['<ident>:] for <src_pat> in <src_expr> <src_loop_block>`
-        // FIXME #6993: change type of opt_ident to Option<Name>
-        ast::ExprForLoop(src_pat, src_expr, src_loop_block, opt_ident) => {
-
-            let span = e.span;
-
-            // to:
-            //
-            //   match &mut <src_expr> {
-            //     i => {
-            //       ['<ident>:] loop {
-            //         match i.next() {
-            //           None => break ['<ident>],
-            //           Some(mut value) => {
-            //             let <src_pat> = value;
-            //             <src_loop_block>
-            //           }
-            //         }
-            //       }
-            //     }
-            //   }
-            //
-            // (The use of the `let` is to give better error messages
-            // when the pattern is refutable.)
-
-            let local_ident = token::gensym_ident("i");
-            let next_ident = fld.cx.ident_of("next");
-            let none_ident = fld.cx.ident_of("None");
-
-            let local_path = fld.cx.path_ident(span, local_ident);
-            let some_path = fld.cx.path_ident(span, fld.cx.ident_of("Some"));
-
-            // `None => break ['<ident>],`
-            let none_arm = {
-                let break_expr = fld.cx.expr(span, ast::ExprBreak(opt_ident));
-                let none_pat = fld.cx.pat_ident(span, none_ident);
-                fld.cx.arm(span, vec!(none_pat), break_expr)
-            };
-
-            // let <src_pat> = value;
-            // use underscore to suppress lint error:
-            let value_ident = token::gensym_ident("_value");
-            // this is careful to use src_pat.span so that error
-            // messages point exact at that.
-            let local = box(GC) ast::Local {
-                ty: fld.cx.ty_infer(src_pat.span),
-                pat: src_pat,
-                init: Some(fld.cx.expr_ident(src_pat.span, value_ident)),
-                id: ast::DUMMY_NODE_ID,
-                span: src_pat.span,
-                source: ast::LocalFor
-            };
-            let local = codemap::respan(src_pat.span, ast::DeclLocal(local));
-            let local = box(GC) codemap::respan(span, ast::StmtDecl(box(GC) local,
-                                                            ast::DUMMY_NODE_ID));
-
-            // { let ...; <src_loop_block> }
-            let block = fld.cx.block(span, vec![local],
-                                     Some(fld.cx.expr_block(src_loop_block)));
-
-            // `Some(mut value) => { ... }`
-            // Note the _'s in the name will stop any unused mutability warnings.
-            let value_pat = fld.cx.pat_ident_binding_mode(span, value_ident,
-                                                          ast::BindByValue(ast::MutMutable));
-            let some_arm =
-                fld.cx.arm(span,
-                           vec!(fld.cx.pat_enum(span, some_path, vec!(value_pat))),
-                           fld.cx.expr_block(block));
-
-            // `match i.next() { ... }`
-            let match_expr = {
-                let next_call_expr =
-                    fld.cx.expr_method_call(span,
-                                            fld.cx.expr_path(local_path),
-                                            next_ident,
-                                            Vec::new());
-
-                fld.cx.expr_match(span, next_call_expr, vec!(none_arm, some_arm))
-            };
-
-            // ['ident:] loop { ... }
-            let loop_expr = fld.cx.expr(span,
-                                        ast::ExprLoop(fld.cx.block_expr(match_expr),
-                                                      opt_ident));
-
-            // `i => loop { ... }`
-
-            // `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, vec!(i_pattern), loop_expr);
-            // why these clone()'s everywhere? I guess I'll follow the pattern....
-            let match_expr = fld.cx.expr_match(span, discrim, vec!(arm));
-            fld.fold_expr(match_expr).clone()
-        }
-
         ast::ExprLoop(loop_block, opt_ident) => {
             let (loop_block, opt_ident) = expand_loop_block(loop_block, opt_ident, fld);
             fld.cx.expr(e.span, ast::ExprLoop(loop_block, opt_ident))
         }
 
+        ast::ExprForLoop(pat, head, body, opt_ident) => {
+            let pat = fld.fold_pat(pat);
+            let head = fld.fold_expr(head);
+            let (body, opt_ident) = expand_loop_block(body, opt_ident, fld);
+            fld.cx.expr(e.span, ast::ExprForLoop(pat, head, body, opt_ident))
+        }
+
         ast::ExprFnBlock(fn_decl, block) => {
             let (rewritten_fn_decl, rewritten_block)
                 = expand_and_rename_fn_decl_and_block(&*fn_decl, block, fld);
diff --git a/src/libunicode/decompose.rs b/src/libunicode/decompose.rs
index 832b65d473996..25e06bf7c13f0 100644
--- a/src/libunicode/decompose.rs
+++ b/src/libunicode/decompose.rs
@@ -39,6 +39,7 @@ pub fn decompose_canonical(c: char, i: |char|) { d(c, i, false); }
 pub fn decompose_compatible(c: char, i: |char|) { d(c, i, true); }
 
 fn d(c: char, i: |char|, k: bool) {
+    #[cfg(stage0)]
     use core::iter::Iterator;
 
     // 7-bit ASCII never decomposes
diff --git a/src/test/bench/shootout-meteor.rs b/src/test/bench/shootout-meteor.rs
index e13c53407e457..615dd1d69d501 100644
--- a/src/test/bench/shootout-meteor.rs
+++ b/src/test/bench/shootout-meteor.rs
@@ -297,10 +297,10 @@ fn search(
     // for every unused piece
     for id in range(0u, 10).filter(|id| board & (1 << (id + 50)) == 0) {
         // for each mask that fits on the board
-        for &m in masks_at.get(id).iter().filter(|&m| board & *m == 0) {
+        for m in masks_at.get(id).iter().filter(|&m| board & *m == 0) {
             // This check is too costy.
             //if is_board_unfeasible(board | m, masks) {continue;}
-            search(masks, board | m, i + 1, Cons(m, &cur), data);
+            search(masks, board | *m, i + 1, Cons(*m, &cur), data);
         }
     }
 }
@@ -311,9 +311,10 @@ fn par_search(masks: Vec<Vec<Vec<u64>>>) -> Data {
 
     // launching the search in parallel on every masks at minimum
     // coordinate (0,0)
-    for &m in masks.get(0).iter().flat_map(|masks_pos| masks_pos.iter()) {
+    for m in masks.get(0).iter().flat_map(|masks_pos| masks_pos.iter()) {
         let masks = masks.clone();
         let tx = tx.clone();
+        let m = *m;
         spawn(proc() {
             let mut data = Data::new();
             search(&*masks, m, 1, Cons(m, &Nil), &mut data);
diff --git a/src/test/compile-fail/for-loop-bogosity.rs b/src/test/compile-fail/for-loop-bogosity.rs
new file mode 100644
index 0000000000000..ba268cf3d6479
--- /dev/null
+++ b/src/test/compile-fail/for-loop-bogosity.rs
@@ -0,0 +1,31 @@
+// Copyright 2014 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.
+
+struct MyStruct {
+    x: int,
+    y: int,
+}
+
+impl MyStruct {
+    fn next(&mut self) -> Option<int> {
+        Some(self.x)
+    }
+}
+
+pub fn main() {
+    let mut bogus = MyStruct {
+        x: 1,
+        y: 2,
+    };
+    for x in bogus {    //~ ERROR does not implement the `Iterator` trait
+        drop(x);
+    }
+}
+
diff --git a/src/test/compile-fail/issue-15167.rs b/src/test/compile-fail/issue-15167.rs
index 61e1e92ff9420..300831b100773 100644
--- a/src/test/compile-fail/issue-15167.rs
+++ b/src/test/compile-fail/issue-15167.rs
@@ -9,13 +9,18 @@
 // except according to those terms.
 
 // macro f should not be able to inject a reference to 'n'.
+//
+// Ignored because `for` loops are not hygienic yet; they will require special
+// handling since they introduce a new pattern binding position.
+
+// ignore-test
 
 #![feature(macro_rules)]
 
 macro_rules! f(() => (n))
 
 fn main() -> (){
-    for n in range(0, 1) {
+    for n in range(0i, 1) {
         println!("{}", f!()); //~ ERROR unresolved name `n`
     }
 }
diff --git a/src/test/compile-fail/vec-mut-iter-borrow.rs b/src/test/compile-fail/vec-mut-iter-borrow.rs
index 9a179f434c275..9060ed7495ee5 100644
--- a/src/test/compile-fail/vec-mut-iter-borrow.rs
+++ b/src/test/compile-fail/vec-mut-iter-borrow.rs
@@ -9,9 +9,9 @@
 // except according to those terms.
 
 fn main() {
-    let mut xs = vec!(1i, 2, 3, 4);
+    let mut xs: Vec<int> = vec!();
 
     for x in xs.mut_iter() {
-        xs.push(1) //~ ERROR cannot borrow `xs`
+        xs.push(1i) //~ ERROR cannot borrow `xs`
     }
 }
diff --git a/src/test/debuginfo/lexical-scope-in-for-loop.rs b/src/test/debuginfo/lexical-scope-in-for-loop.rs
index 13cae3252d804..74d5462431822 100644
--- a/src/test/debuginfo/lexical-scope-in-for-loop.rs
+++ b/src/test/debuginfo/lexical-scope-in-for-loop.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 // ignore-android: FIXME(#10381)
+// ignore-test: Not sure what is going on here --pcwalton
 
 // compile-flags:-g
 
diff --git a/src/test/run-pass/for-loop-goofiness.rs b/src/test/run-pass/for-loop-goofiness.rs
new file mode 100644
index 0000000000000..73f4cdd252e6f
--- /dev/null
+++ b/src/test/run-pass/for-loop-goofiness.rs
@@ -0,0 +1,24 @@
+// Copyright 2014 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.
+
+enum BogusOption<T> {
+    None,
+    Some(T),
+}
+
+type Iterator = int;
+
+pub fn main() {
+    let x = [ 3i, 3, 3 ];
+    for i in x.iter() {
+        assert_eq!(*i, 3);
+    }
+}
+