about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorMarcin Fatyga <marcinf@google.com>2016-11-01 15:26:22 +0100
committerMarcin Fatyga <marcinf@google.com>2016-11-01 15:26:22 +0100
commit655effedf25e2039d283b839429bf2f42b7012a4 (patch)
tree34fd087d891556c70a14b26a90d1bdccd0a7ccb2 /src/libsyntax
parent4e2822c5c28bb342e5862ba7cc0b90b865c68be1 (diff)
parentac968c466451cb9aafd9e8598ddb396ed0e6fe31 (diff)
downloadrust-655effedf25e2039d283b839429bf2f42b7012a4.tar.gz
rust-655effedf25e2039d283b839429bf2f42b7012a4.zip
Merge branch 'master' of https://github.com/rust-lang/rust
Conflicts:
	src/libcoretest/lib.rs
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/abi.rs52
-rw-r--r--src/libsyntax/ast.rs72
-rw-r--r--src/libsyntax/attr.rs19
-rw-r--r--src/libsyntax/codemap.rs83
-rw-r--r--src/libsyntax/config.rs31
-rw-r--r--src/libsyntax/diagnostics/plugin.rs2
-rw-r--r--src/libsyntax/ext/base.rs198
-rw-r--r--src/libsyntax/ext/build.rs48
-rw-r--r--src/libsyntax/ext/expand.rs397
-rw-r--r--src/libsyntax/ext/hygiene.rs5
-rw-r--r--src/libsyntax/ext/placeholders.rs16
-rw-r--r--src/libsyntax/ext/proc_macro_shim.rs6
-rw-r--r--src/libsyntax/ext/quote.rs70
-rw-r--r--src/libsyntax/ext/source_util.rs11
-rw-r--r--src/libsyntax/ext/tt/macro_parser.rs63
-rw-r--r--src/libsyntax/ext/tt/macro_rules.rs300
-rw-r--r--src/libsyntax/ext/tt/transcribe.rs43
-rw-r--r--src/libsyntax/feature_gate.rs298
-rw-r--r--src/libsyntax/fold.rs120
-rw-r--r--src/libsyntax/json.rs16
-rw-r--r--src/libsyntax/lib.rs5
-rw-r--r--src/libsyntax/parse/attr.rs12
-rw-r--r--src/libsyntax/parse/lexer/comments.rs84
-rw-r--r--src/libsyntax/parse/lexer/mod.rs467
-rw-r--r--src/libsyntax/parse/lexer/unicode_chars.rs2
-rw-r--r--src/libsyntax/parse/mod.rs252
-rw-r--r--src/libsyntax/parse/parser.rs1195
-rw-r--r--src/libsyntax/parse/token.rs70
-rw-r--r--src/libsyntax/print/pp.rs69
-rw-r--r--src/libsyntax/print/pprust.rs65
-rw-r--r--src/libsyntax/std_inject.rs22
-rw-r--r--src/libsyntax/test.rs85
-rw-r--r--src/libsyntax/tokenstream.rs16
-rw-r--r--src/libsyntax/util/interner.rs40
-rw-r--r--src/libsyntax/util/parser_testing.rs5
-rw-r--r--src/libsyntax/util/small_vector.rs56
-rw-r--r--src/libsyntax/visit.rs18
37 files changed, 2337 insertions, 1976 deletions
diff --git a/src/libsyntax/abi.rs b/src/libsyntax/abi.rs
index 64a71133a8c..a39cac8db99 100644
--- a/src/libsyntax/abi.rs
+++ b/src/libsyntax/abi.rs
@@ -24,6 +24,7 @@ pub enum Os {
     Netbsd,
     Openbsd,
     NaCl,
+    Haiku,
     Solaris,
 }
 
@@ -32,7 +33,7 @@ pub enum Abi {
     // NB: This ordering MUST match the AbiDatas array below.
     // (This is ensured by the test indices_are_correct().)
 
-    // Single platform ABIs come first (`for_arch()` relies on this)
+    // Single platform ABIs
     Cdecl,
     Stdcall,
     Fastcall,
@@ -41,7 +42,7 @@ pub enum Abi {
     Win64,
     SysV64,
 
-    // Multiplatform ABIs second
+    // Multiplatform / generic ABIs
     Rust,
     C,
     System,
@@ -64,41 +65,31 @@ pub enum Architecture {
 pub struct AbiData {
     abi: Abi,
 
-    // Name of this ABI as we like it called.
+    /// Name of this ABI as we like it called.
     name: &'static str,
-}
 
-#[derive(Copy, Clone)]
-pub enum AbiArchitecture {
-    /// Not a real ABI (e.g., intrinsic)
-    Rust,
-    /// An ABI that specifies cross-platform defaults (e.g., "C")
-    All,
-    /// Multiple architectures (bitset)
-    Archs(u32)
+    /// A generic ABI is supported on all platforms.
+    generic: bool,
 }
 
 #[allow(non_upper_case_globals)]
 const AbiDatas: &'static [AbiData] = &[
     // Platform-specific ABIs
-    AbiData {abi: Abi::Cdecl, name: "cdecl" },
-    AbiData {abi: Abi::Stdcall, name: "stdcall" },
-    AbiData {abi: Abi::Fastcall, name: "fastcall" },
-    AbiData {abi: Abi::Vectorcall, name: "vectorcall"},
-    AbiData {abi: Abi::Aapcs, name: "aapcs" },
-    AbiData {abi: Abi::Win64, name: "win64" },
-    AbiData {abi: Abi::SysV64, name: "sysv64" },
+    AbiData {abi: Abi::Cdecl, name: "cdecl", generic: false },
+    AbiData {abi: Abi::Stdcall, name: "stdcall", generic: false },
+    AbiData {abi: Abi::Fastcall, name: "fastcall", generic: false },
+    AbiData {abi: Abi::Vectorcall, name: "vectorcall", generic: false},
+    AbiData {abi: Abi::Aapcs, name: "aapcs", generic: false },
+    AbiData {abi: Abi::Win64, name: "win64", generic: false },
+    AbiData {abi: Abi::SysV64, name: "sysv64", generic: false },
 
     // Cross-platform ABIs
-    //
-    // NB: Do not adjust this ordering without
-    // adjusting the indices below.
-    AbiData {abi: Abi::Rust, name: "Rust" },
-    AbiData {abi: Abi::C, name: "C" },
-    AbiData {abi: Abi::System, name: "system" },
-    AbiData {abi: Abi::RustIntrinsic, name: "rust-intrinsic" },
-    AbiData {abi: Abi::RustCall, name: "rust-call" },
-    AbiData {abi: Abi::PlatformIntrinsic, name: "platform-intrinsic" }
+    AbiData {abi: Abi::Rust, name: "Rust", generic: true },
+    AbiData {abi: Abi::C, name: "C", generic: true },
+    AbiData {abi: Abi::System, name: "system", generic: true },
+    AbiData {abi: Abi::RustIntrinsic, name: "rust-intrinsic", generic: true },
+    AbiData {abi: Abi::RustCall, name: "rust-call", generic: true },
+    AbiData {abi: Abi::PlatformIntrinsic, name: "platform-intrinsic", generic: true },
 ];
 
 /// Returns the ABI with the given name (if any).
@@ -124,6 +115,10 @@ impl Abi {
     pub fn name(&self) -> &'static str {
         self.data().name
     }
+
+    pub fn generic(&self) -> bool {
+        self.data().generic
+    }
 }
 
 impl fmt::Display for Abi {
@@ -146,6 +141,7 @@ impl fmt::Display for Os {
             Os::Netbsd => "netbsd".fmt(f),
             Os::Openbsd => "openbsd".fmt(f),
             Os::NaCl => "nacl".fmt(f),
+            Os::Haiku => "haiku".fmt(f),
             Os::Solaris => "solaris".fmt(f),
         }
     }
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 40c8ba93bd5..f077ead1f8e 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -27,7 +27,9 @@ use tokenstream::{TokenTree};
 
 use std::fmt;
 use std::rc::Rc;
-use serialize::{Encodable, Decodable, Encoder, Decoder};
+use std::u32;
+
+use serialize::{self, Encodable, Decodable, Encoder, Decoder};
 
 /// A name is a part of an identifier, representing a string or gensym. It's
 /// the result of interning.
@@ -69,7 +71,7 @@ impl Encodable for Name {
 
 impl Decodable for Name {
     fn decode<D: Decoder>(d: &mut D) -> Result<Name, D::Error> {
-        Ok(token::intern(&d.read_str()?[..]))
+        Ok(token::intern(&d.read_str()?))
     }
 }
 
@@ -119,6 +121,7 @@ impl fmt::Debug for Lifetime {
 /// A lifetime definition, e.g. `'a: 'b+'c+'d`
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub struct LifetimeDef {
+    pub attrs: ThinVec<Attribute>,
     pub lifetime: Lifetime,
     pub bounds: Vec<Lifetime>
 }
@@ -158,12 +161,12 @@ impl Path {
         Path {
             span: s,
             global: false,
-            segments: vec!(
+            segments: vec![
                 PathSegment {
                     identifier: identifier,
                     parameters: PathParameters::none()
                 }
-            ),
+            ],
         }
     }
 }
@@ -298,17 +301,53 @@ pub struct ParenthesizedParameterData {
     pub output: Option<P<Ty>>,
 }
 
-pub type CrateNum = u32;
+#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash, Debug)]
+pub struct NodeId(u32);
+
+impl NodeId {
+    pub fn new(x: usize) -> NodeId {
+        assert!(x < (u32::MAX as usize));
+        NodeId(x as u32)
+    }
+
+    pub fn from_u32(x: u32) -> NodeId {
+        NodeId(x)
+    }
+
+    pub fn as_usize(&self) -> usize {
+        self.0 as usize
+    }
+
+    pub fn as_u32(&self) -> u32 {
+        self.0
+    }
+}
+
+impl fmt::Display for NodeId {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Display::fmt(&self.0, f)
+    }
+}
 
-pub type NodeId = u32;
+impl serialize::UseSpecializedEncodable for NodeId {
+    fn default_encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+        s.emit_u32(self.0)
+    }
+}
+
+impl serialize::UseSpecializedDecodable for NodeId {
+    fn default_decode<D: Decoder>(d: &mut D) -> Result<NodeId, D::Error> {
+        d.read_u32().map(NodeId)
+    }
+}
 
 /// Node id used to represent the root of the crate.
-pub const CRATE_NODE_ID: NodeId = 0;
+pub const CRATE_NODE_ID: NodeId = NodeId(0);
 
 /// When parsing and doing expansions, we initially give all AST nodes this AST
 /// node value. Then later, in the renumber pass, we renumber them to have
 /// small, positive ids.
-pub const DUMMY_NODE_ID: NodeId = !0;
+pub const DUMMY_NODE_ID: NodeId = NodeId(!0);
 
 /// The AST represents all type param bounds as types.
 /// typeck::collect::compute_bounds matches these against
@@ -332,6 +371,7 @@ pub type TyParamBounds = P<[TyParamBound]>;
 
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub struct TyParam {
+    pub attrs: ThinVec<Attribute>,
     pub ident: Ident,
     pub id: NodeId,
     pub bounds: TyParamBounds,
@@ -437,7 +477,6 @@ pub type CrateConfig = Vec<P<MetaItem>>;
 pub struct Crate {
     pub module: Mod,
     pub attrs: Vec<Attribute>,
-    pub config: CrateConfig,
     pub span: Span,
     pub exported_macros: Vec<MacroDef>,
 }
@@ -555,7 +594,7 @@ impl Pat {
             PatKind::Box(ref s) | PatKind::Ref(ref s, _) => {
                 s.walk(it)
             }
-            PatKind::Vec(ref before, ref slice, ref after) => {
+            PatKind::Slice(ref before, ref slice, ref after) => {
                 before.iter().all(|p| p.walk(it)) &&
                 slice.iter().all(|p| p.walk(it)) &&
                 after.iter().all(|p| p.walk(it))
@@ -631,8 +670,8 @@ pub enum PatKind {
     /// A range pattern, e.g. `1...2`
     Range(P<Expr>, P<Expr>),
     /// `[a, b, ..i, y, z]` is represented as:
-    ///     `PatKind::Vec(box [a, b], Some(i), box [y, z])`
-    Vec(Vec<P<Pat>>, Option<P<Pat>>, Vec<P<Pat>>),
+    ///     `PatKind::Slice(box [a, b], Some(i), box [y, z])`
+    Slice(Vec<P<Pat>>, Option<P<Pat>>, Vec<P<Pat>>),
     /// A macro pattern; pre-expansion
     Mac(Mac),
 }
@@ -860,6 +899,7 @@ pub struct Field {
     pub ident: SpannedIdent,
     pub expr: P<Expr>,
     pub span: Span,
+    pub is_shorthand: bool,
 }
 
 pub type SpannedIdent = Spanned<Ident>;
@@ -1393,10 +1433,10 @@ pub struct BareFnTy {
 /// The different kinds of types recognized by the compiler
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub enum TyKind {
-    /// A variable-length array (`[T]`)
-    Vec(P<Ty>),
+    /// A variable-length slice (`[T]`)
+    Slice(P<Ty>),
     /// A fixed length array (`[T; n]`)
-    FixedLengthVec(P<Ty>, P<Expr>),
+    Array(P<Ty>, P<Expr>),
     /// A raw pointer (`*const T` or `*mut T`)
     Ptr(MutTy),
     /// A reference (`&'a T` or `&'a mut T`)
@@ -1972,8 +2012,6 @@ pub struct MacroDef {
     pub id: NodeId,
     pub span: Span,
     pub imported_from: Option<Ident>,
-    pub export: bool,
-    pub use_locally: bool,
     pub allow_internal_unstable: bool,
     pub body: Vec<TokenTree>,
 }
diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs
index 81ee96459fd..0335f210347 100644
--- a/src/libsyntax/attr.rs
+++ b/src/libsyntax/attr.rs
@@ -501,10 +501,7 @@ pub fn requests_inline(attrs: &[Attribute]) -> bool {
 }
 
 /// Tests if a cfg-pattern matches the cfg set
-pub fn cfg_matches(cfgs: &[P<MetaItem>], cfg: &ast::MetaItem,
-                   sess: &ParseSess,
-                   features: Option<&Features>)
-                   -> bool {
+pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Features>) -> bool {
     match cfg.node {
         ast::MetaItemKind::List(ref pred, ref mis) => {
             for mi in mis.iter() {
@@ -518,10 +515,10 @@ pub fn cfg_matches(cfgs: &[P<MetaItem>], cfg: &ast::MetaItem,
             // that they won't fail with the loop above.
             match &pred[..] {
                 "any" => mis.iter().any(|mi| {
-                    cfg_matches(cfgs, mi.meta_item().unwrap(), sess, features)
+                    cfg_matches(mi.meta_item().unwrap(), sess, features)
                 }),
                 "all" => mis.iter().all(|mi| {
-                    cfg_matches(cfgs, mi.meta_item().unwrap(), sess, features)
+                    cfg_matches(mi.meta_item().unwrap(), sess, features)
                 }),
                 "not" => {
                     if mis.len() != 1 {
@@ -529,7 +526,7 @@ pub fn cfg_matches(cfgs: &[P<MetaItem>], cfg: &ast::MetaItem,
                         return false;
                     }
 
-                    !cfg_matches(cfgs, mis[0].meta_item().unwrap(), sess, features)
+                    !cfg_matches(mis[0].meta_item().unwrap(), sess, features)
                 },
                 p => {
                     span_err!(sess.span_diagnostic, cfg.span, E0537, "invalid predicate `{}`", p);
@@ -541,7 +538,7 @@ pub fn cfg_matches(cfgs: &[P<MetaItem>], cfg: &ast::MetaItem,
             if let (Some(feats), Some(gated_cfg)) = (features, GatedCfg::gate(cfg)) {
                 gated_cfg.check_and_emit(sess, feats);
             }
-            contains(cfgs, cfg)
+            contains(&sess.config, cfg)
         }
     }
 }
@@ -895,7 +892,7 @@ pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec<ReprAttr>
                         "packed" => Some(ReprPacked),
                         "simd" => Some(ReprSimd),
                         _ => match int_type_of_word(word) {
-                            Some(ity) => Some(ReprInt(item.span, ity)),
+                            Some(ity) => Some(ReprInt(ity)),
                             None => {
                                 // Not a word we recognize
                                 span_err!(diagnostic, item.span, E0552,
@@ -939,7 +936,7 @@ fn int_type_of_word(s: &str) -> Option<IntType> {
 #[derive(PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)]
 pub enum ReprAttr {
     ReprAny,
-    ReprInt(Span, IntType),
+    ReprInt(IntType),
     ReprExtern,
     ReprPacked,
     ReprSimd,
@@ -949,7 +946,7 @@ impl ReprAttr {
     pub fn is_ffi_safe(&self) -> bool {
         match *self {
             ReprAny => false,
-            ReprInt(_sp, ity) => ity.is_ffi_safe(),
+            ReprInt(ity) => ity.is_ffi_safe(),
             ReprExtern => true,
             ReprPacked => false,
             ReprSimd => true,
diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs
index cd6f2874954..49012ad036a 100644
--- a/src/libsyntax/codemap.rs
+++ b/src/libsyntax/codemap.rs
@@ -364,6 +364,46 @@ impl CodeMap {
         }
     }
 
+    /// Returns `Some(span)`, a union of the lhs and rhs span.  The lhs must precede the rhs. If
+    /// there are gaps between lhs and rhs, the resulting union will cross these gaps.
+    /// For this to work, the spans have to be:
+    ///    * the expn_id of both spans much match
+    ///    * the lhs span needs to end on the same line the rhs span begins
+    ///    * the lhs span must start at or before the rhs span
+    pub fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option<Span> {
+        use std::cmp;
+
+        // make sure we're at the same expansion id
+        if sp_lhs.expn_id != sp_rhs.expn_id {
+            return None;
+        }
+
+        let lhs_end = match self.lookup_line(sp_lhs.hi) {
+            Ok(x) => x,
+            Err(_) => return None
+        };
+        let rhs_begin = match self.lookup_line(sp_rhs.lo) {
+            Ok(x) => x,
+            Err(_) => return None
+        };
+
+        // if we must cross lines to merge, don't merge
+        if lhs_end.line != rhs_begin.line {
+            return None;
+        }
+
+        // ensure these follow the expected order and we don't overlap
+        if (sp_lhs.lo <= sp_rhs.lo) && (sp_lhs.hi <= sp_rhs.lo) {
+            Some(Span {
+                lo: cmp::min(sp_lhs.lo, sp_rhs.lo),
+                hi: cmp::max(sp_lhs.hi, sp_rhs.hi),
+                expn_id: sp_lhs.expn_id,
+            })
+        } else {
+            None
+        }
+    }
+
     pub fn span_to_string(&self, sp: Span) -> String {
         if sp == COMMAND_LINE_SP {
             return "<command line option>".to_string();
@@ -764,7 +804,7 @@ impl CodeMap {
     }
 
     pub fn macro_backtrace(&self, span: Span) -> Vec<MacroBacktrace> {
-        let mut last_span = DUMMY_SP;
+        let mut prev_span = DUMMY_SP;
         let mut span = span;
         let mut result = vec![];
         loop {
@@ -787,14 +827,14 @@ impl CodeMap {
                 None => break,
                 Some((call_site, macro_decl_name, def_site_span)) => {
                     // Don't print recursive invocations
-                    if !call_site.source_equal(&last_span) {
+                    if !call_site.source_equal(&prev_span) {
                         result.push(MacroBacktrace {
                             call_site: call_site,
                             macro_decl_name: macro_decl_name,
                             def_site_span: def_site_span,
                         });
                     }
-                    last_span = span;
+                    prev_span = span;
                     span = call_site;
                 }
             }
@@ -819,6 +859,9 @@ impl CodeMapper for CodeMap {
     fn macro_backtrace(&self, span: Span) -> Vec<MacroBacktrace> {
         self.macro_backtrace(span)
     }
+    fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option<Span> {
+        self.merge_spans(sp_lhs, sp_rhs)
+    }
 }
 
 // _____________________________________________________________________________
@@ -1072,6 +1115,40 @@ mod tests {
                     blork.rs:1:1: 1:12\n  `first line.`\n");
     }
 
+    /// Test merging two spans on the same line
+    #[test]
+    fn span_merging() {
+        let cm = CodeMap::new();
+        let inputtext  = "bbbb BB bb CCC\n";
+        let selection1 = "     ~~       \n";
+        let selection2 = "           ~~~\n";
+        cm.new_filemap_and_lines("blork.rs", None, inputtext);
+        let span1 = span_from_selection(inputtext, selection1);
+        let span2 = span_from_selection(inputtext, selection2);
+
+        if let Some(sp) = cm.merge_spans(span1, span2) {
+            let sstr = cm.span_to_expanded_string(sp);
+            assert_eq!(sstr, "blork.rs:1:6: 1:15\n`BB bb CCC`\n");
+        }
+        else {
+            assert!(false);
+        }
+    }
+
+    /// Test failing to merge two spans on different lines
+    #[test]
+    fn span_merging_fail() {
+        let cm = CodeMap::new();
+        let inputtext  = "bbbb BB\ncc CCC\n";
+        let selection1 = "     ~~\n      \n";
+        let selection2 = "       \n   ~~~\n";
+        cm.new_filemap_and_lines("blork.rs", None, inputtext);
+        let span1 = span_from_selection(inputtext, selection1);
+        let span2 = span_from_selection(inputtext, selection2);
+
+        assert!(cm.merge_spans(span1, span2).is_none());
+    }
+
     /// Returns the span corresponding to the `n`th occurrence of
     /// `substring` in `source_text`.
     trait CodeMapExtension {
diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs
index 3f5b294cc04..946257a16d5 100644
--- a/src/libsyntax/config.rs
+++ b/src/libsyntax/config.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use attr::HasAttrs;
-use feature_gate::{emit_feature_err, EXPLAIN_STMT_ATTR_SYNTAX, Features, get_features, GateIssue};
+use feature_gate::{feature_err, EXPLAIN_STMT_ATTR_SYNTAX, Features, get_features, GateIssue};
 use {fold, attr};
 use ast;
 use codemap::{Spanned, respan};
@@ -20,7 +20,6 @@ use util::small_vector::SmallVector;
 
 /// A folder that strips out items that do not belong in the current configuration.
 pub struct StripUnconfigured<'a> {
-    pub config: &'a ast::CrateConfig,
     pub should_test: bool,
     pub sess: &'a ParseSess,
     pub features: Option<&'a Features>,
@@ -32,7 +31,6 @@ pub fn features(mut krate: ast::Crate, sess: &ParseSess, should_test: bool)
     let features;
     {
         let mut strip_unconfigured = StripUnconfigured {
-            config: &krate.config.clone(),
             should_test: should_test,
             sess: sess,
             features: None,
@@ -107,7 +105,7 @@ impl<'a> StripUnconfigured<'a> {
         use attr::cfg_matches;
         match (cfg.meta_item(), mi.meta_item()) {
             (Some(cfg), Some(mi)) =>
-                if cfg_matches(self.config, &cfg, self.sess, self.features) {
+                if cfg_matches(&cfg, self.sess, self.features) {
                     self.process_cfg_attr(respan(mi.span, ast::Attribute_ {
                         id: attr::mk_attr_id(),
                         style: attr.node.style,
@@ -126,7 +124,7 @@ impl<'a> StripUnconfigured<'a> {
     }
 
     // Determine if a node with the given attributes should be included in this configuation.
-    fn in_cfg(&mut self, attrs: &[ast::Attribute]) -> bool {
+    pub fn in_cfg(&mut self, attrs: &[ast::Attribute]) -> bool {
         attrs.iter().all(|attr| {
             // When not compiling with --test we should not compile the #[test] functions
             if !self.should_test && is_test_or_bench(attr) {
@@ -148,20 +146,24 @@ impl<'a> StripUnconfigured<'a> {
                 return true;
             }
 
-            attr::cfg_matches(self.config, mis[0].meta_item().unwrap(), self.sess, self.features)
+            attr::cfg_matches(mis[0].meta_item().unwrap(), self.sess, self.features)
         })
     }
 
     // Visit attributes on expression and statements (but not attributes on items in blocks).
-    fn visit_stmt_or_expr_attrs(&mut self, attrs: &[ast::Attribute]) {
+    fn visit_expr_attrs(&mut self, attrs: &[ast::Attribute]) {
         // flag the offending attributes
         for attr in attrs.iter() {
             if !self.features.map(|features| features.stmt_expr_attributes).unwrap_or(true) {
-                emit_feature_err(&self.sess.span_diagnostic,
-                                 "stmt_expr_attributes",
-                                 attr.span,
-                                 GateIssue::Language,
-                                 EXPLAIN_STMT_ATTR_SYNTAX);
+                let mut err = feature_err(&self.sess,
+                                          "stmt_expr_attributes",
+                                          attr.span,
+                                          GateIssue::Language,
+                                          EXPLAIN_STMT_ATTR_SYNTAX);
+                if attr.node.is_sugared_doc {
+                    err.help("`///` is for documentation comments. For a plain comment, use `//`.");
+                }
+                err.emit();
             }
         }
     }
@@ -227,7 +229,7 @@ impl<'a> StripUnconfigured<'a> {
     }
 
     pub fn configure_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> {
-        self.visit_stmt_or_expr_attrs(expr.attrs());
+        self.visit_expr_attrs(expr.attrs());
 
         // If an expr is valid to cfg away it will have been removed by the
         // outer stmt or expression folder before descending in here.
@@ -245,7 +247,6 @@ impl<'a> StripUnconfigured<'a> {
     }
 
     pub fn configure_stmt(&mut self, stmt: ast::Stmt) -> Option<ast::Stmt> {
-        self.visit_stmt_or_expr_attrs(stmt.attrs());
         self.configure(stmt)
     }
 }
@@ -303,6 +304,6 @@ fn is_cfg(attr: &ast::Attribute) -> bool {
     attr.check_name("cfg")
 }
 
-fn is_test_or_bench(attr: &ast::Attribute) -> bool {
+pub fn is_test_or_bench(attr: &ast::Attribute) -> bool {
     attr.check_name("test") || attr.check_name("bench")
 }
diff --git a/src/libsyntax/diagnostics/plugin.rs b/src/libsyntax/diagnostics/plugin.rs
index 4e50299e836..81c8e0bdb82 100644
--- a/src/libsyntax/diagnostics/plugin.rs
+++ b/src/libsyntax/diagnostics/plugin.rs
@@ -215,7 +215,7 @@ pub fn expand_build_diagnostic_array<'cx>(ecx: &'cx mut ExtCtxt,
 
     let ty = ecx.ty(
         span,
-        ast::TyKind::FixedLengthVec(
+        ast::TyKind::Array(
             ecx.ty(
                 span,
                 ast::TyKind::Tup(vec![ty_str.clone(), ty_str])
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index fb4816d3847..cc097ab0efa 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -8,30 +8,26 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-pub use self::SyntaxExtension::*;
+pub use self::SyntaxExtension::{MultiDecorator, MultiModifier, NormalTT, IdentTT};
 
 use ast::{self, Attribute, Name, PatKind};
 use attr::HasAttrs;
 use codemap::{self, CodeMap, ExpnInfo, Spanned, respan};
 use syntax_pos::{Span, ExpnId, NO_EXPANSION};
 use errors::DiagnosticBuilder;
-use ext::expand::{self, Invocation, Expansion};
+use ext::expand::{self, Expansion};
 use ext::hygiene::Mark;
-use ext::tt::macro_rules;
-use parse;
-use parse::parser;
+use fold::{self, Folder};
+use parse::{self, parser};
 use parse::token;
 use parse::token::{InternedString, str_to_ident};
 use ptr::P;
-use std_inject;
 use util::small_vector::SmallVector;
-use fold::Folder;
-use feature_gate;
 
-use std::collections::HashMap;
 use std::path::PathBuf;
 use std::rc::Rc;
-use tokenstream;
+use std::default::Default;
+use tokenstream::{self, TokenStream};
 
 
 #[derive(Debug,Clone)]
@@ -146,6 +142,50 @@ impl Into<Vec<Annotatable>> for Annotatable {
     }
 }
 
+pub trait ProcMacro {
+    fn expand<'cx>(&self,
+                   ecx: &'cx mut ExtCtxt,
+                   span: Span,
+                   ts: TokenStream)
+                   -> TokenStream;
+}
+
+impl<F> ProcMacro for F
+    where F: Fn(TokenStream) -> TokenStream
+{
+    fn expand<'cx>(&self,
+                   _ecx: &'cx mut ExtCtxt,
+                   _span: Span,
+                   ts: TokenStream)
+                   -> TokenStream {
+        // FIXME setup implicit context in TLS before calling self.
+        (*self)(ts)
+    }
+}
+
+pub trait AttrProcMacro {
+    fn expand<'cx>(&self,
+                   ecx: &'cx mut ExtCtxt,
+                   span: Span,
+                   annotation: TokenStream,
+                   annotated: TokenStream)
+                   -> TokenStream;
+}
+
+impl<F> AttrProcMacro for F
+    where F: Fn(TokenStream, TokenStream) -> TokenStream
+{
+    fn expand<'cx>(&self,
+                   _ecx: &'cx mut ExtCtxt,
+                   _span: Span,
+                   annotation: TokenStream,
+                   annotated: TokenStream)
+                   -> TokenStream {
+        // FIXME setup implicit context in TLS before calling self.
+        (*self)(annotation, annotated)
+    }
+}
+
 /// Represents a thing that maps token trees to Macro Results
 pub trait TTMacroExpander {
     fn expand<'cx>(&self,
@@ -177,7 +217,8 @@ pub trait IdentMacroExpander {
                    cx: &'cx mut ExtCtxt,
                    sp: Span,
                    ident: ast::Ident,
-                   token_tree: Vec<tokenstream::TokenTree> )
+                   token_tree: Vec<tokenstream::TokenTree>,
+                   attrs: Vec<ast::Attribute>)
                    -> Box<MacResult+'cx>;
 }
 
@@ -193,7 +234,8 @@ impl<F> IdentMacroExpander for F
                    cx: &'cx mut ExtCtxt,
                    sp: Span,
                    ident: ast::Ident,
-                   token_tree: Vec<tokenstream::TokenTree> )
+                   token_tree: Vec<tokenstream::TokenTree>,
+                   _attrs: Vec<ast::Attribute>)
                    -> Box<MacResult+'cx>
     {
         (*self)(cx, sp, ident, token_tree)
@@ -437,11 +479,22 @@ pub enum SyntaxExtension {
     /// based upon it.
     ///
     /// `#[derive(...)]` is a `MultiItemDecorator`.
-    MultiDecorator(Box<MultiItemDecorator + 'static>),
+    ///
+    /// Prefer ProcMacro or MultiModifier since they are more flexible.
+    MultiDecorator(Box<MultiItemDecorator>),
 
     /// A syntax extension that is attached to an item and modifies it
-    /// in-place. More flexible version than Modifier.
-    MultiModifier(Box<MultiItemModifier + 'static>),
+    /// in-place. Also allows decoration, i.e., creating new items.
+    MultiModifier(Box<MultiItemModifier>),
+
+    /// A function-like procedural macro. TokenStream -> TokenStream.
+    ProcMacro(Box<ProcMacro>),
+
+    /// An attribute-like procedural macro. TokenStream, TokenStream -> TokenStream.
+    /// The first TokenSteam is the attribute, the second is the annotated item.
+    /// Allows modification of the input items and adding new items, similar to
+    /// MultiModifier, but uses TokenStreams, rather than AST nodes.
+    AttrProcMacro(Box<AttrProcMacro>),
 
     /// A normal, function-like syntax extension.
     ///
@@ -449,50 +502,54 @@ pub enum SyntaxExtension {
     ///
     /// The `bool` dictates whether the contents of the macro can
     /// directly use `#[unstable]` things (true == yes).
-    NormalTT(Box<TTMacroExpander + 'static>, Option<Span>, bool),
+    NormalTT(Box<TTMacroExpander>, Option<Span>, bool),
 
     /// A function-like syntax extension that has an extra ident before
     /// the block.
     ///
-    IdentTT(Box<IdentMacroExpander + 'static>, Option<Span>, bool),
+    IdentTT(Box<IdentMacroExpander>, Option<Span>, bool),
 
-    /// Represents `macro_rules!` itself.
-    MacroRulesTT,
+    CustomDerive(Box<MultiItemModifier>),
 }
 
 pub type NamedSyntaxExtension = (Name, SyntaxExtension);
 
 pub trait Resolver {
-    fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec<LoadedMacro>;
     fn next_node_id(&mut self) -> ast::NodeId;
+    fn get_module_scope(&mut self, id: ast::NodeId) -> Mark;
 
     fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion);
-    fn add_macro(&mut self, scope: Mark, ident: ast::Ident, ext: Rc<SyntaxExtension>);
+    fn add_macro(&mut self, scope: Mark, def: ast::MacroDef, export: bool);
+    fn add_ext(&mut self, ident: ast::Ident, ext: Rc<SyntaxExtension>);
     fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec<Mark>);
 
     fn find_attr_invoc(&mut self, attrs: &mut Vec<Attribute>) -> Option<Attribute>;
-    fn resolve_invoc(&mut self, invoc: &Invocation) -> Option<Rc<SyntaxExtension>>;
+    fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, force: bool)
+                     -> Result<Rc<SyntaxExtension>, Determinacy>;
 }
 
-pub enum LoadedMacro {
-    Def(ast::MacroDef),
-    CustomDerive(String, Box<MultiItemModifier>),
+#[derive(Copy, Clone, Debug)]
+pub enum Determinacy {
+    Determined,
+    Undetermined,
 }
 
 pub struct DummyResolver;
 
 impl Resolver for DummyResolver {
-    fn load_crate(&mut self, _extern_crate: &ast::Item, _allows_macros: bool) -> Vec<LoadedMacro> {
-        Vec::new()
-    }
     fn next_node_id(&mut self) -> ast::NodeId { ast::DUMMY_NODE_ID }
+    fn get_module_scope(&mut self, _id: ast::NodeId) -> Mark { Mark::root() }
 
     fn visit_expansion(&mut self, _invoc: Mark, _expansion: &Expansion) {}
-    fn add_macro(&mut self, _scope: Mark, _ident: ast::Ident, _ext: Rc<SyntaxExtension>) {}
+    fn add_macro(&mut self, _scope: Mark, _def: ast::MacroDef, _export: bool) {}
+    fn add_ext(&mut self, _ident: ast::Ident, _ext: Rc<SyntaxExtension>) {}
     fn add_expansions_at_stmt(&mut self, _id: ast::NodeId, _macros: Vec<Mark>) {}
 
     fn find_attr_invoc(&mut self, _attrs: &mut Vec<Attribute>) -> Option<Attribute> { None }
-    fn resolve_invoc(&mut self, _invoc: &Invocation) -> Option<Rc<SyntaxExtension>> { None }
+    fn resolve_macro(&mut self, _scope: Mark, _path: &ast::Path, _force: bool)
+                     -> Result<Rc<SyntaxExtension>, Determinacy> {
+        Err(Determinacy::Determined)
+    }
 }
 
 #[derive(Clone)]
@@ -507,7 +564,9 @@ pub struct ExpansionData {
     pub depth: usize,
     pub backtrace: ExpnId,
     pub module: Rc<ModuleData>,
-    pub in_block: bool,
+
+    // True if non-inline modules without a `#[path]` are forbidden at the root of this expansion.
+    pub no_noninline_mod: bool,
 }
 
 /// One of these is made during expansion and incrementally updated as we go;
@@ -515,34 +574,30 @@ pub struct ExpansionData {
 /// -> expn_info of their expansion context stored into their span.
 pub struct ExtCtxt<'a> {
     pub parse_sess: &'a parse::ParseSess,
-    pub cfg: ast::CrateConfig,
     pub ecfg: expand::ExpansionConfig<'a>,
     pub crate_root: Option<&'static str>,
     pub resolver: &'a mut Resolver,
-    pub exported_macros: Vec<ast::MacroDef>,
-    pub derive_modes: HashMap<InternedString, Box<MultiItemModifier>>,
+    pub resolve_err_count: usize,
     pub current_expansion: ExpansionData,
 }
 
 impl<'a> ExtCtxt<'a> {
-    pub fn new(parse_sess: &'a parse::ParseSess, cfg: ast::CrateConfig,
+    pub fn new(parse_sess: &'a parse::ParseSess,
                ecfg: expand::ExpansionConfig<'a>,
                resolver: &'a mut Resolver)
                -> ExtCtxt<'a> {
         ExtCtxt {
             parse_sess: parse_sess,
-            cfg: cfg,
             ecfg: ecfg,
             crate_root: None,
-            exported_macros: Vec::new(),
             resolver: resolver,
-            derive_modes: HashMap::new(),
+            resolve_err_count: 0,
             current_expansion: ExpansionData {
                 mark: Mark::root(),
                 depth: 0,
                 backtrace: NO_EXPANSION,
                 module: Rc::new(ModuleData { mod_path: Vec::new(), directory: PathBuf::new() }),
-                in_block: false,
+                no_noninline_mod: false,
             },
         }
     }
@@ -560,11 +615,11 @@ impl<'a> ExtCtxt<'a> {
 
     pub fn new_parser_from_tts(&self, tts: &[tokenstream::TokenTree])
         -> parser::Parser<'a> {
-        parse::tts_to_parser(self.parse_sess, tts.to_vec(), self.cfg())
+        parse::tts_to_parser(self.parse_sess, tts.to_vec())
     }
     pub fn codemap(&self) -> &'a CodeMap { self.parse_sess.codemap() }
     pub fn parse_sess(&self) -> &'a parse::ParseSess { self.parse_sess }
-    pub fn cfg(&self) -> ast::CrateConfig { self.cfg.clone() }
+    pub fn cfg(&self) -> &ast::CrateConfig { &self.parse_sess.config }
     pub fn call_site(&self) -> Span {
         self.codemap().with_expn_info(self.backtrace(), |ei| match ei {
             Some(expn_info) => expn_info.call_site,
@@ -613,31 +668,6 @@ impl<'a> ExtCtxt<'a> {
     }
     pub fn bt_pop(&mut self) {}
 
-    pub fn insert_macro(&mut self, def: ast::MacroDef) {
-        if def.export {
-            self.exported_macros.push(def.clone());
-        }
-        if def.use_locally {
-            let ext = macro_rules::compile(self, &def);
-            self.resolver.add_macro(self.current_expansion.mark, def.ident, Rc::new(ext));
-        }
-    }
-
-    pub fn insert_custom_derive(&mut self, name: &str, ext: Box<MultiItemModifier>, sp: Span) {
-        if !self.ecfg.enable_rustc_macro() {
-            feature_gate::emit_feature_err(&self.parse_sess.span_diagnostic,
-                                           "rustc_macro",
-                                           sp,
-                                           feature_gate::GateIssue::Language,
-                                           "loading custom derive macro crates \
-                                            is experimentally supported");
-        }
-        let name = token::intern_and_get_ident(name);
-        if self.derive_modes.insert(name.clone(), ext).is_some() {
-            self.span_err(sp, &format!("cannot shadow existing derive mode `{}`", name));
-        }
-    }
-
     pub fn struct_span_warn(&self,
                             sp: Span,
                             msg: &str)
@@ -712,28 +742,6 @@ impl<'a> ExtCtxt<'a> {
     pub fn name_of(&self, st: &str) -> ast::Name {
         token::intern(st)
     }
-
-    pub fn initialize(&mut self, user_exts: Vec<NamedSyntaxExtension>, krate: &ast::Crate) {
-        if std_inject::no_core(&krate) {
-            self.crate_root = None;
-        } else if std_inject::no_std(&krate) {
-            self.crate_root = Some("core");
-        } else {
-            self.crate_root = Some("std");
-        }
-
-        for (name, extension) in user_exts {
-            let ident = ast::Ident::with_empty_ctxt(name);
-            self.resolver.add_macro(Mark::root(), ident, Rc::new(extension));
-        }
-
-        let mut module = ModuleData {
-            mod_path: vec![token::str_to_ident(&self.ecfg.crate_name)],
-            directory: PathBuf::from(self.parse_sess.codemap().span_to_filename(krate.span)),
-        };
-        module.directory.pop();
-        self.current_expansion.module = Rc::new(module);
-    }
 }
 
 /// Extract a string literal from the macro expanded version of `expr`,
@@ -818,3 +826,17 @@ pub fn get_exprs_from_tts(cx: &mut ExtCtxt,
     }
     Some(es)
 }
+
+pub struct ChangeSpan {
+    pub span: Span
+}
+
+impl Folder for ChangeSpan {
+    fn new_span(&mut self, _sp: Span) -> Span {
+        self.span
+    }
+
+    fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
+        fold::noop_fold_mac(mac, self)
+    }
+}
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index b81d95a6998..37bd83be7b4 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -73,6 +73,7 @@ pub trait AstBuilder {
     fn typaram(&self,
                span: Span,
                id: ast::Ident,
+               attrs: Vec<ast::Attribute>,
                bounds: ast::TyParamBounds,
                default: Option<P<ast::Ty>>) -> ast::TyParam;
 
@@ -83,6 +84,7 @@ pub trait AstBuilder {
     fn lifetime_def(&self,
                     span: Span,
                     name: ast::Name,
+                    attrs: Vec<ast::Attribute>,
                     bounds: Vec<ast::Lifetime>)
                     -> ast::LifetimeDef;
 
@@ -96,7 +98,7 @@ pub trait AstBuilder {
                       ident: ast::Ident,
                       typ: P<ast::Ty>,
                       ex: P<ast::Expr>)
-                      -> P<ast::Stmt>;
+                      -> ast::Stmt;
     fn stmt_let_type_only(&self, span: Span, ty: P<ast::Ty>) -> ast::Stmt;
     fn stmt_item(&self, sp: Span, item: P<ast::Item>) -> ast::Stmt;
 
@@ -310,7 +312,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
         self.path_all(span, false, strs, Vec::new(), Vec::new(), Vec::new())
     }
     fn path_ident(&self, span: Span, id: ast::Ident) -> ast::Path {
-        self.path(span, vec!(id))
+        self.path(span, vec![id])
     }
     fn path_global(&self, span: Span, strs: Vec<ast::Ident> ) -> ast::Path {
         self.path_all(span, true, strs, Vec::new(), Vec::new(), Vec::new())
@@ -441,7 +443,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
                           true,
                           self.std_path(&["option", "Option"]),
                           Vec::new(),
-                          vec!( ty ),
+                          vec![ ty ],
                           Vec::new()))
     }
 
@@ -452,11 +454,13 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
     fn typaram(&self,
                span: Span,
                id: ast::Ident,
+               attrs: Vec<ast::Attribute>,
                bounds: ast::TyParamBounds,
                default: Option<P<ast::Ty>>) -> ast::TyParam {
         ast::TyParam {
             ident: id,
             id: ast::DUMMY_NODE_ID,
+            attrs: attrs.into(),
             bounds: bounds,
             default: default,
             span: span
@@ -473,7 +477,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
     fn ty_vars_global(&self, ty_params: &P<[ast::TyParam]>) -> Vec<P<ast::Ty>> {
         ty_params
             .iter()
-            .map(|p| self.ty_path(self.path_global(DUMMY_SP, vec!(p.ident))))
+            .map(|p| self.ty_path(self.path_global(DUMMY_SP, vec![p.ident])))
             .collect()
     }
 
@@ -503,9 +507,11 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
     fn lifetime_def(&self,
                     span: Span,
                     name: ast::Name,
+                    attrs: Vec<ast::Attribute>,
                     bounds: Vec<ast::Lifetime>)
                     -> ast::LifetimeDef {
         ast::LifetimeDef {
+            attrs: attrs.into(),
             lifetime: self.lifetime(span, name),
             bounds: bounds
         }
@@ -556,7 +562,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
                       ident: ast::Ident,
                       typ: P<ast::Ty>,
                       ex: P<ast::Expr>)
-                      -> P<ast::Stmt> {
+                      -> ast::Stmt {
         let pat = if mutbl {
             let binding_mode = ast::BindingMode::ByValue(ast::Mutability::Mutable);
             self.pat_ident_binding_mode(sp, ident, binding_mode)
@@ -571,11 +577,11 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
             span: sp,
             attrs: ast::ThinVec::new(),
         });
-        P(ast::Stmt {
+        ast::Stmt {
             id: ast::DUMMY_NODE_ID,
             node: ast::StmtKind::Local(local),
             span: sp,
-        })
+        }
     }
 
     // Generate `let _: Type;`, usually used for type assertions.
@@ -707,7 +713,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
         self.expr(b.span, ast::ExprKind::Block(b))
     }
     fn field_imm(&self, span: Span, name: Ident, e: P<ast::Expr>) -> ast::Field {
-        ast::Field { ident: respan(span, name), expr: e, span: span }
+        ast::Field { ident: respan(span, name), expr: e, span: span, is_shorthand: false }
     }
     fn expr_struct(&self, span: Span, path: ast::Path, fields: Vec<ast::Field>) -> P<ast::Expr> {
         self.expr(span, ast::ExprKind::Struct(path, fields, None))
@@ -764,7 +770,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
 
     fn expr_some(&self, sp: Span, expr: P<ast::Expr>) -> P<ast::Expr> {
         let some = self.std_path(&["option", "Option", "Some"]);
-        self.expr_call_global(sp, some, vec!(expr))
+        self.expr_call_global(sp, some, vec![expr])
     }
 
     fn expr_none(&self, sp: Span) -> P<ast::Expr> {
@@ -788,14 +794,14 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
         let expr_file = self.expr_str(span,
                                       token::intern_and_get_ident(&loc.file.name));
         let expr_line = self.expr_u32(span, loc.line as u32);
-        let expr_file_line_tuple = self.expr_tuple(span, vec!(expr_file, expr_line));
+        let expr_file_line_tuple = self.expr_tuple(span, vec![expr_file, expr_line]);
         let expr_file_line_ptr = self.expr_addr_of(span, expr_file_line_tuple);
         self.expr_call_global(
             span,
             self.std_path(&["rt", "begin_panic"]),
-            vec!(
+            vec![
                 self.expr_str(span, msg),
-                expr_file_line_ptr))
+                expr_file_line_ptr])
     }
 
     fn expr_unreachable(&self, span: Span) -> P<ast::Expr> {
@@ -806,12 +812,12 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
 
     fn expr_ok(&self, sp: Span, expr: P<ast::Expr>) -> P<ast::Expr> {
         let ok = self.std_path(&["result", "Result", "Ok"]);
-        self.expr_call_global(sp, ok, vec!(expr))
+        self.expr_call_global(sp, ok, vec![expr])
     }
 
     fn expr_err(&self, sp: Span, expr: P<ast::Expr>) -> P<ast::Expr> {
         let err = self.std_path(&["result", "Result", "Err"]);
-        self.expr_call_global(sp, err, vec!(expr))
+        self.expr_call_global(sp, err, vec![expr])
     }
 
     fn expr_try(&self, sp: Span, head: P<ast::Expr>) -> P<ast::Expr> {
@@ -830,17 +836,17 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
         // Err(__try_var)  (pattern and expression resp.)
         let err_pat = self.pat_tuple_struct(sp, err_path.clone(), vec![binding_pat]);
         let err_inner_expr = self.expr_call(sp, self.expr_path(err_path),
-                                            vec!(binding_expr.clone()));
+                                            vec![binding_expr.clone()]);
         // return Err(__try_var)
         let err_expr = self.expr(sp, ast::ExprKind::Ret(Some(err_inner_expr)));
 
         // Ok(__try_var) => __try_var
-        let ok_arm = self.arm(sp, vec!(ok_pat), binding_expr);
+        let ok_arm = self.arm(sp, vec![ok_pat], binding_expr);
         // Err(__try_var) => return Err(__try_var)
-        let err_arm = self.arm(sp, vec!(err_pat), err_expr);
+        let err_arm = self.arm(sp, vec![err_pat], err_expr);
 
         // match head { Ok() => ..., Err() => ... }
-        self.expr_match(sp, head, vec!(ok_arm, err_arm))
+        self.expr_match(sp, head, vec![ok_arm, err_arm])
     }
 
 
@@ -906,7 +912,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
 
     fn arm(&self, _span: Span, pats: Vec<P<ast::Pat>>, expr: P<ast::Expr>) -> ast::Arm {
         ast::Arm {
-            attrs: vec!(),
+            attrs: vec![],
             pats: pats,
             guard: None,
             body: expr
@@ -914,7 +920,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
     }
 
     fn arm_unreachable(&self, span: Span) -> ast::Arm {
-        self.arm(span, vec!(self.pat_wild(span)), self.expr_unreachable(span))
+        self.arm(span, vec![self.pat_wild(span)], self.expr_unreachable(span))
     }
 
     fn expr_match(&self, span: Span, arg: P<ast::Expr>, arms: Vec<ast::Arm>) -> P<Expr> {
@@ -964,7 +970,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
     }
 
     fn lambda1(&self, span: Span, blk: P<ast::Block>, ident: ast::Ident) -> P<ast::Expr> {
-        self.lambda(span, vec!(ident), blk)
+        self.lambda(span, vec![ident], blk)
     }
 
     fn lambda_expr(&self, span: Span, ids: Vec<ast::Ident>,
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 62e299684b7..e3b23e239f9 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -8,22 +8,26 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use ast::{Block, Crate, Ident, Mac_, PatKind};
-use ast::{MacStmtStyle, StmtKind, ItemKind};
+use ast::{Block, Ident, Mac_, PatKind};
+use ast::{Name, MacStmtStyle, StmtKind, ItemKind};
 use ast;
 use ext::hygiene::Mark;
-use ext::placeholders::{self, placeholder, PlaceholderExpander};
+use ext::placeholders::{placeholder, PlaceholderExpander};
 use attr::{self, HasAttrs};
 use codemap::{ExpnInfo, NameAndSpan, MacroBang, MacroAttribute};
 use syntax_pos::{self, Span, ExpnId};
-use config::StripUnconfigured;
+use config::{is_test_or_bench, StripUnconfigured};
 use ext::base::*;
 use feature_gate::{self, Features};
 use fold;
 use fold::*;
-use parse::token::{intern, keywords};
+use parse::{ParseSess, PResult, lexer};
+use parse::parser::Parser;
+use parse::token::{self, intern, keywords};
+use print::pprust;
 use ptr::P;
-use tokenstream::TokenTree;
+use std_inject;
+use tokenstream::{TokenTree, TokenStream};
 use util::small_vector::SmallVector;
 use visit::Visitor;
 
@@ -35,12 +39,12 @@ macro_rules! expansions {
     ($($kind:ident: $ty:ty [$($vec:ident, $ty_elt:ty)*], $kind_name:expr, .$make:ident,
             $(.$fold:ident)*  $(lift .$fold_elt:ident)*,
             $(.$visit:ident)*  $(lift .$visit_elt:ident)*;)*) => {
-        #[derive(Copy, Clone)]
+        #[derive(Copy, Clone, PartialEq, Eq)]
         pub enum ExpansionKind { OptExpr, $( $kind, )*  }
         pub enum Expansion { OptExpr(Option<P<ast::Expr>>), $( $kind($ty), )* }
 
         impl ExpansionKind {
-            fn name(self) -> &'static str {
+            pub fn name(self) -> &'static str {
                 match self {
                     ExpansionKind::OptExpr => "expression",
                     $( ExpansionKind::$kind => $kind_name, )*
@@ -103,6 +107,12 @@ macro_rules! expansions {
                 self.expand(Expansion::$kind(SmallVector::one(node))).$make()
             })*)*
         }
+
+        impl<'a> MacResult for ::ext::tt::macro_rules::ParserAnyMacro<'a> {
+            $(fn $make(self: Box<::ext::tt::macro_rules::ParserAnyMacro<'a>>) -> Option<$ty> {
+                Some(self.make(ExpansionKind::$kind).$make())
+            })*
+        }
     }
 }
 
@@ -165,50 +175,43 @@ impl Invocation {
             InvocationKind::Attr { ref attr, .. } => attr.span,
         }
     }
-
-    pub fn mark(&self) -> Mark {
-        self.expansion_data.mark
-    }
 }
 
 pub struct MacroExpander<'a, 'b:'a> {
     pub cx: &'a mut ExtCtxt<'b>,
-    pub single_step: bool,
-    pub keep_macs: bool,
     monotonic: bool, // c.f. `cx.monotonic_expander()`
 }
 
 impl<'a, 'b> MacroExpander<'a, 'b> {
     pub fn new(cx: &'a mut ExtCtxt<'b>, monotonic: bool) -> Self {
-        MacroExpander {
-            cx: cx,
-            monotonic: monotonic,
-            single_step: false,
-            keep_macs: false,
-        }
+        MacroExpander { cx: cx, monotonic: monotonic }
     }
 
-    fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate {
-        let err_count = self.cx.parse_sess.span_diagnostic.err_count();
-
-        let mut krate_item = placeholder(ExpansionKind::Items, ast::DUMMY_NODE_ID)
-            .make_items().pop().unwrap().unwrap();
-        krate_item.node = ast::ItemKind::Mod(krate.module);
-        let krate_item = Expansion::Items(SmallVector::one(P(krate_item)));
-
-        krate.module = match self.expand(krate_item).make_items().pop().unwrap().unwrap().node {
-            ast::ItemKind::Mod(module) => module,
+    pub fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate {
+        self.cx.crate_root = std_inject::injected_crate_name(&krate);
+        let mut module = ModuleData {
+            mod_path: vec![token::str_to_ident(&self.cx.ecfg.crate_name)],
+            directory: PathBuf::from(self.cx.codemap().span_to_filename(krate.span)),
+        };
+        module.directory.pop();
+        self.cx.current_expansion.module = Rc::new(module);
+
+        let krate_item = Expansion::Items(SmallVector::one(P(ast::Item {
+            attrs: krate.attrs,
+            span: krate.span,
+            node: ast::ItemKind::Mod(krate.module),
+            ident: keywords::Invalid.ident(),
+            id: ast::DUMMY_NODE_ID,
+            vis: ast::Visibility::Public,
+        })));
+
+        match self.expand(krate_item).make_items().pop().unwrap().unwrap() {
+            ast::Item { attrs, node: ast::ItemKind::Mod(module), .. } => {
+                krate.attrs = attrs;
+                krate.module = module;
+            },
             _ => unreachable!(),
         };
-        krate.exported_macros = mem::replace(&mut self.cx.exported_macros, Vec::new());
-
-        for def in &mut krate.exported_macros {
-            def.id = self.cx.resolver.next_node_id()
-        }
-
-        if self.cx.parse_sess.span_diagnostic.err_count() > err_count {
-            self.cx.parse_sess.span_diagnostic.abort_if_errors();
-        }
 
         krate
     }
@@ -221,24 +224,58 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         let (expansion, mut invocations) = self.collect_invocations(expansion);
         invocations.reverse();
 
-        let mut expansions = vec![vec![(0, expansion)]];
-        while let Some(invoc) = invocations.pop() {
+        let mut expansions = Vec::new();
+        let mut undetermined_invocations = Vec::new();
+        let (mut progress, mut force) = (false, !self.monotonic);
+        loop {
+            let invoc = if let Some(invoc) = invocations.pop() {
+                invoc
+            } else if undetermined_invocations.is_empty() {
+                break
+            } else {
+                invocations = mem::replace(&mut undetermined_invocations, Vec::new());
+                force = !mem::replace(&mut progress, false);
+                continue
+            };
+
+            let scope =
+                if self.monotonic { invoc.expansion_data.mark } else { orig_expansion_data.mark };
+            let resolution = match invoc.kind {
+                InvocationKind::Bang { ref mac, .. } => {
+                    self.cx.resolver.resolve_macro(scope, &mac.node.path, force)
+                }
+                InvocationKind::Attr { ref attr, .. } => {
+                    let ident = ast::Ident::with_empty_ctxt(intern(&*attr.name()));
+                    let path = ast::Path::from_ident(attr.span, ident);
+                    self.cx.resolver.resolve_macro(scope, &path, force)
+                }
+            };
+            let ext = match resolution {
+                Ok(ext) => Some(ext),
+                Err(Determinacy::Determined) => None,
+                Err(Determinacy::Undetermined) => {
+                    undetermined_invocations.push(invoc);
+                    continue
+                }
+            };
+
+            progress = true;
             let ExpansionData { depth, mark, .. } = invoc.expansion_data;
             self.cx.current_expansion = invoc.expansion_data.clone();
 
-            let expansion = match self.cx.resolver.resolve_invoc(&invoc) {
+            self.cx.current_expansion.mark = scope;
+            let expansion = match ext {
                 Some(ext) => self.expand_invoc(invoc, ext),
                 None => invoc.expansion_kind.dummy(invoc.span()),
             };
 
-            self.cx.current_expansion.depth = depth + 1;
             let (expansion, new_invocations) = self.collect_invocations(expansion);
 
-            if expansions.len() == depth {
+            if expansions.len() < depth {
                 expansions.push(Vec::new());
             }
-            expansions[depth].push((mark.as_u32(), expansion));
-            if !self.single_step {
+            expansions[depth - 1].push((mark.as_u32(), expansion));
+            if !self.cx.ecfg.single_step {
                 invocations.extend(new_invocations.into_iter().rev());
             }
         }
@@ -248,20 +285,17 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         let mut placeholder_expander = PlaceholderExpander::new(self.cx, self.monotonic);
         while let Some(expansions) = expansions.pop() {
             for (mark, expansion) in expansions.into_iter().rev() {
-                let expansion = expansion.fold_with(&mut placeholder_expander);
-                placeholder_expander.add(mark, expansion);
+                placeholder_expander.add(ast::NodeId::from_u32(mark), expansion);
             }
         }
 
-        placeholder_expander.remove(0)
+        expansion.fold_with(&mut placeholder_expander)
     }
 
     fn collect_invocations(&mut self, expansion: Expansion) -> (Expansion, Vec<Invocation>) {
-        let crate_config = mem::replace(&mut self.cx.cfg, Vec::new());
         let result = {
             let mut collector = InvocationCollector {
                 cfg: StripUnconfigured {
-                    config: &crate_config,
                     should_test: self.cx.ecfg.should_test,
                     sess: self.cx.parse_sess,
                     features: self.cx.ecfg.features,
@@ -272,10 +306,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             };
             (expansion.fold_with(&mut collector), collector.invocations)
         };
-        self.cx.cfg = crate_config;
 
-        let mark = self.cx.current_expansion.mark;
-        self.cx.resolver.visit_expansion(mark, &result.0);
+        if self.monotonic {
+            let err_count = self.cx.parse_sess.span_diagnostic.err_count();
+            let mark = self.cx.current_expansion.mark;
+            self.cx.resolver.visit_expansion(mark, &result.0);
+            self.cx.resolve_err_count += self.cx.parse_sess.span_diagnostic.err_count() - err_count;
+        }
+
         result
     }
 
@@ -294,10 +332,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         };
 
         attr::mark_used(&attr);
+        let name = intern(&attr.name());
         self.cx.bt_push(ExpnInfo {
             call_site: attr.span,
             callee: NameAndSpan {
-                format: MacroAttribute(intern(&attr.name())),
+                format: MacroAttribute(name),
                 span: Some(attr.span),
                 allow_internal_unstable: false,
             }
@@ -315,13 +354,28 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 items.push(item);
                 kind.expect_from_annotatables(items)
             }
-            _ => unreachable!(),
+            SyntaxExtension::AttrProcMacro(ref mac) => {
+                let attr_toks = TokenStream::from_tts(tts_for_attr(&attr, &self.cx.parse_sess));
+                let item_toks = TokenStream::from_tts(tts_for_item(&item, &self.cx.parse_sess));
+
+                let tok_result = mac.expand(self.cx, attr.span, attr_toks, item_toks);
+                self.parse_expansion(tok_result, kind, name, attr.span)
+            }
+            SyntaxExtension::CustomDerive(_) => {
+                self.cx.span_err(attr.span, &format!("`{}` is a derive mode", name));
+                kind.dummy(attr.span)
+            }
+            _ => {
+                let msg = &format!("macro `{}` may not be used in attributes", name);
+                self.cx.span_err(attr.span, &msg);
+                kind.dummy(attr.span)
+            }
         }
     }
 
     /// Expand a macro invocation. Returns the result of expansion.
     fn expand_bang_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) -> Expansion {
-        let (mark, kind) = (invoc.mark(), invoc.expansion_kind);
+        let (mark, kind) = (invoc.expansion_data.mark, invoc.expansion_kind);
         let (attrs, mac, ident, span) = match invoc.kind {
             InvocationKind::Bang { attrs, mac, ident, span } => (attrs, mac, ident, span),
             _ => unreachable!(),
@@ -331,7 +385,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         // Detect use of feature-gated or invalid attributes on macro invoations
         // since they will not be detected after macro expansion.
         for attr in attrs.iter() {
-            feature_gate::check_attribute(&attr, &self.cx.parse_sess.span_diagnostic,
+            feature_gate::check_attribute(&attr, &self.cx.parse_sess,
                                           &self.cx.parse_sess.codemap(),
                                           &self.cx.ecfg.features.unwrap());
         }
@@ -381,53 +435,43 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                     }
                 });
 
-                kind.make_from(expander.expand(self.cx, span, ident, marked_tts))
+                kind.make_from(expander.expand(self.cx, span, ident, marked_tts, attrs))
             }
 
-            MacroRulesTT => {
-                if ident.name == keywords::Invalid.name() {
-                    self.cx.span_err(path.span,
-                                    &format!("macro {}! expects an ident argument", extname));
+            MultiDecorator(..) | MultiModifier(..) | SyntaxExtension::AttrProcMacro(..) => {
+                self.cx.span_err(path.span,
+                                 &format!("`{}` can only be used in attributes", extname));
+                return kind.dummy(span);
+            }
+
+            SyntaxExtension::CustomDerive(..) => {
+                self.cx.span_err(path.span, &format!("`{}` is a derive mode", extname));
+                return kind.dummy(span);
+            }
+
+            SyntaxExtension::ProcMacro(ref expandfun) => {
+                if ident.name != keywords::Invalid.name() {
+                    let msg =
+                        format!("macro {}! expects no ident argument, given '{}'", extname, ident);
+                    self.cx.span_err(path.span, &msg);
                     return kind.dummy(span);
-                };
+                }
 
                 self.cx.bt_push(ExpnInfo {
                     call_site: span,
                     callee: NameAndSpan {
                         format: MacroBang(extname),
+                        // FIXME procedural macros do not have proper span info
+                        // yet, when they do, we should use it here.
                         span: None,
-                        // `macro_rules!` doesn't directly allow unstable
-                        // (this is orthogonal to whether the macro it creates allows it)
+                        // FIXME probably want to follow macro_rules macros here.
                         allow_internal_unstable: false,
-                    }
+                    },
                 });
 
-                let def = ast::MacroDef {
-                    ident: ident,
-                    id: ast::DUMMY_NODE_ID,
-                    span: span,
-                    imported_from: None,
-                    use_locally: true,
-                    body: marked_tts,
-                    export: attr::contains_name(&attrs, "macro_export"),
-                    allow_internal_unstable: attr::contains_name(&attrs, "allow_internal_unstable"),
-                    attrs: attrs,
-                };
-
-                self.cx.insert_macro(def.clone());
-
-                // If keep_macs is true, expands to a MacEager::items instead.
-                if self.keep_macs {
-                    Some(placeholders::reconstructed_macro_rules(&def, &path))
-                } else {
-                    Some(placeholders::macro_scope_placeholder())
-                }
-            }
-
-            MultiDecorator(..) | MultiModifier(..) => {
-                self.cx.span_err(path.span,
-                                 &format!("`{}` can only be used in attributes", extname));
-                return kind.dummy(span);
+                let toks = TokenStream::from_tts(marked_tts);
+                let tok_result = expandfun.expand(self.cx, span, toks);
+                Some(self.parse_expansion(tok_result, kind, extname, span))
             }
         };
 
@@ -445,6 +489,75 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             expn_id: Some(self.cx.backtrace()),
         })
     }
+
+    fn parse_expansion(&mut self, toks: TokenStream, kind: ExpansionKind, name: Name, span: Span)
+                       -> Expansion {
+        let mut parser = self.cx.new_parser_from_tts(&toks.to_tts());
+        let expansion = match parser.parse_expansion(kind, false) {
+            Ok(expansion) => expansion,
+            Err(mut err) => {
+                err.emit();
+                return kind.dummy(span);
+            }
+        };
+        parser.ensure_complete_parse(name, kind.name(), span);
+        // FIXME better span info
+        expansion.fold_with(&mut ChangeSpan { span: span })
+    }
+}
+
+impl<'a> Parser<'a> {
+    pub fn parse_expansion(&mut self, kind: ExpansionKind, macro_legacy_warnings: bool)
+                           -> PResult<'a, Expansion> {
+        Ok(match kind {
+            ExpansionKind::Items => {
+                let mut items = SmallVector::zero();
+                while let Some(item) = self.parse_item()? {
+                    items.push(item);
+                }
+                Expansion::Items(items)
+            }
+            ExpansionKind::TraitItems => {
+                let mut items = SmallVector::zero();
+                while self.token != token::Eof {
+                    items.push(self.parse_trait_item()?);
+                }
+                Expansion::TraitItems(items)
+            }
+            ExpansionKind::ImplItems => {
+                let mut items = SmallVector::zero();
+                while self.token != token::Eof {
+                    items.push(self.parse_impl_item()?);
+                }
+                Expansion::ImplItems(items)
+            }
+            ExpansionKind::Stmts => {
+                let mut stmts = SmallVector::zero();
+                while self.token != token::Eof {
+                    if let Some(stmt) = self.parse_full_stmt(macro_legacy_warnings)? {
+                        stmts.push(stmt);
+                    }
+                }
+                Expansion::Stmts(stmts)
+            }
+            ExpansionKind::Expr => Expansion::Expr(self.parse_expr()?),
+            ExpansionKind::OptExpr => Expansion::OptExpr(Some(self.parse_expr()?)),
+            ExpansionKind::Ty => Expansion::Ty(self.parse_ty()?),
+            ExpansionKind::Pat => Expansion::Pat(self.parse_pat()?),
+        })
+    }
+
+    pub fn ensure_complete_parse(&mut self, macro_name: ast::Name, kind_name: &str, span: Span) {
+        if self.token != token::Eof {
+            let msg = format!("macro expansion ignores token `{}` and any following",
+                              self.this_token_to_string());
+            let mut err = self.diagnostic().struct_span_err(self.span, &msg);
+            let msg = format!("caused by the macro expansion here; the usage \
+                               of `{}!` is likely invalid in {} context",
+                               macro_name, kind_name);
+            err.span_note(span, &msg).emit();
+        }
+    }
 }
 
 struct InvocationCollector<'a, 'b: 'a> {
@@ -469,9 +582,13 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
         self.invocations.push(Invocation {
             kind: kind,
             expansion_kind: expansion_kind,
-            expansion_data: ExpansionData { mark: mark, ..self.cx.current_expansion.clone() },
+            expansion_data: ExpansionData {
+                mark: mark,
+                depth: self.cx.current_expansion.depth + 1,
+                ..self.cx.current_expansion.clone()
+            },
         });
-        placeholder(expansion_kind, mark.as_u32())
+        placeholder(expansion_kind, ast::NodeId::from_u32(mark.as_u32()))
     }
 
     fn collect_bang(
@@ -500,6 +617,36 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
     }
 }
 
+// These are pretty nasty. Ideally, we would keep the tokens around, linked from
+// the AST. However, we don't so we need to create new ones. Since the item might
+// have come from a macro expansion (possibly only in part), we can't use the
+// existing codemap.
+//
+// Therefore, we must use the pretty printer (yuck) to turn the AST node into a
+// string, which we then re-tokenise (double yuck), but first we have to patch
+// the pretty-printed string on to the end of the existing codemap (infinity-yuck).
+fn tts_for_item(item: &Annotatable, parse_sess: &ParseSess) -> Vec<TokenTree> {
+    let text = match *item {
+        Annotatable::Item(ref i) => pprust::item_to_string(i),
+        Annotatable::TraitItem(ref ti) => pprust::trait_item_to_string(ti),
+        Annotatable::ImplItem(ref ii) => pprust::impl_item_to_string(ii),
+    };
+    string_to_tts(text, parse_sess)
+}
+
+fn tts_for_attr(attr: &ast::Attribute, parse_sess: &ParseSess) -> Vec<TokenTree> {
+    string_to_tts(pprust::attr_to_string(attr), parse_sess)
+}
+
+fn string_to_tts(text: String, parse_sess: &ParseSess) -> Vec<TokenTree> {
+    let filemap = parse_sess.codemap()
+                            .new_filemap(String::from("<macro expansion>"), None, text);
+
+    let lexer = lexer::StringReader::new(&parse_sess.span_diagnostic, filemap);
+    let mut parser = Parser::new(parse_sess, Box::new(lexer));
+    panictry!(parser.parse_all_token_trees())
+}
+
 impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
     fn fold_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> {
         let mut expr = self.cfg.configure_expr(expr).unwrap();
@@ -568,16 +715,16 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
     }
 
     fn fold_block(&mut self, block: P<Block>) -> P<Block> {
-        let orig_in_block = mem::replace(&mut self.cx.current_expansion.in_block, true);
+        let no_noninline_mod = mem::replace(&mut self.cx.current_expansion.no_noninline_mod, true);
         let result = noop_fold_block(block, self);
-        self.cx.current_expansion.in_block = orig_in_block;
+        self.cx.current_expansion.no_noninline_mod = no_noninline_mod;
         result
     }
 
     fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
         let item = configure!(self, item);
 
-        let (item, attr) = self.classify_item(item);
+        let (mut item, attr) = self.classify_item(item);
         if let Some(attr) = attr {
             let item = Annotatable::Item(fully_configure!(self, item, noop_fold_item));
             return self.collect_attr(attr, item, ExpansionKind::Items).make_items();
@@ -609,6 +756,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
                     return noop_fold_item(item, self);
                 }
 
+                let orig_no_noninline_mod = self.cx.current_expansion.no_noninline_mod;
                 let mut module = (*self.cx.current_expansion.module).clone();
                 module.mod_path.push(item.ident);
 
@@ -618,11 +766,14 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
                 let inline_module = item.span.contains(inner) || inner == syntax_pos::DUMMY_SP;
 
                 if inline_module {
-                    module.directory.push(&*{
-                        ::attr::first_attr_value_str_by_name(&item.attrs, "path")
-                            .unwrap_or(item.ident.name.as_str())
-                    });
+                    if let Some(path) = attr::first_attr_value_str_by_name(&item.attrs, "path") {
+                        self.cx.current_expansion.no_noninline_mod = false;
+                        module.directory.push(&*path);
+                    } else {
+                        module.directory.push(&*item.ident.name.as_str());
+                    }
                 } else {
+                    self.cx.current_expansion.no_noninline_mod = false;
                     module.directory =
                         PathBuf::from(self.cx.parse_sess.codemap().span_to_filename(inner));
                     module.directory.pop();
@@ -632,22 +783,16 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
                     mem::replace(&mut self.cx.current_expansion.module, Rc::new(module));
                 let result = noop_fold_item(item, self);
                 self.cx.current_expansion.module = orig_module;
+                self.cx.current_expansion.no_noninline_mod = orig_no_noninline_mod;
                 return result;
             }
-            ast::ItemKind::ExternCrate(..) => {
-                // We need to error on `#[macro_use] extern crate` when it isn't at the
-                // crate root, because `$crate` won't work properly.
-                let is_crate_root = self.cx.current_expansion.module.mod_path.len() == 1;
-                for def in self.cx.resolver.load_crate(&*item, is_crate_root) {
-                    match def {
-                        LoadedMacro::Def(def) => self.cx.insert_macro(def),
-                        LoadedMacro::CustomDerive(name, ext) => {
-                            self.cx.insert_custom_derive(&name, ext, item.span);
-                        }
-                    }
+            // Ensure that test functions are accessible from the test harness.
+            ast::ItemKind::Fn(..) if self.cx.ecfg.should_test => {
+                if item.attrs.iter().any(|attr| is_test_or_bench(attr)) {
+                    item = item.map(|mut item| { item.vis = ast::Visibility::Public; item });
                 }
                 noop_fold_item(item, self)
-            },
+            }
             _ => noop_fold_item(item, self),
         }
     }
@@ -726,6 +871,8 @@ pub struct ExpansionConfig<'feat> {
     pub recursion_limit: usize,
     pub trace_mac: bool,
     pub should_test: bool, // If false, strip `#[test]` nodes
+    pub single_step: bool,
+    pub keep_macs: bool,
 }
 
 macro_rules! feature_tests {
@@ -749,6 +896,8 @@ impl<'feat> ExpansionConfig<'feat> {
             recursion_limit: 64,
             trace_mac: false,
             should_test: false,
+            single_step: false,
+            keep_macs: false,
         }
     }
 
@@ -761,26 +910,10 @@ impl<'feat> ExpansionConfig<'feat> {
         fn enable_allow_internal_unstable = allow_internal_unstable,
         fn enable_custom_derive = custom_derive,
         fn enable_pushpop_unsafe = pushpop_unsafe,
-        fn enable_rustc_macro = rustc_macro,
+        fn enable_proc_macro = proc_macro,
     }
 }
 
-pub fn expand_crate(cx: &mut ExtCtxt,
-                    user_exts: Vec<NamedSyntaxExtension>,
-                    c: Crate) -> Crate {
-    cx.initialize(user_exts, &c);
-    cx.monotonic_expander().expand_crate(c)
-}
-
-// Expands crate using supplied MacroExpander - allows for
-// non-standard expansion behaviour (e.g. step-wise).
-pub fn expand_crate_with_expander(expander: &mut MacroExpander,
-                                  user_exts: Vec<NamedSyntaxExtension>,
-                                  c: Crate) -> Crate {
-    expander.cx.initialize(user_exts, &c);
-    expander.expand_crate(c)
-}
-
 // A Marker adds the given mark to the syntax context and
 // sets spans' `expn_id` to the given expn_id (unless it is `None`).
 struct Marker { mark: Mark, expn_id: Option<ExpnId> }
@@ -803,6 +936,6 @@ impl Folder for Marker {
 }
 
 // apply a given mark to the given token trees. Used prior to expansion of a macro.
-fn mark_tts(tts: &[TokenTree], m: Mark) -> Vec<TokenTree> {
+pub fn mark_tts(tts: &[TokenTree], m: Mark) -> Vec<TokenTree> {
     noop_fold_tts(tts, &mut Marker{mark:m, expn_id: None})
 }
diff --git a/src/libsyntax/ext/hygiene.rs b/src/libsyntax/ext/hygiene.rs
index 34126fac4ac..0fd72277cca 100644
--- a/src/libsyntax/ext/hygiene.rs
+++ b/src/libsyntax/ext/hygiene.rs
@@ -15,6 +15,7 @@
 //! and definition contexts*. J. Funct. Program. 22, 2 (March 2012), 181-216.
 //! DOI=10.1017/S0956796812000093 http://dx.doi.org/10.1017/S0956796812000093
 
+use ast::NodeId;
 use std::cell::RefCell;
 use std::collections::HashMap;
 use std::fmt;
@@ -46,6 +47,10 @@ impl Mark {
         Mark(0)
     }
 
+    pub fn from_placeholder_id(id: NodeId) -> Self {
+        Mark(id.as_u32())
+    }
+
     pub fn as_u32(&self) -> u32 {
         self.0
     }
diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs
index 47f366a8876..e323dd2f623 100644
--- a/src/libsyntax/ext/placeholders.rs
+++ b/src/libsyntax/ext/placeholders.rs
@@ -13,7 +13,7 @@ use codemap::{DUMMY_SP, dummy_spanned};
 use ext::base::ExtCtxt;
 use ext::expand::{Expansion, ExpansionKind};
 use fold::*;
-use parse::token::keywords;
+use parse::token::{intern, keywords};
 use ptr::P;
 use util::move_map::MoveMap;
 use util::small_vector::SmallVector;
@@ -88,10 +88,11 @@ impl<'a, 'b> PlaceholderExpander<'a, 'b> {
     }
 
     pub fn add(&mut self, id: ast::NodeId, expansion: Expansion) {
+        let expansion = expansion.fold_with(self);
         self.expansions.insert(id, expansion);
     }
 
-    pub fn remove(&mut self, id: ast::NodeId) -> Expansion {
+    fn remove(&mut self, id: ast::NodeId) -> Expansion {
         self.expansions.remove(&id).unwrap()
     }
 }
@@ -214,7 +215,7 @@ impl<'a, 'b> Folder for PlaceholderExpander<'a, 'b> {
     }
 }
 
-pub fn reconstructed_macro_rules(def: &ast::MacroDef, path: &ast::Path) -> Expansion {
+pub fn reconstructed_macro_rules(def: &ast::MacroDef) -> Expansion {
     Expansion::Items(SmallVector::one(P(ast::Item {
         ident: def.ident,
         attrs: def.attrs.clone(),
@@ -222,7 +223,14 @@ pub fn reconstructed_macro_rules(def: &ast::MacroDef, path: &ast::Path) -> Expan
         node: ast::ItemKind::Mac(ast::Mac {
             span: def.span,
             node: ast::Mac_ {
-                path: path.clone(),
+                path: ast::Path {
+                    span: DUMMY_SP,
+                    global: false,
+                    segments: vec![ast::PathSegment {
+                        identifier: ast::Ident::with_empty_ctxt(intern("macro_rules")),
+                        parameters: ast::PathParameters::none(),
+                    }],
+                },
                 tts: def.body.clone(),
             }
         }),
diff --git a/src/libsyntax/ext/proc_macro_shim.rs b/src/libsyntax/ext/proc_macro_shim.rs
index fa37e9b54e4..dc3a01f41bc 100644
--- a/src/libsyntax/ext/proc_macro_shim.rs
+++ b/src/libsyntax/ext/proc_macro_shim.rs
@@ -24,7 +24,9 @@ use ext::base::*;
 
 /// Take a `ExtCtxt`, `Span`, and `TokenStream`, and produce a Macro Result that parses
 /// the TokenStream as a block and returns it as an `Expr`.
-pub fn build_block_emitter<'cx>(cx: &'cx mut ExtCtxt, sp: Span, output: TokenStream)
+pub fn build_block_emitter<'cx>(cx: &'cx mut ExtCtxt,
+                                sp: Span,
+                                output: TokenStream)
                                 -> Box<MacResult + 'cx> {
     let parser = cx.new_parser_from_tts(&output.to_tts());
 
@@ -60,7 +62,7 @@ pub fn build_block_emitter<'cx>(cx: &'cx mut ExtCtxt, sp: Span, output: TokenStr
 }
 
 pub mod prelude {
-    pub use ext::proc_macro_shim::build_block_emitter;
+    pub use super::build_block_emitter;
     pub use ast::Ident;
     pub use codemap::{DUMMY_SP, Span};
     pub use ext::base::{ExtCtxt, MacResult};
diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs
index b70e270df54..f21360755bc 100644
--- a/src/libsyntax/ext/quote.rs
+++ b/src/libsyntax/ext/quote.rs
@@ -46,7 +46,7 @@ pub mod rt {
 
     impl ToTokens for TokenTree {
         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
-            vec!(self.clone())
+            vec![self.clone()]
         }
     }
 
@@ -331,7 +331,6 @@ pub mod rt {
             panictry!(parse::parse_item_from_source_str(
                 "<quote expansion>".to_string(),
                 s,
-                self.cfg(),
                 self.parse_sess())).expect("parse error")
         }
 
@@ -339,7 +338,6 @@ pub mod rt {
             panictry!(parse::parse_stmt_from_source_str(
                 "<quote expansion>".to_string(),
                 s,
-                self.cfg(),
                 self.parse_sess())).expect("parse error")
         }
 
@@ -347,7 +345,6 @@ pub mod rt {
             panictry!(parse::parse_expr_from_source_str(
                 "<quote expansion>".to_string(),
                 s,
-                self.cfg(),
                 self.parse_sess()))
         }
 
@@ -355,7 +352,6 @@ pub mod rt {
             panictry!(parse::parse_tts_from_source_str(
                 "<quote expansion>".to_string(),
                 s,
-                self.cfg(),
                 self.parse_sess()))
         }
     }
@@ -420,7 +416,7 @@ pub fn expand_quote_expr<'cx>(cx: &'cx mut ExtCtxt,
                               sp: Span,
                               tts: &[TokenTree])
                               -> Box<base::MacResult+'cx> {
-    let expanded = expand_parse_call(cx, sp, "parse_expr_panic", vec!(), tts);
+    let expanded = expand_parse_call(cx, sp, "parse_expr_panic", vec![], tts);
     base::MacEager::expr(expanded)
 }
 
@@ -428,7 +424,7 @@ pub fn expand_quote_item<'cx>(cx: &'cx mut ExtCtxt,
                               sp: Span,
                               tts: &[TokenTree])
                               -> Box<base::MacResult+'cx> {
-    let expanded = expand_parse_call(cx, sp, "parse_item_panic", vec!(), tts);
+    let expanded = expand_parse_call(cx, sp, "parse_item_panic", vec![], tts);
     base::MacEager::expr(expanded)
 }
 
@@ -436,7 +432,7 @@ pub fn expand_quote_pat<'cx>(cx: &'cx mut ExtCtxt,
                              sp: Span,
                              tts: &[TokenTree])
                              -> Box<base::MacResult+'cx> {
-    let expanded = expand_parse_call(cx, sp, "parse_pat_panic", vec!(), tts);
+    let expanded = expand_parse_call(cx, sp, "parse_pat_panic", vec![], tts);
     base::MacEager::expr(expanded)
 }
 
@@ -444,7 +440,7 @@ pub fn expand_quote_arm(cx: &mut ExtCtxt,
                         sp: Span,
                         tts: &[TokenTree])
                         -> Box<base::MacResult+'static> {
-    let expanded = expand_parse_call(cx, sp, "parse_arm_panic", vec!(), tts);
+    let expanded = expand_parse_call(cx, sp, "parse_arm_panic", vec![], tts);
     base::MacEager::expr(expanded)
 }
 
@@ -452,7 +448,7 @@ pub fn expand_quote_ty(cx: &mut ExtCtxt,
                        sp: Span,
                        tts: &[TokenTree])
                        -> Box<base::MacResult+'static> {
-    let expanded = expand_parse_call(cx, sp, "parse_ty_panic", vec!(), tts);
+    let expanded = expand_parse_call(cx, sp, "parse_ty_panic", vec![], tts);
     base::MacEager::expr(expanded)
 }
 
@@ -460,7 +456,7 @@ pub fn expand_quote_stmt(cx: &mut ExtCtxt,
                          sp: Span,
                          tts: &[TokenTree])
                          -> Box<base::MacResult+'static> {
-    let expanded = expand_parse_call(cx, sp, "parse_stmt_panic", vec!(), tts);
+    let expanded = expand_parse_call(cx, sp, "parse_stmt_panic", vec![], tts);
     base::MacEager::expr(expanded)
 }
 
@@ -469,7 +465,7 @@ pub fn expand_quote_attr(cx: &mut ExtCtxt,
                          tts: &[TokenTree])
                          -> Box<base::MacResult+'static> {
     let expanded = expand_parse_call(cx, sp, "parse_attribute_panic",
-                                    vec!(cx.expr_bool(sp, true)), tts);
+                                    vec![cx.expr_bool(sp, true)], tts);
 
     base::MacEager::expr(expanded)
 }
@@ -478,7 +474,7 @@ pub fn expand_quote_arg(cx: &mut ExtCtxt,
                         sp: Span,
                         tts: &[TokenTree])
                         -> Box<base::MacResult+'static> {
-    let expanded = expand_parse_call(cx, sp, "parse_arg_panic", vec!(), tts);
+    let expanded = expand_parse_call(cx, sp, "parse_arg_panic", vec![], tts);
     base::MacEager::expr(expanded)
 }
 
@@ -486,7 +482,7 @@ pub fn expand_quote_block(cx: &mut ExtCtxt,
                         sp: Span,
                         tts: &[TokenTree])
                         -> Box<base::MacResult+'static> {
-    let expanded = expand_parse_call(cx, sp, "parse_block_panic", vec!(), tts);
+    let expanded = expand_parse_call(cx, sp, "parse_block_panic", vec![], tts);
     base::MacEager::expr(expanded)
 }
 
@@ -494,7 +490,7 @@ pub fn expand_quote_meta_item(cx: &mut ExtCtxt,
                         sp: Span,
                         tts: &[TokenTree])
                         -> Box<base::MacResult+'static> {
-    let expanded = expand_parse_call(cx, sp, "parse_meta_item_panic", vec!(), tts);
+    let expanded = expand_parse_call(cx, sp, "parse_meta_item_panic", vec![], tts);
     base::MacEager::expr(expanded)
 }
 
@@ -503,7 +499,7 @@ pub fn expand_quote_path(cx: &mut ExtCtxt,
                         tts: &[TokenTree])
                         -> Box<base::MacResult+'static> {
     let mode = mk_parser_path(cx, sp, &["PathStyle", "Type"]);
-    let expanded = expand_parse_call(cx, sp, "parse_path_panic", vec!(mode), tts);
+    let expanded = expand_parse_call(cx, sp, "parse_path_panic", vec![mode], tts);
     base::MacEager::expr(expanded)
 }
 
@@ -535,7 +531,7 @@ fn mk_ident(cx: &ExtCtxt, sp: Span, ident: ast::Ident) -> P<ast::Expr> {
     cx.expr_method_call(sp,
                         cx.expr_ident(sp, id_ext("ext_cx")),
                         id_ext("ident_of"),
-                        vec!(e_str))
+                        vec![e_str])
 }
 
 // Lift a name to the expr that evaluates to that name
@@ -544,16 +540,16 @@ fn mk_name(cx: &ExtCtxt, sp: Span, ident: ast::Ident) -> P<ast::Expr> {
     cx.expr_method_call(sp,
                         cx.expr_ident(sp, id_ext("ext_cx")),
                         id_ext("name_of"),
-                        vec!(e_str))
+                        vec![e_str])
 }
 
 fn mk_tt_path(cx: &ExtCtxt, sp: Span, name: &str) -> P<ast::Expr> {
-    let idents = vec!(id_ext("syntax"), id_ext("tokenstream"), id_ext("TokenTree"), id_ext(name));
+    let idents = vec![id_ext("syntax"), id_ext("tokenstream"), id_ext("TokenTree"), id_ext(name)];
     cx.expr_path(cx.path_global(sp, idents))
 }
 
 fn mk_token_path(cx: &ExtCtxt, sp: Span, name: &str) -> P<ast::Expr> {
-    let idents = vec!(id_ext("syntax"), id_ext("parse"), id_ext("token"), id_ext(name));
+    let idents = vec![id_ext("syntax"), id_ext("parse"), id_ext("token"), id_ext(name)];
     cx.expr_path(cx.path_global(sp, idents))
 }
 
@@ -603,11 +599,11 @@ fn expr_mk_token(cx: &ExtCtxt, sp: Span, tok: &token::Token) -> P<ast::Expr> {
     }
     match *tok {
         token::BinOp(binop) => {
-            return cx.expr_call(sp, mk_token_path(cx, sp, "BinOp"), vec!(mk_binop(cx, sp, binop)));
+            return cx.expr_call(sp, mk_token_path(cx, sp, "BinOp"), vec![mk_binop(cx, sp, binop)]);
         }
         token::BinOpEq(binop) => {
             return cx.expr_call(sp, mk_token_path(cx, sp, "BinOpEq"),
-                                vec!(mk_binop(cx, sp, binop)));
+                                vec![mk_binop(cx, sp, binop)]);
         }
 
         token::OpenDelim(delim) => {
@@ -657,13 +653,13 @@ fn expr_mk_token(cx: &ExtCtxt, sp: Span, tok: &token::Token) -> P<ast::Expr> {
         token::Lifetime(ident) => {
             return cx.expr_call(sp,
                                 mk_token_path(cx, sp, "Lifetime"),
-                                vec!(mk_ident(cx, sp, ident)));
+                                vec![mk_ident(cx, sp, ident)]);
         }
 
         token::DocComment(ident) => {
             return cx.expr_call(sp,
                                 mk_token_path(cx, sp, "DocComment"),
-                                vec!(mk_name(cx, sp, ast::Ident::with_empty_ctxt(ident))));
+                                vec![mk_name(cx, sp, ast::Ident::with_empty_ctxt(ident))]);
         }
 
         token::MatchNt(name, kind) => {
@@ -718,7 +714,7 @@ fn statements_mk_tt(cx: &ExtCtxt, tt: &TokenTree, matcher: bool) -> Vec<ast::Stm
                 cx.expr_method_call(sp,
                                     cx.expr_ident(sp, ident),
                                     id_ext("to_tokens"),
-                                    vec!(cx.expr_ident(sp, id_ext("ext_cx"))));
+                                    vec![cx.expr_ident(sp, id_ext("ext_cx"))]);
             let e_to_toks =
                 cx.expr_method_call(sp, e_to_toks, id_ext("into_iter"), vec![]);
 
@@ -726,9 +722,9 @@ fn statements_mk_tt(cx: &ExtCtxt, tt: &TokenTree, matcher: bool) -> Vec<ast::Stm
                 cx.expr_method_call(sp,
                                     cx.expr_ident(sp, id_ext("tt")),
                                     id_ext("extend"),
-                                    vec!(e_to_toks));
+                                    vec![e_to_toks]);
 
-            vec!(cx.stmt_expr(e_push))
+            vec![cx.stmt_expr(e_push)]
         }
         ref tt @ TokenTree::Token(_, MatchNt(..)) if !matcher => {
             let mut seq = vec![];
@@ -741,13 +737,13 @@ fn statements_mk_tt(cx: &ExtCtxt, tt: &TokenTree, matcher: bool) -> Vec<ast::Stm
             let e_sp = cx.expr_ident(sp, id_ext("_sp"));
             let e_tok = cx.expr_call(sp,
                                      mk_tt_path(cx, sp, "Token"),
-                                     vec!(e_sp, expr_mk_token(cx, sp, tok)));
+                                     vec![e_sp, expr_mk_token(cx, sp, tok)]);
             let e_push =
                 cx.expr_method_call(sp,
                                     cx.expr_ident(sp, id_ext("tt")),
                                     id_ext("push"),
-                                    vec!(e_tok));
-            vec!(cx.stmt_expr(e_push))
+                                    vec![e_tok]);
+            vec![cx.stmt_expr(e_push)]
         },
         TokenTree::Delimited(_, ref delimed) => {
             statements_mk_tt(cx, &delimed.open_tt(), matcher).into_iter()
@@ -800,13 +796,13 @@ fn statements_mk_tt(cx: &ExtCtxt, tt: &TokenTree, matcher: bool) -> Vec<ast::Stm
                                                    vec![e_seq_struct]);
             let e_tok = cx.expr_call(sp,
                                      mk_tt_path(cx, sp, "Sequence"),
-                                     vec!(e_sp, e_rc_new));
+                                     vec![e_sp, e_rc_new]);
             let e_push =
                 cx.expr_method_call(sp,
                                     cx.expr_ident(sp, id_ext("tt")),
                                     id_ext("push"),
-                                    vec!(e_tok));
-            vec!(cx.stmt_expr(e_push))
+                                    vec![e_tok]);
+            vec![cx.stmt_expr(e_push)]
         }
     }
 }
@@ -871,7 +867,7 @@ fn mk_stmts_let(cx: &ExtCtxt, sp: Span) -> Vec<ast::Stmt> {
 
     let stmt_let_tt = cx.stmt_let(sp, true, id_ext("tt"), cx.expr_vec_ng(sp));
 
-    vec!(stmt_let_sp, stmt_let_tt)
+    vec![stmt_let_sp, stmt_let_tt]
 }
 
 fn statements_mk_tts(cx: &ExtCtxt, tts: &[TokenTree], matcher: bool) -> Vec<ast::Stmt> {
@@ -920,10 +916,6 @@ fn expand_parse_call(cx: &ExtCtxt,
                      tts: &[TokenTree]) -> P<ast::Expr> {
     let (cx_expr, tts_expr) = expand_tts(cx, sp, tts);
 
-    let cfg_call = || cx.expr_method_call(
-        sp, cx.expr_ident(sp, id_ext("ext_cx")),
-        id_ext("cfg"), Vec::new());
-
     let parse_sess_call = || cx.expr_method_call(
         sp, cx.expr_ident(sp, id_ext("ext_cx")),
         id_ext("parse_sess"), Vec::new());
@@ -931,7 +923,7 @@ fn expand_parse_call(cx: &ExtCtxt,
     let new_parser_call =
         cx.expr_call(sp,
                      cx.expr_ident(sp, id_ext("new_parser_from_tts")),
-                     vec!(parse_sess_call(), cfg_call(), tts_expr));
+                     vec![parse_sess_call(), tts_expr]);
 
     let path = vec![id_ext("syntax"), id_ext("ext"), id_ext("quote"), id_ext(parse_method)];
     let mut args = vec![cx.expr_mut_addr_of(sp, new_parser_call)];
diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs
index e75e41d0c2d..ec48cae3f76 100644
--- a/src/libsyntax/ext/source_util.rs
+++ b/src/libsyntax/ext/source_util.rs
@@ -92,15 +92,8 @@ pub fn expand_include<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[tokenstream::T
         None => return DummyResult::expr(sp),
     };
     // The file will be added to the code map by the parser
-    let p =
-        parse::new_sub_parser_from_file(cx.parse_sess(),
-                                        cx.cfg(),
-                                        &res_rel_file(cx,
-                                                      sp,
-                                                      Path::new(&file)),
-                                        true,
-                                        None,
-                                        sp);
+    let path = res_rel_file(cx, sp, Path::new(&file));
+    let p = parse::new_sub_parser_from_file(cx.parse_sess(), &path, true, None, sp);
 
     struct ExpandResult<'a> {
         p: parse::parser::Parser<'a>,
diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs
index b0696a986e3..7e3fe328569 100644
--- a/src/libsyntax/ext/tt/macro_parser.rs
+++ b/src/libsyntax/ext/tt/macro_parser.rs
@@ -78,7 +78,6 @@ pub use self::NamedMatch::*;
 pub use self::ParseResult::*;
 use self::TokenTreeOrTokenTreeVec::*;
 
-use ast;
 use ast::Ident;
 use syntax_pos::{self, BytePos, mk_sp, Span};
 use codemap::Spanned;
@@ -92,6 +91,7 @@ use parse::token;
 use print::pprust;
 use ptr::P;
 use tokenstream::{self, TokenTree};
+use util::small_vector::SmallVector;
 
 use std::mem;
 use std::rc::Rc;
@@ -104,7 +104,7 @@ use std::collections::hash_map::Entry::{Vacant, Occupied};
 #[derive(Clone)]
 enum TokenTreeOrTokenTreeVec {
     Tt(tokenstream::TokenTree),
-    TtSeq(Rc<Vec<tokenstream::TokenTree>>),
+    TtSeq(Vec<tokenstream::TokenTree>),
 }
 
 impl TokenTreeOrTokenTreeVec {
@@ -161,7 +161,7 @@ pub fn count_names(ms: &[TokenTree]) -> usize {
     })
 }
 
-pub fn initial_matcher_pos(ms: Rc<Vec<TokenTree>>, sep: Option<Token>, lo: BytePos)
+pub fn initial_matcher_pos(ms: Vec<TokenTree>, sep: Option<Token>, lo: BytePos)
                            -> Box<MatcherPos> {
     let match_idx_hi = count_names(&ms[..]);
     let matches: Vec<_> = (0..match_idx_hi).map(|_| Vec::new()).collect();
@@ -251,14 +251,22 @@ pub fn nameize(p_s: &ParseSess, ms: &[TokenTree], res: &[Rc<NamedMatch>])
 
 pub enum ParseResult<T> {
     Success(T),
-    /// Arm failed to match
-    Failure(syntax_pos::Span, String),
+    /// Arm failed to match. If the second parameter is `token::Eof`, it
+    /// indicates an unexpected end of macro invocation. Otherwise, it
+    /// indicates that no rules expected the given token.
+    Failure(syntax_pos::Span, Token),
     /// Fatal error (malformed macro?). Abort compilation.
     Error(syntax_pos::Span, String)
 }
 
+pub fn parse_failure_msg(tok: Token) -> String {
+    match tok {
+        token::Eof => "unexpected end of macro invocation".to_string(),
+        _ => format!("no rules expected the token `{}`", pprust::token_to_string(&tok)),
+    }
+}
+
 pub type NamedParseResult = ParseResult<HashMap<Ident, Rc<NamedMatch>>>;
-pub type PositionalParseResult = ParseResult<Vec<Rc<NamedMatch>>>;
 
 /// Perform a token equality check, ignoring syntax context (that is, an
 /// unhygienic comparison)
@@ -271,17 +279,10 @@ pub fn token_name_eq(t1 : &Token, t2 : &Token) -> bool {
     }
 }
 
-pub fn parse(sess: &ParseSess,
-             cfg: ast::CrateConfig,
-             mut rdr: TtReader,
-             ms: &[TokenTree])
-             -> NamedParseResult {
-    let mut cur_eis = Vec::new();
-    cur_eis.push(initial_matcher_pos(Rc::new(ms.iter()
-                                                .cloned()
-                                                .collect()),
-                                     None,
-                                     rdr.peek().sp.lo));
+pub fn parse(sess: &ParseSess, mut rdr: TtReader, ms: &[TokenTree]) -> NamedParseResult {
+    let mut cur_eis = SmallVector::one(initial_matcher_pos(ms.to_owned(),
+                                                           None,
+                                                           rdr.peek().sp.lo));
 
     loop {
         let mut bb_eis = Vec::new(); // black-box parsed by parser.rs
@@ -425,8 +426,8 @@ pub fn parse(sess: &ParseSess,
                         cur_eis.push(ei);
                     }
                     TokenTree::Token(_, ref t) => {
-                        let mut ei_t = ei.clone();
                         if token_name_eq(t,&tok) {
+                            let mut ei_t = ei.clone();
                             ei_t.idx += 1;
                             next_eis.push(ei_t);
                         }
@@ -446,7 +447,7 @@ pub fn parse(sess: &ParseSess,
             } else if eof_eis.len() > 1 {
                 return Error(sp, "ambiguity: multiple successful parses".to_string());
             } else {
-                return Failure(sp, "unexpected end of macro invocation".to_string());
+                return Failure(sp, token::Eof);
             }
         } else {
             if (!bb_eis.is_empty() && !next_eis.is_empty())
@@ -467,8 +468,7 @@ pub fn parse(sess: &ParseSess,
                     }
                 ))
             } else if bb_eis.is_empty() && next_eis.is_empty() {
-                return Failure(sp, format!("no rules expected the token `{}`",
-                            pprust::token_to_string(&tok)));
+                return Failure(sp, tok);
             } else if !next_eis.is_empty() {
                 /* Now process the next token */
                 while !next_eis.is_empty() {
@@ -476,24 +476,21 @@ pub fn parse(sess: &ParseSess,
                 }
                 rdr.next_token();
             } else /* bb_eis.len() == 1 */ {
-                let mut rust_parser = Parser::new(sess, cfg.clone(), Box::new(rdr.clone()));
-
-                let mut ei = bb_eis.pop().unwrap();
-                match ei.top_elts.get_tt(ei.idx) {
-                    TokenTree::Token(span, MatchNt(_, ident)) => {
+                rdr.next_tok = {
+                    let mut rust_parser = Parser::new(sess, Box::new(&mut rdr));
+                    let mut ei = bb_eis.pop().unwrap();
+                    if let TokenTree::Token(span, MatchNt(_, ident)) = ei.top_elts.get_tt(ei.idx) {
                         let match_cur = ei.match_cur;
                         (&mut ei.matches[match_cur]).push(Rc::new(MatchedNonterminal(
                             parse_nt(&mut rust_parser, span, &ident.name.as_str()))));
                         ei.idx += 1;
                         ei.match_cur += 1;
+                    } else {
+                        unreachable!()
                     }
-                    _ => panic!()
-                }
-                cur_eis.push(ei);
-
-                for _ in 0..rust_parser.tokens_consumed {
-                    let _ = rdr.next_token();
-                }
+                    cur_eis.push(ei);
+                    Some(TokenAndSpan { tok: rust_parser.token, sp: rust_parser.span })
+                };
             }
         }
 
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs
index 51ef45b97be..431e757368c 100644
--- a/src/libsyntax/ext/tt/macro_rules.rs
+++ b/src/libsyntax/ext/tt/macro_rules.rs
@@ -8,30 +8,29 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use ast;
+use {ast, attr};
 use syntax_pos::{Span, DUMMY_SP};
-use ext::base::{DummyResult, ExtCtxt, MacResult, SyntaxExtension};
-use ext::base::{NormalTT, TTMacroExpander};
+use ext::base::{DummyResult, ExtCtxt, MacEager, MacResult, SyntaxExtension};
+use ext::base::{IdentMacroExpander, NormalTT, TTMacroExpander};
+use ext::expand::{Expansion, ExpansionKind};
+use ext::placeholders;
 use ext::tt::macro_parser::{Success, Error, Failure};
 use ext::tt::macro_parser::{MatchedSeq, MatchedNonterminal};
-use ext::tt::macro_parser::parse;
+use ext::tt::macro_parser::{parse, parse_failure_msg};
+use parse::ParseSess;
 use parse::lexer::new_tt_reader;
 use parse::parser::{Parser, Restrictions};
 use parse::token::{self, gensym_ident, NtTT, Token};
 use parse::token::Token::*;
 use print;
-use ptr::P;
 use tokenstream::{self, TokenTree};
 
-use util::small_vector::SmallVector;
-
-use std::cell::RefCell;
 use std::collections::{HashMap};
 use std::collections::hash_map::{Entry};
 use std::rc::Rc;
 
-struct ParserAnyMacro<'a> {
-    parser: RefCell<Parser<'a>>,
+pub struct ParserAnyMacro<'a> {
+    parser: Parser<'a>,
 
     /// Span of the expansion site of the macro this parser is for
     site_span: Span,
@@ -40,115 +39,25 @@ struct ParserAnyMacro<'a> {
 }
 
 impl<'a> ParserAnyMacro<'a> {
-    /// Make sure we don't have any tokens left to parse, so we don't
-    /// silently drop anything. `allow_semi` is so that "optional"
-    /// semicolons at the end of normal expressions aren't complained
-    /// about e.g. the semicolon in `macro_rules! kapow { () => {
-    /// panic!(); } }` doesn't get picked up by .parse_expr(), but it's
-    /// allowed to be there.
-    fn ensure_complete_parse(&self, allow_semi: bool, context: &str) {
-        let mut parser = self.parser.borrow_mut();
-        if allow_semi && parser.token == token::Semi {
+    pub fn make(mut self: Box<ParserAnyMacro<'a>>, kind: ExpansionKind) -> Expansion {
+        let ParserAnyMacro { site_span, macro_ident, ref mut parser } = *self;
+        let expansion = panictry!(parser.parse_expansion(kind, true));
+
+        // We allow semicolons at the end of expressions -- e.g. the semicolon in
+        // `macro_rules! m { () => { panic!(); } }` isn't parsed by `.parse_expr()`,
+        // but `m!()` is allowed in expression positions (c.f. issue #34706).
+        if kind == ExpansionKind::Expr && parser.token == token::Semi {
             parser.bump();
         }
-        if parser.token != token::Eof {
-            let token_str = parser.this_token_to_string();
-            let msg = format!("macro expansion ignores token `{}` and any \
-                               following",
-                              token_str);
-            let span = parser.span;
-            let mut err = parser.diagnostic().struct_span_err(span, &msg[..]);
-            let msg = format!("caused by the macro expansion here; the usage \
-                               of `{}!` is likely invalid in {} context",
-                               self.macro_ident, context);
-            err.span_note(self.site_span, &msg[..])
-               .emit();
-        }
-    }
-}
-
-impl<'a> MacResult for ParserAnyMacro<'a> {
-    fn make_expr(self: Box<ParserAnyMacro<'a>>) -> Option<P<ast::Expr>> {
-        let ret = panictry!(self.parser.borrow_mut().parse_expr());
-        self.ensure_complete_parse(true, "expression");
-        Some(ret)
-    }
-    fn make_pat(self: Box<ParserAnyMacro<'a>>) -> Option<P<ast::Pat>> {
-        let ret = panictry!(self.parser.borrow_mut().parse_pat());
-        self.ensure_complete_parse(false, "pattern");
-        Some(ret)
-    }
-    fn make_items(self: Box<ParserAnyMacro<'a>>) -> Option<SmallVector<P<ast::Item>>> {
-        let mut ret = SmallVector::zero();
-        while let Some(item) = panictry!(self.parser.borrow_mut().parse_item()) {
-            ret.push(item);
-        }
-        self.ensure_complete_parse(false, "item");
-        Some(ret)
-    }
-
-    fn make_impl_items(self: Box<ParserAnyMacro<'a>>)
-                       -> Option<SmallVector<ast::ImplItem>> {
-        let mut ret = SmallVector::zero();
-        loop {
-            let mut parser = self.parser.borrow_mut();
-            match parser.token {
-                token::Eof => break,
-                _ => ret.push(panictry!(parser.parse_impl_item()))
-            }
-        }
-        self.ensure_complete_parse(false, "item");
-        Some(ret)
-    }
-
-    fn make_trait_items(self: Box<ParserAnyMacro<'a>>)
-                       -> Option<SmallVector<ast::TraitItem>> {
-        let mut ret = SmallVector::zero();
-        loop {
-            let mut parser = self.parser.borrow_mut();
-            match parser.token {
-                token::Eof => break,
-                _ => ret.push(panictry!(parser.parse_trait_item()))
-            }
-        }
-        self.ensure_complete_parse(false, "item");
-        Some(ret)
-    }
-
-
-    fn make_stmts(self: Box<ParserAnyMacro<'a>>)
-                 -> Option<SmallVector<ast::Stmt>> {
-        let mut ret = SmallVector::zero();
-        loop {
-            let mut parser = self.parser.borrow_mut();
-            match parser.token {
-                token::Eof => break,
-                _ => match parser.parse_full_stmt(true) {
-                    Ok(maybe_stmt) => match maybe_stmt {
-                        Some(stmt) => ret.push(stmt),
-                        None => (),
-                    },
-                    Err(mut e) => {
-                        e.emit();
-                        break;
-                    }
-                }
-            }
-        }
-        self.ensure_complete_parse(false, "statement");
-        Some(ret)
-    }
 
-    fn make_ty(self: Box<ParserAnyMacro<'a>>) -> Option<P<ast::Ty>> {
-        let ret = panictry!(self.parser.borrow_mut().parse_ty());
-        self.ensure_complete_parse(false, "type");
-        Some(ret)
+        // Make sure we don't have any tokens left to parse so we don't silently drop anything.
+        parser.ensure_complete_parse(macro_ident.name, kind.name(), site_span);
+        expansion
     }
 }
 
 struct MacroRulesMacroExpander {
     name: ast::Ident,
-    imported_from: Option<ast::Ident>,
     lhses: Vec<TokenTree>,
     rhses: Vec<TokenTree>,
     valid: bool,
@@ -166,7 +75,6 @@ impl TTMacroExpander for MacroRulesMacroExpander {
         generic_extension(cx,
                           sp,
                           self.name,
-                          self.imported_from,
                           arg,
                           &self.lhses,
                           &self.rhses)
@@ -177,7 +85,6 @@ impl TTMacroExpander for MacroRulesMacroExpander {
 fn generic_extension<'cx>(cx: &'cx ExtCtxt,
                           sp: Span,
                           name: ast::Ident,
-                          imported_from: Option<ast::Ident>,
                           arg: &[TokenTree],
                           lhses: &[TokenTree],
                           rhses: &[TokenTree])
@@ -190,7 +97,7 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
 
     // Which arm's failure should we report? (the one furthest along)
     let mut best_fail_spot = DUMMY_SP;
-    let mut best_fail_msg = "internal error: ran no matchers".to_string();
+    let mut best_fail_tok = None;
 
     for (i, lhs) in lhses.iter().enumerate() { // try each arm's matchers
         let lhs_tt = match *lhs {
@@ -206,13 +113,11 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
                     _ => cx.span_bug(sp, "malformed macro rhs"),
                 };
                 // rhs has holes ( `$id` and `$(...)` that need filled)
-                let trncbr = new_tt_reader(&cx.parse_sess().span_diagnostic,
-                                           Some(named_matches),
-                                           imported_from,
-                                           rhs);
-                let mut p = Parser::new(cx.parse_sess(), cx.cfg(), Box::new(trncbr));
+                let trncbr =
+                    new_tt_reader(&cx.parse_sess.span_diagnostic, Some(named_matches), rhs);
+                let mut p = Parser::new(cx.parse_sess(), Box::new(trncbr));
                 p.directory = cx.current_expansion.module.directory.clone();
-                p.restrictions = match cx.current_expansion.in_block {
+                p.restrictions = match cx.current_expansion.no_noninline_mod {
                     true => Restrictions::NO_NONINLINE_MOD,
                     false => Restrictions::empty(),
                 };
@@ -220,7 +125,7 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
                 // Let the context choose how to interpret the result.
                 // Weird, but useful for X-macros.
                 return Box::new(ParserAnyMacro {
-                    parser: RefCell::new(p),
+                    parser: p,
 
                     // Pass along the original expansion site and the name of the macro
                     // so we can print a useful error message if the parse of the expanded
@@ -229,9 +134,9 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
                     macro_ident: name
                 })
             }
-            Failure(sp, ref msg) => if sp.lo >= best_fail_spot.lo {
+            Failure(sp, tok) => if sp.lo >= best_fail_spot.lo {
                 best_fail_spot = sp;
-                best_fail_msg = (*msg).clone();
+                best_fail_tok = Some(tok);
             },
             Error(err_sp, ref msg) => {
                 cx.span_fatal(err_sp.substitute_dummy(sp), &msg[..])
@@ -239,7 +144,40 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
         }
     }
 
-     cx.span_fatal(best_fail_spot.substitute_dummy(sp), &best_fail_msg[..]);
+    let best_fail_msg = parse_failure_msg(best_fail_tok.expect("ran no matchers"));
+    cx.span_fatal(best_fail_spot.substitute_dummy(sp), &best_fail_msg);
+}
+
+pub struct MacroRulesExpander;
+impl IdentMacroExpander for MacroRulesExpander {
+    fn expand(&self,
+              cx: &mut ExtCtxt,
+              span: Span,
+              ident: ast::Ident,
+              tts: Vec<tokenstream::TokenTree>,
+              attrs: Vec<ast::Attribute>)
+              -> Box<MacResult> {
+        let export = attr::contains_name(&attrs, "macro_export");
+        let def = ast::MacroDef {
+            ident: ident,
+            id: ast::DUMMY_NODE_ID,
+            span: span,
+            imported_from: None,
+            body: tts,
+            allow_internal_unstable: attr::contains_name(&attrs, "allow_internal_unstable"),
+            attrs: attrs,
+        };
+
+        // If keep_macs is true, expands to a MacEager::items instead.
+        let result = if cx.ecfg.keep_macs {
+            MacEager::items(placeholders::reconstructed_macro_rules(&def).make_items())
+        } else {
+            MacEager::items(placeholders::macro_scope_placeholder().make_items())
+        };
+
+        cx.resolver.add_macro(cx.current_expansion.mark, def, export);
+        result
+    }
 }
 
 // Note that macro-by-example's input is also matched against a token tree:
@@ -248,9 +186,7 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
 // Holy self-referential!
 
 /// Converts a `macro_rules!` invocation into a syntax extension.
-pub fn compile<'cx>(cx: &'cx mut ExtCtxt,
-                    def: &ast::MacroDef) -> SyntaxExtension {
-
+pub fn compile(sess: &ParseSess, def: &ast::MacroDef) -> SyntaxExtension {
     let lhs_nm =  gensym_ident("lhs");
     let rhs_nm =  gensym_ident("rhs");
 
@@ -282,19 +218,16 @@ pub fn compile<'cx>(cx: &'cx mut ExtCtxt,
     ];
 
     // Parse the macro_rules! invocation (`none` is for no interpolations):
-    let arg_reader = new_tt_reader(&cx.parse_sess().span_diagnostic,
-                                   None,
-                                   None,
-                                   def.body.clone());
-
-    let argument_map = match parse(cx.parse_sess(),
-                                   cx.cfg(),
-                                   arg_reader,
-                                   &argument_gram) {
+    let arg_reader = new_tt_reader(&sess.span_diagnostic, None, def.body.clone());
+
+    let argument_map = match parse(sess, arg_reader, &argument_gram) {
         Success(m) => m,
-        Failure(sp, str) | Error(sp, str) => {
-            panic!(cx.parse_sess().span_diagnostic
-                     .span_fatal(sp.substitute_dummy(def.span), &str[..]));
+        Failure(sp, tok) => {
+            let s = parse_failure_msg(tok);
+            panic!(sess.span_diagnostic.span_fatal(sp.substitute_dummy(def.span), &s));
+        }
+        Error(sp, s) => {
+            panic!(sess.span_diagnostic.span_fatal(sp.substitute_dummy(def.span), &s));
         }
     };
 
@@ -305,32 +238,36 @@ pub fn compile<'cx>(cx: &'cx mut ExtCtxt,
         MatchedSeq(ref s, _) => {
             s.iter().map(|m| match **m {
                 MatchedNonterminal(NtTT(ref tt)) => {
-                    valid &= check_lhs_nt_follows(cx, tt);
+                    valid &= check_lhs_nt_follows(sess, tt);
                     (**tt).clone()
                 }
-                _ => cx.span_bug(def.span, "wrong-structured lhs")
-            }).collect()
+                _ => sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs")
+            }).collect::<Vec<TokenTree>>()
         }
-        _ => cx.span_bug(def.span, "wrong-structured lhs")
+        _ => sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs")
     };
 
     let rhses = match **argument_map.get(&rhs_nm).unwrap() {
         MatchedSeq(ref s, _) => {
             s.iter().map(|m| match **m {
                 MatchedNonterminal(NtTT(ref tt)) => (**tt).clone(),
-                _ => cx.span_bug(def.span, "wrong-structured rhs")
+                _ => sess.span_diagnostic.span_bug(def.span, "wrong-structured rhs")
             }).collect()
         }
-        _ => cx.span_bug(def.span, "wrong-structured rhs")
+        _ => sess.span_diagnostic.span_bug(def.span, "wrong-structured rhs")
     };
 
     for rhs in &rhses {
-        valid &= check_rhs(cx, rhs);
+        valid &= check_rhs(sess, rhs);
+    }
+
+    // don't abort iteration early, so that errors for multiple lhses can be reported
+    for lhs in &lhses {
+        valid &= check_lhs_no_empty_seq(sess, &[lhs.clone()])
     }
 
     let exp: Box<_> = Box::new(MacroRulesMacroExpander {
         name: def.ident,
-        imported_from: def.imported_from,
         lhses: lhses,
         rhses: rhses,
         valid: valid,
@@ -339,14 +276,14 @@ pub fn compile<'cx>(cx: &'cx mut ExtCtxt,
     NormalTT(exp, Some(def.span), def.allow_internal_unstable)
 }
 
-fn check_lhs_nt_follows(cx: &mut ExtCtxt, lhs: &TokenTree) -> bool {
+fn check_lhs_nt_follows(sess: &ParseSess, lhs: &TokenTree) -> bool {
     // lhs is going to be like TokenTree::Delimited(...), where the
     // entire lhs is those tts. Or, it can be a "bare sequence", not wrapped in parens.
     match lhs {
-        &TokenTree::Delimited(_, ref tts) => check_matcher(cx, &tts.tts),
+        &TokenTree::Delimited(_, ref tts) => check_matcher(sess, &tts.tts),
         _ => {
-            cx.span_err(lhs.get_span(), "invalid macro matcher; matchers must \
-                                         be contained in balanced delimiters");
+            let msg = "invalid macro matcher; matchers must be contained in balanced delimiters";
+            sess.span_diagnostic.span_err(lhs.get_span(), msg);
             false
         }
     }
@@ -354,20 +291,52 @@ fn check_lhs_nt_follows(cx: &mut ExtCtxt, lhs: &TokenTree) -> bool {
     // after parsing/expansion. we can report every error in every macro this way.
 }
 
-fn check_rhs(cx: &mut ExtCtxt, rhs: &TokenTree) -> bool {
+/// Check that the lhs contains no repetition which could match an empty token
+/// tree, because then the matcher would hang indefinitely.
+fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[TokenTree]) -> bool {
+    for tt in tts {
+        match *tt {
+            TokenTree::Token(_, _) => (),
+            TokenTree::Delimited(_, ref del) => if !check_lhs_no_empty_seq(sess, &del.tts) {
+                return false;
+            },
+            TokenTree::Sequence(span, ref seq) => {
+                if seq.separator.is_none() {
+                    if seq.tts.iter().all(|seq_tt| {
+                        match *seq_tt {
+                            TokenTree::Sequence(_, ref sub_seq) =>
+                                sub_seq.op == tokenstream::KleeneOp::ZeroOrMore,
+                            _ => false,
+                        }
+                    }) {
+                        sess.span_diagnostic.span_err(span, "repetition matches empty token tree");
+                        return false;
+                    }
+                }
+                if !check_lhs_no_empty_seq(sess, &seq.tts) {
+                    return false;
+                }
+            }
+        }
+    }
+
+    true
+}
+
+fn check_rhs(sess: &ParseSess, rhs: &TokenTree) -> bool {
     match *rhs {
         TokenTree::Delimited(..) => return true,
-        _ => cx.span_err(rhs.get_span(), "macro rhs must be delimited")
+        _ => sess.span_diagnostic.span_err(rhs.get_span(), "macro rhs must be delimited")
     }
     false
 }
 
-fn check_matcher(cx: &mut ExtCtxt, matcher: &[TokenTree]) -> bool {
+fn check_matcher(sess: &ParseSess, matcher: &[TokenTree]) -> bool {
     let first_sets = FirstSets::new(matcher);
     let empty_suffix = TokenSet::empty();
-    let err = cx.parse_sess.span_diagnostic.err_count();
-    check_matcher_core(cx, &first_sets, matcher, &empty_suffix);
-    err == cx.parse_sess.span_diagnostic.err_count()
+    let err = sess.span_diagnostic.err_count();
+    check_matcher_core(sess, &first_sets, matcher, &empty_suffix);
+    err == sess.span_diagnostic.err_count()
 }
 
 // The FirstSets for a matcher is a mapping from subsequences in the
@@ -605,7 +574,7 @@ impl TokenSet {
 //
 // Requires that `first_sets` is pre-computed for `matcher`;
 // see `FirstSets::new`.
-fn check_matcher_core(cx: &mut ExtCtxt,
+fn check_matcher_core(sess: &ParseSess,
                       first_sets: &FirstSets,
                       matcher: &[TokenTree],
                       follow: &TokenSet) -> TokenSet {
@@ -637,7 +606,8 @@ fn check_matcher_core(cx: &mut ExtCtxt,
             TokenTree::Token(sp, ref tok) => {
                 let can_be_followed_by_any;
                 if let Err(bad_frag) = has_legal_fragment_specifier(tok) {
-                    cx.struct_span_err(sp, &format!("invalid fragment specifier `{}`", bad_frag))
+                    let msg = format!("invalid fragment specifier `{}`", bad_frag);
+                    sess.span_diagnostic.struct_span_err(sp, &msg)
                         .help("valid fragment specifiers are `ident`, `block`, \
                                `stmt`, `expr`, `pat`, `ty`, `path`, `meta`, `tt` \
                                and `item`")
@@ -662,7 +632,7 @@ fn check_matcher_core(cx: &mut ExtCtxt,
             }
             TokenTree::Delimited(_, ref d) => {
                 let my_suffix = TokenSet::singleton((d.close_span, Token::CloseDelim(d.delim)));
-                check_matcher_core(cx, first_sets, &d.tts, &my_suffix);
+                check_matcher_core(sess, first_sets, &d.tts, &my_suffix);
                 // don't track non NT tokens
                 last.replace_with_irrelevant();
 
@@ -694,7 +664,7 @@ fn check_matcher_core(cx: &mut ExtCtxt,
                 // At this point, `suffix_first` is built, and
                 // `my_suffix` is some TokenSet that we can use
                 // for checking the interior of `seq_rep`.
-                let next = check_matcher_core(cx, first_sets, &seq_rep.tts, my_suffix);
+                let next = check_matcher_core(sess, first_sets, &seq_rep.tts, my_suffix);
                 if next.maybe_empty {
                     last.add_all(&next);
                 } else {
@@ -714,9 +684,9 @@ fn check_matcher_core(cx: &mut ExtCtxt,
         'each_last: for &(_sp, ref t) in &last.tokens {
             if let MatchNt(ref name, ref frag_spec) = *t {
                 for &(sp, ref next_token) in &suffix_first.tokens {
-                    match is_in_follow(cx, next_token, &frag_spec.name.as_str()) {
+                    match is_in_follow(next_token, &frag_spec.name.as_str()) {
                         Err((msg, help)) => {
-                            cx.struct_span_err(sp, &msg).help(help).emit();
+                            sess.span_diagnostic.struct_span_err(sp, &msg).help(help).emit();
                             // don't bother reporting every source of
                             // conflict for a particular element of `last`.
                             continue 'each_last;
@@ -731,7 +701,7 @@ fn check_matcher_core(cx: &mut ExtCtxt,
                                 "may be"
                             };
 
-                            cx.span_err(
+                            sess.span_diagnostic.span_err(
                                 sp,
                                 &format!("`${name}:{frag}` {may_be} followed by `{next}`, which \
                                           is not allowed for `{frag}` fragments",
@@ -788,7 +758,7 @@ fn frag_can_be_followed_by_any(frag: &str) -> bool {
 /// break macros that were relying on that binary operator as a
 /// separator.
 // when changing this do not forget to update doc/book/macros.md!
-fn is_in_follow(_: &ExtCtxt, tok: &Token, frag: &str) -> Result<bool, (String, &'static str)> {
+fn is_in_follow(tok: &Token, frag: &str) -> Result<bool, (String, &'static str)> {
     if let &CloseDelim(_) = tok {
         // closing a token tree can never be matched by any fragment;
         // iow, we always require that `(` and `)` match, etc.
diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs
index 939425378de..8a6a8e53a3e 100644
--- a/src/libsyntax/ext/tt/transcribe.rs
+++ b/src/libsyntax/ext/tt/transcribe.rs
@@ -10,14 +10,15 @@
 use self::LockstepIterSize::*;
 
 use ast::Ident;
-use syntax_pos::{Span, DUMMY_SP};
 use errors::{Handler, DiagnosticBuilder};
 use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal};
 use parse::token::{DocComment, MatchNt, SubstNt};
-use parse::token::{Token, Interpolated, NtIdent, NtTT, SpecialMacroVar};
+use parse::token::{Token, Interpolated, NtIdent, NtTT};
 use parse::token;
 use parse::lexer::TokenAndSpan;
+use syntax_pos::{Span, DUMMY_SP};
 use tokenstream::{self, TokenTree};
+use util::small_vector::SmallVector;
 
 use std::rc::Rc;
 use std::ops::Add;
@@ -36,18 +37,16 @@ struct TtFrame {
 pub struct TtReader<'a> {
     pub sp_diag: &'a Handler,
     /// the unzipped tree:
-    stack: Vec<TtFrame>,
+    stack: SmallVector<TtFrame>,
     /* for MBE-style macro transcription */
     interpolations: HashMap<Ident, Rc<NamedMatch>>,
-    imported_from: Option<Ident>,
 
-    // Some => return imported_from as the next token
-    crate_name_next: Option<Span>,
     repeat_idx: Vec<usize>,
     repeat_len: Vec<usize>,
     /* cached: */
     pub cur_tok: Token,
     pub cur_span: Span,
+    pub next_tok: Option<TokenAndSpan>,
     /// Transform doc comments. Only useful in macro invocations
     pub desugar_doc_comments: bool,
     pub fatal_errs: Vec<DiagnosticBuilder<'a>>,
@@ -58,10 +57,9 @@ pub struct TtReader<'a> {
 /// (and should) be None.
 pub fn new_tt_reader(sp_diag: &Handler,
                      interp: Option<HashMap<Ident, Rc<NamedMatch>>>,
-                     imported_from: Option<Ident>,
                      src: Vec<tokenstream::TokenTree>)
                      -> TtReader {
-    new_tt_reader_with_doc_flag(sp_diag, interp, imported_from, src, false)
+    new_tt_reader_with_doc_flag(sp_diag, interp, src, false)
 }
 
 /// The extra `desugar_doc_comments` flag enables reading doc comments
@@ -72,13 +70,12 @@ pub fn new_tt_reader(sp_diag: &Handler,
 /// (and should) be None.
 pub fn new_tt_reader_with_doc_flag(sp_diag: &Handler,
                                    interp: Option<HashMap<Ident, Rc<NamedMatch>>>,
-                                   imported_from: Option<Ident>,
                                    src: Vec<tokenstream::TokenTree>,
                                    desugar_doc_comments: bool)
                                    -> TtReader {
     let mut r = TtReader {
         sp_diag: sp_diag,
-        stack: vec!(TtFrame {
+        stack: SmallVector::one(TtFrame {
             forest: TokenTree::Sequence(DUMMY_SP, Rc::new(tokenstream::SequenceRepetition {
                 tts: src,
                 // doesn't matter. This merely holds the root unzipping.
@@ -92,14 +89,13 @@ pub fn new_tt_reader_with_doc_flag(sp_diag: &Handler,
             None => HashMap::new(),
             Some(x) => x,
         },
-        imported_from: imported_from,
-        crate_name_next: None,
         repeat_idx: Vec::new(),
         repeat_len: Vec::new(),
         desugar_doc_comments: desugar_doc_comments,
         /* dummy values, never read: */
         cur_tok: token::Eof,
         cur_span: DUMMY_SP,
+        next_tok: None,
         fatal_errs: Vec::new(),
     };
     tt_next_token(&mut r); /* get cur_tok and cur_span set up */
@@ -178,20 +174,15 @@ fn lockstep_iter_size(t: &TokenTree, r: &TtReader) -> LockstepIterSize {
 /// Return the next token from the TtReader.
 /// EFFECT: advances the reader's token field
 pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan {
+    if let Some(tok) = r.next_tok.take() {
+        return tok;
+    }
     // FIXME(pcwalton): Bad copy?
     let ret_val = TokenAndSpan {
         tok: r.cur_tok.clone(),
         sp: r.cur_span.clone(),
     };
     loop {
-        match r.crate_name_next.take() {
-            None => (),
-            Some(sp) => {
-                r.cur_span = sp;
-                r.cur_tok = token::Ident(r.imported_from.unwrap());
-                return ret_val;
-            },
-        }
         let should_pop = match r.stack.last() {
             None => {
                 assert_eq!(ret_val.tok, token::Eof);
@@ -341,18 +332,6 @@ pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan {
                    sep: None
                 });
             }
-            TokenTree::Token(sp, token::SpecialVarNt(SpecialMacroVar::CrateMacroVar)) => {
-                r.stack.last_mut().unwrap().idx += 1;
-
-                if r.imported_from.is_some() {
-                    r.cur_span = sp;
-                    r.cur_tok = token::ModSep;
-                    r.crate_name_next = Some(sp);
-                    return ret_val;
-                }
-
-                // otherwise emit nothing and proceed to the next token
-            }
             TokenTree::Token(sp, tok) => {
                 r.cur_span = sp;
                 r.cur_tok = tok;
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 27b97a0ad66..129e4a82338 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -30,12 +30,13 @@ use ast::{self, NodeId, PatKind};
 use attr;
 use codemap::{CodeMap, Spanned};
 use syntax_pos::Span;
-use errors::Handler;
+use errors::{DiagnosticBuilder, Handler};
 use visit::{self, FnKind, Visitor};
 use parse::ParseSess;
 use parse::token::InternedString;
 
 use std::ascii::AsciiExt;
+use std::env;
 
 macro_rules! setter {
     ($field: ident) => {{
@@ -166,6 +167,9 @@ declare_features! (
     // RFC 1238
     (active, dropck_parametricity, "1.3.0", Some(28498)),
 
+    // Allows using the may_dangle attribute; RFC 1327
+    (active, dropck_eyepatch, "1.10.0", Some(34761)),
+
     // Allows the use of custom attributes; RFC 572
     (active, custom_attribute, "1.0.0", Some(29642)),
 
@@ -252,9 +256,6 @@ declare_features! (
     // a...b and ...b
     (active, inclusive_range_syntax, "1.7.0", Some(28237)),
 
-    // `expr?`
-    (active, question_mark, "1.9.0", Some(31436)),
-
     // impl specialization (RFC 1210)
     (active, specialization, "1.7.0", Some(31844)),
 
@@ -291,7 +292,7 @@ declare_features! (
     (active, item_like_imports, "1.13.0", Some(35120)),
 
     // Macros 1.1
-    (active, rustc_macro, "1.13.0", Some(35900)),
+    (active, proc_macro, "1.13.0", Some(35900)),
 
     // Allows untagged unions `union U { ... }`
     (active, untagged_unions, "1.13.0", Some(32836)),
@@ -302,6 +303,12 @@ declare_features! (
     // Used to identify the `compiler_builtins` crate
     // rustc internal
     (active, compiler_builtins, "1.13.0", None),
+
+    // Allows attributes on lifetime/type formal parameters in generics (RFC 1327)
+    (active, generic_param_attrs, "1.11.0", Some(34761)),
+
+    // Allows field shorthands (`x` meaning `x: x`) in struct literal expressions.
+    (active, field_init_shorthand, "1.14.0", Some(37340)),
 );
 
 declare_features! (
@@ -344,6 +351,8 @@ declare_features! (
     (accepted, while_let, "1.0.0", None),
     // Allows `#[deprecated]` attribute
     (accepted, deprecated, "1.9.0", Some(29935)),
+    // `expr?`
+    (accepted, question_mark, "1.14.0", Some(31436)),
 );
 // (changing above list without updating src/doc/reference.md makes @cmr sad)
 
@@ -365,17 +374,34 @@ pub enum AttributeType {
 pub enum AttributeGate {
     /// Is gated by a given feature gate, reason
     /// and function to check if enabled
-    Gated(&'static str, &'static str, fn(&Features) -> bool),
+    Gated(Stability, &'static str, &'static str, fn(&Features) -> bool),
 
     /// Ungated attribute, can be used on all release channels
     Ungated,
 }
 
+impl AttributeGate {
+    fn is_deprecated(&self) -> bool {
+        match *self {
+            Gated(Stability::Deprecated(_), ..) => true,
+            _ => false,
+        }
+    }
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub enum Stability {
+    Unstable,
+    // Argument is tracking issue link.
+    Deprecated(&'static str),
+}
+
 // fn() is not Debug
 impl ::std::fmt::Debug for AttributeGate {
     fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
         match *self {
-            Gated(ref name, ref expl, _) => write!(fmt, "Gated({}, {})", name, expl),
+            Gated(ref stab, ref name, ref expl, _) =>
+                write!(fmt, "Gated({:?}, {}, {})", stab, name, expl),
             Ungated => write!(fmt, "Ungated")
         }
     }
@@ -390,6 +416,10 @@ macro_rules! cfg_fn {
     }}
 }
 
+pub fn deprecated_attributes() -> Vec<&'static (&'static str, AttributeType, AttributeGate)> {
+    KNOWN_ATTRIBUTES.iter().filter(|a| a.2.is_deprecated()).collect()
+}
+
 // Attributes that have a special meaning to rustc or rustdoc
 pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGate)] = &[
     // Normal attributes
@@ -426,7 +456,8 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGat
     ("macro_escape", Normal, Ungated),
 
     // RFC #1445.
-    ("structural_match", Whitelisted, Gated("structural_match",
+    ("structural_match", Whitelisted, Gated(Stability::Unstable,
+                                            "structural_match",
                                             "the semantics of constant patterns is \
                                              not yet settled",
                                             cfg_fn!(structural_match))),
@@ -434,140 +465,181 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGat
     // Not used any more, but we can't feature gate it
     ("no_stack_check", Normal, Ungated),
 
-    ("plugin", CrateLevel, Gated("plugin",
+    ("plugin", CrateLevel, Gated(Stability::Unstable,
+                                 "plugin",
                                  "compiler plugins are experimental \
                                   and possibly buggy",
                                  cfg_fn!(plugin))),
 
     ("no_std", CrateLevel, Ungated),
-    ("no_core", CrateLevel, Gated("no_core",
+    ("no_core", CrateLevel, Gated(Stability::Unstable,
+                                  "no_core",
                                   "no_core is experimental",
                                   cfg_fn!(no_core))),
-    ("lang", Normal, Gated("lang_items",
+    ("lang", Normal, Gated(Stability::Unstable,
+                           "lang_items",
                            "language items are subject to change",
                            cfg_fn!(lang_items))),
-    ("linkage", Whitelisted, Gated("linkage",
+    ("linkage", Whitelisted, Gated(Stability::Unstable,
+                                   "linkage",
                                    "the `linkage` attribute is experimental \
                                     and not portable across platforms",
                                    cfg_fn!(linkage))),
-    ("thread_local", Whitelisted, Gated("thread_local",
+    ("thread_local", Whitelisted, Gated(Stability::Unstable,
+                                        "thread_local",
                                         "`#[thread_local]` is an experimental feature, and does \
                                          not currently handle destructors. There is no \
                                          corresponding `#[task_local]` mapping to the task \
                                          model",
                                         cfg_fn!(thread_local))),
 
-    ("rustc_on_unimplemented", Normal, Gated("on_unimplemented",
+    ("rustc_on_unimplemented", Normal, Gated(Stability::Unstable,
+                                             "on_unimplemented",
                                              "the `#[rustc_on_unimplemented]` attribute \
                                               is an experimental feature",
                                              cfg_fn!(on_unimplemented))),
-    ("allocator", Whitelisted, Gated("allocator",
+    ("allocator", Whitelisted, Gated(Stability::Unstable,
+                                     "allocator",
                                      "the `#[allocator]` attribute is an experimental feature",
                                      cfg_fn!(allocator))),
-    ("needs_allocator", Normal, Gated("needs_allocator",
+    ("needs_allocator", Normal, Gated(Stability::Unstable,
+                                      "needs_allocator",
                                       "the `#[needs_allocator]` \
                                        attribute is an experimental \
                                        feature",
                                       cfg_fn!(needs_allocator))),
-    ("panic_runtime", Whitelisted, Gated("panic_runtime",
+    ("panic_runtime", Whitelisted, Gated(Stability::Unstable,
+                                         "panic_runtime",
                                          "the `#[panic_runtime]` attribute is \
                                           an experimental feature",
                                          cfg_fn!(panic_runtime))),
-    ("needs_panic_runtime", Whitelisted, Gated("needs_panic_runtime",
+    ("needs_panic_runtime", Whitelisted, Gated(Stability::Unstable,
+                                               "needs_panic_runtime",
                                                "the `#[needs_panic_runtime]` \
                                                 attribute is an experimental \
                                                 feature",
                                                cfg_fn!(needs_panic_runtime))),
-    ("rustc_variance", Normal, Gated("rustc_attrs",
+    ("rustc_variance", Normal, Gated(Stability::Unstable,
+                                     "rustc_attrs",
                                      "the `#[rustc_variance]` attribute \
                                       is just used for rustc unit tests \
                                       and will never be stable",
                                      cfg_fn!(rustc_attrs))),
-    ("rustc_error", Whitelisted, Gated("rustc_attrs",
+    ("rustc_error", Whitelisted, Gated(Stability::Unstable,
+                                       "rustc_attrs",
                                        "the `#[rustc_error]` attribute \
                                         is just used for rustc unit tests \
                                         and will never be stable",
                                        cfg_fn!(rustc_attrs))),
-    ("rustc_if_this_changed", Whitelisted, Gated("rustc_attrs",
+    ("rustc_if_this_changed", Whitelisted, Gated(Stability::Unstable,
+                                                 "rustc_attrs",
                                                  "the `#[rustc_if_this_changed]` attribute \
                                                   is just used for rustc unit tests \
                                                   and will never be stable",
                                                  cfg_fn!(rustc_attrs))),
-    ("rustc_then_this_would_need", Whitelisted, Gated("rustc_attrs",
+    ("rustc_then_this_would_need", Whitelisted, Gated(Stability::Unstable,
+                                                      "rustc_attrs",
                                                       "the `#[rustc_if_this_changed]` attribute \
                                                        is just used for rustc unit tests \
                                                        and will never be stable",
                                                       cfg_fn!(rustc_attrs))),
-    ("rustc_dirty", Whitelisted, Gated("rustc_attrs",
+    ("rustc_dirty", Whitelisted, Gated(Stability::Unstable,
+                                       "rustc_attrs",
                                        "the `#[rustc_dirty]` attribute \
                                         is just used for rustc unit tests \
                                         and will never be stable",
                                        cfg_fn!(rustc_attrs))),
-    ("rustc_clean", Whitelisted, Gated("rustc_attrs",
+    ("rustc_clean", Whitelisted, Gated(Stability::Unstable,
+                                       "rustc_attrs",
                                        "the `#[rustc_clean]` attribute \
                                         is just used for rustc unit tests \
                                         and will never be stable",
                                        cfg_fn!(rustc_attrs))),
-    ("rustc_partition_reused", Whitelisted, Gated("rustc_attrs",
+    ("rustc_metadata_dirty", Whitelisted, Gated(Stability::Unstable,
+                                                "rustc_attrs",
+                                                "the `#[rustc_metadata_dirty]` attribute \
+                                                 is just used for rustc unit tests \
+                                                 and will never be stable",
+                                                 cfg_fn!(rustc_attrs))),
+    ("rustc_metadata_clean", Whitelisted, Gated(Stability::Unstable,
+                                                "rustc_attrs",
+                                                "the `#[rustc_metadata_clean]` attribute \
+                                                 is just used for rustc unit tests \
+                                                 and will never be stable",
+                                                 cfg_fn!(rustc_attrs))),
+    ("rustc_partition_reused", Whitelisted, Gated(Stability::Unstable,
+                                                  "rustc_attrs",
                                                   "this attribute \
                                                    is just used for rustc unit tests \
                                                    and will never be stable",
                                                   cfg_fn!(rustc_attrs))),
-    ("rustc_partition_translated", Whitelisted, Gated("rustc_attrs",
+    ("rustc_partition_translated", Whitelisted, Gated(Stability::Unstable,
+                                                      "rustc_attrs",
                                                       "this attribute \
                                                        is just used for rustc unit tests \
                                                        and will never be stable",
                                                       cfg_fn!(rustc_attrs))),
-    ("rustc_symbol_name", Whitelisted, Gated("rustc_attrs",
+    ("rustc_symbol_name", Whitelisted, Gated(Stability::Unstable,
+                                             "rustc_attrs",
                                              "internal rustc attributes will never be stable",
                                              cfg_fn!(rustc_attrs))),
-    ("rustc_item_path", Whitelisted, Gated("rustc_attrs",
+    ("rustc_item_path", Whitelisted, Gated(Stability::Unstable,
+                                           "rustc_attrs",
                                            "internal rustc attributes will never be stable",
                                            cfg_fn!(rustc_attrs))),
-    ("rustc_move_fragments", Normal, Gated("rustc_attrs",
+    ("rustc_move_fragments", Normal, Gated(Stability::Unstable,
+                                           "rustc_attrs",
                                            "the `#[rustc_move_fragments]` attribute \
                                             is just used for rustc unit tests \
                                             and will never be stable",
                                            cfg_fn!(rustc_attrs))),
-    ("rustc_mir", Whitelisted, Gated("rustc_attrs",
+    ("rustc_mir", Whitelisted, Gated(Stability::Unstable,
+                                     "rustc_attrs",
                                      "the `#[rustc_mir]` attribute \
                                       is just used for rustc unit tests \
                                       and will never be stable",
                                      cfg_fn!(rustc_attrs))),
-    ("rustc_inherit_overflow_checks", Whitelisted, Gated("rustc_attrs",
+    ("rustc_inherit_overflow_checks", Whitelisted, Gated(Stability::Unstable,
+                                                         "rustc_attrs",
                                                          "the `#[rustc_inherit_overflow_checks]` \
                                                           attribute is just used to control \
                                                           overflow checking behavior of several \
                                                           libcore functions that are inlined \
                                                           across crates and will never be stable",
                                                           cfg_fn!(rustc_attrs))),
-    ("compiler_builtins", Whitelisted, Gated("compiler_builtins",
+    ("compiler_builtins", Whitelisted, Gated(Stability::Unstable,
+                                             "compiler_builtins",
                                              "the `#[compiler_builtins]` attribute is used to \
                                               identify the `compiler_builtins` crate which \
                                               contains compiler-rt intrinsics and will never be \
                                               stable",
                                           cfg_fn!(compiler_builtins))),
 
-    ("allow_internal_unstable", Normal, Gated("allow_internal_unstable",
+    ("allow_internal_unstable", Normal, Gated(Stability::Unstable,
+                                              "allow_internal_unstable",
                                               EXPLAIN_ALLOW_INTERNAL_UNSTABLE,
                                               cfg_fn!(allow_internal_unstable))),
 
-    ("fundamental", Whitelisted, Gated("fundamental",
+    ("fundamental", Whitelisted, Gated(Stability::Unstable,
+                                       "fundamental",
                                        "the `#[fundamental]` attribute \
                                         is an experimental feature",
                                        cfg_fn!(fundamental))),
 
-    ("linked_from", Normal, Gated("linked_from",
+    ("linked_from", Normal, Gated(Stability::Unstable,
+                                  "linked_from",
                                   "the `#[linked_from]` attribute \
                                    is an experimental feature",
                                   cfg_fn!(linked_from))),
 
-    ("rustc_macro_derive", Normal, Gated("rustc_macro",
-                                         "the `#[rustc_macro_derive]` attribute \
-                                          is an experimental feature",
-                                         cfg_fn!(rustc_macro))),
+    ("proc_macro_derive", Normal, Gated(Stability::Unstable,
+                                        "proc_macro",
+                                        "the `#[proc_macro_derive]` attribute \
+                                         is an experimental feature",
+                                        cfg_fn!(proc_macro))),
 
-    ("rustc_copy_clone_marker", Whitelisted, Gated("rustc_attrs",
+    ("rustc_copy_clone_marker", Whitelisted, Gated(Stability::Unstable,
+                                                   "rustc_attrs",
                                                    "internal implementation detail",
                                                    cfg_fn!(rustc_attrs))),
 
@@ -577,7 +649,8 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGat
     // FIXME: #14406 these are processed in trans, which happens after the
     // lint pass
     ("cold", Whitelisted, Ungated),
-    ("naked", Whitelisted, Gated("naked_functions",
+    ("naked", Whitelisted, Gated(Stability::Unstable,
+                                 "naked_functions",
                                  "the `#[naked]` attribute \
                                   is an experimental feature",
                                  cfg_fn!(naked_functions))),
@@ -588,26 +661,38 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGat
     ("link_section", Whitelisted, Ungated),
     ("no_builtins", Whitelisted, Ungated),
     ("no_mangle", Whitelisted, Ungated),
-    ("no_debug", Whitelisted, Gated("no_debug",
-                                    "the `#[no_debug]` attribute \
-                                     is an experimental feature",
-                                    cfg_fn!(no_debug))),
-    ("omit_gdb_pretty_printer_section", Whitelisted, Gated("omit_gdb_pretty_printer_section",
+    ("no_debug", Whitelisted, Gated(
+        Stability::Deprecated("https://github.com/rust-lang/rust/issues/29721"),
+        "no_debug",
+        "the `#[no_debug]` attribute is an experimental feature",
+        cfg_fn!(no_debug))),
+    ("omit_gdb_pretty_printer_section", Whitelisted, Gated(Stability::Unstable,
+                                                       "omit_gdb_pretty_printer_section",
                                                        "the `#[omit_gdb_pretty_printer_section]` \
                                                         attribute is just used for the Rust test \
                                                         suite",
                                                        cfg_fn!(omit_gdb_pretty_printer_section))),
     ("unsafe_destructor_blind_to_params",
      Normal,
-     Gated("dropck_parametricity",
+     Gated(Stability::Unstable,
+           "dropck_parametricity",
            "unsafe_destructor_blind_to_params has unstable semantics \
             and may be removed in the future",
            cfg_fn!(dropck_parametricity))),
-    ("unwind", Whitelisted, Gated("unwind_attributes", "#[unwind] is experimental",
+    ("may_dangle",
+     Normal,
+     Gated(Stability::Unstable,
+           "dropck_eyepatch",
+           "may_dangle has unstable semantics and may be removed in the future",
+           cfg_fn!(dropck_eyepatch))),
+    ("unwind", Whitelisted, Gated(Stability::Unstable,
+                                  "unwind_attributes",
+                                  "#[unwind] is experimental",
                                   cfg_fn!(unwind_attributes))),
 
     // used in resolve
-    ("prelude_import", Whitelisted, Gated("prelude_import",
+    ("prelude_import", Whitelisted, Gated(Stability::Unstable,
+                                          "prelude_import",
                                           "`#[prelude_import]` is for use by rustc only",
                                           cfg_fn!(prelude_import))),
 
@@ -619,10 +704,12 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGat
     ("unstable", Whitelisted, Ungated),
     ("deprecated", Normal, Ungated),
 
-    ("rustc_paren_sugar", Normal, Gated("unboxed_closures",
+    ("rustc_paren_sugar", Normal, Gated(Stability::Unstable,
+                                        "unboxed_closures",
                                         "unboxed_closures are still evolving",
                                         cfg_fn!(unboxed_closures))),
-    ("rustc_reflect_like", Whitelisted, Gated("reflect",
+    ("rustc_reflect_like", Whitelisted, Gated(Stability::Unstable,
+                                              "reflect",
                                               "defining reflective traits is still evolving",
                                               cfg_fn!(reflect))),
 
@@ -644,7 +731,7 @@ const GATED_CFGS: &'static [(&'static str, &'static str, fn(&Features) -> bool)]
     ("target_vendor", "cfg_target_vendor", cfg_fn!(cfg_target_vendor)),
     ("target_thread_local", "cfg_target_thread_local", cfg_fn!(cfg_target_thread_local)),
     ("target_has_atomic", "cfg_target_has_atomic", cfg_fn!(cfg_target_has_atomic)),
-    ("rustc_macro", "rustc_macro", cfg_fn!(rustc_macro)),
+    ("proc_macro", "proc_macro", cfg_fn!(proc_macro)),
 ];
 
 #[derive(Debug, Eq, PartialEq)]
@@ -669,16 +756,15 @@ impl GatedCfg {
     pub fn check_and_emit(&self, sess: &ParseSess, features: &Features) {
         let (cfg, feature, has_feature) = GATED_CFGS[self.index];
         if !has_feature(features) && !sess.codemap().span_allows_unstable(self.span) {
-            let diagnostic = &sess.span_diagnostic;
             let explain = format!("`cfg({})` is experimental and subject to change", cfg);
-            emit_feature_err(diagnostic, feature, self.span, GateIssue::Language, &explain);
+            emit_feature_err(sess, feature, self.span, GateIssue::Language, &explain);
         }
     }
 }
 
 struct Context<'a> {
     features: &'a Features,
-    span_handler: &'a Handler,
+    parse_sess: &'a ParseSess,
     cm: &'a CodeMap,
     plugin_attributes: &'a [(String, AttributeType)],
 }
@@ -689,7 +775,7 @@ macro_rules! gate_feature_fn {
         let has_feature: bool = has_feature(&$cx.features);
         debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature);
         if !has_feature && !cx.cm.span_allows_unstable(span) {
-            emit_feature_err(cx.span_handler, name, span, GateIssue::Language, explain);
+            emit_feature_err(cx.parse_sess, name, span, GateIssue::Language, explain);
         }
     }}
 }
@@ -706,7 +792,7 @@ impl<'a> Context<'a> {
         let name = &*attr.name();
         for &(n, ty, ref gateage) in KNOWN_ATTRIBUTES {
             if n == name {
-                if let &Gated(ref name, ref desc, ref has_feature) = gateage {
+                if let &Gated(_, ref name, ref desc, ref has_feature) = gateage {
                     gate_feature_fn!(self, has_feature, attr.span, name, desc);
                 }
                 debug!("check_attribute: {:?} is known, {:?}, {:?}", name, ty, gateage);
@@ -746,10 +832,10 @@ impl<'a> Context<'a> {
     }
 }
 
-pub fn check_attribute(attr: &ast::Attribute, handler: &Handler,
+pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess,
                        cm: &CodeMap, features: &Features) {
     let cx = Context {
-        features: features, span_handler: handler,
+        features: features, parse_sess: parse_sess,
         cm: cm, plugin_attributes: &[]
     };
     cx.check_attribute(attr, true);
@@ -778,8 +864,15 @@ pub enum GateIssue {
     Library(Option<u32>)
 }
 
-pub fn emit_feature_err(diag: &Handler, feature: &str, span: Span, issue: GateIssue,
+pub fn emit_feature_err(sess: &ParseSess, feature: &str, span: Span, issue: GateIssue,
                         explain: &str) {
+    feature_err(sess, feature, span, issue, explain).emit();
+}
+
+pub fn feature_err<'a>(sess: &'a ParseSess, feature: &str, span: Span, issue: GateIssue,
+                   explain: &str) -> DiagnosticBuilder<'a> {
+    let diag = &sess.span_diagnostic;
+
     let issue = match issue {
         GateIssue::Language => find_lang_feature_issue(feature),
         GateIssue::Library(lib) => lib,
@@ -792,14 +885,13 @@ pub fn emit_feature_err(diag: &Handler, feature: &str, span: Span, issue: GateIs
     };
 
     // #23973: do not suggest `#![feature(...)]` if we are in beta/stable
-    if option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some() {
-        err.emit();
-        return;
+    if sess.unstable_features.is_nightly_build() {
+        err.help(&format!("add #![feature({})] to the \
+                           crate attributes to enable",
+                          feature));
     }
-    err.help(&format!("add #![feature({})] to the \
-                       crate attributes to enable",
-                      feature));
-    err.emit();
+
+    err
 }
 
 const EXPLAIN_BOX_SYNTAX: &'static str =
@@ -823,7 +915,12 @@ pub const EXPLAIN_ALLOW_INTERNAL_UNSTABLE: &'static str =
     "allow_internal_unstable side-steps feature gating and stability checks";
 
 pub const EXPLAIN_CUSTOM_DERIVE: &'static str =
-    "`#[derive]` for custom traits is not stable enough for use and is subject to change";
+    "`#[derive]` for custom traits is not stable enough for use. It is deprecated and will \
+     be removed in v1.15";
+
+pub const EXPLAIN_DEPR_CUSTOM_DERIVE: &'static str =
+    "`#[derive]` for custom traits is deprecated and will be removed in v1.15. Prefer using \
+     procedural macro custom derive";
 
 pub const EXPLAIN_DERIVE_UNDERSCORE: &'static str =
     "attributes of the form `#[derive_*]` are reserved for the compiler";
@@ -952,9 +1049,10 @@ impl<'a> Visitor for PostExpansionVisitor<'a> {
                 if attr::contains_name(&i.attrs[..], "simd") {
                     gate_feature_post!(&self, simd, i.span,
                                        "SIMD types are experimental and possibly buggy");
-                    self.context.span_handler.span_warn(i.span,
-                                                        "the `#[simd]` attribute is deprecated, \
-                                                         use `#[repr(simd)]` instead");
+                    self.context.parse_sess.span_diagnostic.span_warn(i.span,
+                                                                      "the `#[simd]` attribute \
+                                                                       is deprecated, use \
+                                                                       `#[repr(simd)]` instead");
                 }
                 for attr in &i.attrs {
                     if attr.name() == "repr" {
@@ -1057,12 +1155,17 @@ impl<'a> Visitor for PostExpansionVisitor<'a> {
                                   e.span,
                                   "inclusive range syntax is experimental");
             }
-            ast::ExprKind::Try(..) => {
-                gate_feature_post!(&self, question_mark, e.span, "the `?` operator is not stable");
-            }
             ast::ExprKind::InPlace(..) => {
                 gate_feature_post!(&self, placement_in_syntax, e.span, EXPLAIN_PLACEMENT_IN);
             }
+            ast::ExprKind::Struct(_, ref fields, _) => {
+                for field in fields {
+                    if field.is_shorthand {
+                        gate_feature_post!(&self, field_init_shorthand, field.span,
+                                           "struct field shorthands are unstable");
+                    }
+                }
+            }
             _ => {}
         }
         visit::walk_expr(self, e);
@@ -1070,14 +1173,14 @@ impl<'a> Visitor for PostExpansionVisitor<'a> {
 
     fn visit_pat(&mut self, pattern: &ast::Pat) {
         match pattern.node {
-            PatKind::Vec(_, Some(_), ref last) if !last.is_empty() => {
+            PatKind::Slice(_, Some(_), ref last) if !last.is_empty() => {
                 gate_feature_post!(&self, advanced_slice_patterns,
                                   pattern.span,
                                   "multiple-element slice matches anywhere \
                                    but at the end of a slice (e.g. \
                                    `[0, ..xs, 0]`) are experimental")
             }
-            PatKind::Vec(..) => {
+            PatKind::Slice(..) => {
                 gate_feature_post!(&self, slice_patterns,
                                   pattern.span,
                                   "slice pattern syntax is experimental");
@@ -1208,6 +1311,24 @@ impl<'a> Visitor for PostExpansionVisitor<'a> {
 
         visit::walk_vis(self, vis)
     }
+
+    fn visit_generics(&mut self, g: &ast::Generics) {
+        for t in &g.ty_params {
+            if !t.attrs.is_empty() {
+                gate_feature_post!(&self, generic_param_attrs, t.attrs[0].span,
+                                   "attributes on type parameter bindings are experimental");
+            }
+        }
+        visit::walk_generics(self, g)
+    }
+
+    fn visit_lifetime_def(&mut self, lifetime_def: &ast::LifetimeDef) {
+        if !lifetime_def.attrs.is_empty() {
+            gate_feature_post!(&self, generic_param_attrs, lifetime_def.attrs[0].span,
+                               "attributes on lifetime bindings are experimental");
+        }
+        visit::walk_lifetime_def(self, lifetime_def)
+    }
 }
 
 pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute]) -> Features {
@@ -1263,7 +1384,7 @@ pub fn check_crate(krate: &ast::Crate,
     maybe_stage_features(&sess.span_diagnostic, krate, unstable);
     let ctx = Context {
         features: features,
-        span_handler: &sess.span_diagnostic,
+        parse_sess: sess,
         cm: sess.codemap(),
         plugin_attributes: plugin_attributes,
     };
@@ -1275,7 +1396,7 @@ pub enum UnstableFeatures {
     /// Hard errors for unstable features are active, as on
     /// beta/stable channels.
     Disallow,
-    /// Allow features to me activated, as on nightly.
+    /// Allow features to be activated, as on nightly.
     Allow,
     /// Errors are bypassed for bootstrapping. This is required any time
     /// during the build that feature-related lints are set to warn or above
@@ -1284,6 +1405,27 @@ pub enum UnstableFeatures {
     Cheat
 }
 
+impl UnstableFeatures {
+    pub fn from_environment() -> UnstableFeatures {
+        // Whether this is a feature-staged build, i.e. on the beta or stable channel
+        let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some();
+        // Whether we should enable unstable features for bootstrapping
+        let bootstrap = env::var("RUSTC_BOOTSTRAP").is_ok();
+        match (disable_unstable_features, bootstrap) {
+            (_, true) => UnstableFeatures::Cheat,
+            (true, _) => UnstableFeatures::Disallow,
+            (false, _) => UnstableFeatures::Allow
+        }
+    }
+
+    pub fn is_nightly_build(&self) -> bool {
+        match *self {
+            UnstableFeatures::Allow | UnstableFeatures::Cheat => true,
+            _ => false,
+        }
+    }
+}
+
 fn maybe_stage_features(span_handler: &Handler, krate: &ast::Crate,
                         unstable: UnstableFeatures) {
     let allow_features = match unstable {
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 9fb4d0203f4..4bf6e55d674 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -356,7 +356,7 @@ pub fn noop_fold_ty<T: Folder>(t: P<Ty>, fld: &mut T) -> P<Ty> {
         id: fld.new_id(id),
         node: match node {
             TyKind::Infer | TyKind::ImplicitSelf => node,
-            TyKind::Vec(ty) => TyKind::Vec(fld.fold_ty(ty)),
+            TyKind::Slice(ty) => TyKind::Slice(fld.fold_ty(ty)),
             TyKind::Ptr(mt) => TyKind::Ptr(fld.fold_mt(mt)),
             TyKind::Rptr(region, mt) => {
                 TyKind::Rptr(fld.fold_opt_lifetime(region), fld.fold_mt(mt))
@@ -385,8 +385,8 @@ pub fn noop_fold_ty<T: Folder>(t: P<Ty>, fld: &mut T) -> P<Ty> {
                 TyKind::ObjectSum(fld.fold_ty(ty),
                             fld.fold_bounds(bounds))
             }
-            TyKind::FixedLengthVec(ty, e) => {
-                TyKind::FixedLengthVec(fld.fold_ty(ty), fld.fold_expr(e))
+            TyKind::Array(ty, e) => {
+                TyKind::Array(fld.fold_ty(ty), fld.fold_expr(e))
             }
             TyKind::Typeof(expr) => {
                 TyKind::Typeof(fld.fold_expr(expr))
@@ -478,8 +478,8 @@ pub fn noop_fold_parenthesized_parameter_data<T: Folder>(data: ParenthesizedPara
 pub fn noop_fold_local<T: Folder>(l: P<Local>, fld: &mut T) -> P<Local> {
     l.map(|Local {id, pat, ty, init, span, attrs}| Local {
         id: fld.new_id(id),
-        ty: ty.map(|t| fld.fold_ty(t)),
         pat: fld.fold_pat(pat),
+        ty: ty.map(|t| fld.fold_ty(t)),
         init: init.map(|e| fld.fold_expr(e)),
         span: fld.new_span(span),
         attrs: fold_attrs(attrs.into(), fld).into(),
@@ -662,8 +662,13 @@ pub fn noop_fold_ty_param_bound<T>(tpb: TyParamBound, fld: &mut T)
 }
 
 pub fn noop_fold_ty_param<T: Folder>(tp: TyParam, fld: &mut T) -> TyParam {
-    let TyParam {id, ident, bounds, default, span} = tp;
+    let TyParam {attrs, id, ident, bounds, default, span} = tp;
+    let attrs: Vec<_> = attrs.into();
     TyParam {
+        attrs: attrs.into_iter()
+            .flat_map(|x| fld.fold_attribute(x).into_iter())
+            .collect::<Vec<_>>()
+            .into(),
         id: fld.new_id(id),
         ident: ident,
         bounds: fld.fold_bounds(bounds),
@@ -687,7 +692,12 @@ pub fn noop_fold_lifetime<T: Folder>(l: Lifetime, fld: &mut T) -> Lifetime {
 
 pub fn noop_fold_lifetime_def<T: Folder>(l: LifetimeDef, fld: &mut T)
                                          -> LifetimeDef {
+    let attrs: Vec<_> = l.attrs.into();
     LifetimeDef {
+        attrs: attrs.into_iter()
+            .flat_map(|x| fld.fold_attribute(x).into_iter())
+            .collect::<Vec<_>>()
+            .into(),
         lifetime: fld.fold_lifetime(l.lifetime),
         bounds: fld.fold_lifetimes(l.bounds),
     }
@@ -813,11 +823,12 @@ pub fn noop_fold_struct_field<T: Folder>(f: StructField, fld: &mut T) -> StructF
     }
 }
 
-pub fn noop_fold_field<T: Folder>(Field {ident, expr, span}: Field, folder: &mut T) -> Field {
+pub fn noop_fold_field<T: Folder>(f: Field, folder: &mut T) -> Field {
     Field {
-        ident: respan(ident.span, folder.fold_ident(ident.node)),
-        expr: folder.fold_expr(expr),
-        span: folder.new_span(span)
+        ident: respan(f.ident.span, folder.fold_ident(f.ident.node)),
+        expr: folder.fold_expr(f.expr),
+        span: folder.new_span(f.span),
+        is_shorthand: f.is_shorthand,
     }
 }
 
@@ -860,14 +871,10 @@ pub fn noop_fold_item_kind<T: Folder>(i: ItemKind, folder: &mut T) -> ItemKind {
             ItemKind::Const(folder.fold_ty(t), folder.fold_expr(e))
         }
         ItemKind::Fn(decl, unsafety, constness, abi, generics, body) => {
-            ItemKind::Fn(
-                folder.fold_fn_decl(decl),
-                unsafety,
-                constness,
-                abi,
-                folder.fold_generics(generics),
-                folder.fold_block(body)
-            )
+            let generics = folder.fold_generics(generics);
+            let decl = folder.fold_fn_decl(decl);
+            let body = folder.fold_block(body);
+            ItemKind::Fn(decl, unsafety, constness, abi, generics, body)
         }
         ItemKind::Mod(m) => ItemKind::Mod(folder.fold_mod(m)),
         ItemKind::ForeignMod(nm) => ItemKind::ForeignMod(folder.fold_foreign_mod(nm)),
@@ -875,50 +882,35 @@ pub fn noop_fold_item_kind<T: Folder>(i: ItemKind, folder: &mut T) -> ItemKind {
             ItemKind::Ty(folder.fold_ty(t), folder.fold_generics(generics))
         }
         ItemKind::Enum(enum_definition, generics) => {
-            ItemKind::Enum(
-                ast::EnumDef {
-                    variants: enum_definition.variants.move_map(|x| folder.fold_variant(x)),
-                },
-                folder.fold_generics(generics))
+            let generics = folder.fold_generics(generics);
+            let variants = enum_definition.variants.move_map(|x| folder.fold_variant(x));
+            ItemKind::Enum(ast::EnumDef { variants: variants }, generics)
         }
         ItemKind::Struct(struct_def, generics) => {
-            let struct_def = folder.fold_variant_data(struct_def);
-            ItemKind::Struct(struct_def, folder.fold_generics(generics))
+            let generics = folder.fold_generics(generics);
+            ItemKind::Struct(folder.fold_variant_data(struct_def), generics)
         }
         ItemKind::Union(struct_def, generics) => {
-            let struct_def = folder.fold_variant_data(struct_def);
-            ItemKind::Union(struct_def, folder.fold_generics(generics))
+            let generics = folder.fold_generics(generics);
+            ItemKind::Union(folder.fold_variant_data(struct_def), generics)
         }
         ItemKind::DefaultImpl(unsafety, ref trait_ref) => {
             ItemKind::DefaultImpl(unsafety, folder.fold_trait_ref((*trait_ref).clone()))
         }
-        ItemKind::Impl(unsafety, polarity, generics, ifce, ty, impl_items) => {
-            let new_impl_items = impl_items.move_flat_map(|item| {
-                folder.fold_impl_item(item)
-            });
-            let ifce = match ifce {
-                None => None,
-                Some(ref trait_ref) => {
-                    Some(folder.fold_trait_ref((*trait_ref).clone()))
-                }
-            };
-            ItemKind::Impl(unsafety,
-                     polarity,
-                     folder.fold_generics(generics),
-                     ifce,
-                     folder.fold_ty(ty),
-                     new_impl_items)
-        }
-        ItemKind::Trait(unsafety, generics, bounds, items) => {
-            let bounds = folder.fold_bounds(bounds);
-            let items = items.move_flat_map(|item| {
-                folder.fold_trait_item(item)
-            });
-            ItemKind::Trait(unsafety,
-                      folder.fold_generics(generics),
-                      bounds,
-                      items)
-        }
+        ItemKind::Impl(unsafety, polarity, generics, ifce, ty, impl_items) => ItemKind::Impl(
+            unsafety,
+            polarity,
+            folder.fold_generics(generics),
+            ifce.map(|trait_ref| folder.fold_trait_ref(trait_ref.clone())),
+            folder.fold_ty(ty),
+            impl_items.move_flat_map(|item| folder.fold_impl_item(item)),
+        ),
+        ItemKind::Trait(unsafety, generics, bounds, items) => ItemKind::Trait(
+            unsafety,
+            folder.fold_generics(generics),
+            folder.fold_bounds(bounds),
+            items.move_flat_map(|item| folder.fold_trait_item(item)),
+        ),
         ItemKind::Mac(m) => ItemKind::Mac(folder.fold_mac(m)),
     }
 }
@@ -954,9 +946,9 @@ pub fn noop_fold_impl_item<T: Folder>(i: ImplItem, folder: &mut T)
                                       -> SmallVector<ImplItem> {
     SmallVector::one(ImplItem {
         id: folder.new_id(i.id),
+        vis: folder.fold_vis(i.vis),
         ident: folder.fold_ident(i.ident),
         attrs: fold_attrs(i.attrs, folder),
-        vis: folder.fold_vis(i.vis),
         defaultness: i.defaultness,
         node: match i.node  {
             ast::ImplItemKind::Const(ty, expr) => {
@@ -980,10 +972,8 @@ pub fn noop_fold_mod<T: Folder>(Mod {inner, items}: Mod, folder: &mut T) -> Mod
     }
 }
 
-pub fn noop_fold_crate<T: Folder>(Crate {module, attrs, config, mut exported_macros, span}: Crate,
+pub fn noop_fold_crate<T: Folder>(Crate {module, attrs, mut exported_macros, span}: Crate,
                                   folder: &mut T) -> Crate {
-    let config = folder.fold_meta_items(config);
-
     let mut items = folder.fold_item(P(ast::Item {
         ident: keywords::Invalid.ident(),
         attrs: attrs,
@@ -1017,7 +1007,6 @@ pub fn noop_fold_crate<T: Folder>(Crate {module, attrs, config, mut exported_mac
     Crate {
         module: module,
         attrs: attrs,
-        config: config,
         exported_macros: exported_macros,
         span: span,
     }
@@ -1031,15 +1020,12 @@ pub fn noop_fold_item<T: Folder>(i: P<Item>, folder: &mut T) -> SmallVector<P<It
 // fold one item into exactly one item
 pub fn noop_fold_item_simple<T: Folder>(Item {id, ident, attrs, node, vis, span}: Item,
                                         folder: &mut T) -> Item {
-    let id = folder.new_id(id);
-    let node = folder.fold_item_kind(node);
-
     Item {
-        id: id,
+        id: folder.new_id(id),
+        vis: folder.fold_vis(vis),
         ident: folder.fold_ident(ident),
         attrs: fold_attrs(attrs, folder),
-        node: node,
-        vis: folder.fold_vis(vis),
+        node: folder.fold_item_kind(node),
         span: folder.new_span(span)
     }
 }
@@ -1047,6 +1033,7 @@ pub fn noop_fold_item_simple<T: Folder>(Item {id, ident, attrs, node, vis, span}
 pub fn noop_fold_foreign_item<T: Folder>(ni: ForeignItem, folder: &mut T) -> ForeignItem {
     ForeignItem {
         id: folder.new_id(ni.id),
+        vis: folder.fold_vis(ni.vis),
         ident: folder.fold_ident(ni.ident),
         attrs: fold_attrs(ni.attrs, folder),
         node: match ni.node {
@@ -1057,7 +1044,6 @@ pub fn noop_fold_foreign_item<T: Folder>(ni: ForeignItem, folder: &mut T) -> For
                 ForeignItemKind::Static(folder.fold_ty(t), m)
             }
         },
-        vis: folder.fold_vis(ni.vis),
         span: folder.new_span(ni.span)
     }
 }
@@ -1114,8 +1100,8 @@ pub fn noop_fold_pat<T: Folder>(p: P<Pat>, folder: &mut T) -> P<Pat> {
             PatKind::Range(e1, e2) => {
                 PatKind::Range(folder.fold_expr(e1), folder.fold_expr(e2))
             },
-            PatKind::Vec(before, slice, after) => {
-                PatKind::Vec(before.move_map(|x| folder.fold_pat(x)),
+            PatKind::Slice(before, slice, after) => {
+                PatKind::Slice(before.move_map(|x| folder.fold_pat(x)),
                        slice.map(|x| folder.fold_pat(x)),
                        after.move_map(|x| folder.fold_pat(x)))
             }
diff --git a/src/libsyntax/json.rs b/src/libsyntax/json.rs
index a40c30b3e33..a1c273baeea 100644
--- a/src/libsyntax/json.rs
+++ b/src/libsyntax/json.rs
@@ -38,14 +38,24 @@ pub struct JsonEmitter {
 }
 
 impl JsonEmitter {
+    pub fn stderr(registry: Option<Registry>,
+                  code_map: Rc<CodeMap>) -> JsonEmitter {
+        JsonEmitter {
+            dst: Box::new(io::stderr()),
+            registry: registry,
+            cm: code_map,
+        }
+    }
+
     pub fn basic() -> JsonEmitter {
         JsonEmitter::stderr(None, Rc::new(CodeMap::new()))
     }
 
-    pub fn stderr(registry: Option<Registry>,
-                  code_map: Rc<CodeMap>) -> JsonEmitter {
+    pub fn new(dst: Box<Write + Send>,
+               registry: Option<Registry>,
+               code_map: Rc<CodeMap>) -> JsonEmitter {
         JsonEmitter {
-            dst: Box::new(io::stderr()),
+            dst: dst,
             registry: registry,
             cm: code_map,
         }
diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs
index 4a2c9aff2d2..b86e508d899 100644
--- a/src/libsyntax/lib.rs
+++ b/src/libsyntax/lib.rs
@@ -31,9 +31,12 @@
 #![feature(staged_api)]
 #![feature(str_escape)]
 #![feature(unicode)]
-#![feature(question_mark)]
+#![cfg_attr(stage0, feature(question_mark))]
 #![feature(rustc_diagnostic_macros)]
+#![feature(specialization)]
+#![feature(dotdot_in_tuple_patterns)]
 
+extern crate core;
 extern crate serialize;
 extern crate term;
 extern crate libc;
diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs
index a0defbc09dc..3cb34fa3c91 100644
--- a/src/libsyntax/parse/attr.rs
+++ b/src/libsyntax/parse/attr.rs
@@ -125,8 +125,8 @@ impl<'a> Parser<'a> {
 
                 self.expect(&token::OpenDelim(token::Bracket))?;
                 let meta_item = self.parse_meta_item()?;
-                let hi = self.last_span.hi;
                 self.expect(&token::CloseDelim(token::Bracket))?;
+                let hi = self.prev_span.hi;
 
                 (mk_sp(lo, hi), meta_item, style)
             }
@@ -231,16 +231,16 @@ impl<'a> Parser<'a> {
             token::Eq => {
                 self.bump();
                 let lit = self.parse_unsuffixed_lit()?;
-                let hi = self.last_span.hi;
+                let hi = self.prev_span.hi;
                 Ok(P(spanned(lo, hi, ast::MetaItemKind::NameValue(name, lit))))
             }
             token::OpenDelim(token::Paren) => {
                 let inner_items = self.parse_meta_seq()?;
-                let hi = self.last_span.hi;
+                let hi = self.prev_span.hi;
                 Ok(P(spanned(lo, hi, ast::MetaItemKind::List(name, inner_items))))
             }
             _ => {
-                let hi = self.last_span.hi;
+                let hi = self.prev_span.hi;
                 Ok(P(spanned(lo, hi, ast::MetaItemKind::Word(name))))
             }
         }
@@ -253,14 +253,14 @@ impl<'a> Parser<'a> {
 
         match self.parse_unsuffixed_lit() {
             Ok(lit) => {
-                return Ok(spanned(lo, self.last_span.hi, ast::NestedMetaItemKind::Literal(lit)))
+                return Ok(spanned(lo, self.prev_span.hi, ast::NestedMetaItemKind::Literal(lit)))
             }
             Err(ref mut err) => self.diagnostic().cancel(err)
         }
 
         match self.parse_meta_item() {
             Ok(mi) => {
-                return Ok(spanned(lo, self.last_span.hi, ast::NestedMetaItemKind::MetaItem(mi)))
+                return Ok(spanned(lo, self.prev_span.hi, ast::NestedMetaItemKind::MetaItem(mi)))
             }
             Err(ref mut err) => self.diagnostic().cancel(err)
         }
diff --git a/src/libsyntax/parse/lexer/comments.rs b/src/libsyntax/parse/lexer/comments.rs
index 5eb5605ea71..ba83a55ea79 100644
--- a/src/libsyntax/parse/lexer/comments.rs
+++ b/src/libsyntax/parse/lexer/comments.rs
@@ -24,7 +24,7 @@ use str::char_at;
 use std::io::Read;
 use std::usize;
 
-#[derive(Clone, Copy, PartialEq)]
+#[derive(Clone, Copy, PartialEq, Debug)]
 pub enum CommentStyle {
     /// No code on either side of each line of the comment
     Isolated,
@@ -149,25 +149,24 @@ fn push_blank_line_comment(rdr: &StringReader, comments: &mut Vec<Comment>) {
     comments.push(Comment {
         style: BlankLine,
         lines: Vec::new(),
-        pos: rdr.last_pos,
+        pos: rdr.pos,
     });
 }
 
 fn consume_whitespace_counting_blank_lines(rdr: &mut StringReader, comments: &mut Vec<Comment>) {
-    while is_pattern_whitespace(rdr.curr) && !rdr.is_eof() {
-        if rdr.col == CharPos(0) && rdr.curr_is('\n') {
+    while is_pattern_whitespace(rdr.ch) && !rdr.is_eof() {
+        if rdr.ch_is('\n') {
             push_blank_line_comment(rdr, &mut *comments);
         }
         rdr.bump();
     }
 }
 
-
 fn read_shebang_comment(rdr: &mut StringReader,
                         code_to_the_left: bool,
                         comments: &mut Vec<Comment>) {
     debug!(">>> shebang comment");
-    let p = rdr.last_pos;
+    let p = rdr.pos;
     debug!("<<< shebang comment");
     comments.push(Comment {
         style: if code_to_the_left { Trailing } else { Isolated },
@@ -180,9 +179,9 @@ fn read_line_comments(rdr: &mut StringReader,
                       code_to_the_left: bool,
                       comments: &mut Vec<Comment>) {
     debug!(">>> line comments");
-    let p = rdr.last_pos;
+    let p = rdr.pos;
     let mut lines: Vec<String> = Vec::new();
-    while rdr.curr_is('/') && rdr.nextch_is('/') {
+    while rdr.ch_is('/') && rdr.nextch_is('/') {
         let line = rdr.read_one_line_comment();
         debug!("{}", line);
         // Doc comments are not put in comments.
@@ -240,7 +239,7 @@ fn read_block_comment(rdr: &mut StringReader,
                       code_to_the_left: bool,
                       comments: &mut Vec<Comment>) {
     debug!(">>> block comment");
-    let p = rdr.last_pos;
+    let p = rdr.pos;
     let mut lines: Vec<String> = Vec::new();
     let col = rdr.col;
     rdr.bump();
@@ -249,9 +248,9 @@ fn read_block_comment(rdr: &mut StringReader,
     let mut curr_line = String::from("/*");
 
     // doc-comments are not really comments, they are attributes
-    if (rdr.curr_is('*') && !rdr.nextch_is('*')) || rdr.curr_is('!') {
-        while !(rdr.curr_is('*') && rdr.nextch_is('/')) && !rdr.is_eof() {
-            curr_line.push(rdr.curr.unwrap());
+    if (rdr.ch_is('*') && !rdr.nextch_is('*')) || rdr.ch_is('!') {
+        while !(rdr.ch_is('*') && rdr.nextch_is('/')) && !rdr.is_eof() {
+            curr_line.push(rdr.ch.unwrap());
             rdr.bump();
         }
         if !rdr.is_eof() {
@@ -271,19 +270,19 @@ fn read_block_comment(rdr: &mut StringReader,
             if rdr.is_eof() {
                 panic!(rdr.fatal("unterminated block comment"));
             }
-            if rdr.curr_is('\n') {
+            if rdr.ch_is('\n') {
                 trim_whitespace_prefix_and_push_line(&mut lines, curr_line, col);
                 curr_line = String::new();
                 rdr.bump();
             } else {
-                curr_line.push(rdr.curr.unwrap());
-                if rdr.curr_is('/') && rdr.nextch_is('*') {
+                curr_line.push(rdr.ch.unwrap());
+                if rdr.ch_is('/') && rdr.nextch_is('*') {
                     rdr.bump();
                     rdr.bump();
                     curr_line.push('*');
                     level += 1;
                 } else {
-                    if rdr.curr_is('*') && rdr.nextch_is('/') {
+                    if rdr.ch_is('*') && rdr.nextch_is('/') {
                         rdr.bump();
                         rdr.bump();
                         curr_line.push('/');
@@ -305,7 +304,7 @@ fn read_block_comment(rdr: &mut StringReader,
         Isolated
     };
     rdr.consume_non_eol_whitespace();
-    if !rdr.is_eof() && !rdr.curr_is('\n') && lines.len() == 1 {
+    if !rdr.is_eof() && !rdr.ch_is('\n') && lines.len() == 1 {
         style = Mixed;
     }
     debug!("<<< block comment");
@@ -317,14 +316,22 @@ fn read_block_comment(rdr: &mut StringReader,
 }
 
 
-fn consume_comment(rdr: &mut StringReader, code_to_the_left: bool, comments: &mut Vec<Comment>) {
+fn consume_comment(rdr: &mut StringReader,
+                   comments: &mut Vec<Comment>,
+                   code_to_the_left: &mut bool,
+                   anything_to_the_left: &mut bool) {
     debug!(">>> consume comment");
-    if rdr.curr_is('/') && rdr.nextch_is('/') {
-        read_line_comments(rdr, code_to_the_left, comments);
-    } else if rdr.curr_is('/') && rdr.nextch_is('*') {
-        read_block_comment(rdr, code_to_the_left, comments);
-    } else if rdr.curr_is('#') && rdr.nextch_is('!') {
-        read_shebang_comment(rdr, code_to_the_left, comments);
+    if rdr.ch_is('/') && rdr.nextch_is('/') {
+        read_line_comments(rdr, *code_to_the_left, comments);
+        *code_to_the_left = false;
+        *anything_to_the_left = false;
+    } else if rdr.ch_is('/') && rdr.nextch_is('*') {
+        read_block_comment(rdr, *code_to_the_left, comments);
+        *anything_to_the_left = true;
+    } else if rdr.ch_is('#') && rdr.nextch_is('!') {
+        read_shebang_comment(rdr, *code_to_the_left, comments);
+        *code_to_the_left = false;
+        *anything_to_the_left = false;
     } else {
         panic!();
     }
@@ -352,24 +359,30 @@ pub fn gather_comments_and_literals(span_diagnostic: &errors::Handler,
 
     let mut comments: Vec<Comment> = Vec::new();
     let mut literals: Vec<Literal> = Vec::new();
-    let mut first_read: bool = true;
+    let mut code_to_the_left = false; // Only code
+    let mut anything_to_the_left = false; // Code or comments
     while !rdr.is_eof() {
         loop {
-            let mut code_to_the_left = !first_read;
+            // Eat all the whitespace and count blank lines.
             rdr.consume_non_eol_whitespace();
-            if rdr.curr_is('\n') {
-                code_to_the_left = false;
+            if rdr.ch_is('\n') {
+                if anything_to_the_left {
+                    rdr.bump(); // The line is not blank, do not count.
+                }
                 consume_whitespace_counting_blank_lines(&mut rdr, &mut comments);
+                code_to_the_left = false;
+                anything_to_the_left = false;
             }
-            while rdr.peeking_at_comment() {
-                consume_comment(&mut rdr, code_to_the_left, &mut comments);
-                consume_whitespace_counting_blank_lines(&mut rdr, &mut comments);
+            // Eat one comment group
+            if rdr.peeking_at_comment() {
+                consume_comment(&mut rdr, &mut comments,
+                                &mut code_to_the_left, &mut anything_to_the_left);
+            } else {
+                break
             }
-            break;
         }
 
-
-        let bstart = rdr.last_pos;
+        let bstart = rdr.pos;
         rdr.next_token();
         // discard, and look ahead; we're working with internal state
         let TokenAndSpan { tok, sp } = rdr.peek();
@@ -384,7 +397,8 @@ pub fn gather_comments_and_literals(span_diagnostic: &errors::Handler,
         } else {
             debug!("tok: {}", pprust::token_to_string(&tok));
         }
-        first_read = false;
+        code_to_the_left = true;
+        anything_to_the_left = true;
     }
 
     (comments, literals)
diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs
index 9e9ea096460..5e20f6e4192 100644
--- a/src/libsyntax/parse/lexer/mod.rs
+++ b/src/libsyntax/parse/lexer/mod.rs
@@ -74,17 +74,29 @@ pub struct TokenAndSpan {
     pub sp: Span,
 }
 
+impl Default for TokenAndSpan {
+    fn default() -> Self {
+        TokenAndSpan { tok: token::Underscore, sp: syntax_pos::DUMMY_SP }
+    }
+}
+
 pub struct StringReader<'a> {
     pub span_diagnostic: &'a Handler,
     /// The absolute offset within the codemap of the next character to read
+    pub next_pos: BytePos,
+    /// The absolute offset within the codemap of the current character
     pub pos: BytePos,
-    /// The absolute offset within the codemap of the last character read(curr)
-    pub last_pos: BytePos,
     /// The column of the next character to read
     pub col: CharPos,
-    /// The last character to be read
-    pub curr: Option<char>,
+    /// The current character (which has been read from self.pos)
+    pub ch: Option<char>,
     pub filemap: Rc<syntax_pos::FileMap>,
+    /// If Some, stop reading the source at this position (inclusive).
+    pub terminator: Option<BytePos>,
+    /// Whether to record new-lines in filemap. This is only necessary the first
+    /// time a filemap is lexed. If part of a filemap is being re-lexed, this
+    /// should be set to false.
+    pub save_new_lines: bool,
     // cached:
     pub peek_tok: token::Token,
     pub peek_span: Span,
@@ -96,7 +108,14 @@ pub struct StringReader<'a> {
 
 impl<'a> Reader for StringReader<'a> {
     fn is_eof(&self) -> bool {
-        self.curr.is_none()
+        if self.ch.is_none() {
+            return true;
+        }
+
+        match self.terminator {
+            Some(t) => self.next_pos > t,
+            None => false,
+        }
     }
     /// Return the next token. EFFECT: advances the string_reader.
     fn try_next_token(&mut self) -> Result<TokenAndSpan, ()> {
@@ -131,7 +150,7 @@ impl<'a> Reader for StringReader<'a> {
 
 impl<'a> Reader for TtReader<'a> {
     fn is_eof(&self) -> bool {
-        self.cur_tok == token::Eof
+        self.peek().tok == token::Eof
     }
     fn try_next_token(&mut self) -> Result<TokenAndSpan, ()> {
         assert!(self.fatal_errs.is_empty());
@@ -152,18 +171,47 @@ impl<'a> Reader for TtReader<'a> {
         self.fatal_errs.clear();
     }
     fn peek(&self) -> TokenAndSpan {
-        TokenAndSpan {
+        self.next_tok.clone().unwrap_or(TokenAndSpan {
             tok: self.cur_tok.clone(),
             sp: self.cur_span,
-        }
+        })
+    }
+}
+
+impl<'a, 'b> Reader for &'b mut TtReader<'a> {
+    fn is_eof(&self) -> bool {
+        (**self).is_eof()
+    }
+    fn try_next_token(&mut self) -> Result<TokenAndSpan, ()> {
+        (**self).try_next_token()
+    }
+    fn fatal(&self, m: &str) -> FatalError {
+        (**self).fatal(m)
+    }
+    fn err(&self, m: &str) {
+        (**self).err(m)
+    }
+    fn emit_fatal_errors(&mut self) {
+        (**self).emit_fatal_errors()
+    }
+    fn peek(&self) -> TokenAndSpan {
+        (**self).peek()
     }
 }
 
 impl<'a> StringReader<'a> {
-    /// For comments.rs, which hackily pokes into pos and curr
+    /// For comments.rs, which hackily pokes into next_pos and ch
     pub fn new_raw<'b>(span_diagnostic: &'b Handler,
                        filemap: Rc<syntax_pos::FileMap>)
                        -> StringReader<'b> {
+        let mut sr = StringReader::new_raw_internal(span_diagnostic, filemap);
+        sr.bump();
+        sr
+    }
+
+    fn new_raw_internal<'b>(span_diagnostic: &'b Handler,
+                            filemap: Rc<syntax_pos::FileMap>)
+                            -> StringReader<'b> {
         if filemap.src.is_none() {
             span_diagnostic.bug(&format!("Cannot lex filemap \
                                           without source: {}",
@@ -172,21 +220,21 @@ impl<'a> StringReader<'a> {
 
         let source_text = (*filemap.src.as_ref().unwrap()).clone();
 
-        let mut sr = StringReader {
+        StringReader {
             span_diagnostic: span_diagnostic,
+            next_pos: filemap.start_pos,
             pos: filemap.start_pos,
-            last_pos: filemap.start_pos,
             col: CharPos(0),
-            curr: Some('\n'),
+            ch: Some('\n'),
             filemap: filemap,
+            terminator: None,
+            save_new_lines: true,
             // dummy values; not read
             peek_tok: token::Eof,
             peek_span: syntax_pos::DUMMY_SP,
             source_text: source_text,
             fatal_errs: Vec::new(),
-        };
-        sr.bump();
-        sr
+        }
     }
 
     pub fn new<'b>(span_diagnostic: &'b Handler,
@@ -200,8 +248,8 @@ impl<'a> StringReader<'a> {
         sr
     }
 
-    pub fn curr_is(&self, c: char) -> bool {
-        self.curr == Some(c)
+    pub fn ch_is(&self, c: char) -> bool {
+        self.ch == Some(c)
     }
 
     /// Report a fatal lexical error with a given span.
@@ -296,9 +344,9 @@ impl<'a> StringReader<'a> {
                     self.peek_tok = token::Eof;
                     self.peek_span = syntax_pos::mk_sp(self.filemap.end_pos, self.filemap.end_pos);
                 } else {
-                    let start_bytepos = self.last_pos;
+                    let start_bytepos = self.pos;
                     self.peek_tok = self.next_token_inner()?;
-                    self.peek_span = syntax_pos::mk_sp(start_bytepos, self.last_pos);
+                    self.peek_span = syntax_pos::mk_sp(start_bytepos, self.pos);
                 };
             }
         }
@@ -310,19 +358,19 @@ impl<'a> StringReader<'a> {
     }
 
     /// Calls `f` with a string slice of the source text spanning from `start`
-    /// up to but excluding `self.last_pos`, meaning the slice does not include
-    /// the character `self.curr`.
+    /// up to but excluding `self.pos`, meaning the slice does not include
+    /// the character `self.ch`.
     pub fn with_str_from<T, F>(&self, start: BytePos, f: F) -> T
         where F: FnOnce(&str) -> T
     {
-        self.with_str_from_to(start, self.last_pos, f)
+        self.with_str_from_to(start, self.pos, f)
     }
 
     /// Create a Name from a given offset to the current offset, each
     /// adjusted 1 towards each other (assumes that on either side there is a
     /// single-byte delimiter).
     pub fn name_from(&self, start: BytePos) -> ast::Name {
-        debug!("taking an ident from {:?} to {:?}", start, self.last_pos);
+        debug!("taking an ident from {:?} to {:?}", start, self.pos);
         self.with_str_from(start, token::intern)
     }
 
@@ -393,32 +441,35 @@ impl<'a> StringReader<'a> {
     /// Advance the StringReader by one character. If a newline is
     /// discovered, add it to the FileMap's list of line start offsets.
     pub fn bump(&mut self) {
-        self.last_pos = self.pos;
-        let current_byte_offset = self.byte_offset(self.pos).to_usize();
-        if current_byte_offset < self.source_text.len() {
-            assert!(self.curr.is_some());
-            let last_char = self.curr.unwrap();
-            let ch = char_at(&self.source_text, current_byte_offset);
-            let next = current_byte_offset + ch.len_utf8();
-            let byte_offset_diff = next - current_byte_offset;
-            self.pos = self.pos + Pos::from_usize(byte_offset_diff);
-            self.curr = Some(ch);
-            self.col = self.col + CharPos(1);
-            if last_char == '\n' {
-                self.filemap.next_line(self.last_pos);
+        let new_pos = self.next_pos;
+        let new_byte_offset = self.byte_offset(new_pos).to_usize();
+        if new_byte_offset < self.source_text.len() {
+            let old_ch_is_newline = self.ch.unwrap() == '\n';
+            let new_ch = char_at(&self.source_text, new_byte_offset);
+            let new_ch_len = new_ch.len_utf8();
+
+            self.ch = Some(new_ch);
+            self.pos = new_pos;
+            self.next_pos = new_pos + Pos::from_usize(new_ch_len);
+            if old_ch_is_newline {
+                if self.save_new_lines {
+                    self.filemap.next_line(self.pos);
+                }
                 self.col = CharPos(0);
+            } else {
+                self.col = self.col + CharPos(1);
             }
-
-            if byte_offset_diff > 1 {
-                self.filemap.record_multibyte_char(self.last_pos, byte_offset_diff);
+            if new_ch_len > 1 {
+                self.filemap.record_multibyte_char(self.pos, new_ch_len);
             }
         } else {
-            self.curr = None;
+            self.ch = None;
+            self.pos = new_pos;
         }
     }
 
     pub fn nextch(&self) -> Option<char> {
-        let offset = self.byte_offset(self.pos).to_usize();
+        let offset = self.byte_offset(self.next_pos).to_usize();
         if offset < self.source_text.len() {
             Some(char_at(&self.source_text, offset))
         } else {
@@ -431,7 +482,7 @@ impl<'a> StringReader<'a> {
     }
 
     pub fn nextnextch(&self) -> Option<char> {
-        let offset = self.byte_offset(self.pos).to_usize();
+        let offset = self.byte_offset(self.next_pos).to_usize();
         let s = &self.source_text[..];
         if offset >= s.len() {
             return None;
@@ -450,11 +501,11 @@ impl<'a> StringReader<'a> {
 
     /// Eats <XID_start><XID_continue>*, if possible.
     fn scan_optional_raw_name(&mut self) -> Option<ast::Name> {
-        if !ident_start(self.curr) {
+        if !ident_start(self.ch) {
             return None;
         }
-        let start = self.last_pos;
-        while ident_continue(self.curr) {
+        let start = self.pos;
+        while ident_continue(self.ch) {
             self.bump();
         }
 
@@ -467,41 +518,37 @@ impl<'a> StringReader<'a> {
         })
     }
 
-    /// PRECONDITION: self.curr is not whitespace
+    /// PRECONDITION: self.ch is not whitespace
     /// Eats any kind of comment.
     fn scan_comment(&mut self) -> Option<TokenAndSpan> {
-        if let Some(c) = self.curr {
+        if let Some(c) = self.ch {
             if c.is_whitespace() {
-                self.span_diagnostic.span_err(syntax_pos::mk_sp(self.last_pos, self.last_pos),
+                self.span_diagnostic.span_err(syntax_pos::mk_sp(self.pos, self.pos),
                                               "called consume_any_line_comment, but there \
                                                was whitespace");
             }
         }
 
-        if self.curr_is('/') {
+        if self.ch_is('/') {
             match self.nextch() {
                 Some('/') => {
                     self.bump();
                     self.bump();
 
                     // line comments starting with "///" or "//!" are doc-comments
-                    let doc_comment = self.curr_is('/') || self.curr_is('!');
-                    let start_bpos = if doc_comment {
-                        self.pos - BytePos(3)
-                    } else {
-                        self.last_pos - BytePos(2)
-                    };
+                    let doc_comment = self.ch_is('/') || self.ch_is('!');
+                    let start_bpos = self.pos - BytePos(2);
 
                     while !self.is_eof() {
-                        match self.curr.unwrap() {
+                        match self.ch.unwrap() {
                             '\n' => break,
                             '\r' => {
                                 if self.nextch_is('\n') {
                                     // CRLF
                                     break;
                                 } else if doc_comment {
-                                    self.err_span_(self.last_pos,
-                                                   self.pos,
+                                    self.err_span_(self.pos,
+                                                   self.next_pos,
                                                    "bare CR not allowed in doc-comment");
                                 }
                             }
@@ -521,13 +568,13 @@ impl<'a> StringReader<'a> {
 
                             Some(TokenAndSpan {
                                 tok: tok,
-                                sp: syntax_pos::mk_sp(start_bpos, self.last_pos),
+                                sp: syntax_pos::mk_sp(start_bpos, self.pos),
                             })
                         })
                     } else {
                         Some(TokenAndSpan {
                             tok: token::Comment,
-                            sp: syntax_pos::mk_sp(start_bpos, self.last_pos),
+                            sp: syntax_pos::mk_sp(start_bpos, self.pos),
                         })
                     };
                 }
@@ -538,7 +585,7 @@ impl<'a> StringReader<'a> {
                 }
                 _ => None,
             }
-        } else if self.curr_is('#') {
+        } else if self.ch_is('#') {
             if self.nextch_is('!') {
 
                 // Parse an inner attribute.
@@ -550,17 +597,17 @@ impl<'a> StringReader<'a> {
                 // we're at the beginning of the file...
                 let cmap = CodeMap::new();
                 cmap.files.borrow_mut().push(self.filemap.clone());
-                let loc = cmap.lookup_char_pos_adj(self.last_pos);
+                let loc = cmap.lookup_char_pos_adj(self.pos);
                 debug!("Skipping a shebang");
                 if loc.line == 1 && loc.col == CharPos(0) {
                     // FIXME: Add shebang "token", return it
-                    let start = self.last_pos;
-                    while !self.curr_is('\n') && !self.is_eof() {
+                    let start = self.pos;
+                    while !self.ch_is('\n') && !self.is_eof() {
                         self.bump();
                     }
                     return Some(TokenAndSpan {
                         tok: token::Shebang(self.name_from(start)),
-                        sp: syntax_pos::mk_sp(start, self.last_pos),
+                        sp: syntax_pos::mk_sp(start, self.pos),
                     });
                 }
             }
@@ -573,7 +620,7 @@ impl<'a> StringReader<'a> {
     /// If there is whitespace, shebang, or a comment, scan it. Otherwise,
     /// return None.
     fn scan_whitespace_or_comment(&mut self) -> Option<TokenAndSpan> {
-        match self.curr.unwrap_or('\0') {
+        match self.ch.unwrap_or('\0') {
             // # to handle shebang at start of file -- this is the entry point
             // for skipping over all "junk"
             '/' | '#' => {
@@ -582,13 +629,13 @@ impl<'a> StringReader<'a> {
                 c
             },
             c if is_pattern_whitespace(Some(c)) => {
-                let start_bpos = self.last_pos;
-                while is_pattern_whitespace(self.curr) {
+                let start_bpos = self.pos;
+                while is_pattern_whitespace(self.ch) {
                     self.bump();
                 }
                 let c = Some(TokenAndSpan {
                     tok: token::Whitespace,
-                    sp: syntax_pos::mk_sp(start_bpos, self.last_pos),
+                    sp: syntax_pos::mk_sp(start_bpos, self.pos),
                 });
                 debug!("scanning whitespace: {:?}", c);
                 c
@@ -600,8 +647,8 @@ impl<'a> StringReader<'a> {
     /// Might return a sugared-doc-attr
     fn scan_block_comment(&mut self) -> Option<TokenAndSpan> {
         // block comments starting with "/**" or "/*!" are doc-comments
-        let is_doc_comment = self.curr_is('*') || self.curr_is('!');
-        let start_bpos = self.last_pos - BytePos(2);
+        let is_doc_comment = self.ch_is('*') || self.ch_is('!');
+        let start_bpos = self.pos - BytePos(2);
 
         let mut level: isize = 1;
         let mut has_cr = false;
@@ -612,10 +659,10 @@ impl<'a> StringReader<'a> {
                 } else {
                     "unterminated block comment"
                 };
-                let last_bpos = self.last_pos;
+                let last_bpos = self.pos;
                 panic!(self.fatal_span_(start_bpos, last_bpos, msg));
             }
-            let n = self.curr.unwrap();
+            let n = self.ch.unwrap();
             match n {
                 '/' if self.nextch_is('*') => {
                     level += 1;
@@ -650,7 +697,7 @@ impl<'a> StringReader<'a> {
 
             Some(TokenAndSpan {
                 tok: tok,
-                sp: syntax_pos::mk_sp(start_bpos, self.last_pos),
+                sp: syntax_pos::mk_sp(start_bpos, self.pos),
             })
         })
     }
@@ -665,7 +712,7 @@ impl<'a> StringReader<'a> {
         assert!(real_radix <= scan_radix);
         let mut len = 0;
         loop {
-            let c = self.curr;
+            let c = self.ch;
             if c == Some('_') {
                 debug!("skipping a _");
                 self.bump();
@@ -677,8 +724,8 @@ impl<'a> StringReader<'a> {
                     // check that the hypothetical digit is actually
                     // in range for the true radix
                     if c.unwrap().to_digit(real_radix).is_none() {
-                        self.err_span_(self.last_pos,
-                                       self.pos,
+                        self.err_span_(self.pos,
+                                       self.next_pos,
                                        &format!("invalid digit for a base {} literal", real_radix));
                     }
                     len += 1;
@@ -693,12 +740,12 @@ impl<'a> StringReader<'a> {
     fn scan_number(&mut self, c: char) -> token::Lit {
         let num_digits;
         let mut base = 10;
-        let start_bpos = self.last_pos;
+        let start_bpos = self.pos;
 
         self.bump();
 
         if c == '0' {
-            match self.curr.unwrap_or('\0') {
+            match self.ch.unwrap_or('\0') {
                 'b' => {
                     self.bump();
                     base = 2;
@@ -730,7 +777,7 @@ impl<'a> StringReader<'a> {
 
         if num_digits == 0 {
             self.err_span_(start_bpos,
-                           self.last_pos,
+                           self.pos,
                            "no valid digits found for number");
             return token::Integer(token::intern("0"));
         }
@@ -738,26 +785,26 @@ impl<'a> StringReader<'a> {
         // might be a float, but don't be greedy if this is actually an
         // integer literal followed by field/method access or a range pattern
         // (`0..2` and `12.foo()`)
-        if self.curr_is('.') && !self.nextch_is('.') &&
+        if self.ch_is('.') && !self.nextch_is('.') &&
            !self.nextch()
                 .unwrap_or('\0')
                 .is_xid_start() {
             // might have stuff after the ., and if it does, it needs to start
             // with a number
             self.bump();
-            if self.curr.unwrap_or('\0').is_digit(10) {
+            if self.ch.unwrap_or('\0').is_digit(10) {
                 self.scan_digits(10, 10);
                 self.scan_float_exponent();
             }
-            let last_pos = self.last_pos;
-            self.check_float_base(start_bpos, last_pos, base);
+            let pos = self.pos;
+            self.check_float_base(start_bpos, pos, base);
             return token::Float(self.name_from(start_bpos));
         } else {
             // it might be a float if it has an exponent
-            if self.curr_is('e') || self.curr_is('E') {
+            if self.ch_is('e') || self.ch_is('E') {
                 self.scan_float_exponent();
-                let last_pos = self.last_pos;
-                self.check_float_base(start_bpos, last_pos, base);
+                let pos = self.pos;
+                self.check_float_base(start_bpos, pos, base);
                 return token::Float(self.name_from(start_bpos));
             }
             // but we certainly have an integer!
@@ -769,30 +816,30 @@ impl<'a> StringReader<'a> {
     /// error if too many or too few digits are encountered.
     fn scan_hex_digits(&mut self, n_digits: usize, delim: char, below_0x7f_only: bool) -> bool {
         debug!("scanning {} digits until {:?}", n_digits, delim);
-        let start_bpos = self.last_pos;
+        let start_bpos = self.pos;
         let mut accum_int = 0;
 
         let mut valid = true;
         for _ in 0..n_digits {
             if self.is_eof() {
-                let last_bpos = self.last_pos;
+                let last_bpos = self.pos;
                 panic!(self.fatal_span_(start_bpos,
                                         last_bpos,
                                         "unterminated numeric character escape"));
             }
-            if self.curr_is(delim) {
-                let last_bpos = self.last_pos;
+            if self.ch_is(delim) {
+                let last_bpos = self.pos;
                 self.err_span_(start_bpos,
                                last_bpos,
                                "numeric character escape is too short");
                 valid = false;
                 break;
             }
-            let c = self.curr.unwrap_or('\x00');
+            let c = self.ch.unwrap_or('\x00');
             accum_int *= 16;
             accum_int += c.to_digit(16).unwrap_or_else(|| {
-                self.err_span_char(self.last_pos,
-                                   self.pos,
+                self.err_span_char(self.pos,
+                                   self.next_pos,
                                    "invalid character in numeric character escape",
                                    c);
 
@@ -804,7 +851,7 @@ impl<'a> StringReader<'a> {
 
         if below_0x7f_only && accum_int >= 0x80 {
             self.err_span_(start_bpos,
-                           self.last_pos,
+                           self.pos,
                            "this form of character escape may only be used with characters in \
                             the range [\\x00-\\x7f]");
             valid = false;
@@ -813,7 +860,7 @@ impl<'a> StringReader<'a> {
         match char::from_u32(accum_int) {
             Some(_) => valid,
             None => {
-                let last_bpos = self.last_pos;
+                let last_bpos = self.pos;
                 self.err_span_(start_bpos, last_bpos, "invalid numeric character escape");
                 false
             }
@@ -834,8 +881,8 @@ impl<'a> StringReader<'a> {
         match first_source_char {
             '\\' => {
                 // '\X' for some X must be a character constant:
-                let escaped = self.curr;
-                let escaped_pos = self.last_pos;
+                let escaped = self.ch;
+                let escaped_pos = self.pos;
                 self.bump();
                 match escaped {
                     None => {}  // EOF here is an error that will be checked later.
@@ -844,10 +891,10 @@ impl<'a> StringReader<'a> {
                             'n' | 'r' | 't' | '\\' | '\'' | '"' | '0' => true,
                             'x' => self.scan_byte_escape(delim, !ascii_only),
                             'u' => {
-                                let valid = if self.curr_is('{') {
+                                let valid = if self.ch_is('{') {
                                     self.scan_unicode_escape(delim) && !ascii_only
                                 } else {
-                                    let span = syntax_pos::mk_sp(start, self.last_pos);
+                                    let span = syntax_pos::mk_sp(start, self.pos);
                                     self.span_diagnostic
                                         .struct_span_err(span, "incorrect unicode escape sequence")
                                         .span_help(span,
@@ -858,7 +905,7 @@ impl<'a> StringReader<'a> {
                                 };
                                 if ascii_only {
                                     self.err_span_(start,
-                                                   self.last_pos,
+                                                   self.pos,
                                                    "unicode escape sequences cannot be used as a \
                                                     byte or in a byte string");
                                 }
@@ -869,14 +916,14 @@ impl<'a> StringReader<'a> {
                                 self.consume_whitespace();
                                 true
                             }
-                            '\r' if delim == '"' && self.curr_is('\n') => {
+                            '\r' if delim == '"' && self.ch_is('\n') => {
                                 self.consume_whitespace();
                                 true
                             }
                             c => {
-                                let last_pos = self.last_pos;
+                                let pos = self.pos;
                                 let mut err = self.struct_err_span_char(escaped_pos,
-                                                                        last_pos,
+                                                                        pos,
                                                                         if ascii_only {
                                                                             "unknown byte escape"
                                                                         } else {
@@ -885,13 +932,13 @@ impl<'a> StringReader<'a> {
                                                                         },
                                                                         c);
                                 if e == '\r' {
-                                    err.span_help(syntax_pos::mk_sp(escaped_pos, last_pos),
+                                    err.span_help(syntax_pos::mk_sp(escaped_pos, pos),
                                                   "this is an isolated carriage return; consider \
                                                    checking your editor and version control \
                                                    settings");
                                 }
                                 if (e == '{' || e == '}') && !ascii_only {
-                                    err.span_help(syntax_pos::mk_sp(escaped_pos, last_pos),
+                                    err.span_help(syntax_pos::mk_sp(escaped_pos, pos),
                                                   "if used in a formatting string, curly braces \
                                                    are escaped with `{{` and `}}`");
                                 }
@@ -903,9 +950,9 @@ impl<'a> StringReader<'a> {
                 }
             }
             '\t' | '\n' | '\r' | '\'' if delim == '\'' => {
-                let last_pos = self.last_pos;
+                let pos = self.pos;
                 self.err_span_char(start,
-                                   last_pos,
+                                   pos,
                                    if ascii_only {
                                        "byte constant must be escaped"
                                    } else {
@@ -915,21 +962,21 @@ impl<'a> StringReader<'a> {
                 return false;
             }
             '\r' => {
-                if self.curr_is('\n') {
+                if self.ch_is('\n') {
                     self.bump();
                     return true;
                 } else {
                     self.err_span_(start,
-                                   self.last_pos,
+                                   self.pos,
                                    "bare CR not allowed in string, use \\r instead");
                     return false;
                 }
             }
             _ => {
                 if ascii_only && first_source_char > '\x7F' {
-                    let last_pos = self.last_pos;
+                    let pos = self.pos;
                     self.err_span_(start,
-                                   last_pos,
+                                   pos,
                                    "byte constant must be ASCII. Use a \\xHH escape for a \
                                     non-ASCII byte");
                     return false;
@@ -945,29 +992,29 @@ impl<'a> StringReader<'a> {
     /// will read at least one digit, and up to 6, and pass over the }.
     fn scan_unicode_escape(&mut self, delim: char) -> bool {
         self.bump(); // past the {
-        let start_bpos = self.last_pos;
+        let start_bpos = self.pos;
         let mut count = 0;
         let mut accum_int = 0;
         let mut valid = true;
 
-        while !self.curr_is('}') && count <= 6 {
-            let c = match self.curr {
+        while !self.ch_is('}') && count <= 6 {
+            let c = match self.ch {
                 Some(c) => c,
                 None => {
                     panic!(self.fatal_span_(start_bpos,
-                                            self.last_pos,
+                                            self.pos,
                                             "unterminated unicode escape (found EOF)"));
                 }
             };
             accum_int *= 16;
             accum_int += c.to_digit(16).unwrap_or_else(|| {
                 if c == delim {
-                    panic!(self.fatal_span_(self.last_pos,
-                                            self.pos,
+                    panic!(self.fatal_span_(self.pos,
+                                            self.next_pos,
                                             "unterminated unicode escape (needed a `}`)"));
                 } else {
-                    self.err_span_char(self.last_pos,
-                                       self.pos,
+                    self.err_span_char(self.pos,
+                                       self.next_pos,
                                        "invalid character in unicode escape",
                                        c);
                 }
@@ -980,14 +1027,14 @@ impl<'a> StringReader<'a> {
 
         if count > 6 {
             self.err_span_(start_bpos,
-                           self.last_pos,
+                           self.pos,
                            "overlong unicode escape (can have at most 6 hex digits)");
             valid = false;
         }
 
         if valid && (char::from_u32(accum_int).is_none() || count == 0) {
             self.err_span_(start_bpos,
-                           self.last_pos,
+                           self.pos,
                            "invalid unicode character escape");
             valid = false;
         }
@@ -998,14 +1045,14 @@ impl<'a> StringReader<'a> {
 
     /// Scan over a float exponent.
     fn scan_float_exponent(&mut self) {
-        if self.curr_is('e') || self.curr_is('E') {
+        if self.ch_is('e') || self.ch_is('E') {
             self.bump();
-            if self.curr_is('-') || self.curr_is('+') {
+            if self.ch_is('-') || self.ch_is('+') {
                 self.bump();
             }
             if self.scan_digits(10, 10) == 0 {
-                self.err_span_(self.last_pos,
-                               self.pos,
+                self.err_span_(self.pos,
+                               self.next_pos,
                                "expected at least one digit in exponent")
             }
         }
@@ -1036,7 +1083,7 @@ impl<'a> StringReader<'a> {
 
     fn binop(&mut self, op: token::BinOpToken) -> token::Token {
         self.bump();
-        if self.curr_is('=') {
+        if self.ch_is('=') {
             self.bump();
             return token::BinOpEq(op);
         } else {
@@ -1047,7 +1094,7 @@ impl<'a> StringReader<'a> {
     /// Return the next token from the string, advances the input past that
     /// token, and updates the interner
     fn next_token_inner(&mut self) -> Result<token::Token, ()> {
-        let c = self.curr;
+        let c = self.ch;
         if ident_start(c) &&
            match (c.unwrap(), self.nextch(), self.nextnextch()) {
             // Note: r as in r" or r#" is part of a raw string literal,
@@ -1061,8 +1108,8 @@ impl<'a> StringReader<'a> {
             ('b', Some('r'), Some('#')) => false,
             _ => true,
         } {
-            let start = self.last_pos;
-            while ident_continue(self.curr) {
+            let start = self.pos;
+            while ident_continue(self.ch) {
                 self.bump();
             }
 
@@ -1095,9 +1142,9 @@ impl<'a> StringReader<'a> {
             }
             '.' => {
                 self.bump();
-                return if self.curr_is('.') {
+                return if self.ch_is('.') {
                     self.bump();
-                    if self.curr_is('.') {
+                    if self.ch_is('.') {
                         self.bump();
                         Ok(token::DotDotDot)
                     } else {
@@ -1149,7 +1196,7 @@ impl<'a> StringReader<'a> {
             }
             ':' => {
                 self.bump();
-                if self.curr_is(':') {
+                if self.ch_is(':') {
                     self.bump();
                     return Ok(token::ModSep);
                 } else {
@@ -1165,10 +1212,10 @@ impl<'a> StringReader<'a> {
             // Multi-byte tokens.
             '=' => {
                 self.bump();
-                if self.curr_is('=') {
+                if self.ch_is('=') {
                     self.bump();
                     return Ok(token::EqEq);
-                } else if self.curr_is('>') {
+                } else if self.ch_is('>') {
                     self.bump();
                     return Ok(token::FatArrow);
                 } else {
@@ -1177,7 +1224,7 @@ impl<'a> StringReader<'a> {
             }
             '!' => {
                 self.bump();
-                if self.curr_is('=') {
+                if self.ch_is('=') {
                     self.bump();
                     return Ok(token::Ne);
                 } else {
@@ -1186,7 +1233,7 @@ impl<'a> StringReader<'a> {
             }
             '<' => {
                 self.bump();
-                match self.curr.unwrap_or('\x00') {
+                match self.ch.unwrap_or('\x00') {
                     '=' => {
                         self.bump();
                         return Ok(token::Le);
@@ -1196,7 +1243,7 @@ impl<'a> StringReader<'a> {
                     }
                     '-' => {
                         self.bump();
-                        match self.curr.unwrap_or('\x00') {
+                        match self.ch.unwrap_or('\x00') {
                             _ => {
                                 return Ok(token::LArrow);
                             }
@@ -1209,7 +1256,7 @@ impl<'a> StringReader<'a> {
             }
             '>' => {
                 self.bump();
-                match self.curr.unwrap_or('\x00') {
+                match self.ch.unwrap_or('\x00') {
                     '=' => {
                         self.bump();
                         return Ok(token::Ge);
@@ -1224,25 +1271,25 @@ impl<'a> StringReader<'a> {
             }
             '\'' => {
                 // Either a character constant 'a' OR a lifetime name 'abc
-                let start_with_quote = self.last_pos;
+                let start_with_quote = self.pos;
                 self.bump();
-                let start = self.last_pos;
+                let start = self.pos;
 
                 // the eof will be picked up by the final `'` check below
-                let c2 = self.curr.unwrap_or('\x00');
+                let c2 = self.ch.unwrap_or('\x00');
                 self.bump();
 
                 // If the character is an ident start not followed by another single
                 // quote, then this is a lifetime name:
-                if ident_start(Some(c2)) && !self.curr_is('\'') {
-                    while ident_continue(self.curr) {
+                if ident_start(Some(c2)) && !self.ch_is('\'') {
+                    while ident_continue(self.ch) {
                         self.bump();
                     }
                     // lifetimes shouldn't end with a single quote
                     // if we find one, then this is an invalid character literal
-                    if self.curr_is('\'') {
+                    if self.ch_is('\'') {
                         panic!(self.fatal_span_verbose(
-                               start_with_quote, self.pos,
+                               start_with_quote, self.next_pos,
                                String::from("character literal may only contain one codepoint")));
 
                     }
@@ -1260,7 +1307,7 @@ impl<'a> StringReader<'a> {
                         str_to_ident(lifetime_name)
                     });
                     let keyword_checking_token = &token::Ident(keyword_checking_ident);
-                    let last_bpos = self.last_pos;
+                    let last_bpos = self.pos;
                     if keyword_checking_token.is_any_keyword() &&
                        !keyword_checking_token.is_keyword(keywords::Static) {
                         self.err_span_(start, last_bpos, "lifetimes cannot use keyword names");
@@ -1275,9 +1322,9 @@ impl<'a> StringReader<'a> {
                                                    false,
                                                    '\'');
 
-                if !self.curr_is('\'') {
+                if !self.ch_is('\'') {
                     panic!(self.fatal_span_verbose(
-                           start_with_quote, self.last_pos,
+                           start_with_quote, self.pos,
                            String::from("character literal may only contain one codepoint")));
                 }
 
@@ -1286,13 +1333,13 @@ impl<'a> StringReader<'a> {
                 } else {
                     token::intern("0")
                 };
-                self.bump(); // advance curr past token
+                self.bump(); // advance ch past token
                 let suffix = self.scan_optional_raw_name();
                 return Ok(token::Literal(token::Char(id), suffix));
             }
             'b' => {
                 self.bump();
-                let lit = match self.curr {
+                let lit = match self.ch {
                     Some('\'') => self.scan_byte(),
                     Some('"') => self.scan_byte_string(),
                     Some('r') => self.scan_raw_byte_string(),
@@ -1302,19 +1349,19 @@ impl<'a> StringReader<'a> {
                 return Ok(token::Literal(lit, suffix));
             }
             '"' => {
-                let start_bpos = self.last_pos;
+                let start_bpos = self.pos;
                 let mut valid = true;
                 self.bump();
-                while !self.curr_is('"') {
+                while !self.ch_is('"') {
                     if self.is_eof() {
-                        let last_bpos = self.last_pos;
+                        let last_bpos = self.pos;
                         panic!(self.fatal_span_(start_bpos,
                                                 last_bpos,
                                                 "unterminated double quote string"));
                     }
 
-                    let ch_start = self.last_pos;
-                    let ch = self.curr.unwrap();
+                    let ch_start = self.pos;
+                    let ch = self.ch.unwrap();
                     self.bump();
                     valid &= self.scan_char_or_byte(ch_start,
                                                     ch,
@@ -1333,20 +1380,20 @@ impl<'a> StringReader<'a> {
                 return Ok(token::Literal(token::Str_(id), suffix));
             }
             'r' => {
-                let start_bpos = self.last_pos;
+                let start_bpos = self.pos;
                 self.bump();
                 let mut hash_count = 0;
-                while self.curr_is('#') {
+                while self.ch_is('#') {
                     self.bump();
                     hash_count += 1;
                 }
 
                 if self.is_eof() {
-                    let last_bpos = self.last_pos;
+                    let last_bpos = self.pos;
                     panic!(self.fatal_span_(start_bpos, last_bpos, "unterminated raw string"));
-                } else if !self.curr_is('"') {
-                    let last_bpos = self.last_pos;
-                    let curr_char = self.curr.unwrap();
+                } else if !self.ch_is('"') {
+                    let last_bpos = self.pos;
+                    let curr_char = self.ch.unwrap();
                     panic!(self.fatal_span_char(start_bpos,
                                                 last_bpos,
                                                 "found invalid character; only `#` is allowed \
@@ -1354,27 +1401,27 @@ impl<'a> StringReader<'a> {
                                                 curr_char));
                 }
                 self.bump();
-                let content_start_bpos = self.last_pos;
+                let content_start_bpos = self.pos;
                 let mut content_end_bpos;
                 let mut valid = true;
                 'outer: loop {
                     if self.is_eof() {
-                        let last_bpos = self.last_pos;
+                        let last_bpos = self.pos;
                         panic!(self.fatal_span_(start_bpos, last_bpos, "unterminated raw string"));
                     }
-                    // if self.curr_is('"') {
-                    // content_end_bpos = self.last_pos;
+                    // if self.ch_is('"') {
+                    // content_end_bpos = self.pos;
                     // for _ in 0..hash_count {
                     // self.bump();
-                    // if !self.curr_is('#') {
+                    // if !self.ch_is('#') {
                     // continue 'outer;
-                    let c = self.curr.unwrap();
+                    let c = self.ch.unwrap();
                     match c {
                         '"' => {
-                            content_end_bpos = self.last_pos;
+                            content_end_bpos = self.pos;
                             for _ in 0..hash_count {
                                 self.bump();
-                                if !self.curr_is('#') {
+                                if !self.ch_is('#') {
                                     continue 'outer;
                                 }
                             }
@@ -1382,7 +1429,7 @@ impl<'a> StringReader<'a> {
                         }
                         '\r' => {
                             if !self.nextch_is('\n') {
-                                let last_bpos = self.last_pos;
+                                let last_bpos = self.pos;
                                 self.err_span_(start_bpos,
                                                last_bpos,
                                                "bare CR not allowed in raw string, use \\r \
@@ -1449,8 +1496,8 @@ impl<'a> StringReader<'a> {
                 return Ok(self.binop(token::Percent));
             }
             c => {
-                let last_bpos = self.last_pos;
-                let bpos = self.pos;
+                let last_bpos = self.pos;
+                let bpos = self.next_pos;
                 let mut err = self.struct_fatal_span_char(last_bpos,
                                                           bpos,
                                                           "unknown start of token",
@@ -1463,18 +1510,18 @@ impl<'a> StringReader<'a> {
     }
 
     fn consume_whitespace(&mut self) {
-        while is_pattern_whitespace(self.curr) && !self.is_eof() {
+        while is_pattern_whitespace(self.ch) && !self.is_eof() {
             self.bump();
         }
     }
 
     fn read_to_eol(&mut self) -> String {
         let mut val = String::new();
-        while !self.curr_is('\n') && !self.is_eof() {
-            val.push(self.curr.unwrap());
+        while !self.ch_is('\n') && !self.is_eof() {
+            val.push(self.ch.unwrap());
             self.bump();
         }
-        if self.curr_is('\n') {
+        if self.ch_is('\n') {
             self.bump();
         }
         return val;
@@ -1488,23 +1535,23 @@ impl<'a> StringReader<'a> {
     }
 
     fn consume_non_eol_whitespace(&mut self) {
-        while is_pattern_whitespace(self.curr) && !self.curr_is('\n') && !self.is_eof() {
+        while is_pattern_whitespace(self.ch) && !self.ch_is('\n') && !self.is_eof() {
             self.bump();
         }
     }
 
     fn peeking_at_comment(&self) -> bool {
-        (self.curr_is('/') && self.nextch_is('/')) || (self.curr_is('/') && self.nextch_is('*')) ||
+        (self.ch_is('/') && self.nextch_is('/')) || (self.ch_is('/') && self.nextch_is('*')) ||
         // consider shebangs comments, but not inner attributes
-        (self.curr_is('#') && self.nextch_is('!') && !self.nextnextch_is('['))
+        (self.ch_is('#') && self.nextch_is('!') && !self.nextnextch_is('['))
     }
 
     fn scan_byte(&mut self) -> token::Lit {
         self.bump();
-        let start = self.last_pos;
+        let start = self.pos;
 
         // the eof will be picked up by the final `'` check below
-        let c2 = self.curr.unwrap_or('\x00');
+        let c2 = self.ch.unwrap_or('\x00');
         self.bump();
 
         let valid = self.scan_char_or_byte(start,
@@ -1512,13 +1559,13 @@ impl<'a> StringReader<'a> {
                                            // ascii_only =
                                            true,
                                            '\'');
-        if !self.curr_is('\'') {
+        if !self.ch_is('\'') {
             // Byte offsetting here is okay because the
             // character before position `start` are an
             // ascii single quote and ascii 'b'.
-            let last_pos = self.last_pos;
+            let pos = self.pos;
             panic!(self.fatal_span_verbose(start - BytePos(2),
-                                           last_pos,
+                                           pos,
                                            "unterminated byte constant".to_string()));
         }
 
@@ -1527,7 +1574,7 @@ impl<'a> StringReader<'a> {
         } else {
             token::intern("?")
         };
-        self.bump(); // advance curr past token
+        self.bump(); // advance ch past token
         return token::Byte(id);
     }
 
@@ -1537,17 +1584,17 @@ impl<'a> StringReader<'a> {
 
     fn scan_byte_string(&mut self) -> token::Lit {
         self.bump();
-        let start = self.last_pos;
+        let start = self.pos;
         let mut valid = true;
 
-        while !self.curr_is('"') {
+        while !self.ch_is('"') {
             if self.is_eof() {
-                let last_pos = self.last_pos;
-                panic!(self.fatal_span_(start, last_pos, "unterminated double quote byte string"));
+                let pos = self.pos;
+                panic!(self.fatal_span_(start, pos, "unterminated double quote byte string"));
             }
 
-            let ch_start = self.last_pos;
-            let ch = self.curr.unwrap();
+            let ch_start = self.pos;
+            let ch = self.ch.unwrap();
             self.bump();
             valid &= self.scan_char_or_byte(ch_start,
                                             ch,
@@ -1565,40 +1612,40 @@ impl<'a> StringReader<'a> {
     }
 
     fn scan_raw_byte_string(&mut self) -> token::Lit {
-        let start_bpos = self.last_pos;
+        let start_bpos = self.pos;
         self.bump();
         let mut hash_count = 0;
-        while self.curr_is('#') {
+        while self.ch_is('#') {
             self.bump();
             hash_count += 1;
         }
 
         if self.is_eof() {
-            let last_pos = self.last_pos;
-            panic!(self.fatal_span_(start_bpos, last_pos, "unterminated raw string"));
-        } else if !self.curr_is('"') {
-            let last_pos = self.last_pos;
-            let ch = self.curr.unwrap();
+            let pos = self.pos;
+            panic!(self.fatal_span_(start_bpos, pos, "unterminated raw string"));
+        } else if !self.ch_is('"') {
+            let pos = self.pos;
+            let ch = self.ch.unwrap();
             panic!(self.fatal_span_char(start_bpos,
-                                        last_pos,
+                                        pos,
                                         "found invalid character; only `#` is allowed in raw \
                                          string delimitation",
                                         ch));
         }
         self.bump();
-        let content_start_bpos = self.last_pos;
+        let content_start_bpos = self.pos;
         let mut content_end_bpos;
         'outer: loop {
-            match self.curr {
+            match self.ch {
                 None => {
-                    let last_pos = self.last_pos;
-                    panic!(self.fatal_span_(start_bpos, last_pos, "unterminated raw string"))
+                    let pos = self.pos;
+                    panic!(self.fatal_span_(start_bpos, pos, "unterminated raw string"))
                 }
                 Some('"') => {
-                    content_end_bpos = self.last_pos;
+                    content_end_bpos = self.pos;
                     for _ in 0..hash_count {
                         self.bump();
-                        if !self.curr_is('#') {
+                        if !self.ch_is('#') {
                             continue 'outer;
                         }
                     }
@@ -1606,8 +1653,8 @@ impl<'a> StringReader<'a> {
                 }
                 Some(c) => {
                     if c > '\x7F' {
-                        let last_pos = self.last_pos;
-                        self.err_span_char(last_pos, last_pos, "raw byte string must be ASCII", c);
+                        let pos = self.pos;
+                        self.err_span_char(pos, pos, "raw byte string must be ASCII", c);
                     }
                 }
             }
@@ -1721,7 +1768,7 @@ mod tests {
         assert_eq!(tok1, tok2);
         assert_eq!(string_reader.next_token().tok, token::Whitespace);
         // the 'main' id is already read:
-        assert_eq!(string_reader.last_pos.clone(), BytePos(28));
+        assert_eq!(string_reader.pos.clone(), BytePos(28));
         // read another token:
         let tok3 = string_reader.next_token();
         let tok4 = TokenAndSpan {
@@ -1734,7 +1781,7 @@ mod tests {
         };
         assert_eq!(tok3, tok4);
         // the lparen is already read:
-        assert_eq!(string_reader.last_pos.clone(), BytePos(29))
+        assert_eq!(string_reader.pos.clone(), BytePos(29))
     }
 
     // check that the given reader produces the desired stream
diff --git a/src/libsyntax/parse/lexer/unicode_chars.rs b/src/libsyntax/parse/lexer/unicode_chars.rs
index dab97d1d5a6..1e08b20b7e1 100644
--- a/src/libsyntax/parse/lexer/unicode_chars.rs
+++ b/src/libsyntax/parse/lexer/unicode_chars.rs
@@ -234,7 +234,7 @@ pub fn check_for_substitution<'a>(reader: &StringReader<'a>,
     .iter()
     .find(|&&(c, _, _)| c == ch)
     .map(|&(_, u_name, ascii_char)| {
-        let span = make_span(reader.last_pos, reader.pos);
+        let span = make_span(reader.pos, reader.next_pos);
         match ASCII_ARRAY.iter().find(|&&(c, _)| c == ascii_char) {
             Some(&(ascii_char, ascii_name)) => {
                 let msg =
diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs
index a1eceb6921c..12408c7d3c9 100644
--- a/src/libsyntax/parse/mod.rs
+++ b/src/libsyntax/parse/mod.rs
@@ -10,10 +10,11 @@
 
 //! The main parser interface
 
-use ast;
+use ast::{self, CrateConfig};
 use codemap::CodeMap;
 use syntax_pos::{self, Span, FileMap};
 use errors::{Handler, ColorConfig, DiagnosticBuilder};
+use feature_gate::UnstableFeatures;
 use parse::parser::Parser;
 use parse::token::InternedString;
 use ptr::P;
@@ -42,13 +43,15 @@ pub mod obsolete;
 /// Info about a parsing session.
 pub struct ParseSess {
     pub span_diagnostic: Handler, // better be the same as the one in the reader!
+    pub unstable_features: UnstableFeatures,
+    pub config: CrateConfig,
     /// Used to determine and report recursive mod inclusions
     included_mod_stack: RefCell<Vec<PathBuf>>,
     code_map: Rc<CodeMap>,
 }
 
 impl ParseSess {
-    pub fn new() -> ParseSess {
+    pub fn new() -> Self {
         let cm = Rc::new(CodeMap::new());
         let handler = Handler::with_tty_emitter(ColorConfig::Auto,
                                                 true,
@@ -60,6 +63,8 @@ impl ParseSess {
     pub fn with_span_handler(handler: Handler, code_map: Rc<CodeMap>) -> ParseSess {
         ParseSess {
             span_diagnostic: handler,
+            unstable_features: UnstableFeatures::from_environment(),
+            config: Vec::new(),
             included_mod_stack: RefCell::new(vec![]),
             code_map: code_map
         }
@@ -75,146 +80,90 @@ impl ParseSess {
 // uses a HOF to parse anything, and <source> includes file and
 // source_str.
 
-pub fn parse_crate_from_file<'a>(input: &Path,
-                                 cfg: ast::CrateConfig,
-                                 sess: &'a ParseSess)
-                                 -> PResult<'a, ast::Crate> {
-    let mut parser = new_parser_from_file(sess, cfg, input);
+pub fn parse_crate_from_file<'a>(input: &Path, sess: &'a ParseSess) -> PResult<'a, ast::Crate> {
+    let mut parser = new_parser_from_file(sess, input);
     parser.parse_crate_mod()
 }
 
-pub fn parse_crate_attrs_from_file<'a>(input: &Path,
-                                       cfg: ast::CrateConfig,
-                                       sess: &'a ParseSess)
+pub fn parse_crate_attrs_from_file<'a>(input: &Path, sess: &'a ParseSess)
                                        -> PResult<'a, Vec<ast::Attribute>> {
-    let mut parser = new_parser_from_file(sess, cfg, input);
+    let mut parser = new_parser_from_file(sess, input);
     parser.parse_inner_attributes()
 }
 
-pub fn parse_crate_from_source_str<'a>(name: String,
-                                       source: String,
-                                       cfg: ast::CrateConfig,
-                                       sess: &'a ParseSess)
+pub fn parse_crate_from_source_str<'a>(name: String, source: String, sess: &'a ParseSess)
                                        -> PResult<'a, ast::Crate> {
-    let mut p = new_parser_from_source_str(sess,
-                                           cfg,
-                                           name,
-                                           source);
-    p.parse_crate_mod()
+    new_parser_from_source_str(sess, name, source).parse_crate_mod()
 }
 
-pub fn parse_crate_attrs_from_source_str<'a>(name: String,
-                                             source: String,
-                                             cfg: ast::CrateConfig,
-                                             sess: &'a ParseSess)
+pub fn parse_crate_attrs_from_source_str<'a>(name: String, source: String, sess: &'a ParseSess)
                                              -> PResult<'a, Vec<ast::Attribute>> {
-    let mut p = new_parser_from_source_str(sess,
-                                           cfg,
-                                           name,
-                                           source);
-    p.parse_inner_attributes()
+    new_parser_from_source_str(sess, name, source).parse_inner_attributes()
 }
 
-pub fn parse_expr_from_source_str<'a>(name: String,
-                                      source: String,
-                                      cfg: ast::CrateConfig,
-                                      sess: &'a ParseSess)
+pub fn parse_expr_from_source_str<'a>(name: String, source: String, sess: &'a ParseSess)
                                       -> PResult<'a, P<ast::Expr>> {
-    let mut p = new_parser_from_source_str(sess, cfg, name, source);
-    p.parse_expr()
+    new_parser_from_source_str(sess, name, source).parse_expr()
 }
 
 /// Parses an item.
 ///
 /// Returns `Ok(Some(item))` when successful, `Ok(None)` when no item was found, and`Err`
 /// when a syntax error occurred.
-pub fn parse_item_from_source_str<'a>(name: String,
-                                      source: String,
-                                      cfg: ast::CrateConfig,
-                                      sess: &'a ParseSess)
+pub fn parse_item_from_source_str<'a>(name: String, source: String, sess: &'a ParseSess)
                                       -> PResult<'a, Option<P<ast::Item>>> {
-    let mut p = new_parser_from_source_str(sess, cfg, name, source);
-    p.parse_item()
+    new_parser_from_source_str(sess, name, source).parse_item()
 }
 
-pub fn parse_meta_from_source_str<'a>(name: String,
-                                      source: String,
-                                      cfg: ast::CrateConfig,
-                                      sess: &'a ParseSess)
+pub fn parse_meta_from_source_str<'a>(name: String, source: String, sess: &'a ParseSess)
                                       -> PResult<'a, P<ast::MetaItem>> {
-    let mut p = new_parser_from_source_str(sess, cfg, name, source);
-    p.parse_meta_item()
+    new_parser_from_source_str(sess, name, source).parse_meta_item()
 }
 
-pub fn parse_stmt_from_source_str<'a>(name: String,
-                                      source: String,
-                                      cfg: ast::CrateConfig,
-                                      sess: &'a ParseSess)
+pub fn parse_stmt_from_source_str<'a>(name: String, source: String, sess: &'a ParseSess)
                                       -> PResult<'a, Option<ast::Stmt>> {
-    let mut p = new_parser_from_source_str(
-        sess,
-        cfg,
-        name,
-        source
-    );
-    p.parse_stmt()
+    new_parser_from_source_str(sess, name, source).parse_stmt()
 }
 
 // Warning: This parses with quote_depth > 0, which is not the default.
-pub fn parse_tts_from_source_str<'a>(name: String,
-                                     source: String,
-                                     cfg: ast::CrateConfig,
-                                     sess: &'a ParseSess)
+pub fn parse_tts_from_source_str<'a>(name: String, source: String, sess: &'a ParseSess)
                                      -> PResult<'a, Vec<tokenstream::TokenTree>> {
-    let mut p = new_parser_from_source_str(
-        sess,
-        cfg,
-        name,
-        source
-    );
+    let mut p = new_parser_from_source_str(sess, name, source);
     p.quote_depth += 1;
     // right now this is re-creating the token trees from ... token trees.
     p.parse_all_token_trees()
 }
 
 // Create a new parser from a source string
-pub fn new_parser_from_source_str<'a>(sess: &'a ParseSess,
-                                      cfg: ast::CrateConfig,
-                                      name: String,
-                                      source: String)
+pub fn new_parser_from_source_str<'a>(sess: &'a ParseSess, name: String, source: String)
                                       -> Parser<'a> {
-    filemap_to_parser(sess, sess.codemap().new_filemap(name, None, source), cfg)
+    filemap_to_parser(sess, sess.codemap().new_filemap(name, None, source))
 }
 
 /// Create a new parser, handling errors as appropriate
 /// if the file doesn't exist
-pub fn new_parser_from_file<'a>(sess: &'a ParseSess,
-                                cfg: ast::CrateConfig,
-                                path: &Path) -> Parser<'a> {
-    filemap_to_parser(sess, file_to_filemap(sess, path, None), cfg)
+pub fn new_parser_from_file<'a>(sess: &'a ParseSess, path: &Path) -> Parser<'a> {
+    filemap_to_parser(sess, file_to_filemap(sess, path, None))
 }
 
 /// Given a session, a crate config, a path, and a span, add
 /// the file at the given path to the codemap, and return a parser.
 /// On an error, use the given span as the source of the problem.
 pub fn new_sub_parser_from_file<'a>(sess: &'a ParseSess,
-                                    cfg: ast::CrateConfig,
                                     path: &Path,
                                     owns_directory: bool,
                                     module_name: Option<String>,
                                     sp: Span) -> Parser<'a> {
-    let mut p = filemap_to_parser(sess, file_to_filemap(sess, path, Some(sp)), cfg);
+    let mut p = filemap_to_parser(sess, file_to_filemap(sess, path, Some(sp)));
     p.owns_directory = owns_directory;
     p.root_module_name = module_name;
     p
 }
 
 /// Given a filemap and config, return a parser
-pub fn filemap_to_parser<'a>(sess: &'a ParseSess,
-                             filemap: Rc<FileMap>,
-                             cfg: ast::CrateConfig) -> Parser<'a> {
+pub fn filemap_to_parser<'a>(sess: &'a ParseSess, filemap: Rc<FileMap>, ) -> Parser<'a> {
     let end_pos = filemap.end_pos;
-    let mut parser = tts_to_parser(sess, filemap_to_tts(sess, filemap), cfg);
+    let mut parser = tts_to_parser(sess, filemap_to_tts(sess, filemap));
 
     if parser.token == token::Eof && parser.span == syntax_pos::DUMMY_SP {
         parser.span = syntax_pos::mk_sp(end_pos, end_pos);
@@ -225,18 +174,13 @@ pub fn filemap_to_parser<'a>(sess: &'a ParseSess,
 
 // must preserve old name for now, because quote! from the *existing*
 // compiler expands into it
-pub fn new_parser_from_tts<'a>(sess: &'a ParseSess,
-                               cfg: ast::CrateConfig,
-                               tts: Vec<tokenstream::TokenTree>)
+pub fn new_parser_from_tts<'a>(sess: &'a ParseSess, tts: Vec<tokenstream::TokenTree>)
                                -> Parser<'a> {
-    tts_to_parser(sess, tts, cfg)
+    tts_to_parser(sess, tts)
 }
 
-pub fn new_parser_from_ts<'a>(sess: &'a ParseSess,
-                              cfg: ast::CrateConfig,
-                              ts: tokenstream::TokenStream)
-                              -> Parser<'a> {
-    tts_to_parser(sess, ts.to_tts(), cfg)
+pub fn new_parser_from_ts<'a>(sess: &'a ParseSess, ts: tokenstream::TokenStream) -> Parser<'a> {
+    tts_to_parser(sess, ts.to_tts())
 }
 
 
@@ -263,18 +207,15 @@ pub fn filemap_to_tts(sess: &ParseSess, filemap: Rc<FileMap>)
     -> Vec<tokenstream::TokenTree> {
     // it appears to me that the cfg doesn't matter here... indeed,
     // parsing tt's probably shouldn't require a parser at all.
-    let cfg = Vec::new();
     let srdr = lexer::StringReader::new(&sess.span_diagnostic, filemap);
-    let mut p1 = Parser::new(sess, cfg, Box::new(srdr));
+    let mut p1 = Parser::new(sess, Box::new(srdr));
     panictry!(p1.parse_all_token_trees())
 }
 
-/// Given tts and cfg, produce a parser
-pub fn tts_to_parser<'a>(sess: &'a ParseSess,
-                         tts: Vec<tokenstream::TokenTree>,
-                         cfg: ast::CrateConfig) -> Parser<'a> {
-    let trdr = lexer::new_tt_reader(&sess.span_diagnostic, None, None, tts);
-    let mut p = Parser::new(sess, cfg, Box::new(trdr));
+/// Given tts and the ParseSess, produce a parser
+pub fn tts_to_parser<'a>(sess: &'a ParseSess, tts: Vec<tokenstream::TokenTree>) -> Parser<'a> {
+    let trdr = lexer::new_tt_reader(&sess.span_diagnostic, None, tts);
+    let mut p = Parser::new(sess, Box::new(trdr));
     p.check_unknown_macro_variable();
     p
 }
@@ -286,52 +227,37 @@ pub fn tts_to_parser<'a>(sess: &'a ParseSess,
 pub fn char_lit(lit: &str) -> (char, isize) {
     use std::char;
 
-    let mut chars = lit.chars();
-    match (chars.next(), chars.next()) {
-        (Some(c), None) if c != '\\' => return (c, 1),
-        (Some('\\'), Some(c)) => match c {
-            '"' => return ('"', 2),
-            'n' => return ('\n', 2),
-            'r' => return ('\r', 2),
-            't' => return ('\t', 2),
-            '\\' => return ('\\', 2),
-            '\'' => return ('\'', 2),
-            '0' => return ('\0', 2),
-            _ => {}
-        },
-        _ => panic!("lexer accepted invalid char escape `{}`", lit)
-    };
-
-    fn esc(len: usize, lit: &str) -> Option<(char, isize)> {
-        u32::from_str_radix(&lit[2..len], 16).ok()
-        .and_then(char::from_u32)
-        .map(|x| (x, len as isize))
+    // Handle non-escaped chars first.
+    if lit.as_bytes()[0] != b'\\' {
+        // If the first byte isn't '\\' it might part of a multi-byte char, so
+        // get the char with chars().
+        let c = lit.chars().next().unwrap();
+        return (c, 1);
     }
 
-    let unicode_escape = || -> Option<(char, isize)> {
-        if lit.as_bytes()[2] == b'{' {
-            let idx = lit.find('}').unwrap_or_else(|| {
-                panic!("lexer should have rejected a bad character escape {}", lit)
-            });
-
-            let subslice = &lit[3..idx];
-            u32::from_str_radix(subslice, 16).ok()
-                .and_then(char::from_u32)
-                .map(|x| (x, subslice.chars().count() as isize + 4))
-        } else {
-            esc(6, lit)
+    // Handle escaped chars.
+    match lit.as_bytes()[1] as char {
+        '"' => ('"', 2),
+        'n' => ('\n', 2),
+        'r' => ('\r', 2),
+        't' => ('\t', 2),
+        '\\' => ('\\', 2),
+        '\'' => ('\'', 2),
+        '0' => ('\0', 2),
+        'x' => {
+            let v = u32::from_str_radix(&lit[2..4], 16).unwrap();
+            let c = char::from_u32(v).unwrap();
+            (c, 4)
         }
-    };
-
-    // Unicode escapes
-    return match lit.as_bytes()[1] as char {
-        'x' | 'X' => esc(4, lit),
-        'u' => unicode_escape(),
-        'U' => esc(10, lit),
-        _ => None,
-    }.unwrap_or_else(|| {
-        panic!("lexer should have rejected a bad character escape {}", lit)
-    })
+        'u' => {
+            assert!(lit.as_bytes()[2] == b'{');
+            let idx = lit.find('}').unwrap();
+            let v = u32::from_str_radix(&lit[3..idx], 16).unwrap();
+            let c = char::from_u32(v).unwrap();
+            (c, (idx + 1) as isize)
+        }
+        _ => panic!("lexer should have rejected a bad character escape {}", lit)
+    }
 }
 
 /// Parse a string representing a string literal into its final form. Does
@@ -698,12 +624,12 @@ mod tests {
                     node: ast::ExprKind::Path(None, ast::Path {
                         span: sp(0, 1),
                         global: false,
-                        segments: vec!(
+                        segments: vec![
                             ast::PathSegment {
                                 identifier: str_to_ident("a"),
                                 parameters: ast::PathParameters::none(),
                             }
-                        ),
+                        ],
                     }),
                     span: sp(0, 1),
                     attrs: ThinVec::new(),
@@ -717,7 +643,7 @@ mod tests {
                     node: ast::ExprKind::Path(None, ast::Path {
                             span: sp(0, 6),
                             global: true,
-                            segments: vec!(
+                            segments: vec![
                                 ast::PathSegment {
                                     identifier: str_to_ident("a"),
                                     parameters: ast::PathParameters::none(),
@@ -726,7 +652,7 @@ mod tests {
                                     identifier: str_to_ident("b"),
                                     parameters: ast::PathParameters::none(),
                                 }
-                            )
+                            ]
                         }),
                     span: sp(0, 6),
                     attrs: ThinVec::new(),
@@ -837,12 +763,12 @@ mod tests {
                         node:ast::ExprKind::Path(None, ast::Path{
                             span: sp(7, 8),
                             global: false,
-                            segments: vec!(
+                            segments: vec![
                                 ast::PathSegment {
                                     identifier: str_to_ident("d"),
                                     parameters: ast::PathParameters::none(),
                                 }
-                            ),
+                            ],
                         }),
                         span:sp(7,8),
                         attrs: ThinVec::new(),
@@ -860,12 +786,12 @@ mod tests {
                            node: ast::ExprKind::Path(None, ast::Path {
                                span:sp(0,1),
                                global:false,
-                               segments: vec!(
+                               segments: vec![
                                 ast::PathSegment {
                                     identifier: str_to_ident("b"),
                                     parameters: ast::PathParameters::none(),
                                 }
-                               ),
+                               ],
                             }),
                            span: sp(0,1),
                            attrs: ThinVec::new()})),
@@ -902,18 +828,18 @@ mod tests {
                             attrs:Vec::new(),
                             id: ast::DUMMY_NODE_ID,
                             node: ast::ItemKind::Fn(P(ast::FnDecl {
-                                inputs: vec!(ast::Arg{
+                                inputs: vec![ast::Arg{
                                     ty: P(ast::Ty{id: ast::DUMMY_NODE_ID,
                                                   node: ast::TyKind::Path(None, ast::Path{
                                         span:sp(10,13),
                                         global:false,
-                                        segments: vec!(
+                                        segments: vec![
                                             ast::PathSegment {
                                                 identifier:
                                                     str_to_ident("i32"),
                                                 parameters: ast::PathParameters::none(),
                                             }
-                                        ),
+                                        ],
                                         }),
                                         span:sp(10,13)
                                     }),
@@ -929,7 +855,7 @@ mod tests {
                                             span: sp(6,7)
                                     }),
                                         id: ast::DUMMY_NODE_ID
-                                    }),
+                                    }],
                                 output: ast::FunctionRetTy::Default(sp(15, 15)),
                                 variadic: false
                             }),
@@ -949,14 +875,14 @@ mod tests {
                                         span: syntax_pos::DUMMY_SP,
                                     },
                                     P(ast::Block {
-                                        stmts: vec!(ast::Stmt {
+                                        stmts: vec![ast::Stmt {
                                             node: ast::StmtKind::Semi(P(ast::Expr{
                                                 id: ast::DUMMY_NODE_ID,
                                                 node: ast::ExprKind::Path(None,
                                                       ast::Path{
                                                         span:sp(17,18),
                                                         global:false,
-                                                        segments: vec!(
+                                                        segments: vec![
                                                             ast::PathSegment {
                                                                 identifier:
                                                                 str_to_ident(
@@ -964,12 +890,12 @@ mod tests {
                                                                 parameters:
                                                                 ast::PathParameters::none(),
                                                             }
-                                                        ),
+                                                        ],
                                                       }),
                                                 span: sp(17,18),
                                                 attrs: ThinVec::new()})),
                                             id: ast::DUMMY_NODE_ID,
-                                            span: sp(17,19)}),
+                                            span: sp(17,19)}],
                                         id: ast::DUMMY_NODE_ID,
                                         rules: ast::BlockCheckMode::Default, // no idea
                                         span: sp(15,21),
@@ -1069,13 +995,13 @@ mod tests {
 
         let name = "<source>".to_string();
         let source = "/// doc comment\r\nfn foo() {}".to_string();
-        let item = parse_item_from_source_str(name.clone(), source, Vec::new(), &sess)
+        let item = parse_item_from_source_str(name.clone(), source, &sess)
             .unwrap().unwrap();
         let doc = first_attr_value_str_by_name(&item.attrs, "doc").unwrap();
         assert_eq!(&doc[..], "/// doc comment");
 
         let source = "/// doc comment\r\n/// line 2\r\nfn foo() {}".to_string();
-        let item = parse_item_from_source_str(name.clone(), source, Vec::new(), &sess)
+        let item = parse_item_from_source_str(name.clone(), source, &sess)
             .unwrap().unwrap();
         let docs = item.attrs.iter().filter(|a| &*a.name() == "doc")
                     .map(|a| a.value_str().unwrap().to_string()).collect::<Vec<_>>();
@@ -1083,7 +1009,7 @@ mod tests {
         assert_eq!(&docs[..], b);
 
         let source = "/** doc comment\r\n *  with CRLF */\r\nfn foo() {}".to_string();
-        let item = parse_item_from_source_str(name, source, Vec::new(), &sess).unwrap().unwrap();
+        let item = parse_item_from_source_str(name, source, &sess).unwrap().unwrap();
         let doc = first_attr_value_str_by_name(&item.attrs, "doc").unwrap();
         assert_eq!(&doc[..], "/** doc comment\n *  with CRLF */");
     }
@@ -1092,7 +1018,7 @@ mod tests {
     fn ttdelim_span() {
         let sess = ParseSess::new();
         let expr = parse::parse_expr_from_source_str("foo".to_string(),
-            "foo!( fn main() { body } )".to_string(), vec![], &sess).unwrap();
+            "foo!( fn main() { body } )".to_string(), &sess).unwrap();
 
         let tts = match expr.node {
             ast::ExprKind::Mac(ref mac) => mac.node.tts.clone(),
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index d0936fd981b..b80aa667be6 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -15,7 +15,7 @@ use ast::Unsafety;
 use ast::{Mod, Arg, Arm, Attribute, BindingMode, TraitItemKind};
 use ast::Block;
 use ast::{BlockCheckMode, CaptureBy};
-use ast::{Constness, Crate, CrateConfig};
+use ast::{Constness, Crate};
 use ast::Defaultness;
 use ast::EnumDef;
 use ast::{Expr, ExprKind, RangeLimits};
@@ -48,8 +48,7 @@ use parse::classify;
 use parse::common::SeqSep;
 use parse::lexer::{Reader, TokenAndSpan};
 use parse::obsolete::ObsoleteSyntax;
-use parse::token::{self, intern, MatchNt, SubstNt, SpecialVarNt, InternedString};
-use parse::token::{keywords, SpecialMacroVar};
+use parse::token::{self, intern, keywords, MatchNt, SubstNt, InternedString};
 use parse::{new_sub_parser_from_file, ParseSess};
 use util::parser::{AssocOp, Fixity};
 use print::pprust;
@@ -237,6 +236,31 @@ fn maybe_append(mut lhs: Vec<Attribute>, rhs: Option<Vec<Attribute>>)
     lhs
 }
 
+#[derive(PartialEq)]
+enum PrevTokenKind {
+    DocComment,
+    Comma,
+    Interpolated,
+    Eof,
+    Other,
+}
+
+// Simple circular buffer used for keeping few next tokens.
+#[derive(Default)]
+struct LookaheadBuffer {
+    buffer: [TokenAndSpan; LOOKAHEAD_BUFFER_CAPACITY],
+    start: usize,
+    end: usize,
+}
+
+const LOOKAHEAD_BUFFER_CAPACITY: usize = 8;
+
+impl LookaheadBuffer {
+    fn len(&self) -> usize {
+        (LOOKAHEAD_BUFFER_CAPACITY + self.end - self.start) % LOOKAHEAD_BUFFER_CAPACITY
+    }
+}
+
 /* ident is handled by common.rs */
 
 pub struct Parser<'a> {
@@ -245,16 +269,11 @@ pub struct Parser<'a> {
     pub token: token::Token,
     /// the span of the current token:
     pub span: Span,
-    /// the span of the prior token:
-    pub last_span: Span,
-    pub cfg: CrateConfig,
-    /// the previous token or None (only stashed sometimes).
-    pub last_token: Option<Box<token::Token>>,
-    last_token_interpolated: bool,
-    last_token_eof: bool,
-    pub buffer: [TokenAndSpan; 4],
-    pub buffer_start: isize,
-    pub buffer_end: isize,
+    /// the span of the previous token:
+    pub prev_span: Span,
+    /// the previous token kind
+    prev_token_kind: PrevTokenKind,
+    lookahead_buffer: LookaheadBuffer,
     pub tokens_consumed: usize,
     pub restrictions: Restrictions,
     pub quote_depth: usize, // not (yet) related to the quasiquoter
@@ -338,11 +357,7 @@ impl From<P<Expr>> for LhsExpr {
 }
 
 impl<'a> Parser<'a> {
-    pub fn new(sess: &'a ParseSess,
-               cfg: ast::CrateConfig,
-               mut rdr: Box<Reader+'a>)
-               -> Parser<'a>
-    {
+    pub fn new(sess: &'a ParseSess, mut rdr: Box<Reader+'a>) -> Self {
         let tok0 = rdr.real_token();
         let span = tok0.sp;
         let mut directory = match span {
@@ -350,29 +365,15 @@ impl<'a> Parser<'a> {
             _ => PathBuf::from(sess.codemap().span_to_filename(span)),
         };
         directory.pop();
-        let placeholder = TokenAndSpan {
-            tok: token::Underscore,
-            sp: span,
-        };
 
         Parser {
             reader: rdr,
             sess: sess,
-            cfg: cfg,
             token: tok0.tok,
             span: span,
-            last_span: span,
-            last_token: None,
-            last_token_interpolated: false,
-            last_token_eof: false,
-            buffer: [
-                placeholder.clone(),
-                placeholder.clone(),
-                placeholder.clone(),
-                placeholder.clone(),
-            ],
-            buffer_start: 0,
-            buffer_end: 0,
+            prev_span: span,
+            prev_token_kind: PrevTokenKind::Other,
+            lookahead_buffer: Default::default(),
             tokens_consumed: 0,
             restrictions: Restrictions::empty(),
             quote_depth: 0,
@@ -409,8 +410,7 @@ impl<'a> Parser<'a> {
 
     pub fn unexpected_last<T>(&self, t: &token::Token) -> PResult<'a, T> {
         let token_str = Parser::token_to_string(t);
-        let last_span = self.last_span;
-        Err(self.span_fatal(last_span, &format!("unexpected token: `{}`", token_str)))
+        Err(self.span_fatal(self.prev_span, &format!("unexpected token: `{}`", token_str)))
     }
 
     pub fn unexpected<T>(&mut self) -> PResult<'a, T> {
@@ -500,8 +500,8 @@ impl<'a> Parser<'a> {
                                  expr: PResult<'a, P<Expr>>)
                                  -> PResult<'a, (Span, P<Expr>)> {
         expr.map(|e| {
-            if self.last_token_interpolated {
-                (self.last_span, e)
+            if self.prev_token_kind == PrevTokenKind::Interpolated {
+                (self.prev_span, e)
             } else {
                 (e.span, e)
             }
@@ -520,30 +520,23 @@ impl<'a> Parser<'a> {
                 self.bug("ident interpolation not converted to real token");
             }
             _ => {
-                let last_token = self.last_token.clone().map(|t| *t);
-                Err(match last_token {
-                    Some(token::DocComment(_)) => self.span_fatal_help(self.last_span,
+                Err(if self.prev_token_kind == PrevTokenKind::DocComment {
+                    self.span_fatal_help(self.prev_span,
                         "found a documentation comment that doesn't document anything",
                         "doc comments must come before what they document, maybe a comment was \
-                        intended with `//`?"),
-                    _ => {
+                        intended with `//`?")
+                    } else {
                         let mut err = self.fatal(&format!("expected identifier, found `{}`",
                                                           self.this_token_to_string()));
                         if self.token == token::Underscore {
                             err.note("`_` is a wildcard pattern, not an identifier");
                         }
                         err
-                    }
-                })
+                    })
             }
         }
     }
 
-    fn parse_ident_into_path(&mut self) -> PResult<'a, ast::Path> {
-        let ident = self.parse_ident()?;
-        Ok(ast::Path::from_ident(self.last_span, ident))
-    }
-
     /// Check if the next token is `tok`, and return `true` if so.
     ///
     /// This method will automatically add `tok` to `expected_tokens` if `tok` is not
@@ -808,10 +801,12 @@ impl<'a> Parser<'a> {
     /// Eat and discard tokens until one of `kets` is encountered. Respects token trees,
     /// passes through any errors encountered. Used for error recovery.
     pub fn eat_to_tokens(&mut self, kets: &[&token::Token]) {
+        let handler = self.diagnostic();
+
         self.parse_seq_to_before_tokens(kets,
                                         SeqSep::none(),
                                         |p| p.parse_token_tree(),
-                                        |mut e| e.cancel());
+                                        |mut e| handler.cancel(&mut e));
     }
 
     /// Parse a sequence, including the closing delimiter. The function
@@ -853,7 +848,7 @@ impl<'a> Parser<'a> {
               Fe: FnMut(DiagnosticBuilder)
     {
         let mut first: bool = true;
-        let mut v = vec!();
+        let mut v = vec![];
         while !kets.contains(&&self.token) {
             match sep.sep {
                 Some(ref t) => {
@@ -923,39 +918,29 @@ impl<'a> Parser<'a> {
 
     /// Advance the parser by one token
     pub fn bump(&mut self) {
-        if self.last_token_eof {
+        if self.prev_token_kind == PrevTokenKind::Eof {
             // Bumping after EOF is a bad sign, usually an infinite loop.
             self.bug("attempted to bump the parser past EOF (may be stuck in a loop)");
         }
 
-        if self.token == token::Eof {
-            self.last_token_eof = true;
-        }
+        self.prev_span = self.span;
 
-        self.last_span = self.span;
-        // Stash token for error recovery (sometimes; clone is not necessarily cheap).
-        self.last_token = if self.token.is_ident() ||
-                          self.token.is_path() ||
-                          self.token.is_doc_comment() ||
-                          self.token == token::Comma {
-            Some(Box::new(self.token.clone()))
-        } else {
-            None
+        // Record last token kind for possible error recovery.
+        self.prev_token_kind = match self.token {
+            token::DocComment(..) => PrevTokenKind::DocComment,
+            token::Comma => PrevTokenKind::Comma,
+            token::Interpolated(..) => PrevTokenKind::Interpolated,
+            token::Eof => PrevTokenKind::Eof,
+            _ => PrevTokenKind::Other,
         };
-        self.last_token_interpolated = self.token.is_interpolated();
-        let next = if self.buffer_start == self.buffer_end {
+
+        let next = if self.lookahead_buffer.start == self.lookahead_buffer.end {
             self.reader.real_token()
         } else {
             // Avoid token copies with `replace`.
-            let buffer_start = self.buffer_start as usize;
-            let next_index = (buffer_start + 1) & 3;
-            self.buffer_start = next_index as isize;
-
-            let placeholder = TokenAndSpan {
-                tok: token::Underscore,
-                sp: self.span,
-            };
-            mem::replace(&mut self.buffer[buffer_start], placeholder)
+            let old_start = self.lookahead_buffer.start;
+            self.lookahead_buffer.start = (old_start + 1) % LOOKAHEAD_BUFFER_CAPACITY;
+            mem::replace(&mut self.lookahead_buffer.buffer[old_start], Default::default())
         };
         self.span = next.sp;
         self.token = next.tok;
@@ -978,32 +963,32 @@ impl<'a> Parser<'a> {
                      next: token::Token,
                      lo: BytePos,
                      hi: BytePos) {
-        self.last_span = mk_sp(self.span.lo, lo);
-        // It would be incorrect to just stash current token, but fortunately
-        // for tokens currently using `bump_with`, last_token will be of no
-        // use anyway.
-        self.last_token = None;
-        self.last_token_interpolated = false;
+        self.prev_span = mk_sp(self.span.lo, lo);
+        // It would be incorrect to record the kind of the current token, but
+        // fortunately for tokens currently using `bump_with`, the
+        // prev_token_kind will be of no use anyway.
+        self.prev_token_kind = PrevTokenKind::Other;
         self.span = mk_sp(lo, hi);
         self.token = next;
         self.expected_tokens.clear();
     }
 
-    pub fn buffer_length(&mut self) -> isize {
-        if self.buffer_start <= self.buffer_end {
-            return self.buffer_end - self.buffer_start;
-        }
-        return (4 - self.buffer_start) + self.buffer_end;
-    }
-    pub fn look_ahead<R, F>(&mut self, distance: usize, f: F) -> R where
+    pub fn look_ahead<R, F>(&mut self, dist: usize, f: F) -> R where
         F: FnOnce(&token::Token) -> R,
     {
-        let dist = distance as isize;
-        while self.buffer_length() < dist {
-            self.buffer[self.buffer_end as usize] = self.reader.real_token();
-            self.buffer_end = (self.buffer_end + 1) & 3;
+        if dist == 0 {
+            f(&self.token)
+        } else if dist < LOOKAHEAD_BUFFER_CAPACITY {
+            while self.lookahead_buffer.len() < dist {
+                self.lookahead_buffer.buffer[self.lookahead_buffer.end] = self.reader.real_token();
+                self.lookahead_buffer.end =
+                    (self.lookahead_buffer.end + 1) % LOOKAHEAD_BUFFER_CAPACITY;
+            }
+            let index = (self.lookahead_buffer.start + dist - 1) % LOOKAHEAD_BUFFER_CAPACITY;
+            f(&self.lookahead_buffer.buffer[index].tok)
+        } else {
+            self.bug("lookahead distance is too large");
         }
-        f(&self.buffer[((self.buffer_start + dist - 1) & 3) as usize].tok)
     }
     pub fn fatal(&self, m: &str) -> DiagnosticBuilder<'a> {
         self.sess.span_diagnostic.struct_span_fatal(self.span, m)
@@ -1040,6 +1025,10 @@ impl<'a> Parser<'a> {
         self.sess.span_diagnostic.abort_if_errors();
     }
 
+    fn cancel(&self, err: &mut DiagnosticBuilder) {
+        self.sess.span_diagnostic.cancel(err)
+    }
+
     pub fn diagnostic(&self) -> &'a errors::Handler {
         &self.sess.span_diagnostic
     }
@@ -1115,14 +1104,12 @@ impl<'a> Parser<'a> {
         let bounds = self.parse_ty_param_bounds(BoundParsingMode::Modified)?;
 
         if !bounds.iter().any(|b| if let TraitTyParamBound(..) = *b { true } else { false }) {
-            let last_span = self.last_span;
-            self.span_err(last_span, "at least one trait must be specified");
+            self.span_err(self.prev_span, "at least one trait must be specified");
         }
 
         Ok(ast::TyKind::ImplTrait(bounds))
     }
 
-
     pub fn parse_ty_path(&mut self) -> PResult<'a, TyKind> {
         Ok(TyKind::Path(None, self.parse_path(PathStyle::Type)?))
     }
@@ -1180,7 +1167,7 @@ impl<'a> Parser<'a> {
         let lo = self.span.lo;
 
         let (name, node) = if self.eat_keyword(keywords::Type) {
-            let TyParam {ident, bounds, default, ..} = self.parse_ty_param()?;
+            let TyParam {ident, bounds, default, ..} = self.parse_ty_param(vec![])?;
             self.expect(&token::Semi)?;
             (ident, TraitItemKind::Type(bounds, default))
         } else if self.is_const_item() {
@@ -1198,100 +1185,93 @@ impl<'a> Parser<'a> {
                 None
             };
             (ident, TraitItemKind::Const(ty, default))
-        } else if !self.token.is_any_keyword()
-            && self.look_ahead(1, |t| *t == token::Not)
-            && (self.look_ahead(2, |t| *t == token::OpenDelim(token::Paren))
-                || self.look_ahead(2, |t| *t == token::OpenDelim(token::Brace))) {
-                // trait item macro.
-                // code copied from parse_macro_use_or_failure... abstraction!
-                let lo = self.span.lo;
-                let pth = self.parse_ident_into_path()?;
-                self.expect(&token::Not)?;
+        } else if self.token.is_path_start() {
+            // trait item macro.
+            // code copied from parse_macro_use_or_failure... abstraction!
+            let lo = self.span.lo;
+            let pth = self.parse_path(PathStyle::Mod)?;
+            self.expect(&token::Not)?;
 
-                // eat a matched-delimiter token tree:
-                let delim = self.expect_open_delim()?;
-                let tts = self.parse_seq_to_end(&token::CloseDelim(delim),
-                                             SeqSep::none(),
-                                             |pp| pp.parse_token_tree())?;
-                let m_ = Mac_ { path: pth, tts: tts };
-                let m: ast::Mac = codemap::Spanned { node: m_,
-                                                     span: mk_sp(lo,
-                                                                 self.last_span.hi) };
-                if delim != token::Brace {
-                    self.expect(&token::Semi)?
-                }
-                (keywords::Invalid.ident(), ast::TraitItemKind::Macro(m))
-            } else {
-                let (constness, unsafety, abi) = match self.parse_fn_front_matter() {
-                    Ok(cua) => cua,
-                    Err(e) => {
-                        loop {
-                            match self.token {
-                                token::Eof => break,
-                                token::CloseDelim(token::Brace) |
-                                token::Semi => {
-                                    self.bump();
-                                    break;
-                                }
-                                token::OpenDelim(token::Brace) => {
-                                    self.parse_token_tree()?;
-                                    break;
-                                }
-                                _ => self.bump()
+            // eat a matched-delimiter token tree:
+            let delim = self.expect_open_delim()?;
+            let tts = self.parse_seq_to_end(&token::CloseDelim(delim),
+                                            SeqSep::none(),
+                                            |pp| pp.parse_token_tree())?;
+            if delim != token::Brace {
+                self.expect(&token::Semi)?
+            }
+
+            let mac = spanned(lo, self.prev_span.hi, Mac_ { path: pth, tts: tts });
+            (keywords::Invalid.ident(), ast::TraitItemKind::Macro(mac))
+        } else {
+            let (constness, unsafety, abi) = match self.parse_fn_front_matter() {
+                Ok(cua) => cua,
+                Err(e) => {
+                    loop {
+                        match self.token {
+                            token::Eof => break,
+                            token::CloseDelim(token::Brace) |
+                            token::Semi => {
+                                self.bump();
+                                break;
+                            }
+                            token::OpenDelim(token::Brace) => {
+                                self.parse_token_tree()?;
+                                break;
                             }
+                            _ => self.bump(),
                         }
-
-                        return Err(e);
                     }
-                };
 
-                let ident = self.parse_ident()?;
-                let mut generics = self.parse_generics()?;
+                    return Err(e);
+                }
+            };
 
-                let d = self.parse_fn_decl_with_self(|p: &mut Parser<'a>|{
-                    // This is somewhat dubious; We don't want to allow
-                    // argument names to be left off if there is a
-                    // definition...
-                    p.parse_arg_general(false)
-                })?;
+            let ident = self.parse_ident()?;
+            let mut generics = self.parse_generics()?;
 
-                generics.where_clause = self.parse_where_clause()?;
-                let sig = ast::MethodSig {
-                    unsafety: unsafety,
-                    constness: constness,
-                    decl: d,
-                    generics: generics,
-                    abi: abi,
-                };
+            let d = self.parse_fn_decl_with_self(|p: &mut Parser<'a>|{
+                // This is somewhat dubious; We don't want to allow
+                // argument names to be left off if there is a
+                // definition...
+                p.parse_arg_general(false)
+            })?;
 
-                let body = match self.token {
-                    token::Semi => {
-                        self.bump();
-                        debug!("parse_trait_methods(): parsing required method");
-                        None
-                    }
-                    token::OpenDelim(token::Brace) => {
-                        debug!("parse_trait_methods(): parsing provided method");
-                        let (inner_attrs, body) =
-                            self.parse_inner_attrs_and_block()?;
-                        attrs.extend(inner_attrs.iter().cloned());
-                        Some(body)
-                    }
+            generics.where_clause = self.parse_where_clause()?;
+            let sig = ast::MethodSig {
+                unsafety: unsafety,
+                constness: constness,
+                decl: d,
+                generics: generics,
+                abi: abi,
+            };
 
-                    _ => {
-                        let token_str = self.this_token_to_string();
-                        return Err(self.fatal(&format!("expected `;` or `{{`, found `{}`",
-                                                    token_str)[..]))
-                    }
-                };
-                (ident, ast::TraitItemKind::Method(sig, body))
+            let body = match self.token {
+                token::Semi => {
+                    self.bump();
+                    debug!("parse_trait_methods(): parsing required method");
+                    None
+                }
+                token::OpenDelim(token::Brace) => {
+                    debug!("parse_trait_methods(): parsing provided method");
+                    let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
+                    attrs.extend(inner_attrs.iter().cloned());
+                    Some(body)
+                }
+                _ => {
+                    let token_str = self.this_token_to_string();
+                    return Err(self.fatal(&format!("expected `;` or `{{`, found `{}`", token_str)));
+                }
             };
+            (ident, ast::TraitItemKind::Method(sig, body))
+        };
+
         Ok(TraitItem {
             id: ast::DUMMY_NODE_ID,
             ident: name,
             attrs: attrs,
             node: node,
-            span: mk_sp(lo, self.last_span.hi),
+            span: mk_sp(lo, self.prev_span.hi),
         })
     }
 
@@ -1338,13 +1318,13 @@ impl<'a> Parser<'a> {
         // In type grammar, `+` is treated like a binary operator,
         // and hence both L and R side are required.
         if bounds.is_empty() {
-            let last_span = self.last_span;
-            self.span_err(last_span,
+            let prev_span = self.prev_span;
+            self.span_err(prev_span,
                           "at least one type parameter bound \
                           must be specified");
         }
 
-        let sp = mk_sp(lo, self.last_span.hi);
+        let sp = mk_sp(lo, self.prev_span.hi);
         let sum = ast::TyKind::ObjectSum(lhs, bounds);
         Ok(P(Ty {id: ast::DUMMY_NODE_ID, node: sum, span: sp}))
     }
@@ -1394,8 +1374,8 @@ impl<'a> Parser<'a> {
             // Parse the `; e` in `[ i32; e ]`
             // where `e` is a const expression
             let t = match self.maybe_parse_fixed_length_of_vec()? {
-                None => TyKind::Vec(t),
-                Some(suffix) => TyKind::FixedLengthVec(t, suffix)
+                None => TyKind::Slice(t),
+                Some(suffix) => TyKind::Array(t, suffix)
             };
             self.expect(&token::CloseDelim(token::Bracket))?;
             t
@@ -1426,9 +1406,8 @@ impl<'a> Parser<'a> {
             TyKind::Path(Some(qself), path)
         } else if self.token.is_path_start() {
             let path = self.parse_path(PathStyle::Type)?;
-            if self.check(&token::Not) {
+            if self.eat(&token::Not) {
                 // MACRO INVOCATION
-                self.bump();
                 let delim = self.expect_open_delim()?;
                 let tts = self.parse_seq_to_end(&token::CloseDelim(delim),
                                                 SeqSep::none(),
@@ -1447,7 +1426,7 @@ impl<'a> Parser<'a> {
             return Err(self.fatal(&msg));
         };
 
-        let sp = mk_sp(lo, self.last_span.hi);
+        let sp = mk_sp(lo, self.prev_span.hi);
         Ok(P(Ty {id: ast::DUMMY_NODE_ID, node: t, span: sp}))
     }
 
@@ -1465,7 +1444,7 @@ impl<'a> Parser<'a> {
         } else if self.eat_keyword(keywords::Const) {
             Mutability::Immutable
         } else {
-            let span = self.last_span;
+            let span = self.prev_span;
             self.span_err(span,
                           "expected mut or const in raw pointer type (use \
                            `*mut T` or `*const T` as appropriate)");
@@ -1508,7 +1487,7 @@ impl<'a> Parser<'a> {
             pat
         } else {
             debug!("parse_arg_general ident_to_pat");
-            let sp = self.last_span;
+            let sp = self.prev_span;
             let spanned = Spanned { span: sp, node: keywords::Invalid.ident() };
             P(Pat {
                 id: ast::DUMMY_NODE_ID,
@@ -1633,7 +1612,7 @@ impl<'a> Parser<'a> {
             let lit = self.parse_lit_token()?;
             lit
         };
-        Ok(codemap::Spanned { node: lit, span: mk_sp(lo, self.last_span.hi) })
+        Ok(codemap::Spanned { node: lit, span: mk_sp(lo, self.prev_span.hi) })
     }
 
     /// matches '-' lit | lit
@@ -1642,11 +1621,11 @@ impl<'a> Parser<'a> {
         let minus_present = self.eat(&token::BinOp(token::Minus));
         let lo = self.span.lo;
         let literal = P(self.parse_lit()?);
-        let hi = self.last_span.hi;
+        let hi = self.prev_span.hi;
         let expr = self.mk_expr(lo, hi, ExprKind::Lit(literal), ThinVec::new());
 
         if minus_present {
-            let minus_hi = self.last_span.hi;
+            let minus_hi = self.prev_span.hi;
             let unary = self.mk_unary(UnOp::Neg, expr);
             Ok(self.mk_expr(minus_lo, minus_hi, unary, ThinVec::new()))
         } else {
@@ -1681,7 +1660,7 @@ impl<'a> Parser<'a> {
     /// `<T as U>::F::a::<S>`
     pub fn parse_qualified_path(&mut self, mode: PathStyle)
                                 -> PResult<'a, (QSelf, ast::Path)> {
-        let span = self.last_span;
+        let span = self.prev_span;
         let self_type = self.parse_ty_sum()?;
         let mut path = if self.eat_keyword(keywords::As) {
             self.parse_path(PathStyle::Type)?
@@ -1714,7 +1693,7 @@ impl<'a> Parser<'a> {
         };
         path.segments.extend(segments);
 
-        path.span.hi = self.last_span.hi;
+        path.span.hi = self.prev_span.hi;
 
         Ok((qself, path))
     }
@@ -1752,7 +1731,7 @@ impl<'a> Parser<'a> {
         };
 
         // Assemble the span.
-        let span = mk_sp(lo, self.last_span.hi);
+        let span = mk_sp(lo, self.prev_span.hi);
 
         // Assemble the result.
         Ok(ast::Path {
@@ -1772,6 +1751,17 @@ impl<'a> Parser<'a> {
             // First, parse an identifier.
             let identifier = self.parse_path_segment_ident()?;
 
+            if self.check(&token::ModSep) && self.look_ahead(1, |t| *t == token::Lt) {
+                self.bump();
+                let prev_span = self.prev_span;
+
+                let mut err = self.diagnostic().struct_span_err(prev_span,
+                    "unexpected token: `::`");
+                err.help(
+                    "use `<...>` instead of `::<...>` if you meant to specify type arguments");
+                err.emit();
+            }
+
             // Parse types, optionally.
             let parameters = if self.eat_lt() {
                 let (lifetimes, types, bindings) = self.parse_generic_values_after_lt()?;
@@ -1782,7 +1772,7 @@ impl<'a> Parser<'a> {
                     bindings: P::from_vec(bindings),
                 })
             } else if self.eat(&token::OpenDelim(token::Paren)) {
-                let lo = self.last_span.lo;
+                let lo = self.prev_span.lo;
 
                 let inputs = self.parse_seq_to_end(
                     &token::CloseDelim(token::Paren),
@@ -1795,7 +1785,7 @@ impl<'a> Parser<'a> {
                     None
                 };
 
-                let hi = self.last_span.hi;
+                let hi = self.prev_span.hi;
 
                 ast::PathParameters::Parenthesized(ast::ParenthesizedParameterData {
                     span: mk_sp(lo, hi),
@@ -1919,10 +1909,22 @@ impl<'a> Parser<'a> {
 
     /// Parses `lifetime_defs = [ lifetime_defs { ',' lifetime_defs } ]` where `lifetime_def  =
     /// lifetime [':' lifetimes]`
-    pub fn parse_lifetime_defs(&mut self) -> PResult<'a, Vec<ast::LifetimeDef>> {
-
+    ///
+    /// If `followed_by_ty_params` is None, then we are in a context
+    /// where only lifetime parameters are allowed, and thus we should
+    /// error if we encounter attributes after the bound lifetimes.
+    ///
+    /// If `followed_by_ty_params` is Some(r), then there may be type
+    /// parameter bindings after the lifetimes, so we should pass
+    /// along the parsed attributes to be attached to the first such
+    /// type parmeter.
+    pub fn parse_lifetime_defs(&mut self,
+                               followed_by_ty_params: Option<&mut Vec<ast::Attribute>>)
+                               -> PResult<'a, Vec<ast::LifetimeDef>>
+    {
         let mut res = Vec::new();
         loop {
+            let attrs = self.parse_outer_attributes()?;
             match self.token {
                 token::Lifetime(_) => {
                     let lifetime = self.parse_lifetime()?;
@@ -1932,11 +1934,20 @@ impl<'a> Parser<'a> {
                         } else {
                             Vec::new()
                         };
-                    res.push(ast::LifetimeDef { lifetime: lifetime,
+                    res.push(ast::LifetimeDef { attrs: attrs.into(),
+                                                lifetime: lifetime,
                                                 bounds: bounds });
                 }
 
                 _ => {
+                    if let Some(recv) = followed_by_ty_params {
+                        assert!(recv.is_empty());
+                        *recv = attrs;
+                    } else {
+                        let msg = "trailing attribute after lifetime parameters";
+                        return Err(self.fatal(msg));
+                    }
+                    debug!("parse_lifetime_defs ret {:?}", res);
                     return Ok(res);
                 }
             }
@@ -2001,17 +2012,30 @@ impl<'a> Parser<'a> {
         }
     }
 
-    /// Parse ident COLON expr
+    /// Parse ident (COLON expr)?
     pub fn parse_field(&mut self) -> PResult<'a, Field> {
         let lo = self.span.lo;
-        let i = self.parse_field_name()?;
-        let hi = self.last_span.hi;
-        self.expect(&token::Colon)?;
-        let e = self.parse_expr()?;
+        let hi;
+
+        // Check if a colon exists one ahead. This means we're parsing a fieldname.
+        let (fieldname, expr, is_shorthand) = if self.look_ahead(1, |t| t == &token::Colon) {
+            let fieldname = self.parse_field_name()?;
+            self.bump();
+            hi = self.prev_span.hi;
+            (fieldname, self.parse_expr()?, false)
+        } else {
+            let fieldname = self.parse_ident()?;
+            hi = self.prev_span.hi;
+
+            // Mimic `x: x` for the `x` field shorthand.
+            let path = ast::Path::from_ident(mk_sp(lo, hi), fieldname);
+            (fieldname, self.mk_expr(lo, hi, ExprKind::Path(None, path), ThinVec::new()), true)
+        };
         Ok(ast::Field {
-            ident: spanned(lo, hi, i),
-            span: mk_sp(lo, e.span.hi),
-            expr: e,
+            ident: spanned(lo, hi, fieldname),
+            span: mk_sp(lo, expr.span.hi),
+            expr: expr,
+            is_shorthand: is_shorthand,
         })
     }
 
@@ -2160,7 +2184,7 @@ impl<'a> Parser<'a> {
                 }
                 self.bump();
 
-                hi = self.last_span.hi;
+                hi = self.prev_span.hi;
                 return if es.len() == 1 && !trailing_comma {
                     Ok(self.mk_expr(lo, hi, ExprKind::Paren(es.into_iter().nth(0).unwrap()), attrs))
                 } else {
@@ -2200,16 +2224,16 @@ impl<'a> Parser<'a> {
                             SeqSep::trailing_allowed(token::Comma),
                             |p| Ok(p.parse_expr()?)
                         )?;
-                        let mut exprs = vec!(first_expr);
+                        let mut exprs = vec![first_expr];
                         exprs.extend(remaining_exprs);
                         ex = ExprKind::Vec(exprs);
                     } else {
                         // Vector with one element.
                         self.expect(&token::CloseDelim(token::Bracket))?;
-                        ex = ExprKind::Vec(vec!(first_expr));
+                        ex = ExprKind::Vec(vec![first_expr]);
                     }
                 }
-                hi = self.last_span.hi;
+                hi = self.prev_span.hi;
             }
             _ => {
                 if self.eat_lt() {
@@ -2219,18 +2243,18 @@ impl<'a> Parser<'a> {
                     return Ok(self.mk_expr(lo, hi, ExprKind::Path(Some(qself), path), attrs));
                 }
                 if self.eat_keyword(keywords::Move) {
-                    let lo = self.last_span.lo;
+                    let lo = self.prev_span.lo;
                     return self.parse_lambda_expr(lo, CaptureBy::Value, attrs);
                 }
                 if self.eat_keyword(keywords::If) {
                     return self.parse_if_expr(attrs);
                 }
                 if self.eat_keyword(keywords::For) {
-                    let lo = self.last_span.lo;
+                    let lo = self.prev_span.lo;
                     return self.parse_for_expr(None, lo, attrs);
                 }
                 if self.eat_keyword(keywords::While) {
-                    let lo = self.last_span.lo;
+                    let lo = self.prev_span.lo;
                     return self.parse_while_expr(None, lo, attrs);
                 }
                 if self.token.is_lifetime() {
@@ -2251,7 +2275,7 @@ impl<'a> Parser<'a> {
                     return Err(self.fatal("expected `while`, `for`, or `loop` after a label"))
                 }
                 if self.eat_keyword(keywords::Loop) {
-                    let lo = self.last_span.lo;
+                    let lo = self.prev_span.lo;
                     return self.parse_loop_expr(None, lo, attrs);
                 }
                 if self.eat_keyword(keywords::Continue) {
@@ -2265,7 +2289,7 @@ impl<'a> Parser<'a> {
                     } else {
                         ExprKind::Continue(None)
                     };
-                    let hi = self.last_span.hi;
+                    let hi = self.prev_span.hi;
                     return Ok(self.mk_expr(lo, hi, ex, attrs));
                 }
                 if self.eat_keyword(keywords::Match) {
@@ -2295,7 +2319,7 @@ impl<'a> Parser<'a> {
                     } else {
                         ex = ExprKind::Break(None);
                     }
-                    hi = self.last_span.hi;
+                    hi = self.prev_span.hi;
                 } else if self.token.is_keyword(keywords::Let) {
                     // Catch this syntax error here, instead of in `check_strict_keywords`, so
                     // that we can explicitly mention that let is not to be used as an expression
@@ -2306,21 +2330,14 @@ impl<'a> Parser<'a> {
                     let pth = self.parse_path(PathStyle::Expr)?;
 
                     // `!`, as an operator, is prefix, so we know this isn't that
-                    if self.check(&token::Not) {
+                    if self.eat(&token::Not) {
                         // MACRO INVOCATION expression
-                        self.bump();
-
                         let delim = self.expect_open_delim()?;
-                        let tts = self.parse_seq_to_end(
-                            &token::CloseDelim(delim),
-                            SeqSep::none(),
-                            |p| p.parse_token_tree())?;
-                        let hi = self.last_span.hi;
-
-                        return Ok(self.mk_mac_expr(lo,
-                                                   hi,
-                                                   Mac_ { path: pth, tts: tts },
-                                                   attrs));
+                        let tts = self.parse_seq_to_end(&token::CloseDelim(delim),
+                                                        SeqSep::none(),
+                                                        |p| p.parse_token_tree())?;
+                        let hi = self.prev_span.hi;
+                        return Ok(self.mk_mac_expr(lo, hi, Mac_ { path: pth, tts: tts }, attrs));
                     }
                     if self.check(&token::OpenDelim(token::Brace)) {
                         // This is a struct literal, unless we're prohibited
@@ -2329,51 +2346,7 @@ impl<'a> Parser<'a> {
                             Restrictions::RESTRICTION_NO_STRUCT_LITERAL
                         );
                         if !prohibited {
-                            // It's a struct literal.
-                            self.bump();
-                            let mut fields = Vec::new();
-                            let mut base = None;
-
-                            attrs.extend(self.parse_inner_attributes()?);
-
-                            while self.token != token::CloseDelim(token::Brace) {
-                                if self.eat(&token::DotDot) {
-                                    match self.parse_expr() {
-                                        Ok(e) => {
-                                            base = Some(e);
-                                        }
-                                        Err(mut e) => {
-                                            e.emit();
-                                            self.recover_stmt();
-                                        }
-                                    }
-                                    break;
-                                }
-
-                                match self.parse_field() {
-                                    Ok(f) => fields.push(f),
-                                    Err(mut e) => {
-                                        e.emit();
-                                        self.recover_stmt();
-                                        break;
-                                    }
-                                }
-
-                                match self.expect_one_of(&[token::Comma],
-                                                         &[token::CloseDelim(token::Brace)]) {
-                                    Ok(()) => {}
-                                    Err(mut e) => {
-                                        e.emit();
-                                        self.recover_stmt();
-                                        break;
-                                    }
-                                }
-                            }
-
-                            hi = self.span.hi;
-                            self.expect(&token::CloseDelim(token::Brace))?;
-                            ex = ExprKind::Struct(pth, fields, base);
-                            return Ok(self.mk_expr(lo, hi, ex, attrs));
+                            return self.parse_struct_expr(lo, pth, attrs);
                         }
                     }
 
@@ -2386,7 +2359,7 @@ impl<'a> Parser<'a> {
                             ex = ExprKind::Lit(P(lit));
                         }
                         Err(mut err) => {
-                            err.cancel();
+                            self.cancel(&mut err);
                             let msg = format!("expected expression, found {}",
                                               self.this_token_descr());
                             return Err(self.fatal(&msg));
@@ -2399,6 +2372,53 @@ impl<'a> Parser<'a> {
         return Ok(self.mk_expr(lo, hi, ex, attrs));
     }
 
+    fn parse_struct_expr(&mut self, lo: BytePos, pth: ast::Path, mut attrs: ThinVec<Attribute>)
+                         -> PResult<'a, P<Expr>> {
+        self.bump();
+        let mut fields = Vec::new();
+        let mut base = None;
+
+        attrs.extend(self.parse_inner_attributes()?);
+
+        while self.token != token::CloseDelim(token::Brace) {
+            if self.eat(&token::DotDot) {
+                match self.parse_expr() {
+                    Ok(e) => {
+                        base = Some(e);
+                    }
+                    Err(mut e) => {
+                        e.emit();
+                        self.recover_stmt();
+                    }
+                }
+                break;
+            }
+
+            match self.parse_field() {
+                Ok(f) => fields.push(f),
+                Err(mut e) => {
+                    e.emit();
+                    self.recover_stmt();
+                    break;
+                }
+            }
+
+            match self.expect_one_of(&[token::Comma],
+                                     &[token::CloseDelim(token::Brace)]) {
+                Ok(()) => {}
+                Err(mut e) => {
+                    e.emit();
+                    self.recover_stmt();
+                    break;
+                }
+            }
+        }
+
+        let hi = self.span.hi;
+        self.expect(&token::CloseDelim(token::Brace))?;
+        return Ok(self.mk_expr(lo, hi, ExprKind::Struct(pth, fields, base), attrs));
+    }
+
     fn parse_or_use_outer_attributes(&mut self,
                                      already_parsed_attrs: Option<ThinVec<Attribute>>)
                                      -> PResult<'a, ThinVec<Attribute>> {
@@ -2481,8 +2501,8 @@ impl<'a> Parser<'a> {
         };
 
         if !bindings.is_empty() {
-            let last_span = self.last_span;
-            self.span_err(last_span, "type bindings are only permitted on trait paths");
+            let prev_span = self.prev_span;
+            self.span_err(prev_span, "type bindings are only permitted on trait paths");
         }
 
         Ok(match self.token {
@@ -2494,7 +2514,7 @@ impl<'a> Parser<'a> {
                     SeqSep::trailing_allowed(token::Comma),
                     |p| Ok(p.parse_expr()?)
                 )?;
-                let hi = self.last_span.hi;
+                let hi = self.prev_span.hi;
 
                 es.insert(0, self_value);
                 let id = spanned(ident_span.lo, ident_span.hi, ident);
@@ -2504,8 +2524,8 @@ impl<'a> Parser<'a> {
             // Field access.
             _ => {
                 if !tys.is_empty() {
-                    let last_span = self.last_span;
-                    self.span_err(last_span,
+                    let prev_span = self.prev_span;
+                    self.span_err(prev_span,
                                   "field expressions may not \
                                    have type parameters");
                 }
@@ -2523,7 +2543,7 @@ impl<'a> Parser<'a> {
         loop {
             // expr?
             while self.eat(&token::Question) {
-                let hi = self.last_span.hi;
+                let hi = self.prev_span.hi;
                 e = self.mk_expr(lo, hi, ExprKind::Try(e), ThinVec::new());
             }
 
@@ -2531,7 +2551,7 @@ impl<'a> Parser<'a> {
             if self.eat(&token::Dot) {
                 match self.token {
                   token::Ident(i) => {
-                    let dot_pos = self.last_span.hi;
+                    let dot_pos = self.prev_span.hi;
                     hi = self.span.hi;
                     self.bump();
 
@@ -2543,7 +2563,7 @@ impl<'a> Parser<'a> {
                     // A tuple index may not have a suffix
                     self.expect_no_suffix(sp, "tuple index", suf);
 
-                    let dot = self.last_span.hi;
+                    let dot = self.prev_span.hi;
                     hi = self.span.hi;
                     self.bump();
 
@@ -2555,16 +2575,16 @@ impl<'a> Parser<'a> {
                             e = self.mk_expr(lo, hi, field, ThinVec::new());
                         }
                         None => {
-                            let last_span = self.last_span;
-                            self.span_err(last_span, "invalid tuple or tuple struct index");
+                            let prev_span = self.prev_span;
+                            self.span_err(prev_span, "invalid tuple or tuple struct index");
                         }
                     }
                   }
                   token::Literal(token::Float(n), _suf) => {
                     self.bump();
-                    let last_span = self.last_span;
+                    let prev_span = self.prev_span;
                     let fstr = n.as_str();
-                    let mut err = self.diagnostic().struct_span_err(last_span,
+                    let mut err = self.diagnostic().struct_span_err(prev_span,
                         &format!("unexpected token: `{}`", n.as_str()));
                     if fstr.chars().all(|x| "0123456789.".contains(x)) {
                         let float = match fstr.parse::<f64>().ok() {
@@ -2583,7 +2603,7 @@ impl<'a> Parser<'a> {
                     let actual = self.this_token_to_string();
                     self.span_err(self.span, &format!("unexpected token: `{}`", actual));
 
-                    let dot_pos = self.last_span.hi;
+                    let dot_pos = self.prev_span.hi;
                     e = self.parse_dot_suffix(keywords::Invalid.ident(),
                                               mk_sp(dot_pos, dot_pos),
                                               e, lo)?;
@@ -2601,7 +2621,7 @@ impl<'a> Parser<'a> {
                     SeqSep::trailing_allowed(token::Comma),
                     |p| Ok(p.parse_expr()?)
                 )?;
-                hi = self.last_span.hi;
+                hi = self.prev_span.hi;
 
                 let nd = self.mk_call(e, es);
                 e = self.mk_expr(lo, hi, nd, ThinVec::new());
@@ -2647,8 +2667,12 @@ impl<'a> Parser<'a> {
                                           num_captures: name_num
                                       })));
                 } else if self.token.is_keyword(keywords::Crate) {
+                    let ident = match self.token {
+                        token::Ident(id) => ast::Ident { name: token::intern("$crate"), ..id },
+                        _ => unreachable!(),
+                    };
                     self.bump();
-                    return Ok(TokenTree::Token(sp, SpecialVarNt(SpecialMacroVar::CrateMacroVar)));
+                    return Ok(TokenTree::Token(sp, token::Ident(ident)));
                 } else {
                     sp = mk_sp(sp.lo, self.span.hi);
                     self.parse_ident().unwrap_or_else(|mut e| {
@@ -2944,8 +2968,8 @@ impl<'a> Parser<'a> {
         self.expected_tokens.push(TokenType::Operator);
         while let Some(op) = AssocOp::from_token(&self.token) {
 
-            let lhs_span = if self.last_token_interpolated {
-                self.last_span
+            let lhs_span = if self.prev_token_kind == PrevTokenKind::Interpolated {
+                self.prev_span
             } else {
                 lhs.span
             };
@@ -3138,7 +3162,7 @@ impl<'a> Parser<'a> {
         if self.check_keyword(keywords::Let) {
             return self.parse_if_let_expr(attrs);
         }
-        let lo = self.last_span.lo;
+        let lo = self.prev_span.lo;
         let cond = self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL, None)?;
         let thn = self.parse_block()?;
         let mut els: Option<P<Expr>> = None;
@@ -3154,7 +3178,7 @@ impl<'a> Parser<'a> {
     /// Parse an 'if let' expression ('if' token already eaten)
     pub fn parse_if_let_expr(&mut self, attrs: ThinVec<Attribute>)
                              -> PResult<'a, P<Expr>> {
-        let lo = self.last_span.lo;
+        let lo = self.prev_span.lo;
         self.expect_keyword(keywords::Let)?;
         let pat = self.parse_pat()?;
         self.expect(&token::Eq)?;
@@ -3177,7 +3201,7 @@ impl<'a> Parser<'a> {
                              -> PResult<'a, P<Expr>>
     {
         let decl = self.parse_fn_block_decl()?;
-        let decl_hi = self.last_span.hi;
+        let decl_hi = self.prev_span.hi;
         let body = match decl.output {
             FunctionRetTy::Default(_) => {
                 // If no explicit return type is given, parse any
@@ -3230,7 +3254,7 @@ impl<'a> Parser<'a> {
         let (iattrs, loop_block) = self.parse_inner_attrs_and_block()?;
         attrs.extend(iattrs);
 
-        let hi = self.last_span.hi;
+        let hi = self.prev_span.hi;
 
         Ok(self.mk_expr(span_lo, hi,
                         ExprKind::ForLoop(pat, expr, loop_block, opt_ident),
@@ -3278,8 +3302,8 @@ impl<'a> Parser<'a> {
 
     // `match` token already eaten
     fn parse_match_expr(&mut self, mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
-        let match_span = self.last_span;
-        let lo = self.last_span.lo;
+        let match_span = self.prev_span;
+        let lo = self.prev_span.lo;
         let discriminant = self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL,
                                                None)?;
         if let Err(mut e) = self.expect(&token::OpenDelim(token::Brace)) {
@@ -3401,7 +3425,7 @@ impl<'a> Parser<'a> {
                 }
             } else if ddpos.is_some() && self.eat(&token::DotDot) {
                 // Emit a friendly error, ignore `..` and continue parsing
-                self.span_err(self.last_span, "`..` can only be used once per \
+                self.span_err(self.prev_span, "`..` can only be used once per \
                                                tuple or tuple struct pattern");
             } else {
                 fields.push(self.parse_pat()?);
@@ -3512,7 +3536,7 @@ impl<'a> Parser<'a> {
                 let is_ref = self.eat_keyword(keywords::Ref);
                 let is_mut = self.eat_keyword(keywords::Mut);
                 let fieldname = self.parse_ident()?;
-                hi = self.last_span.hi;
+                hi = self.prev_span.hi;
 
                 let bind_type = match (is_ref, is_mut) {
                     (true, true) => BindingMode::ByRef(Mutability::Mutable),
@@ -3520,7 +3544,7 @@ impl<'a> Parser<'a> {
                     (false, true) => BindingMode::ByValue(Mutability::Mutable),
                     (false, false) => BindingMode::ByValue(Mutability::Immutable),
                 };
-                let fieldpath = codemap::Spanned{span:self.last_span, node:fieldname};
+                let fieldpath = codemap::Spanned{span:self.prev_span, node:fieldname};
                 let fieldpat = P(ast::Pat{
                     id: ast::DUMMY_NODE_ID,
                     node: PatKind::Ident(bind_type, fieldpath, None),
@@ -3559,7 +3583,7 @@ impl<'a> Parser<'a> {
                 // Parse an unqualified path
                 (None, self.parse_path(PathStyle::Expr)?)
             };
-            let hi = self.last_span.hi;
+            let hi = self.prev_span.hi;
             Ok(self.mk_expr(lo, hi, ExprKind::Path(qself, path), ThinVec::new()))
         } else {
             self.parse_pat_literal_maybe_minus()
@@ -3573,39 +3597,37 @@ impl<'a> Parser<'a> {
         let lo = self.span.lo;
         let pat;
         match self.token {
-          token::Underscore => {
-            // Parse _
-            self.bump();
-            pat = PatKind::Wild;
-          }
-          token::BinOp(token::And) | token::AndAnd => {
-            // Parse &pat / &mut pat
-            self.expect_and()?;
-            let mutbl = self.parse_mutability()?;
-            if let token::Lifetime(ident) = self.token {
-                return Err(self.fatal(&format!("unexpected lifetime `{}` in pattern", ident)));
+            token::Underscore => {
+                // Parse _
+                self.bump();
+                pat = PatKind::Wild;
+            }
+            token::BinOp(token::And) | token::AndAnd => {
+                // Parse &pat / &mut pat
+                self.expect_and()?;
+                let mutbl = self.parse_mutability()?;
+                if let token::Lifetime(ident) = self.token {
+                    return Err(self.fatal(&format!("unexpected lifetime `{}` in pattern", ident)));
+                }
+                let subpat = self.parse_pat()?;
+                pat = PatKind::Ref(subpat, mutbl);
+            }
+            token::OpenDelim(token::Paren) => {
+                // Parse (pat,pat,pat,...) as tuple pattern
+                self.bump();
+                let (fields, ddpos) = self.parse_pat_tuple_elements(true)?;
+                self.expect(&token::CloseDelim(token::Paren))?;
+                pat = PatKind::Tuple(fields, ddpos);
+            }
+            token::OpenDelim(token::Bracket) => {
+                // Parse [pat,pat,...] as slice pattern
+                self.bump();
+                let (before, slice, after) = self.parse_pat_vec_elements()?;
+                self.expect(&token::CloseDelim(token::Bracket))?;
+                pat = PatKind::Slice(before, slice, after);
             }
-
-            let subpat = self.parse_pat()?;
-            pat = PatKind::Ref(subpat, mutbl);
-          }
-          token::OpenDelim(token::Paren) => {
-            // Parse (pat,pat,pat,...) as tuple pattern
-            self.bump();
-            let (fields, ddpos) = self.parse_pat_tuple_elements(true)?;
-            self.expect(&token::CloseDelim(token::Paren))?;
-            pat = PatKind::Tuple(fields, ddpos);
-          }
-          token::OpenDelim(token::Bracket) => {
-            // Parse [pat,pat,...] as slice pattern
-            self.bump();
-            let (before, slice, after) = self.parse_pat_vec_elements()?;
-            self.expect(&token::CloseDelim(token::Bracket))?;
-            pat = PatKind::Vec(before, slice, after);
-          }
-          _ => {
             // At this point, token != _, &, &&, (, [
-            if self.eat_keyword(keywords::Mut) {
+            _ => if self.eat_keyword(keywords::Mut) {
                 // Parse mut ident @ pat
                 pat = self.parse_pat_ident(BindingMode::ByValue(Mutability::Mutable))?;
             } else if self.eat_keyword(keywords::Ref) {
@@ -3616,53 +3638,49 @@ impl<'a> Parser<'a> {
                 // Parse box pat
                 let subpat = self.parse_pat()?;
                 pat = PatKind::Box(subpat);
+            } else if self.token.is_ident() && !self.token.is_any_keyword() &&
+                      self.look_ahead(1, |t| match *t {
+                          token::OpenDelim(token::Paren) | token::OpenDelim(token::Brace) |
+                          token::DotDotDot | token::ModSep | token::Not => false,
+                          _ => true,
+                      }) {
+                // Parse ident @ pat
+                // This can give false positives and parse nullary enums,
+                // they are dealt with later in resolve
+                let binding_mode = BindingMode::ByValue(Mutability::Immutable);
+                pat = self.parse_pat_ident(binding_mode)?;
             } else if self.token.is_path_start() {
                 // Parse pattern starting with a path
-                if self.token.is_ident() && self.look_ahead(1, |t| *t != token::DotDotDot &&
-                        *t != token::OpenDelim(token::Brace) &&
-                        *t != token::OpenDelim(token::Paren) &&
-                        *t != token::ModSep) {
-                    // Plain idents have some extra abilities here compared to general paths
-                    if self.look_ahead(1, |t| *t == token::Not) {
+                let (qself, path) = if self.eat_lt() {
+                    // Parse a qualified path
+                    let (qself, path) = self.parse_qualified_path(PathStyle::Expr)?;
+                    (Some(qself), path)
+                } else {
+                    // Parse an unqualified path
+                    (None, self.parse_path(PathStyle::Expr)?)
+                };
+                match self.token {
+                    token::Not if qself.is_none() => {
                         // Parse macro invocation
-                        let path = self.parse_ident_into_path()?;
                         self.bump();
                         let delim = self.expect_open_delim()?;
-                        let tts = self.parse_seq_to_end(
-                            &token::CloseDelim(delim),
-                            SeqSep::none(), |p| p.parse_token_tree())?;
-                        let mac = Mac_ { path: path, tts: tts };
-                        pat = PatKind::Mac(codemap::Spanned {node: mac,
-                                                               span: mk_sp(lo, self.last_span.hi)});
-                    } else {
-                        // Parse ident @ pat
-                        // This can give false positives and parse nullary enums,
-                        // they are dealt with later in resolve
-                        let binding_mode = BindingMode::ByValue(Mutability::Immutable);
-                        pat = self.parse_pat_ident(binding_mode)?;
+                        let tts = self.parse_seq_to_end(&token::CloseDelim(delim),
+                                                        SeqSep::none(),
+                                                        |p| p.parse_token_tree())?;
+                        let mac = spanned(lo, self.prev_span.hi, Mac_ { path: path, tts: tts });
+                        pat = PatKind::Mac(mac);
                     }
-                } else {
-                    let (qself, path) = if self.eat_lt() {
-                        // Parse a qualified path
-                        let (qself, path) =
-                            self.parse_qualified_path(PathStyle::Expr)?;
-                        (Some(qself), path)
-                    } else {
-                        // Parse an unqualified path
-                        (None, self.parse_path(PathStyle::Expr)?)
-                    };
-                    match self.token {
-                      token::DotDotDot => {
+                    token::DotDotDot => {
                         // Parse range
-                        let hi = self.last_span.hi;
+                        let hi = self.prev_span.hi;
                         let begin =
                               self.mk_expr(lo, hi, ExprKind::Path(qself, path), ThinVec::new());
                         self.bump();
                         let end = self.parse_pat_range_end()?;
                         pat = PatKind::Range(begin, end);
-                      }
-                      token::OpenDelim(token::Brace) => {
-                         if qself.is_some() {
+                    }
+                    token::OpenDelim(token::Brace) => {
+                        if qself.is_some() {
                             return Err(self.fatal("unexpected `{` after qualified path"));
                         }
                         // Parse struct pattern
@@ -3674,8 +3692,8 @@ impl<'a> Parser<'a> {
                         });
                         self.bump();
                         pat = PatKind::Struct(path, fields, etc);
-                      }
-                      token::OpenDelim(token::Paren) => {
+                    }
+                    token::OpenDelim(token::Paren) => {
                         if qself.is_some() {
                             return Err(self.fatal("unexpected `(` after qualified path"));
                         }
@@ -3684,11 +3702,8 @@ impl<'a> Parser<'a> {
                         let (fields, ddpos) = self.parse_pat_tuple_elements(false)?;
                         self.expect(&token::CloseDelim(token::Paren))?;
                         pat = PatKind::TupleStruct(path, fields, ddpos)
-                      }
-                      _ => {
-                        pat = PatKind::Path(qself, path);
-                      }
                     }
+                    _ => pat = PatKind::Path(qself, path),
                 }
             } else {
                 // Try to parse everything else as literal with optional minus
@@ -3702,16 +3717,15 @@ impl<'a> Parser<'a> {
                         }
                     }
                     Err(mut err) => {
-                        err.cancel();
+                        self.cancel(&mut err);
                         let msg = format!("expected pattern, found {}", self.this_token_descr());
                         return Err(self.fatal(&msg));
                     }
                 }
             }
-          }
         }
 
-        let hi = self.last_span.hi;
+        let hi = self.prev_span.hi;
         Ok(P(ast::Pat {
             id: ast::DUMMY_NODE_ID,
             node: pat,
@@ -3726,8 +3740,8 @@ impl<'a> Parser<'a> {
                        binding_mode: ast::BindingMode)
                        -> PResult<'a, PatKind> {
         let ident = self.parse_ident()?;
-        let last_span = self.last_span;
-        let name = codemap::Spanned{span: last_span, node: ident};
+        let prev_span = self.prev_span;
+        let name = codemap::Spanned{span: prev_span, node: ident};
         let sub = if self.eat(&token::At) {
             Some(self.parse_pat()?)
         } else {
@@ -3741,9 +3755,8 @@ impl<'a> Parser<'a> {
         // binding mode then we do not end up here, because the lookahead
         // will direct us over to parse_enum_variant()
         if self.token == token::OpenDelim(token::Paren) {
-            let last_span = self.last_span;
             return Err(self.span_fatal(
-                last_span,
+                self.prev_span,
                 "expected identifier, found enum pattern"))
         }
 
@@ -3765,7 +3778,7 @@ impl<'a> Parser<'a> {
             pat: pat,
             init: init,
             id: ast::DUMMY_NODE_ID,
-            span: mk_sp(lo, self.last_span.hi),
+            span: mk_sp(lo, self.prev_span.hi),
             attrs: attrs,
         }))
     }
@@ -3780,7 +3793,7 @@ impl<'a> Parser<'a> {
         self.expect(&token::Colon)?;
         let ty = self.parse_ty_sum()?;
         Ok(StructField {
-            span: mk_sp(lo, self.last_span.hi),
+            span: mk_sp(lo, self.prev_span.hi),
             ident: Some(name),
             vis: vis,
             id: ast::DUMMY_NODE_ID,
@@ -3798,7 +3811,7 @@ impl<'a> Parser<'a> {
             _ => "expected item after attributes",
         };
 
-        self.span_err(self.last_span, message);
+        self.span_err(self.prev_span, message);
     }
 
     /// Parse a statement. This stops just before trailing semicolons on everything but items.
@@ -3868,15 +3881,22 @@ impl<'a> Parser<'a> {
         }
     }
 
-    fn parse_stmt_(&mut self, macro_expanded: bool) -> Option<Stmt> {
-        self.parse_stmt_without_recovery(macro_expanded).unwrap_or_else(|mut e| {
+    fn parse_stmt_(&mut self, macro_legacy_warnings: bool) -> Option<Stmt> {
+        self.parse_stmt_without_recovery(macro_legacy_warnings).unwrap_or_else(|mut e| {
             e.emit();
             self.recover_stmt_(SemiColonMode::Break);
             None
         })
     }
 
-    fn parse_stmt_without_recovery(&mut self, macro_expanded: bool) -> PResult<'a, Option<Stmt>> {
+    fn is_union_item(&mut self) -> bool {
+        self.token.is_keyword(keywords::Union) &&
+        self.look_ahead(1, |t| t.is_ident() && !t.is_any_keyword())
+    }
+
+    fn parse_stmt_without_recovery(&mut self,
+                                   macro_legacy_warnings: bool)
+                                   -> PResult<'a, Option<Stmt>> {
         maybe_whole!(Some deref self, NtStmt);
 
         let attrs = self.parse_outer_attributes()?;
@@ -3886,18 +3906,35 @@ impl<'a> Parser<'a> {
             Stmt {
                 id: ast::DUMMY_NODE_ID,
                 node: StmtKind::Local(self.parse_local(attrs.into())?),
-                span: mk_sp(lo, self.last_span.hi),
+                span: mk_sp(lo, self.prev_span.hi),
             }
-        } else if self.token.is_ident()
-            && !self.token.is_any_keyword()
-            && self.look_ahead(1, |t| *t == token::Not) {
-            // it's a macro invocation:
+        // Starts like a simple path, but not a union item.
+        } else if self.token.is_path_start() &&
+                  !self.token.is_qpath_start() &&
+                  !self.is_union_item() {
+            let pth = self.parse_path(PathStyle::Expr)?;
 
-            // Potential trouble: if we allow macros with paths instead of
-            // idents, we'd need to look ahead past the whole path here...
-            let pth = self.parse_ident_into_path()?;
-            self.bump();
+            if !self.eat(&token::Not) {
+                let expr = if self.check(&token::OpenDelim(token::Brace)) {
+                    self.parse_struct_expr(lo, pth, ThinVec::new())?
+                } else {
+                    let hi = self.prev_span.hi;
+                    self.mk_expr(lo, hi, ExprKind::Path(None, pth), ThinVec::new())
+                };
 
+                let expr = self.with_res(Restrictions::RESTRICTION_STMT_EXPR, |this| {
+                    let expr = this.parse_dot_or_call_expr_with(expr, lo, attrs.into())?;
+                    this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr))
+                })?;
+
+                return Ok(Some(Stmt {
+                    id: ast::DUMMY_NODE_ID,
+                    node: StmtKind::Expr(expr),
+                    span: mk_sp(lo, self.prev_span.hi),
+                }));
+            }
+
+            // it's a macro invocation
             let id = match self.token {
                 token::OpenDelim(_) => keywords::Invalid.ident(), // no special identifier
                 _ => self.parse_ident()?,
@@ -3929,7 +3966,7 @@ impl<'a> Parser<'a> {
                 SeqSep::none(),
                 |p| p.parse_token_tree()
             )?;
-            let hi = self.last_span.hi;
+            let hi = self.prev_span.hi;
 
             let style = if delim == token::Brace {
                 MacStmtStyle::Braces
@@ -3946,7 +3983,7 @@ impl<'a> Parser<'a> {
                 // We used to incorrectly stop parsing macro-expanded statements here.
                 // If the next token will be an error anyway but could have parsed with the
                 // earlier behavior, stop parsing here and emit a warning to avoid breakage.
-                else if macro_expanded && self.token.can_begin_expr() && match self.token {
+                else if macro_legacy_warnings && self.token.can_begin_expr() && match self.token {
                     // These can continue an expression, so we can't stop parsing and warn.
                     token::OpenDelim(token::Paren) | token::OpenDelim(token::Bracket) |
                     token::BinOp(token::Minus) | token::BinOp(token::Star) |
@@ -3974,8 +4011,7 @@ impl<'a> Parser<'a> {
                 // Require a semicolon or braces.
                 if style != MacStmtStyle::Braces {
                     if !self.eat(&token::Semi) {
-                        let last_span = self.last_span;
-                        self.span_err(last_span,
+                        self.span_err(self.prev_span,
                                       "macros that expand to items must \
                                        either be surrounded with braces or \
                                        followed by a semicolon");
@@ -4006,13 +4042,13 @@ impl<'a> Parser<'a> {
                 None => {
                     let unused_attrs = |attrs: &[_], s: &mut Self| {
                         if attrs.len() > 0 {
-                            let last_token = s.last_token.clone().map(|t| *t);
-                            match last_token {
-                                Some(token::DocComment(_)) => s.span_err_help(s.last_span,
+                            if s.prev_token_kind == PrevTokenKind::DocComment {
+                                s.span_err_help(s.prev_span,
                                     "found a documentation comment that doesn't document anything",
                                     "doc comments must come before what they document, maybe a \
-                                    comment was intended with `//`?"),
-                                _ => s.span_err(s.span, "expected statement after outer attribute"),
+                                    comment was intended with `//`?");
+                            } else {
+                                s.span_err(s.span, "expected statement after outer attribute");
                             }
                         }
                     };
@@ -4070,13 +4106,13 @@ impl<'a> Parser<'a> {
                     let mut stmt_span = stmt.span;
                     // expand the span to include the semicolon, if it exists
                     if self.eat(&token::Semi) {
-                        stmt_span.hi = self.last_span.hi;
+                        stmt_span.hi = self.prev_span.hi;
                     }
                     e.span_help(stmt_span, "try placing this code inside a block");
                 }
                 Err(mut e) => {
                     self.recover_stmt_(SemiColonMode::Break);
-                    e.cancel();
+                    self.cancel(&mut e);
                 }
                 _ => ()
             }
@@ -4116,13 +4152,13 @@ impl<'a> Parser<'a> {
             stmts: stmts,
             id: ast::DUMMY_NODE_ID,
             rules: s,
-            span: mk_sp(lo, self.last_span.hi),
+            span: mk_sp(lo, self.prev_span.hi),
         }))
     }
 
     /// Parse a statement, including the trailing semicolon.
-    pub fn parse_full_stmt(&mut self, macro_expanded: bool) -> PResult<'a, Option<Stmt>> {
-        let mut stmt = match self.parse_stmt_(macro_expanded) {
+    pub fn parse_full_stmt(&mut self, macro_legacy_warnings: bool) -> PResult<'a, Option<Stmt>> {
+        let mut stmt = match self.parse_stmt_(macro_legacy_warnings) {
             Some(stmt) => stmt,
             None => return Ok(None),
         };
@@ -4142,7 +4178,7 @@ impl<'a> Parser<'a> {
             }
             StmtKind::Local(..) => {
                 // We used to incorrectly allow a macro-expanded let statement to lack a semicolon.
-                if macro_expanded && self.token != token::Semi {
+                if macro_legacy_warnings && self.token != token::Semi {
                     self.warn_missing_semicolon();
                 } else {
                     self.expect_one_of(&[token::Semi], &[])?;
@@ -4155,7 +4191,7 @@ impl<'a> Parser<'a> {
             stmt = stmt.add_trailing_semicolon();
         }
 
-        stmt.span.hi = self.last_span.hi;
+        stmt.span.hi = self.prev_span.hi;
         Ok(Some(stmt))
     }
 
@@ -4188,7 +4224,7 @@ impl<'a> Parser<'a> {
                              mode: BoundParsingMode)
                              -> PResult<'a, TyParamBounds>
     {
-        let mut result = vec!();
+        let mut result = vec![];
         loop {
             let question_span = self.span;
             let ate_question = self.eat(&token::Question);
@@ -4232,7 +4268,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Matches typaram = IDENT (`?` unbound)? optbounds ( EQ ty )?
-    fn parse_ty_param(&mut self) -> PResult<'a, TyParam> {
+    fn parse_ty_param(&mut self, preceding_attrs: Vec<ast::Attribute>) -> PResult<'a, TyParam> {
         let span = self.span;
         let ident = self.parse_ident()?;
 
@@ -4246,6 +4282,7 @@ impl<'a> Parser<'a> {
         };
 
         Ok(TyParam {
+            attrs: preceding_attrs.into(),
             ident: ident,
             id: ast::DUMMY_NODE_ID,
             bounds: bounds,
@@ -4266,20 +4303,42 @@ impl<'a> Parser<'a> {
         let span_lo = self.span.lo;
 
         if self.eat(&token::Lt) {
-            let lifetime_defs = self.parse_lifetime_defs()?;
+            // Upon encountering attribute in generics list, we do not
+            // know if it is attached to lifetime or to type param.
+            //
+            // Solution: 1. eagerly parse attributes in tandem with
+            // lifetime defs, 2. store last set of parsed (and unused)
+            // attributes in `attrs`, and 3. pass in those attributes
+            // when parsing formal type param after lifetime defs.
+            let mut attrs = vec![];
+            let lifetime_defs = self.parse_lifetime_defs(Some(&mut attrs))?;
             let mut seen_default = false;
+            let mut post_lifetime_attrs = Some(attrs);
             let ty_params = self.parse_seq_to_gt(Some(token::Comma), |p| {
                 p.forbid_lifetime()?;
-                let ty_param = p.parse_ty_param()?;
+                // Move out of `post_lifetime_attrs` if present. O/w
+                // not first type param: parse attributes anew.
+                let attrs = match post_lifetime_attrs.as_mut() {
+                    None => p.parse_outer_attributes()?,
+                    Some(attrs) => mem::replace(attrs, vec![]),
+                };
+                post_lifetime_attrs = None;
+                let ty_param = p.parse_ty_param(attrs)?;
                 if ty_param.default.is_some() {
                     seen_default = true;
                 } else if seen_default {
-                    let last_span = p.last_span;
-                    p.span_err(last_span,
+                    let prev_span = p.prev_span;
+                    p.span_err(prev_span,
                                "type parameters with a default must be trailing");
                 }
                 Ok(ty_param)
             })?;
+            if let Some(attrs) = post_lifetime_attrs {
+                if !attrs.is_empty() {
+                    self.span_err(attrs[0].span,
+                                  "trailing attribute after lifetime parameters");
+                }
+            }
             Ok(ast::Generics {
                 lifetimes: lifetime_defs,
                 ty_params: ty_params,
@@ -4287,7 +4346,7 @@ impl<'a> Parser<'a> {
                     id: ast::DUMMY_NODE_ID,
                     predicates: Vec::new(),
                 },
-                span: mk_sp(span_lo, self.last_span.hi),
+                span: mk_sp(span_lo, self.prev_span.hi),
             })
         } else {
             Ok(ast::Generics::default())
@@ -4302,9 +4361,7 @@ impl<'a> Parser<'a> {
 
         let missing_comma = !lifetimes.is_empty() &&
                             !self.token.is_like_gt() &&
-                            self.last_token
-                                .as_ref().map_or(true,
-                                                 |x| &**x != &token::Comma);
+                            self.prev_token_kind != PrevTokenKind::Comma;
 
         if missing_comma {
 
@@ -4317,7 +4374,7 @@ impl<'a> Parser<'a> {
             let span_hi = match self.parse_ty() {
                 Ok(..) => self.span.hi,
                 Err(ref mut err) => {
-                    err.cancel();
+                    self.cancel(err);
                     span_hi
                 }
             };
@@ -4411,7 +4468,7 @@ impl<'a> Parser<'a> {
                     let bounds =
                         self.parse_lifetimes(token::BinOp(token::Plus))?;
 
-                    let hi = self.last_span.hi;
+                    let hi = self.prev_span.hi;
                     let span = mk_sp(lo, hi);
 
                     where_clause.predicates.push(ast::WherePredicate::RegionPredicate(
@@ -4429,7 +4486,7 @@ impl<'a> Parser<'a> {
                     let bound_lifetimes = if self.eat_keyword(keywords::For) {
                         // Higher ranked constraint.
                         self.expect(&token::Lt)?;
-                        let lifetime_defs = self.parse_lifetime_defs()?;
+                        let lifetime_defs = self.parse_lifetime_defs(None)?;
                         self.expect_gt()?;
                         lifetime_defs
                     } else {
@@ -4440,7 +4497,7 @@ impl<'a> Parser<'a> {
 
                     if self.eat(&token::Colon) {
                         let bounds = self.parse_ty_param_bounds(BoundParsingMode::Bare)?;
-                        let hi = self.last_span.hi;
+                        let hi = self.prev_span.hi;
                         let span = mk_sp(lo, hi);
 
                         if bounds.is_empty() {
@@ -4460,7 +4517,7 @@ impl<'a> Parser<'a> {
                         parsed_something = true;
                     } else if self.eat(&token::Eq) {
                         // let ty = try!(self.parse_ty());
-                        let hi = self.last_span.hi;
+                        let hi = self.prev_span.hi;
                         let span = mk_sp(lo, hi);
                         // where_clause.predicates.push(
                         //     ast::WherePredicate::EqPredicate(ast::WhereEqPredicate {
@@ -4475,8 +4532,8 @@ impl<'a> Parser<'a> {
                                      "equality constraints are not yet supported \
                                      in where clauses (#20041)");
                     } else {
-                        let last_span = self.last_span;
-                        self.span_err(last_span,
+                        let prev_span = self.prev_span;
+                        self.span_err(prev_span,
                               "unexpected token in `where` clause");
                     }
                 }
@@ -4488,8 +4545,8 @@ impl<'a> Parser<'a> {
         }
 
         if !parsed_something {
-            let last_span = self.last_span;
-            self.span_err(last_span,
+            let prev_span = self.prev_span;
+            self.span_err(prev_span,
                           "a `where` clause must have at least one predicate \
                            in it");
         }
@@ -4562,9 +4619,13 @@ impl<'a> Parser<'a> {
     fn parse_self_arg(&mut self) -> PResult<'a, Option<Arg>> {
         let expect_ident = |this: &mut Self| match this.token {
             // Preserve hygienic context.
-            token::Ident(ident) => { this.bump(); codemap::respan(this.last_span, ident) }
+            token::Ident(ident) => { this.bump(); codemap::respan(this.prev_span, ident) }
             _ => unreachable!()
         };
+        let isolated_self = |this: &mut Self, n| {
+            this.look_ahead(n, |t| t.is_keyword(keywords::SelfValue)) &&
+            this.look_ahead(n + 1, |t| t != &token::ModSep)
+        };
 
         // Parse optional self parameter of a method.
         // Only a limited set of initial token sequences is considered self parameters, anything
@@ -4577,22 +4638,22 @@ impl<'a> Parser<'a> {
                 // &'lt self
                 // &'lt mut self
                 // &not_self
-                if self.look_ahead(1, |t| t.is_keyword(keywords::SelfValue)) {
+                if isolated_self(self, 1) {
                     self.bump();
                     (SelfKind::Region(None, Mutability::Immutable), expect_ident(self))
                 } else if self.look_ahead(1, |t| t.is_keyword(keywords::Mut)) &&
-                          self.look_ahead(2, |t| t.is_keyword(keywords::SelfValue)) {
+                          isolated_self(self, 2) {
                     self.bump();
                     self.bump();
                     (SelfKind::Region(None, Mutability::Mutable), expect_ident(self))
                 } else if self.look_ahead(1, |t| t.is_lifetime()) &&
-                          self.look_ahead(2, |t| t.is_keyword(keywords::SelfValue)) {
+                          isolated_self(self, 2) {
                     self.bump();
                     let lt = self.parse_lifetime()?;
                     (SelfKind::Region(Some(lt), Mutability::Immutable), expect_ident(self))
                 } else if self.look_ahead(1, |t| t.is_lifetime()) &&
                           self.look_ahead(2, |t| t.is_keyword(keywords::Mut)) &&
-                          self.look_ahead(3, |t| t.is_keyword(keywords::SelfValue)) {
+                          isolated_self(self, 3) {
                     self.bump();
                     let lt = self.parse_lifetime()?;
                     self.bump();
@@ -4607,12 +4668,12 @@ impl<'a> Parser<'a> {
                 // *mut self
                 // *not_self
                 // Emit special error for `self` cases.
-                if self.look_ahead(1, |t| t.is_keyword(keywords::SelfValue)) {
+                if isolated_self(self, 1) {
                     self.bump();
                     self.span_err(self.span, "cannot pass `self` by raw pointer");
                     (SelfKind::Value(Mutability::Immutable), expect_ident(self))
                 } else if self.look_ahead(1, |t| t.is_mutability()) &&
-                          self.look_ahead(2, |t| t.is_keyword(keywords::SelfValue)) {
+                          isolated_self(self, 2) {
                     self.bump();
                     self.bump();
                     self.span_err(self.span, "cannot pass `self` by raw pointer");
@@ -4622,7 +4683,7 @@ impl<'a> Parser<'a> {
                 }
             }
             token::Ident(..) => {
-                if self.token.is_keyword(keywords::SelfValue) {
+                if isolated_self(self, 0) {
                     // self
                     // self: TYPE
                     let eself_ident = expect_ident(self);
@@ -4633,7 +4694,7 @@ impl<'a> Parser<'a> {
                         (SelfKind::Value(Mutability::Immutable), eself_ident)
                     }
                 } else if self.token.is_keyword(keywords::Mut) &&
-                        self.look_ahead(1, |t| t.is_keyword(keywords::SelfValue)) {
+                          isolated_self(self, 1) {
                     // mut self
                     // mut self: TYPE
                     self.bump();
@@ -4651,7 +4712,7 @@ impl<'a> Parser<'a> {
             _ => return Ok(None),
         };
 
-        let eself = codemap::respan(mk_sp(eself_lo, self.last_span.hi), eself);
+        let eself = codemap::respan(mk_sp(eself_lo, self.prev_span.hi), eself);
         Ok(Some(Arg::from_self(eself, eself_ident)))
     }
 
@@ -4769,7 +4830,7 @@ impl<'a> Parser<'a> {
                                                 ast::Unsafety,
                                                 abi::Abi)> {
         let is_const_fn = self.eat_keyword(keywords::Const);
-        let const_span = self.last_span;
+        let const_span = self.prev_span;
         let unsafety = self.parse_unsafety()?;
         let (constness, unsafety, abi) = if is_const_fn {
             (respan(const_span, Constness::Const), unsafety, Abi::Rust)
@@ -4779,7 +4840,7 @@ impl<'a> Parser<'a> {
             } else {
                 Abi::Rust
             };
-            (respan(self.last_span, Constness::NotConst), unsafety, abi)
+            (respan(self.prev_span, Constness::NotConst), unsafety, abi)
         };
         self.expect_keyword(keywords::Fn)?;
         Ok((constness, unsafety, abi))
@@ -4816,7 +4877,7 @@ impl<'a> Parser<'a> {
 
         Ok(ImplItem {
             id: ast::DUMMY_NODE_ID,
-            span: mk_sp(lo, self.last_span.hi),
+            span: mk_sp(lo, self.prev_span.hi),
             ident: name,
             vis: vis,
             defaultness: defaultness,
@@ -4853,17 +4914,14 @@ impl<'a> Parser<'a> {
     fn parse_impl_method(&mut self, vis: &Visibility)
                          -> PResult<'a, (Ident, Vec<ast::Attribute>, ast::ImplItemKind)> {
         // code copied from parse_macro_use_or_failure... abstraction!
-        if !self.token.is_any_keyword()
-            && self.look_ahead(1, |t| *t == token::Not)
-            && (self.look_ahead(2, |t| *t == token::OpenDelim(token::Paren))
-                || self.look_ahead(2, |t| *t == token::OpenDelim(token::Brace))) {
+        if self.token.is_path_start() {
             // method macro.
 
-            let last_span = self.last_span;
-            self.complain_if_pub_macro(&vis, last_span);
+            let prev_span = self.prev_span;
+            self.complain_if_pub_macro(&vis, prev_span);
 
             let lo = self.span.lo;
-            let pth = self.parse_ident_into_path()?;
+            let pth = self.parse_path(PathStyle::Mod)?;
             self.expect(&token::Not)?;
 
             // eat a matched-delimiter token tree:
@@ -4871,14 +4929,12 @@ impl<'a> Parser<'a> {
             let tts = self.parse_seq_to_end(&token::CloseDelim(delim),
                                             SeqSep::none(),
                                             |p| p.parse_token_tree())?;
-            let m_ = Mac_ { path: pth, tts: tts };
-            let m: ast::Mac = codemap::Spanned { node: m_,
-                                                    span: mk_sp(lo,
-                                                                self.last_span.hi) };
             if delim != token::Brace {
                 self.expect(&token::Semi)?
             }
-            Ok((keywords::Invalid.ident(), vec![], ast::ImplItemKind::Macro(m)))
+
+            let mac = spanned(lo, self.prev_span.hi, Mac_ { path: pth, tts: tts });
+            Ok((keywords::Invalid.ident(), vec![], ast::ImplItemKind::Macro(mac)))
         } else {
             let (constness, unsafety, abi) = self.parse_fn_front_matter()?;
             let ident = self.parse_ident()?;
@@ -5002,7 +5058,7 @@ impl<'a> Parser<'a> {
     fn parse_late_bound_lifetime_defs(&mut self) -> PResult<'a, Vec<ast::LifetimeDef>> {
         if self.eat_keyword(keywords::For) {
             self.expect(&token::Lt)?;
-            let lifetime_defs = self.parse_lifetime_defs()?;
+            let lifetime_defs = self.parse_lifetime_defs(None)?;
             self.expect_gt()?;
             Ok(lifetime_defs)
         } else {
@@ -5018,7 +5074,7 @@ impl<'a> Parser<'a> {
         Ok(ast::PolyTraitRef {
             bound_lifetimes: lifetime_defs,
             trait_ref: self.parse_trait_ref()?,
-            span: mk_sp(lo, self.last_span.hi),
+            span: mk_sp(lo, self.prev_span.hi),
         })
     }
 
@@ -5094,7 +5150,11 @@ impl<'a> Parser<'a> {
         let mut fields = Vec::new();
         if self.eat(&token::OpenDelim(token::Brace)) {
             while self.token != token::CloseDelim(token::Brace) {
-                fields.push(self.parse_struct_decl_field()?);
+                fields.push(self.parse_struct_decl_field().map_err(|e| {
+                    self.recover_stmt();
+                    self.eat(&token::CloseDelim(token::Brace));
+                    e
+                })?);
             }
 
             self.bump();
@@ -5184,7 +5244,7 @@ impl<'a> Parser<'a> {
     // If `allow_path` is false, just parse the `pub` in `pub(path)` (but still parse `pub(crate)`)
     fn parse_visibility(&mut self, allow_path: bool) -> PResult<'a, Visibility> {
         let pub_crate = |this: &mut Self| {
-            let span = this.last_span;
+            let span = this.prev_span;
             this.expect(&token::CloseDelim(token::Paren))?;
             Ok(Visibility::Crate(span))
         };
@@ -5235,7 +5295,7 @@ impl<'a> Parser<'a> {
         let hi = if self.span == syntax_pos::DUMMY_SP {
             inner_lo
         } else {
-            self.last_span.hi
+            self.prev_span.hi
         };
 
         Ok(ast::Mod {
@@ -5260,39 +5320,51 @@ impl<'a> Parser<'a> {
 
     /// Parse a `mod <foo> { ... }` or `mod <foo>;` item
     fn parse_item_mod(&mut self, outer_attrs: &[Attribute]) -> PResult<'a, ItemInfo> {
-        let outer_attrs = ::config::StripUnconfigured {
-            config: &self.cfg,
-            sess: self.sess,
-            should_test: false, // irrelevant
-            features: None, // don't perform gated feature checking
-        }.process_cfg_attrs(outer_attrs.to_owned());
+        let (in_cfg, outer_attrs) = {
+            let mut strip_unconfigured = ::config::StripUnconfigured {
+                sess: self.sess,
+                should_test: false, // irrelevant
+                features: None, // don't perform gated feature checking
+            };
+            let outer_attrs = strip_unconfigured.process_cfg_attrs(outer_attrs.to_owned());
+            (strip_unconfigured.in_cfg(&outer_attrs), outer_attrs)
+        };
 
         let id_span = self.span;
         let id = self.parse_ident()?;
         if self.check(&token::Semi) {
             self.bump();
-            // This mod is in an external file. Let's go get it!
-            let (m, attrs) = self.eval_src_mod(id, &outer_attrs, id_span)?;
-            Ok((id, m, Some(attrs)))
+            if in_cfg {
+                // This mod is in an external file. Let's go get it!
+                let (m, attrs) = self.eval_src_mod(id, &outer_attrs, id_span)?;
+                Ok((id, m, Some(attrs)))
+            } else {
+                let placeholder = ast::Mod { inner: syntax_pos::DUMMY_SP, items: Vec::new() };
+                Ok((id, ItemKind::Mod(placeholder), None))
+            }
         } else {
             let directory = self.directory.clone();
-            self.push_directory(id, &outer_attrs);
+            let restrictions = self.push_directory(id, &outer_attrs);
             self.expect(&token::OpenDelim(token::Brace))?;
             let mod_inner_lo = self.span.lo;
             let attrs = self.parse_inner_attributes()?;
-            let m = self.parse_mod_items(&token::CloseDelim(token::Brace), mod_inner_lo)?;
+            let m = self.with_res(restrictions, |this| {
+                this.parse_mod_items(&token::CloseDelim(token::Brace), mod_inner_lo)
+            })?;
             self.directory = directory;
             Ok((id, ItemKind::Mod(m), Some(attrs)))
         }
     }
 
-    fn push_directory(&mut self, id: Ident, attrs: &[Attribute]) {
-        let default_path = self.id_to_interned_str(id);
-        let file_path = match ::attr::first_attr_value_str_by_name(attrs, "path") {
-            Some(d) => d,
-            None => default_path,
-        };
-        self.directory.push(&*file_path)
+    fn push_directory(&mut self, id: Ident, attrs: &[Attribute]) -> Restrictions {
+        if let Some(path) = ::attr::first_attr_value_str_by_name(attrs, "path") {
+            self.directory.push(&*path);
+            self.restrictions - Restrictions::NO_NONINLINE_MOD
+        } else {
+            let default_path = self.id_to_interned_str(id);
+            self.directory.push(&*default_path);
+            self.restrictions
+        }
     }
 
     pub fn submod_path_from_attr(attrs: &[ast::Attribute], dir_path: &Path) -> Option<PathBuf> {
@@ -5417,12 +5489,7 @@ impl<'a> Parser<'a> {
         included_mod_stack.push(path.clone());
         drop(included_mod_stack);
 
-        let mut p0 = new_sub_parser_from_file(self.sess,
-                                              self.cfg.clone(),
-                                              &path,
-                                              owns_directory,
-                                              Some(name),
-                                              id_sp);
+        let mut p0 = new_sub_parser_from_file(self.sess, &path, owns_directory, Some(name), id_sp);
         let mod_inner_lo = p0.span.lo;
         let mod_attrs = p0.parse_inner_attributes()?;
         let m0 = p0.parse_mod_items(&token::Eof, mod_inner_lo)?;
@@ -5491,9 +5558,9 @@ impl<'a> Parser<'a> {
         };
         self.expect(&token::Semi)?;
 
-        let last_span = self.last_span;
+        let prev_span = self.prev_span;
         Ok(self.mk_item(lo,
-                        last_span.hi,
+                        prev_span.hi,
                         ident,
                         ItemKind::ExternCrate(maybe_path),
                         visibility,
@@ -5528,13 +5595,13 @@ impl<'a> Parser<'a> {
         }
         self.expect(&token::CloseDelim(token::Brace))?;
 
-        let last_span = self.last_span;
+        let prev_span = self.prev_span;
         let m = ast::ForeignMod {
             abi: abi,
             items: foreign_items
         };
         Ok(self.mk_item(lo,
-                     last_span.hi,
+                     prev_span.hi,
                      keywords::Invalid.ident(),
                      ItemKind::ForeignMod(m),
                      visibility,
@@ -5587,7 +5654,7 @@ impl<'a> Parser<'a> {
                 data: struct_def,
                 disr_expr: disr_expr,
             };
-            variants.push(spanned(vlo, self.last_span.hi, vr));
+            variants.push(spanned(vlo, self.prev_span.hi, vr));
 
             if !self.eat(&token::Comma) { break; }
         }
@@ -5609,7 +5676,11 @@ impl<'a> Parser<'a> {
         generics.where_clause = self.parse_where_clause()?;
         self.expect(&token::OpenDelim(token::Brace))?;
 
-        let enum_definition = self.parse_enum_def(&generics)?;
+        let enum_definition = self.parse_enum_def(&generics).map_err(|e| {
+            self.recover_stmt();
+            self.eat(&token::CloseDelim(token::Brace));
+            e
+        })?;
         Ok((id, ItemKind::Enum(enum_definition, generics), None))
     }
 
@@ -5624,9 +5695,9 @@ impl<'a> Parser<'a> {
                 match abi::lookup(&s.as_str()) {
                     Some(abi) => Ok(Some(abi)),
                     None => {
-                        let last_span = self.last_span;
+                        let prev_span = self.prev_span;
                         self.span_err(
-                            last_span,
+                            prev_span,
                             &format!("invalid ABI: expected one of [{}], \
                                      found `{}`",
                                     abi::all_names().join(", "),
@@ -5668,9 +5739,9 @@ impl<'a> Parser<'a> {
             let item_ = ItemKind::Use(self.parse_view_path()?);
             self.expect(&token::Semi)?;
 
-            let last_span = self.last_span;
+            let prev_span = self.prev_span;
             let item = self.mk_item(lo,
-                                    last_span.hi,
+                                    prev_span.hi,
                                     keywords::Invalid.ident(),
                                     item_,
                                     visibility,
@@ -5687,15 +5758,15 @@ impl<'a> Parser<'a> {
 
             if self.eat_keyword(keywords::Fn) {
                 // EXTERN FUNCTION ITEM
-                let fn_span = self.last_span;
+                let fn_span = self.prev_span;
                 let abi = opt_abi.unwrap_or(Abi::C);
                 let (ident, item_, extra_attrs) =
                     self.parse_item_fn(Unsafety::Normal,
                                        respan(fn_span, Constness::NotConst),
                                        abi)?;
-                let last_span = self.last_span;
+                let prev_span = self.prev_span;
                 let item = self.mk_item(lo,
-                                        last_span.hi,
+                                        prev_span.hi,
                                         ident,
                                         item_,
                                         visibility,
@@ -5716,9 +5787,9 @@ impl<'a> Parser<'a> {
                 Mutability::Immutable
             };
             let (ident, item_, extra_attrs) = self.parse_item_const(Some(m))?;
-            let last_span = self.last_span;
+            let prev_span = self.prev_span;
             let item = self.mk_item(lo,
-                                    last_span.hi,
+                                    prev_span.hi,
                                     ident,
                                     item_,
                                     visibility,
@@ -5726,7 +5797,7 @@ impl<'a> Parser<'a> {
             return Ok(Some(item));
         }
         if self.eat_keyword(keywords::Const) {
-            let const_span = self.last_span;
+            let const_span = self.prev_span;
             if self.check_keyword(keywords::Fn)
                 || (self.check_keyword(keywords::Unsafe)
                     && self.look_ahead(1, |t| t.is_keyword(keywords::Fn))) {
@@ -5741,9 +5812,9 @@ impl<'a> Parser<'a> {
                     self.parse_item_fn(unsafety,
                                        respan(const_span, Constness::Const),
                                        Abi::Rust)?;
-                let last_span = self.last_span;
+                let prev_span = self.prev_span;
                 let item = self.mk_item(lo,
-                                        last_span.hi,
+                                        prev_span.hi,
                                         ident,
                                         item_,
                                         visibility,
@@ -5753,15 +5824,15 @@ impl<'a> Parser<'a> {
 
             // CONST ITEM
             if self.eat_keyword(keywords::Mut) {
-                let last_span = self.last_span;
-                self.diagnostic().struct_span_err(last_span, "const globals cannot be mutable")
+                let prev_span = self.prev_span;
+                self.diagnostic().struct_span_err(prev_span, "const globals cannot be mutable")
                                  .help("did you mean to declare a static?")
                                  .emit();
             }
             let (ident, item_, extra_attrs) = self.parse_item_const(None)?;
-            let last_span = self.last_span;
+            let prev_span = self.prev_span;
             let item = self.mk_item(lo,
-                                    last_span.hi,
+                                    prev_span.hi,
                                     ident,
                                     item_,
                                     visibility,
@@ -5776,9 +5847,9 @@ impl<'a> Parser<'a> {
             self.expect_keyword(keywords::Trait)?;
             let (ident, item_, extra_attrs) =
                 self.parse_item_trait(ast::Unsafety::Unsafe)?;
-            let last_span = self.last_span;
+            let prev_span = self.prev_span;
             let item = self.mk_item(lo,
-                                    last_span.hi,
+                                    prev_span.hi,
                                     ident,
                                     item_,
                                     visibility,
@@ -5792,9 +5863,9 @@ impl<'a> Parser<'a> {
             self.expect_keyword(keywords::Unsafe)?;
             self.expect_keyword(keywords::Impl)?;
             let (ident, item_, extra_attrs) = self.parse_item_impl(ast::Unsafety::Unsafe)?;
-            let last_span = self.last_span;
+            let prev_span = self.prev_span;
             let item = self.mk_item(lo,
-                                    last_span.hi,
+                                    prev_span.hi,
                                     ident,
                                     item_,
                                     visibility,
@@ -5804,14 +5875,14 @@ impl<'a> Parser<'a> {
         if self.check_keyword(keywords::Fn) {
             // FUNCTION ITEM
             self.bump();
-            let fn_span = self.last_span;
+            let fn_span = self.prev_span;
             let (ident, item_, extra_attrs) =
                 self.parse_item_fn(Unsafety::Normal,
                                    respan(fn_span, Constness::NotConst),
                                    Abi::Rust)?;
-            let last_span = self.last_span;
+            let prev_span = self.prev_span;
             let item = self.mk_item(lo,
-                                    last_span.hi,
+                                    prev_span.hi,
                                     ident,
                                     item_,
                                     visibility,
@@ -5828,14 +5899,14 @@ impl<'a> Parser<'a> {
                 Abi::Rust
             };
             self.expect_keyword(keywords::Fn)?;
-            let fn_span = self.last_span;
+            let fn_span = self.prev_span;
             let (ident, item_, extra_attrs) =
                 self.parse_item_fn(Unsafety::Unsafe,
                                    respan(fn_span, Constness::NotConst),
                                    abi)?;
-            let last_span = self.last_span;
+            let prev_span = self.prev_span;
             let item = self.mk_item(lo,
-                                    last_span.hi,
+                                    prev_span.hi,
                                     ident,
                                     item_,
                                     visibility,
@@ -5846,9 +5917,9 @@ impl<'a> Parser<'a> {
             // MODULE ITEM
             let (ident, item_, extra_attrs) =
                 self.parse_item_mod(&attrs[..])?;
-            let last_span = self.last_span;
+            let prev_span = self.prev_span;
             let item = self.mk_item(lo,
-                                    last_span.hi,
+                                    prev_span.hi,
                                     ident,
                                     item_,
                                     visibility,
@@ -5858,9 +5929,9 @@ impl<'a> Parser<'a> {
         if self.eat_keyword(keywords::Type) {
             // TYPE ITEM
             let (ident, item_, extra_attrs) = self.parse_item_type()?;
-            let last_span = self.last_span;
+            let prev_span = self.prev_span;
             let item = self.mk_item(lo,
-                                    last_span.hi,
+                                    prev_span.hi,
                                     ident,
                                     item_,
                                     visibility,
@@ -5870,9 +5941,9 @@ impl<'a> Parser<'a> {
         if self.eat_keyword(keywords::Enum) {
             // ENUM ITEM
             let (ident, item_, extra_attrs) = self.parse_item_enum()?;
-            let last_span = self.last_span;
+            let prev_span = self.prev_span;
             let item = self.mk_item(lo,
-                                    last_span.hi,
+                                    prev_span.hi,
                                     ident,
                                     item_,
                                     visibility,
@@ -5883,9 +5954,9 @@ impl<'a> Parser<'a> {
             // TRAIT ITEM
             let (ident, item_, extra_attrs) =
                 self.parse_item_trait(ast::Unsafety::Normal)?;
-            let last_span = self.last_span;
+            let prev_span = self.prev_span;
             let item = self.mk_item(lo,
-                                    last_span.hi,
+                                    prev_span.hi,
                                     ident,
                                     item_,
                                     visibility,
@@ -5895,9 +5966,9 @@ impl<'a> Parser<'a> {
         if self.eat_keyword(keywords::Impl) {
             // IMPL ITEM
             let (ident, item_, extra_attrs) = self.parse_item_impl(ast::Unsafety::Normal)?;
-            let last_span = self.last_span;
+            let prev_span = self.prev_span;
             let item = self.mk_item(lo,
-                                    last_span.hi,
+                                    prev_span.hi,
                                     ident,
                                     item_,
                                     visibility,
@@ -5907,23 +5978,22 @@ impl<'a> Parser<'a> {
         if self.eat_keyword(keywords::Struct) {
             // STRUCT ITEM
             let (ident, item_, extra_attrs) = self.parse_item_struct()?;
-            let last_span = self.last_span;
+            let prev_span = self.prev_span;
             let item = self.mk_item(lo,
-                                    last_span.hi,
+                                    prev_span.hi,
                                     ident,
                                     item_,
                                     visibility,
                                     maybe_append(attrs, extra_attrs));
             return Ok(Some(item));
         }
-        if self.check_keyword(keywords::Union) &&
-                self.look_ahead(1, |t| t.is_ident() && !t.is_any_keyword()) {
+        if self.is_union_item() {
             // UNION ITEM
             self.bump();
             let (ident, item_, extra_attrs) = self.parse_item_union()?;
-            let last_span = self.last_span;
+            let prev_span = self.prev_span;
             let item = self.mk_item(lo,
-                                    last_span.hi,
+                                    prev_span.hi,
                                     ident,
                                     item_,
                                     visibility,
@@ -5966,20 +6036,16 @@ impl<'a> Parser<'a> {
         lo: BytePos,
         visibility: Visibility
     ) -> PResult<'a, Option<P<Item>>> {
-        if macros_allowed && !self.token.is_any_keyword()
-                && self.look_ahead(1, |t| *t == token::Not)
-                && (self.look_ahead(2, |t| t.is_ident())
-                    || self.look_ahead(2, |t| *t == token::OpenDelim(token::Paren))
-                    || self.look_ahead(2, |t| *t == token::OpenDelim(token::Brace))) {
+        if macros_allowed && self.token.is_path_start() {
             // MACRO INVOCATION ITEM
 
-            let last_span = self.last_span;
-            self.complain_if_pub_macro(&visibility, last_span);
+            let prev_span = self.prev_span;
+            self.complain_if_pub_macro(&visibility, prev_span);
 
             let mac_lo = self.span.lo;
 
             // item macro.
-            let pth = self.parse_ident_into_path()?;
+            let pth = self.parse_path(PathStyle::Mod)?;
             self.expect(&token::Not)?;
 
             // a 'special' identifier (like what `macro_rules!` uses)
@@ -5995,30 +6061,19 @@ impl<'a> Parser<'a> {
             let tts = self.parse_seq_to_end(&token::CloseDelim(delim),
                                             SeqSep::none(),
                                             |p| p.parse_token_tree())?;
-            // single-variant-enum... :
-            let m = Mac_ { path: pth, tts: tts };
-            let m: ast::Mac = codemap::Spanned { node: m,
-                                                 span: mk_sp(mac_lo,
-                                                             self.last_span.hi) };
-
             if delim != token::Brace {
                 if !self.eat(&token::Semi) {
-                    let last_span = self.last_span;
-                    self.span_err(last_span,
+                    let prev_span = self.prev_span;
+                    self.span_err(prev_span,
                                   "macros that expand to items must either \
                                    be surrounded with braces or followed by \
                                    a semicolon");
                 }
             }
 
-            let item_ = ItemKind::Mac(m);
-            let last_span = self.last_span;
-            let item = self.mk_item(lo,
-                                    last_span.hi,
-                                    id,
-                                    item_,
-                                    visibility,
-                                    attrs);
+            let hi = self.prev_span.hi;
+            let mac = spanned(mac_lo, hi, Mac_ { path: pth, tts: tts });
+            let item = self.mk_item(lo, hi, id, ItemKind::Mac(mac), visibility, attrs);
             return Ok(Some(item));
         }
 
@@ -6026,8 +6081,8 @@ impl<'a> Parser<'a> {
         match visibility {
             Visibility::Inherited => {}
             _ => {
-                let last_span = self.last_span;
-                return Err(self.span_fatal(last_span, "unmatched visibility `pub`"));
+                let prev_span = self.prev_span;
+                return Err(self.span_fatal(prev_span, "unmatched visibility `pub`"));
             }
         }
 
@@ -6058,7 +6113,7 @@ impl<'a> Parser<'a> {
                 rename: rename,
                 id: ast::DUMMY_NODE_ID
             };
-            let hi = this.last_span.hi;
+            let hi = this.prev_span.hi;
             Ok(spanned(lo, hi, node))
         })
     }
@@ -6078,15 +6133,20 @@ impl<'a> Parser<'a> {
     /// MOD_SEP? LBRACE item_seq RBRACE
     fn parse_view_path(&mut self) -> PResult<'a, P<ViewPath>> {
         let lo = self.span.lo;
-        if self.check(&token::OpenDelim(token::Brace)) || self.is_import_coupler() {
-            // `{foo, bar}` or `::{foo, bar}`
+        if self.check(&token::OpenDelim(token::Brace)) || self.check(&token::BinOp(token::Star)) ||
+           self.is_import_coupler() {
+            // `{foo, bar}`, `::{foo, bar}`, `*`, or `::*`.
             let prefix = ast::Path {
                 global: self.eat(&token::ModSep),
                 segments: Vec::new(),
                 span: mk_sp(lo, self.span.hi),
             };
-            let items = self.parse_path_list_items()?;
-            Ok(P(spanned(lo, self.span.hi, ViewPathList(prefix, items))))
+            let view_path_kind = if self.eat(&token::BinOp(token::Star)) {
+                ViewPathGlob(prefix)
+            } else {
+                ViewPathList(prefix, self.parse_path_list_items()?)
+            };
+            Ok(P(spanned(lo, self.span.hi, view_path_kind)))
         } else {
             let prefix = self.parse_path(PathStyle::Mod)?;
             if self.is_import_coupler() {
@@ -6103,7 +6163,7 @@ impl<'a> Parser<'a> {
                 // `foo::bar` or `foo::bar as baz`
                 let rename = self.parse_rename()?.
                                   unwrap_or(prefix.segments.last().unwrap().identifier);
-                Ok(P(spanned(lo, self.last_span.hi, ViewPathSimple(rename, prefix))))
+                Ok(P(spanned(lo, self.prev_span.hi, ViewPathSimple(rename, prefix))))
             }
         }
     }
@@ -6123,7 +6183,6 @@ impl<'a> Parser<'a> {
         Ok(ast::Crate {
             attrs: self.parse_inner_attributes()?,
             module: self.parse_mod_items(&token::Eof, lo)?,
-            config: self.cfg.clone(),
             span: mk_sp(lo, self.span.lo),
             exported_macros: Vec::new(),
         })
@@ -6151,7 +6210,7 @@ impl<'a> Parser<'a> {
     pub fn parse_str(&mut self) -> PResult<'a, (InternedString, StrStyle)> {
         match self.parse_optional_str() {
             Some((s, style, suf)) => {
-                let sp = self.last_span;
+                let sp = self.prev_span;
                 self.expect_no_suffix(sp, "string literal", suf);
                 Ok((s, style))
             }
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index ff01d375815..4d0da660302 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -14,7 +14,7 @@ pub use self::DelimToken::*;
 pub use self::Lit::*;
 pub use self::Token::*;
 
-use ast::{self, BinOpKind};
+use ast::{self};
 use ptr::P;
 use util::interner::Interner;
 use tokenstream;
@@ -53,21 +53,6 @@ pub enum DelimToken {
 }
 
 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)]
-pub enum SpecialMacroVar {
-    /// `$crate` will be filled in with the name of the crate a macro was
-    /// imported from, if any.
-    CrateMacroVar,
-}
-
-impl SpecialMacroVar {
-    pub fn as_str(self) -> &'static str {
-        match self {
-            SpecialMacroVar::CrateMacroVar => "crate",
-        }
-    }
-}
-
-#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)]
 pub enum Lit {
     Byte(ast::Name),
     Char(ast::Name),
@@ -148,8 +133,6 @@ pub enum Token {
     // In right-hand-sides of MBE macros:
     /// A syntactic variable that will be filled in by macro expansion.
     SubstNt(ast::Ident),
-    /// A macro variable with special meaning.
-    SpecialVarNt(SpecialMacroVar),
 
     // Junk. These carry no data because we don't really care about the data
     // they *would* carry, and don't really want to allocate a new ident for
@@ -176,10 +159,8 @@ impl Token {
     /// Returns `true` if the token can appear at the start of an expression.
     pub fn can_begin_expr(&self) -> bool {
         match *self {
-            OpenDelim(_)                => true,
+            OpenDelim(..)               => true,
             Ident(..)                   => true,
-            Underscore                  => true,
-            Tilde                       => true,
             Literal(..)                 => true,
             Not                         => true,
             BinOp(Minus)                => true,
@@ -189,6 +170,7 @@ impl Token {
             OrOr                        => true, // in lambda syntax
             AndAnd                      => true, // double borrow
             DotDot | DotDotDot          => true, // range notation
+            Lt | BinOp(Shl)             => true, // associated path
             ModSep                      => true,
             Interpolated(NtExpr(..))    => true,
             Interpolated(NtIdent(..))   => true,
@@ -253,34 +235,13 @@ impl Token {
         self.is_keyword(keywords::Const)
     }
 
-    pub fn is_path_start(&self) -> bool {
-        self == &ModSep || self == &Lt || self.is_path() ||
-        self.is_path_segment_keyword() || self.is_ident() && !self.is_any_keyword()
+    pub fn is_qpath_start(&self) -> bool {
+        self == &Lt || self == &BinOp(Shl)
     }
 
-    /// Maps a token to its corresponding binary operator.
-    pub fn to_binop(&self) -> Option<BinOpKind> {
-        match *self {
-            BinOp(Star)     => Some(BinOpKind::Mul),
-            BinOp(Slash)    => Some(BinOpKind::Div),
-            BinOp(Percent)  => Some(BinOpKind::Rem),
-            BinOp(Plus)     => Some(BinOpKind::Add),
-            BinOp(Minus)    => Some(BinOpKind::Sub),
-            BinOp(Shl)      => Some(BinOpKind::Shl),
-            BinOp(Shr)      => Some(BinOpKind::Shr),
-            BinOp(And)      => Some(BinOpKind::BitAnd),
-            BinOp(Caret)    => Some(BinOpKind::BitXor),
-            BinOp(Or)       => Some(BinOpKind::BitOr),
-            Lt              => Some(BinOpKind::Lt),
-            Le              => Some(BinOpKind::Le),
-            Ge              => Some(BinOpKind::Ge),
-            Gt              => Some(BinOpKind::Gt),
-            EqEq            => Some(BinOpKind::Eq),
-            Ne              => Some(BinOpKind::Ne),
-            AndAnd          => Some(BinOpKind::And),
-            OrOr            => Some(BinOpKind::Or),
-            _               => None,
-        }
+    pub fn is_path_start(&self) -> bool {
+        self == &ModSep || self.is_qpath_start() || self.is_path() ||
+        self.is_path_segment_keyword() || self.is_ident() && !self.is_any_keyword()
     }
 
     /// Returns `true` if the token is a given keyword, `kw`.
@@ -503,27 +464,20 @@ pub fn clear_ident_interner() {
 /// somehow.
 #[derive(Clone, PartialEq, Hash, PartialOrd, Eq, Ord)]
 pub struct InternedString {
-    string: Rc<String>,
+    string: Rc<str>,
 }
 
 impl InternedString {
     #[inline]
     pub fn new(string: &'static str) -> InternedString {
         InternedString {
-            string: Rc::new(string.to_owned()),
-        }
-    }
-
-    #[inline]
-    fn new_from_rc_str(string: Rc<String>) -> InternedString {
-        InternedString {
-            string: string,
+            string: Rc::__from_str(string),
         }
     }
 
     #[inline]
     pub fn new_from_name(name: ast::Name) -> InternedString {
-        with_ident_interner(|interner| InternedString::new_from_rc_str(interner.get(name)))
+        with_ident_interner(|interner| InternedString { string: interner.get(name) })
     }
 }
 
@@ -591,7 +545,7 @@ impl PartialEq<InternedString> for str {
 
 impl Decodable for InternedString {
     fn decode<D: Decoder>(d: &mut D) -> Result<InternedString, D::Error> {
-        Ok(intern(d.read_str()?.as_ref()).as_str())
+        Ok(intern(&d.read_str()?).as_str())
     }
 }
 
diff --git a/src/libsyntax/print/pp.rs b/src/libsyntax/print/pp.rs
index 32b66da4d96..792239e7219 100644
--- a/src/libsyntax/print/pp.rs
+++ b/src/libsyntax/print/pp.rs
@@ -125,9 +125,8 @@ impl fmt::Display for Token {
     }
 }
 
-fn buf_str(toks: &[Token], szs: &[isize], left: usize, right: usize, lim: usize) -> String {
-    let n = toks.len();
-    assert_eq!(n, szs.len());
+fn buf_str(buf: &[BufEntry], left: usize, right: usize, lim: usize) -> String {
+    let n = buf.len();
     let mut i = left;
     let mut l = lim;
     let mut s = String::from("[");
@@ -136,7 +135,7 @@ fn buf_str(toks: &[Token], szs: &[isize], left: usize, right: usize, lim: usize)
         if i != left {
             s.push_str(", ");
         }
-        s.push_str(&format!("{}={}", szs[i], &toks[i]));
+        s.push_str(&format!("{}={}", buf[i].size, &buf[i].token));
         i += 1;
         i %= n;
     }
@@ -159,13 +158,9 @@ pub struct PrintStackElem {
 const SIZE_INFINITY: isize = 0xffff;
 
 pub fn mk_printer<'a>(out: Box<io::Write+'a>, linewidth: usize) -> Printer<'a> {
-    // Yes 55, it makes the ring buffers big enough to never
-    // fall behind.
+    // Yes 55, it makes the ring buffers big enough to never fall behind.
     let n: usize = 55 * linewidth;
     debug!("mk_printer {}", linewidth);
-    let token = vec![Token::Eof; n];
-    let size = vec![0; n];
-    let scan_stack = VecDeque::with_capacity(n);
     Printer {
         out: out,
         buf_len: n,
@@ -173,11 +168,10 @@ pub fn mk_printer<'a>(out: Box<io::Write+'a>, linewidth: usize) -> Printer<'a> {
         space: linewidth as isize,
         left: 0,
         right: 0,
-        token: token,
-        size: size,
+        buf: vec![BufEntry { token: Token::Eof, size: 0 }; n],
         left_total: 0,
         right_total: 0,
-        scan_stack: scan_stack,
+        scan_stack: VecDeque::new(),
         print_stack: Vec::new(),
         pending_indentation: 0
     }
@@ -269,10 +263,8 @@ pub struct Printer<'a> {
     left: usize,
     /// Index of right side of input stream
     right: usize,
-    /// Ring-buffer stream goes through
-    token: Vec<Token> ,
-    /// Ring-buffer of calculated sizes
-    size: Vec<isize> ,
+    /// Ring-buffer of tokens and calculated sizes
+    buf: Vec<BufEntry>,
     /// Running size of stream "...left"
     left_total: isize,
     /// Running size of stream "...right"
@@ -283,20 +275,26 @@ pub struct Printer<'a> {
     /// Begin (if there is any) on top of it. Stuff is flushed off the
     /// bottom as it becomes irrelevant due to the primary ring-buffer
     /// advancing.
-    scan_stack: VecDeque<usize> ,
+    scan_stack: VecDeque<usize>,
     /// Stack of blocks-in-progress being flushed by print
     print_stack: Vec<PrintStackElem> ,
     /// Buffered indentation to avoid writing trailing whitespace
     pending_indentation: isize,
 }
 
+#[derive(Clone)]
+struct BufEntry {
+    token: Token,
+    size: isize,
+}
+
 impl<'a> Printer<'a> {
     pub fn last_token(&mut self) -> Token {
-        self.token[self.right].clone()
+        self.buf[self.right].token.clone()
     }
     // be very careful with this!
     pub fn replace_last_token(&mut self, t: Token) {
-        self.token[self.right] = t;
+        self.buf[self.right].token = t;
     }
     pub fn pretty_print(&mut self, token: Token) -> io::Result<()> {
         debug!("pp Vec<{},{}>", self.left, self.right);
@@ -318,8 +316,7 @@ impl<'a> Printer<'a> {
             } else { self.advance_right(); }
             debug!("pp Begin({})/buffer Vec<{},{}>",
                    b.offset, self.left, self.right);
-            self.token[self.right] = token;
-            self.size[self.right] = -self.right_total;
+            self.buf[self.right] = BufEntry { token: token, size: -self.right_total };
             let right = self.right;
             self.scan_push(right);
             Ok(())
@@ -331,8 +328,7 @@ impl<'a> Printer<'a> {
             } else {
                 debug!("pp End/buffer Vec<{},{}>", self.left, self.right);
                 self.advance_right();
-                self.token[self.right] = token;
-                self.size[self.right] = -1;
+                self.buf[self.right] = BufEntry { token: token, size: -1 };
                 let right = self.right;
                 self.scan_push(right);
                 Ok(())
@@ -350,8 +346,7 @@ impl<'a> Printer<'a> {
             self.check_stack(0);
             let right = self.right;
             self.scan_push(right);
-            self.token[self.right] = token;
-            self.size[self.right] = -self.right_total;
+            self.buf[self.right] = BufEntry { token: token, size: -self.right_total };
             self.right_total += b.blank_space;
             Ok(())
           }
@@ -364,8 +359,7 @@ impl<'a> Printer<'a> {
                 debug!("pp String('{}')/buffer Vec<{},{}>",
                        s, self.left, self.right);
                 self.advance_right();
-                self.token[self.right] = Token::String(s, len);
-                self.size[self.right] = len;
+                self.buf[self.right] = BufEntry { token: Token::String(s, len), size: len };
                 self.right_total += len;
                 self.check_stream()
             }
@@ -381,7 +375,7 @@ impl<'a> Printer<'a> {
             if Some(&self.left) == self.scan_stack.back() {
                 debug!("setting {} to infinity and popping", self.left);
                 let scanned = self.scan_pop_bottom();
-                self.size[scanned] = SIZE_INFINITY;
+                self.buf[scanned].size = SIZE_INFINITY;
             }
             self.advance_left()?;
             if self.left != self.right {
@@ -410,12 +404,12 @@ impl<'a> Printer<'a> {
     }
     pub fn advance_left(&mut self) -> io::Result<()> {
         debug!("advance_left Vec<{},{}>, sizeof({})={}", self.left, self.right,
-               self.left, self.size[self.left]);
+               self.left, self.buf[self.left].size);
 
-        let mut left_size = self.size[self.left];
+        let mut left_size = self.buf[self.left].size;
 
         while left_size >= 0 {
-            let left = self.token[self.left].clone();
+            let left = self.buf[self.left].token.clone();
 
             let len = match left {
                 Token::Break(b) => b.blank_space,
@@ -437,7 +431,7 @@ impl<'a> Printer<'a> {
             self.left += 1;
             self.left %= self.buf_len;
 
-            left_size = self.size[self.left];
+            left_size = self.buf[self.left].size;
         }
 
         Ok(())
@@ -445,23 +439,23 @@ impl<'a> Printer<'a> {
     pub fn check_stack(&mut self, k: isize) {
         if !self.scan_stack.is_empty() {
             let x = self.scan_top();
-            match self.token[x] {
+            match self.buf[x].token {
                 Token::Begin(_) => {
                     if k > 0 {
                         let popped = self.scan_pop();
-                        self.size[popped] = self.size[x] + self.right_total;
+                        self.buf[popped].size = self.buf[x].size + self.right_total;
                         self.check_stack(k - 1);
                     }
                 }
                 Token::End => {
                     // paper says + not =, but that makes no sense.
                     let popped = self.scan_pop();
-                    self.size[popped] = 1;
+                    self.buf[popped].size = 1;
                     self.check_stack(k + 1);
                 }
                 _ => {
                     let popped = self.scan_pop();
-                    self.size[popped] = self.size[x] + self.right_total;
+                    self.buf[popped].size = self.buf[x].size + self.right_total;
                     if k > 0 {
                         self.check_stack(k);
                     }
@@ -499,8 +493,7 @@ impl<'a> Printer<'a> {
     pub fn print(&mut self, token: Token, l: isize) -> io::Result<()> {
         debug!("print {} {} (remaining line space={})", token, l,
                self.space);
-        debug!("{}", buf_str(&self.token,
-                             &self.size,
+        debug!("{}", buf_str(&self.buf,
                              self.left,
                              self.right,
                              6));
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 8563d27908d..b0bd6446743 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -112,7 +112,7 @@ pub fn print_crate<'a>(cm: &'a CodeMap,
                                       out,
                                       ann,
                                       is_expanded);
-    if is_expanded && !std_inject::no_std(krate) {
+    if is_expanded && !std_inject::injected_crate_name(krate).is_none() {
         // We need to print `#![no_std]` (and its feature gate) so that
         // compiling pretty-printed source won't inject libstd again.
         // However we don't want these attributes in the AST because
@@ -285,8 +285,6 @@ pub fn token_to_string(tok: &Token) -> String {
         token::Comment              => "/* */".to_string(),
         token::Shebang(s)           => format!("/* shebang: {}*/", s),
 
-        token::SpecialVarNt(var)    => format!("${}", var.as_str()),
-
         token::Interpolated(ref nt) => match *nt {
             token::NtExpr(ref e)        => expr_to_string(&e),
             token::NtMeta(ref e)        => meta_item_to_string(&e),
@@ -545,15 +543,12 @@ pub trait PrintState<'a> {
     }
 
     fn maybe_print_comment(&mut self, pos: BytePos) -> io::Result<()> {
-        loop {
-            match self.next_comment() {
-                Some(ref cmnt) => {
-                    if (*cmnt).pos < pos {
-                        try!(self.print_comment(cmnt));
-                        self.cur_cmnt_and_lit().cur_cmnt += 1;
-                    } else { break; }
-                }
-                _ => break
+        while let Some(ref cmnt) = self.next_comment() {
+            if cmnt.pos < pos {
+                try!(self.print_comment(cmnt));
+                self.cur_cmnt_and_lit().cur_cmnt += 1;
+            } else {
+                break
             }
         }
         Ok(())
@@ -581,7 +576,9 @@ pub trait PrintState<'a> {
                 Ok(())
             }
             comments::Trailing => {
-                try!(word(self.writer(), " "));
+                if !self.is_bol() {
+                    try!(word(self.writer(), " "));
+                }
                 if cmnt.lines.len() == 1 {
                     try!(word(self.writer(), &cmnt.lines[0]));
                     hardbreak(self.writer())
@@ -972,7 +969,7 @@ impl<'a> State<'a> {
         try!(self.maybe_print_comment(ty.span.lo));
         try!(self.ibox(0));
         match ty.node {
-            ast::TyKind::Vec(ref ty) => {
+            ast::TyKind::Slice(ref ty) => {
                 try!(word(&mut self.s, "["));
                 try!(self.print_type(&ty));
                 try!(word(&mut self.s, "]"));
@@ -1039,7 +1036,7 @@ impl<'a> State<'a> {
             ast::TyKind::ImplTrait(ref bounds) => {
                 try!(self.print_bounds("impl ", &bounds[..]));
             }
-            ast::TyKind::FixedLengthVec(ref ty, ref v) => {
+            ast::TyKind::Array(ref ty, ref v) => {
                 try!(word(&mut self.s, "["));
                 try!(self.print_type(&ty));
                 try!(word(&mut self.s, "; "));
@@ -1361,6 +1358,7 @@ impl<'a> State<'a> {
                 if comma {
                     try!(self.word_space(","))
                 }
+                try!(self.print_outer_attributes_inline(&lifetime_def.attrs));
                 try!(self.print_lifetime_bounds(&lifetime_def.lifetime, &lifetime_def.bounds));
                 comma = true;
             }
@@ -1715,6 +1713,7 @@ impl<'a> State<'a> {
         for (i, st) in blk.stmts.iter().enumerate() {
             match st.node {
                 ast::StmtKind::Expr(ref expr) if i == blk.stmts.len() - 1 => {
+                    try!(self.maybe_print_comment(st.span.lo));
                     try!(self.space_if_not_bol());
                     try!(self.print_expr_outer_attr_style(&expr, false));
                     try!(self.maybe_print_trailing_comment(expr.span, Some(blk.span.hi)));
@@ -1894,8 +1893,10 @@ impl<'a> State<'a> {
             &fields[..],
             |s, field| {
                 try!(s.ibox(INDENT_UNIT));
-                try!(s.print_ident(field.ident.node));
-                try!(s.word_space(":"));
+                if !field.is_shorthand {
+                    try!(s.print_ident(field.ident.node));
+                    try!(s.word_space(":"));
+                }
                 try!(s.print_expr(&field.expr));
                 s.end()
             },
@@ -2276,7 +2277,7 @@ impl<'a> State<'a> {
                     Ok(())
                 }));
 
-                let mut options = vec!();
+                let mut options = vec![];
                 if a.volatile {
                     options.push("volatile");
                 }
@@ -2450,13 +2451,10 @@ impl<'a> State<'a> {
                     |s, ty| s.print_type(&ty)));
                 try!(word(&mut self.s, ")"));
 
-                match data.output {
-                    None => { }
-                    Some(ref ty) => {
-                        try!(self.space_if_not_bol());
-                        try!(self.word_space("->"));
-                        try!(self.print_type(&ty));
-                    }
+                if let Some(ref ty) = data.output {
+                    try!(self.space_if_not_bol());
+                    try!(self.word_space("->"));
+                    try!(self.print_type(&ty));
                 }
             }
         }
@@ -2573,7 +2571,7 @@ impl<'a> State<'a> {
                 try!(word(&mut self.s, "..."));
                 try!(self.print_expr(&end));
             }
-            PatKind::Vec(ref before, ref slice, ref after) => {
+            PatKind::Slice(ref before, ref slice, ref after) => {
                 try!(word(&mut self.s, "["));
                 try!(self.commasep(Inconsistent,
                                    &before[..],
@@ -2604,6 +2602,7 @@ impl<'a> State<'a> {
         }
         try!(self.cbox(INDENT_UNIT));
         try!(self.ibox(0));
+        try!(self.maybe_print_comment(arm.pats[0].span.lo));
         try!(self.print_outer_attributes(&arm.attrs));
         let mut first = true;
         for p in &arm.pats {
@@ -2803,6 +2802,7 @@ impl<'a> State<'a> {
         try!(self.commasep(Inconsistent, &ints[..], |s, &idx| {
             if idx < generics.lifetimes.len() {
                 let lifetime_def = &generics.lifetimes[idx];
+                try!(s.print_outer_attributes_inline(&lifetime_def.attrs));
                 s.print_lifetime_bounds(&lifetime_def.lifetime, &lifetime_def.bounds)
             } else {
                 let idx = idx - generics.lifetimes.len();
@@ -2816,6 +2816,7 @@ impl<'a> State<'a> {
     }
 
     pub fn print_ty_param(&mut self, param: &ast::TyParam) -> io::Result<()> {
+        try!(self.print_outer_attributes_inline(&param.attrs));
         try!(self.print_ident(param.ident));
         try!(self.print_bounds(":", &param.bounds));
         match param.default {
@@ -3007,15 +3008,11 @@ impl<'a> State<'a> {
             _ => return Ok(())
         };
         if let Some(ref cmnt) = self.next_comment() {
-            if (*cmnt).style != comments::Trailing { return Ok(()) }
+            if cmnt.style != comments::Trailing { return Ok(()) }
             let span_line = cm.lookup_char_pos(span.hi);
-            let comment_line = cm.lookup_char_pos((*cmnt).pos);
-            let mut next = (*cmnt).pos + BytePos(1);
-            if let Some(p) = next_pos {
-                next = p;
-            }
-            if span.hi < (*cmnt).pos && (*cmnt).pos < next &&
-               span_line.line == comment_line.line {
+            let comment_line = cm.lookup_char_pos(cmnt.pos);
+            let next = next_pos.unwrap_or(cmnt.pos + BytePos(1));
+            if span.hi < cmnt.pos && cmnt.pos < next && span_line.line == comment_line.line {
                 self.print_comment(cmnt)?;
                 self.cur_cmnt_and_lit.cur_cmnt += 1;
             }
diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs
index d1454ab06cb..1b63a2b7076 100644
--- a/src/libsyntax/std_inject.rs
+++ b/src/libsyntax/std_inject.rs
@@ -34,23 +34,25 @@ fn ignored_span(sess: &ParseSess, sp: Span) -> Span {
     return sp;
 }
 
-pub fn no_core(krate: &ast::Crate) -> bool {
-    attr::contains_name(&krate.attrs, "no_core")
-}
-
-pub fn no_std(krate: &ast::Crate) -> bool {
-    attr::contains_name(&krate.attrs, "no_std") || no_core(krate)
+pub fn injected_crate_name(krate: &ast::Crate) -> Option<&'static str> {
+    if attr::contains_name(&krate.attrs, "no_core") {
+        None
+    } else if attr::contains_name(&krate.attrs, "no_std") {
+        Some("core")
+    } else {
+        Some("std")
+    }
 }
 
 pub fn maybe_inject_crates_ref(sess: &ParseSess,
                                mut krate: ast::Crate,
                                alt_std_name: Option<String>)
                                -> ast::Crate {
-    if no_core(&krate) {
-        return krate;
-    }
+    let name = match injected_crate_name(&krate) {
+        Some(name) => name,
+        None => return krate,
+    };
 
-    let name = if no_std(&krate) { "core" } else { "std" };
     let crate_name = token::intern(&alt_std_name.unwrap_or(name.to_string()));
 
     krate.module.items.insert(0, P(ast::Item {
diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs
index 6327e8f71bc..618878c1f79 100644
--- a/src/libsyntax/test.rs
+++ b/src/libsyntax/test.rs
@@ -19,7 +19,7 @@ use std::iter;
 use std::slice;
 use std::mem;
 use std::vec;
-use attr;
+use attr::{self, HasAttrs};
 use syntax_pos::{self, DUMMY_SP, NO_EXPANSION, Span, FileMap, BytePos};
 use std::rc::Rc;
 
@@ -119,7 +119,7 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> {
         }
         debug!("current path: {}", path_name_i(&self.cx.path));
 
-        let i = if is_test_fn(&self.cx, &i) || is_bench_fn(&self.cx, &i) {
+        if is_test_fn(&self.cx, &i) || is_bench_fn(&self.cx, &i) {
             match i.node {
                 ast::ItemKind::Fn(_, ast::Unsafety::Unsafe, _, _, _, _) => {
                     let diag = self.cx.span_diagnostic;
@@ -136,54 +136,37 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> {
                     };
                     self.cx.testfns.push(test);
                     self.tests.push(i.ident);
-                    // debug!("have {} test/bench functions",
-                    //        cx.testfns.len());
-
-                    // Make all tests public so we can call them from outside
-                    // the module (note that the tests are re-exported and must
-                    // be made public themselves to avoid privacy errors).
-                    i.map(|mut i| {
-                        i.vis = ast::Visibility::Public;
-                        i
-                    })
                 }
             }
-        } else {
-            i
-        };
+        }
 
+        let mut item = i.unwrap();
         // We don't want to recurse into anything other than mods, since
         // mods or tests inside of functions will break things
-        let res = match i.node {
-            ast::ItemKind::Mod(..) => fold::noop_fold_item(i, self),
-            _ => SmallVector::one(i),
-        };
+        if let ast::ItemKind::Mod(module) = item.node {
+            let tests = mem::replace(&mut self.tests, Vec::new());
+            let tested_submods = mem::replace(&mut self.tested_submods, Vec::new());
+            let mut mod_folded = fold::noop_fold_mod(module, self);
+            let tests = mem::replace(&mut self.tests, tests);
+            let tested_submods = mem::replace(&mut self.tested_submods, tested_submods);
+
+            if !tests.is_empty() || !tested_submods.is_empty() {
+                let (it, sym) = mk_reexport_mod(&mut self.cx, item.id, tests, tested_submods);
+                mod_folded.items.push(it);
+
+                if !self.cx.path.is_empty() {
+                    self.tested_submods.push((self.cx.path[self.cx.path.len()-1], sym));
+                } else {
+                    debug!("pushing nothing, sym: {:?}", sym);
+                    self.cx.toplevel_reexport = Some(sym);
+                }
+            }
+            item.node = ast::ItemKind::Mod(mod_folded);
+        }
         if ident.name != keywords::Invalid.name() {
             self.cx.path.pop();
         }
-        res
-    }
-
-    fn fold_mod(&mut self, m: ast::Mod) -> ast::Mod {
-        let tests = mem::replace(&mut self.tests, Vec::new());
-        let tested_submods = mem::replace(&mut self.tested_submods, Vec::new());
-        let mut mod_folded = fold::noop_fold_mod(m, self);
-        let tests = mem::replace(&mut self.tests, tests);
-        let tested_submods = mem::replace(&mut self.tested_submods, tested_submods);
-
-        if !tests.is_empty() || !tested_submods.is_empty() {
-            let (it, sym) = mk_reexport_mod(&mut self.cx, tests, tested_submods);
-            mod_folded.items.push(it);
-
-            if !self.cx.path.is_empty() {
-                self.tested_submods.push((self.cx.path[self.cx.path.len()-1], sym));
-            } else {
-                debug!("pushing nothing, sym: {:?}", sym);
-                self.cx.toplevel_reexport = Some(sym);
-            }
-        }
-
-        mod_folded
+        SmallVector::one(P(item))
     }
 
     fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { mac }
@@ -239,16 +222,24 @@ impl fold::Folder for EntryPointCleaner {
     fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { mac }
 }
 
-fn mk_reexport_mod(cx: &mut TestCtxt, tests: Vec<ast::Ident>,
+fn mk_reexport_mod(cx: &mut TestCtxt, parent: ast::NodeId, tests: Vec<ast::Ident>,
                    tested_submods: Vec<(ast::Ident, ast::Ident)>) -> (P<ast::Item>, ast::Ident) {
     let super_ = token::str_to_ident("super");
 
+    // Generate imports with `#[allow(private_in_public)]` to work around issue #36768.
+    let allow_private_in_public = cx.ext_cx.attribute(DUMMY_SP, cx.ext_cx.meta_list(
+        DUMMY_SP,
+        InternedString::new("allow"),
+        vec![cx.ext_cx.meta_list_item_word(DUMMY_SP, InternedString::new("private_in_public"))],
+    ));
     let items = tests.into_iter().map(|r| {
         cx.ext_cx.item_use_simple(DUMMY_SP, ast::Visibility::Public,
                                   cx.ext_cx.path(DUMMY_SP, vec![super_, r]))
+            .map_attrs(|_| vec![allow_private_in_public.clone()])
     }).chain(tested_submods.into_iter().map(|(r, sym)| {
         let path = cx.ext_cx.path(DUMMY_SP, vec![super_, r, sym]);
         cx.ext_cx.item_use_simple_(DUMMY_SP, ast::Visibility::Public, r, path)
+            .map_attrs(|_| vec![allow_private_in_public.clone()])
     })).collect();
 
     let reexport_mod = ast::Mod {
@@ -257,6 +248,8 @@ fn mk_reexport_mod(cx: &mut TestCtxt, tests: Vec<ast::Ident>,
     };
 
     let sym = token::gensym_ident("__test_reexports");
+    let parent = if parent == ast::DUMMY_NODE_ID { ast::CRATE_NODE_ID } else { parent };
+    cx.ext_cx.current_expansion.mark = cx.ext_cx.resolver.get_module_scope(parent);
     let it = cx.ext_cx.monotonic_expander().fold_item(P(ast::Item {
         ident: sym.clone(),
         attrs: Vec::new(),
@@ -281,7 +274,7 @@ fn generate_test_harness(sess: &ParseSess,
     let mut cx: TestCtxt = TestCtxt {
         sess: sess,
         span_diagnostic: sd,
-        ext_cx: ExtCtxt::new(sess, vec![], ExpansionConfig::default("test".to_string()), resolver),
+        ext_cx: ExtCtxt::new(sess, ExpansionConfig::default("test".to_string()), resolver),
         path: Vec::new(),
         testfns: Vec::new(),
         reexport_test_harness_main: reexport_test_harness_main,
@@ -437,7 +430,7 @@ fn mk_std(cx: &TestCtxt) -> P<ast::Item> {
     let (vi, vis, ident) = if cx.is_test_crate {
         (ast::ItemKind::Use(
             P(nospan(ast::ViewPathSimple(id_test,
-                                         path_node(vec!(id_test)))))),
+                                         path_node(vec![id_test]))))),
          ast::Visibility::Public, keywords::Invalid.ident())
     } else {
         (ast::ItemKind::ExternCrate(None), ast::Visibility::Inherited, id_test)
@@ -579,7 +572,7 @@ fn mk_tests(cx: &TestCtxt) -> P<ast::Item> {
     let static_lt = ecx.lifetime(sp, keywords::StaticLifetime.name());
     // &'static [self::test::TestDescAndFn]
     let static_type = ecx.ty_rptr(sp,
-                                  ecx.ty(sp, ast::TyKind::Vec(struct_type)),
+                                  ecx.ty(sp, ast::TyKind::Slice(struct_type)),
                                   Some(static_lt),
                                   ast::Mutability::Immutable);
     // static TESTS: $static_type = &[...];
diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs
index 7b1df6f0e97..9e644e59e86 100644
--- a/src/libsyntax/tokenstream.rs
+++ b/src/libsyntax/tokenstream.rs
@@ -33,6 +33,7 @@ use parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration};
 use parse::lexer;
 use parse;
 use parse::token::{self, Token, Lit, Nonterminal};
+use print::pprust;
 
 use std::fmt;
 use std::iter::*;
@@ -133,7 +134,6 @@ impl TokenTree {
                     AttrStyle::Inner => 3,
                 }
             }
-            TokenTree::Token(_, token::SpecialVarNt(..)) => 2,
             TokenTree::Token(_, token::MatchNt(..)) => 3,
             TokenTree::Token(_, token::Interpolated(Nonterminal::NtTT(..))) => 1,
             TokenTree::Delimited(_, ref delimed) => delimed.tts.len() + 2,
@@ -187,11 +187,6 @@ impl TokenTree {
                 }
                 delimed.tts[index - 1].clone()
             }
-            (&TokenTree::Token(sp, token::SpecialVarNt(var)), _) => {
-                let v = [TokenTree::Token(sp, token::Dollar),
-                         TokenTree::Token(sp, token::Ident(token::str_to_ident(var.as_str())))];
-                v[index].clone()
-            }
             (&TokenTree::Token(sp, token::MatchNt(name, kind)), _) => {
                 let v = [TokenTree::Token(sp, token::SubstNt(name)),
                          TokenTree::Token(sp, token::Colon),
@@ -223,10 +218,9 @@ impl TokenTree {
         // `None` is because we're not interpolating
         let arg_rdr = lexer::new_tt_reader_with_doc_flag(&cx.parse_sess().span_diagnostic,
                                                          None,
-                                                         None,
                                                          tts.iter().cloned().collect(),
                                                          true);
-        macro_parser::parse(cx.parse_sess(), cx.cfg(), arg_rdr, mtch)
+        macro_parser::parse(cx.parse_sess(), arg_rdr, mtch)
     }
 
     /// Check if this TokenTree is equal to the other, regardless of span information.
@@ -781,6 +775,12 @@ impl TokenStream {
     }
 }
 
+impl fmt::Display for TokenStream {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.write_str(&pprust::tts_to_string(&self.to_tts()))
+    }
+}
+
 // FIXME Reimplement this iterator to hold onto a slice iterator for a leaf, getting the
 // next leaf's iterator when the current one is exhausted.
 pub struct Iter<'a> {
diff --git a/src/libsyntax/util/interner.rs b/src/libsyntax/util/interner.rs
index 6bb409715aa..f56c6cedcd1 100644
--- a/src/libsyntax/util/interner.rs
+++ b/src/libsyntax/util/interner.rs
@@ -14,23 +14,13 @@
 
 use ast::Name;
 
-use std::borrow::Borrow;
 use std::collections::HashMap;
 use std::rc::Rc;
 
-#[derive(PartialEq, Eq, Hash)]
-struct RcStr(Rc<String>);
-
-impl Borrow<str> for RcStr {
-    fn borrow(&self) -> &str {
-        &self.0
-    }
-}
-
 #[derive(Default)]
 pub struct Interner {
-    names: HashMap<RcStr, Name>,
-    strings: Vec<Rc<String>>,
+    names: HashMap<Rc<str>, Name>,
+    strings: Vec<Rc<str>>,
 }
 
 /// When traits can extend traits, we should extend index<Name,T> to get []
@@ -47,22 +37,22 @@ impl Interner {
         this
     }
 
-    pub fn intern<T: Borrow<str> + Into<String>>(&mut self, string: T) -> Name {
-        if let Some(&name) = self.names.get(string.borrow()) {
+    pub fn intern(&mut self, string: &str) -> Name {
+        if let Some(&name) = self.names.get(string) {
             return name;
         }
 
         let name = Name(self.strings.len() as u32);
-        let string = Rc::new(string.into());
+        let string = Rc::__from_str(string);
         self.strings.push(string.clone());
-        self.names.insert(RcStr(string), name);
+        self.names.insert(string, name);
         name
     }
 
     pub fn gensym(&mut self, string: &str) -> Name {
         let gensym = Name(self.strings.len() as u32);
         // leave out of `names` to avoid colliding
-        self.strings.push(Rc::new(string.to_owned()));
+        self.strings.push(Rc::__from_str(string));
         gensym
     }
 
@@ -75,7 +65,7 @@ impl Interner {
         gensym
     }
 
-    pub fn get(&self, name: Name) -> Rc<String> {
+    pub fn get(&self, name: Name) -> Rc<str> {
         self.strings[name.0 as usize].clone()
     }
 
@@ -109,13 +99,13 @@ mod tests {
         assert_eq!(i.gensym("dog"), Name(4));
         // gensym tests again with gensym_copy:
         assert_eq!(i.gensym_copy(Name(2)), Name(5));
-        assert_eq!(*i.get(Name(5)), "zebra");
+        assert_eq!(&*i.get(Name(5)), "zebra");
         assert_eq!(i.gensym_copy(Name(2)), Name(6));
-        assert_eq!(*i.get(Name(6)), "zebra");
-        assert_eq!(*i.get(Name(0)), "dog");
-        assert_eq!(*i.get(Name(1)), "cat");
-        assert_eq!(*i.get(Name(2)), "zebra");
-        assert_eq!(*i.get(Name(3)), "zebra");
-        assert_eq!(*i.get(Name(4)), "dog");
+        assert_eq!(&*i.get(Name(6)), "zebra");
+        assert_eq!(&*i.get(Name(0)), "dog");
+        assert_eq!(&*i.get(Name(1)), "cat");
+        assert_eq!(&*i.get(Name(2)), "zebra");
+        assert_eq!(&*i.get(Name(3)), "zebra");
+        assert_eq!(&*i.get(Name(4)), "dog");
     }
 }
diff --git a/src/libsyntax/util/parser_testing.rs b/src/libsyntax/util/parser_testing.rs
index f59428bf536..76d3f2a063c 100644
--- a/src/libsyntax/util/parser_testing.rs
+++ b/src/libsyntax/util/parser_testing.rs
@@ -25,10 +25,7 @@ pub fn string_to_tts(source_str: String) -> Vec<tokenstream::TokenTree> {
 
 /// Map string to parser (via tts)
 pub fn string_to_parser<'a>(ps: &'a ParseSess, source_str: String) -> Parser<'a> {
-    new_parser_from_source_str(ps,
-                               Vec::new(),
-                               "bogofile".to_string(),
-                               source_str)
+    new_parser_from_source_str(ps, "bogofile".to_string(), source_str)
 }
 
 fn with_error_checking_parse<'a, T, F>(s: String, ps: &'a ParseSess, f: F) -> T where
diff --git a/src/libsyntax/util/small_vector.rs b/src/libsyntax/util/small_vector.rs
index 373dfc4ddfa..9be7dbd6817 100644
--- a/src/libsyntax/util/small_vector.rs
+++ b/src/libsyntax/util/small_vector.rs
@@ -11,6 +11,7 @@
 use self::SmallVectorRepr::*;
 use self::IntoIterRepr::*;
 
+use core::ops;
 use std::iter::{IntoIterator, FromIterator};
 use std::mem;
 use std::slice;
@@ -19,10 +20,12 @@ use std::vec;
 use util::move_map::MoveMap;
 
 /// A vector type optimized for cases where the size is almost always 0 or 1
+#[derive(Clone)]
 pub struct SmallVector<T> {
     repr: SmallVectorRepr<T>,
 }
 
+#[derive(Clone)]
 enum SmallVectorRepr<T> {
     Zero,
     One(T),
@@ -75,16 +78,11 @@ impl<T> SmallVector<T> {
     }
 
     pub fn as_slice(&self) -> &[T] {
-        match self.repr {
-            Zero => {
-                let result: &[T] = &[];
-                result
-            }
-            One(ref v) => {
-                unsafe { slice::from_raw_parts(v, 1) }
-            }
-            Many(ref vs) => vs
-        }
+        self
+    }
+
+    pub fn as_mut_slice(&mut self) -> &mut [T] {
+        self
     }
 
     pub fn pop(&mut self) -> Option<T> {
@@ -107,7 +105,7 @@ impl<T> SmallVector<T> {
             One(..) => {
                 let one = mem::replace(&mut self.repr, Zero);
                 match one {
-                    One(v1) => mem::replace(&mut self.repr, Many(vec!(v1, v))),
+                    One(v1) => mem::replace(&mut self.repr, Many(vec![v1, v])),
                     _ => unreachable!()
                 };
             }
@@ -163,6 +161,38 @@ impl<T> SmallVector<T> {
     }
 }
 
+impl<T> ops::Deref for SmallVector<T> {
+    type Target = [T];
+
+    fn deref(&self) -> &[T] {
+        match self.repr {
+            Zero => {
+                let result: &[T] = &[];
+                result
+            }
+            One(ref v) => {
+                unsafe { slice::from_raw_parts(v, 1) }
+            }
+            Many(ref vs) => vs
+        }
+    }
+}
+
+impl<T> ops::DerefMut for SmallVector<T> {
+    fn deref_mut(&mut self) -> &mut [T] {
+        match self.repr {
+            Zero => {
+                let result: &mut [T] = &mut [];
+                result
+            }
+            One(ref mut v) => {
+                unsafe { slice::from_raw_parts_mut(v, 1) }
+            }
+            Many(ref mut vs) => vs
+        }
+    }
+}
+
 impl<T> IntoIterator for SmallVector<T> {
     type Item = T;
     type IntoIter = IntoIter<T>;
@@ -284,12 +314,12 @@ mod tests {
     #[test]
     #[should_panic]
     fn test_expect_one_many() {
-        SmallVector::many(vec!(1, 2)).expect_one("");
+        SmallVector::many(vec![1, 2]).expect_one("");
     }
 
     #[test]
     fn test_expect_one_one() {
         assert_eq!(1, SmallVector::one(1).expect_one(""));
-        assert_eq!(1, SmallVector::many(vec!(1)).expect_one(""));
+        assert_eq!(1, SmallVector::many(vec![1]).expect_one(""));
     }
 }
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index efd9b027504..7fb3e5c6bee 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -201,6 +201,7 @@ pub fn walk_lifetime<V: Visitor>(visitor: &mut V, lifetime: &Lifetime) {
 pub fn walk_lifetime_def<V: Visitor>(visitor: &mut V, lifetime_def: &LifetimeDef) {
     visitor.visit_lifetime(&lifetime_def.lifetime);
     walk_list!(visitor, visit_lifetime, &lifetime_def.bounds);
+    walk_list!(visitor, visit_attribute, &*lifetime_def.attrs);
 }
 
 pub fn walk_poly_trait_ref<V>(visitor: &mut V, trait_ref: &PolyTraitRef, _: &TraitBoundModifier)
@@ -313,7 +314,7 @@ pub fn walk_variant<V>(visitor: &mut V, variant: &Variant, generics: &Generics,
 
 pub fn walk_ty<V: Visitor>(visitor: &mut V, typ: &Ty) {
     match typ.node {
-        TyKind::Vec(ref ty) | TyKind::Paren(ref ty) => {
+        TyKind::Slice(ref ty) | TyKind::Paren(ref ty) => {
             visitor.visit_ty(ty)
         }
         TyKind::Ptr(ref mutable_type) => {
@@ -341,7 +342,7 @@ pub fn walk_ty<V: Visitor>(visitor: &mut V, typ: &Ty) {
             visitor.visit_ty(ty);
             walk_list!(visitor, visit_ty_param_bound, bounds);
         }
-        TyKind::FixedLengthVec(ref ty, ref expression) => {
+        TyKind::Array(ref ty, ref expression) => {
             visitor.visit_ty(ty);
             visitor.visit_expr(expression)
         }
@@ -434,7 +435,7 @@ pub fn walk_pat<V: Visitor>(visitor: &mut V, pattern: &Pat) {
             visitor.visit_expr(upper_bound)
         }
         PatKind::Wild => (),
-        PatKind::Vec(ref prepatterns, ref slice_pattern, ref postpatterns) => {
+        PatKind::Slice(ref prepatterns, ref slice_pattern, ref postpatterns) => {
             walk_list!(visitor, visit_pat, prepatterns);
             walk_list!(visitor, visit_pat, slice_pattern);
             walk_list!(visitor, visit_pat, postpatterns);
@@ -474,6 +475,7 @@ pub fn walk_generics<V: Visitor>(visitor: &mut V, generics: &Generics) {
         visitor.visit_ident(param.span, param.ident);
         walk_list!(visitor, visit_ty_param_bound, &param.bounds);
         walk_list!(visitor, visit_ty, &param.default);
+        walk_list!(visitor, visit_attribute, &*param.attrs);
     }
     walk_list!(visitor, visit_lifetime_def, &generics.lifetimes);
     for predicate in &generics.where_clause.predicates {
@@ -532,8 +534,8 @@ pub fn walk_fn_kind<V: Visitor>(visitor: &mut V, function_kind: FnKind) {
 pub fn walk_fn<V>(visitor: &mut V, kind: FnKind, declaration: &FnDecl, body: &Block, _span: Span)
     where V: Visitor,
 {
-    walk_fn_decl(visitor, declaration);
     walk_fn_kind(visitor, kind);
+    walk_fn_decl(visitor, declaration);
     visitor.visit_block(body)
 }
 
@@ -652,13 +654,13 @@ pub fn walk_expr<V: Visitor>(visitor: &mut V, expression: &Expr) {
             walk_list!(visitor, visit_expr, subexpressions);
         }
         ExprKind::Call(ref callee_expression, ref arguments) => {
+            visitor.visit_expr(callee_expression);
             walk_list!(visitor, visit_expr, arguments);
-            visitor.visit_expr(callee_expression)
         }
         ExprKind::MethodCall(ref ident, ref types, ref arguments) => {
             visitor.visit_ident(ident.span, ident.node);
-            walk_list!(visitor, visit_expr, arguments);
             walk_list!(visitor, visit_ty, types);
+            walk_list!(visitor, visit_expr, arguments);
         }
         ExprKind::Binary(_, ref left_expression, ref right_expression) => {
             visitor.visit_expr(left_expression);
@@ -717,12 +719,12 @@ pub fn walk_expr<V: Visitor>(visitor: &mut V, expression: &Expr) {
         }
         ExprKind::Block(ref block) => visitor.visit_block(block),
         ExprKind::Assign(ref left_hand_expression, ref right_hand_expression) => {
+            visitor.visit_expr(left_hand_expression);
             visitor.visit_expr(right_hand_expression);
-            visitor.visit_expr(left_hand_expression)
         }
         ExprKind::AssignOp(_, ref left_expression, ref right_expression) => {
+            visitor.visit_expr(left_expression);
             visitor.visit_expr(right_expression);
-            visitor.visit_expr(left_expression)
         }
         ExprKind::Field(ref subexpression, ref ident) => {
             visitor.visit_expr(subexpression);