about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2017-04-04 08:10:22 -0700
committerEsteban Küber <esteban@kuber.com.ar>2017-04-04 08:13:27 -0700
commitdedb7bbbbf272226f327b8cda8aaa12cf6325eca (patch)
tree9c7c7b656750a53b5ca4f7646ee1dfe60829b271 /src/libsyntax
parentb477682dca3343eb89a467f0d3c73986a53d49d9 (diff)
parent5309a3e31d88def1f3ea966162ed4f81f161d500 (diff)
downloadrust-dedb7bbbbf272226f327b8cda8aaa12cf6325eca.tar.gz
rust-dedb7bbbbf272226f327b8cda8aaa12cf6325eca.zip
Merge branch 'master' into issue-32540
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/Cargo.toml2
-rw-r--r--src/libsyntax/ast.rs86
-rw-r--r--src/libsyntax/attr.rs22
-rw-r--r--src/libsyntax/codemap.rs480
-rw-r--r--src/libsyntax/ext/base.rs95
-rw-r--r--src/libsyntax/ext/derive.rs50
-rw-r--r--src/libsyntax/ext/expand.rs117
-rw-r--r--src/libsyntax/ext/hygiene.rs127
-rw-r--r--src/libsyntax/ext/placeholders.rs20
-rw-r--r--src/libsyntax/ext/source_util.rs2
-rw-r--r--src/libsyntax/ext/tt/macro_parser.rs11
-rw-r--r--src/libsyntax/ext/tt/macro_rules.rs4
-rw-r--r--src/libsyntax/ext/tt/quoted.rs27
-rw-r--r--src/libsyntax/ext/tt/transcribe.rs9
-rw-r--r--src/libsyntax/feature_gate.rs29
-rw-r--r--src/libsyntax/json.rs2
-rw-r--r--src/libsyntax/lib.rs4
-rw-r--r--src/libsyntax/parse/attr.rs29
-rw-r--r--src/libsyntax/parse/lexer/mod.rs42
-rw-r--r--src/libsyntax/parse/lexer/unicode_chars.rs4
-rw-r--r--src/libsyntax/parse/mod.rs10
-rw-r--r--src/libsyntax/parse/obsolete.rs1
-rw-r--r--src/libsyntax/parse/parser.rs744
-rw-r--r--src/libsyntax/parse/token.rs48
-rw-r--r--src/libsyntax/std_inject.rs21
-rw-r--r--src/libsyntax/symbol.rs306
-rw-r--r--src/libsyntax/test.rs23
-rw-r--r--src/libsyntax/test_snippet.rs2
-rw-r--r--src/libsyntax/tokenstream.rs16
29 files changed, 671 insertions, 1662 deletions
diff --git a/src/libsyntax/Cargo.toml b/src/libsyntax/Cargo.toml
index 0b38f5450b6..97d37266130 100644
--- a/src/libsyntax/Cargo.toml
+++ b/src/libsyntax/Cargo.toml
@@ -10,7 +10,7 @@ crate-type = ["dylib"]
 
 [dependencies]
 serialize = { path = "../libserialize" }
-log = { path = "../liblog" }
+log = "0.3"
 rustc_bitflags = { path = "../librustc_bitflags" }
 syntax_pos = { path = "../libsyntax_pos" }
 rustc_errors = { path = "../librustc_errors" }
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 4347046b6b8..9eb86aa006d 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -14,73 +14,25 @@ pub use self::TyParamBound::*;
 pub use self::UnsafeSource::*;
 pub use self::ViewPath_::*;
 pub use self::PathParameters::*;
-pub use symbol::Symbol as Name;
+pub use symbol::{Ident, Symbol as Name};
 pub use util::ThinVec;
 
-use syntax_pos::{mk_sp, BytePos, Span, DUMMY_SP, ExpnId};
+use syntax_pos::{Span, DUMMY_SP};
 use codemap::{respan, Spanned};
 use abi::Abi;
-use ext::hygiene::SyntaxContext;
+use ext::hygiene::{Mark, SyntaxContext};
 use print::pprust;
 use ptr::P;
+use rustc_data_structures::indexed_vec;
 use symbol::{Symbol, keywords};
 use tokenstream::{ThinTokenStream, TokenStream};
 
+use serialize::{self, Encoder, Decoder};
 use std::collections::HashSet;
 use std::fmt;
 use std::rc::Rc;
 use std::u32;
 
-use serialize::{self, Encodable, Decodable, Encoder, Decoder};
-
-/// An identifier contains a Name (index into the interner
-/// table) and a SyntaxContext to track renaming and
-/// macro expansion per Flatt et al., "Macros That Work Together"
-#[derive(Clone, Copy, PartialEq, Eq, Hash)]
-pub struct Ident {
-    pub name: Symbol,
-    pub ctxt: SyntaxContext
-}
-
-impl Ident {
-    pub const fn with_empty_ctxt(name: Name) -> Ident {
-        Ident { name: name, ctxt: SyntaxContext::empty() }
-    }
-
-    /// Maps a string to an identifier with an empty syntax context.
-    pub fn from_str(s: &str) -> Ident {
-        Ident::with_empty_ctxt(Symbol::intern(s))
-    }
-
-    pub fn unhygienize(&self) -> Ident {
-        Ident { name: self.name, ctxt: SyntaxContext::empty() }
-    }
-}
-
-impl fmt::Debug for Ident {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}{:?}", self.name, self.ctxt)
-    }
-}
-
-impl fmt::Display for Ident {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        fmt::Display::fmt(&self.name, f)
-    }
-}
-
-impl Encodable for Ident {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        self.name.encode(s)
-    }
-}
-
-impl Decodable for Ident {
-    fn decode<D: Decoder>(d: &mut D) -> Result<Ident, D::Error> {
-        Ok(Ident::with_empty_ctxt(Name::decode(d)?))
-    }
-}
-
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)]
 pub struct Lifetime {
     pub id: NodeId,
@@ -255,6 +207,14 @@ impl NodeId {
     pub fn as_u32(&self) -> u32 {
         self.0
     }
+
+    pub fn placeholder_from_mark(mark: Mark) -> Self {
+        NodeId(mark.as_u32())
+    }
+
+    pub fn placeholder_to_mark(self) -> Mark {
+        Mark::from_u32(self.0)
+    }
 }
 
 impl fmt::Display for NodeId {
@@ -275,6 +235,16 @@ impl serialize::UseSpecializedDecodable for NodeId {
     }
 }
 
+impl indexed_vec::Idx for NodeId {
+    fn new(idx: usize) -> Self {
+        NodeId::new(idx)
+    }
+
+    fn index(self) -> usize {
+        self.as_usize()
+    }
+}
+
 /// Node id used to represent the root of the crate.
 pub const CRATE_NODE_ID: NodeId = NodeId(0);
 
@@ -1426,7 +1396,7 @@ pub struct InlineAsm {
     pub volatile: bool,
     pub alignstack: bool,
     pub dialect: AsmDialect,
-    pub expn_id: ExpnId,
+    pub ctxt: SyntaxContext,
 }
 
 /// An argument in a function header.
@@ -1463,7 +1433,7 @@ impl Arg {
                     TyKind::Rptr(lt, MutTy{ref ty, mutbl}) if ty.node == TyKind::ImplicitSelf => {
                         Some(respan(self.pat.span, SelfKind::Region(lt, mutbl)))
                     }
-                    _ => Some(respan(mk_sp(self.pat.span.lo, self.ty.span.hi),
+                    _ => Some(respan(self.pat.span.to(self.ty.span),
                                      SelfKind::Explicit(self.ty.clone(), mutbl))),
                 }
             }
@@ -1480,7 +1450,7 @@ impl Arg {
     }
 
     pub fn from_self(eself: ExplicitSelf, eself_ident: SpannedIdent) -> Arg {
-        let span = mk_sp(eself.span.lo, eself_ident.span.hi);
+        let span = eself.span.to(eself_ident.span);
         let infer_ty = P(Ty {
             id: DUMMY_NODE_ID,
             node: TyKind::ImplicitSelf,
@@ -1717,11 +1687,11 @@ pub struct PolyTraitRef {
 }
 
 impl PolyTraitRef {
-    pub fn new(lifetimes: Vec<LifetimeDef>, path: Path, lo: BytePos, hi: BytePos) -> Self {
+    pub fn new(lifetimes: Vec<LifetimeDef>, path: Path, span: Span) -> Self {
         PolyTraitRef {
             bound_lifetimes: lifetimes,
             trait_ref: TraitRef { path: path, ref_id: DUMMY_NODE_ID },
-            span: mk_sp(lo, hi),
+            span: span,
         }
     }
 }
diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs
index 2f1efd6ad00..6f5f52ff1e9 100644
--- a/src/libsyntax/attr.rs
+++ b/src/libsyntax/attr.rs
@@ -18,8 +18,8 @@ use ast;
 use ast::{AttrId, Attribute, Name, Ident};
 use ast::{MetaItem, MetaItemKind, NestedMetaItem, NestedMetaItemKind};
 use ast::{Lit, LitKind, Expr, ExprKind, Item, Local, Stmt, StmtKind};
-use codemap::{Spanned, spanned, dummy_spanned, mk_sp};
-use syntax_pos::{Span, BytePos, DUMMY_SP};
+use codemap::{Spanned, respan, dummy_spanned};
+use syntax_pos::{Span, DUMMY_SP};
 use errors::Handler;
 use feature_gate::{Features, GatedCfg};
 use parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration};
@@ -447,17 +447,16 @@ pub fn mk_spanned_attr_outer(sp: Span, id: AttrId, item: MetaItem) -> Attribute
     }
 }
 
-pub fn mk_sugared_doc_attr(id: AttrId, text: Symbol, lo: BytePos, hi: BytePos)
-                           -> Attribute {
+pub fn mk_sugared_doc_attr(id: AttrId, text: Symbol, span: Span) -> Attribute {
     let style = doc_comment_style(&text.as_str());
-    let lit = spanned(lo, hi, LitKind::Str(text, ast::StrStyle::Cooked));
+    let lit = respan(span, LitKind::Str(text, ast::StrStyle::Cooked));
     Attribute {
         id: id,
         style: style,
-        path: ast::Path::from_ident(mk_sp(lo, hi), ast::Ident::from_str("doc")),
-        tokens: MetaItemKind::NameValue(lit).tokens(mk_sp(lo, hi)),
+        path: ast::Path::from_ident(span, ast::Ident::from_str("doc")),
+        tokens: MetaItemKind::NameValue(lit).tokens(span),
         is_sugared_doc: true,
-        span: mk_sp(lo, hi),
+        span: span,
     }
 }
 
@@ -1016,9 +1015,10 @@ impl MetaItem {
     {
         let (mut span, name) = match tokens.next() {
             Some(TokenTree::Token(span, Token::Ident(ident))) => (span, ident.name),
-            Some(TokenTree::Token(_, Token::Interpolated(ref nt))) => return match **nt {
-                token::Nonterminal::NtMeta(ref meta) => Some(meta.clone()),
-                _ => None,
+            Some(TokenTree::Token(_, Token::Interpolated(ref nt))) => match **nt {
+                token::Nonterminal::NtIdent(ident) => (ident.span, ident.node.name),
+                token::Nonterminal::NtMeta(ref meta) => return Some(meta.clone()),
+                _ => return None,
             },
             _ => return None,
         };
diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs
index 0f4b844b0ea..4d67390d442 100644
--- a/src/libsyntax/codemap.rs
+++ b/src/libsyntax/codemap.rs
@@ -17,6 +17,8 @@
 //! within the CodeMap, which upon request can be converted to line and column
 //! information, source code snippets, etc.
 
+pub use syntax_pos::*;
+pub use syntax_pos::hygiene::{ExpnFormat, ExpnInfo, NameAndSpan};
 pub use self::ExpnFormat::*;
 
 use std::cell::RefCell;
@@ -26,45 +28,27 @@ use std::rc::Rc;
 use std::env;
 use std::fs;
 use std::io::{self, Read};
-pub use syntax_pos::*;
 use errors::CodeMapper;
 
-use ast::Name;
-
 /// Return the span itself if it doesn't come from a macro expansion,
 /// otherwise return the call site span up to the `enclosing_sp` by
 /// following the `expn_info` chain.
-pub fn original_sp(cm: &CodeMap, sp: Span, enclosing_sp: Span) -> Span {
-    let call_site1 = cm.with_expn_info(sp.expn_id, |ei| ei.map(|ei| ei.call_site));
-    let call_site2 = cm.with_expn_info(enclosing_sp.expn_id, |ei| ei.map(|ei| ei.call_site));
+pub fn original_sp(sp: Span, enclosing_sp: Span) -> Span {
+    let call_site1 = sp.ctxt.outer().expn_info().map(|ei| ei.call_site);
+    let call_site2 = enclosing_sp.ctxt.outer().expn_info().map(|ei| ei.call_site);
     match (call_site1, call_site2) {
         (None, _) => sp,
         (Some(call_site1), Some(call_site2)) if call_site1 == call_site2 => sp,
-        (Some(call_site1), _) => original_sp(cm, call_site1, enclosing_sp),
+        (Some(call_site1), _) => original_sp(call_site1, enclosing_sp),
     }
 }
 
-/// The source of expansion.
-#[derive(Clone, Hash, Debug, PartialEq, Eq)]
-pub enum ExpnFormat {
-    /// e.g. #[derive(...)] <item>
-    MacroAttribute(Name),
-    /// e.g. `format!()`
-    MacroBang(Name),
-    /// Desugaring done by the compiler during HIR lowering.
-    CompilerDesugaring(Name)
-}
-
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
 pub struct Spanned<T> {
     pub node: T,
     pub span: Span,
 }
 
-pub fn spanned<T>(lo: BytePos, hi: BytePos, t: T) -> Spanned<T> {
-    respan(mk_sp(lo, hi), t)
-}
-
 pub fn respan<T>(sp: Span, t: T) -> Spanned<T> {
     Spanned {node: t, span: sp}
 }
@@ -73,47 +57,6 @@ pub fn dummy_spanned<T>(t: T) -> Spanned<T> {
     respan(DUMMY_SP, t)
 }
 
-#[derive(Clone, Hash, Debug)]
-pub struct NameAndSpan {
-    /// The format with which the macro was invoked.
-    pub format: ExpnFormat,
-    /// Whether the macro is allowed to use #[unstable]/feature-gated
-    /// features internally without forcing the whole crate to opt-in
-    /// to them.
-    pub allow_internal_unstable: bool,
-    /// The span of the macro definition itself. The macro may not
-    /// have a sensible definition span (e.g. something defined
-    /// completely inside libsyntax) in which case this is None.
-    pub span: Option<Span>
-}
-
-impl NameAndSpan {
-    pub fn name(&self) -> Name {
-        match self.format {
-            ExpnFormat::MacroAttribute(s) |
-            ExpnFormat::MacroBang(s) |
-            ExpnFormat::CompilerDesugaring(s) => s,
-        }
-    }
-}
-
-/// Extra information for tracking spans of macro and syntax sugar expansion
-#[derive(Hash, Debug)]
-pub struct ExpnInfo {
-    /// The location of the actual macro invocation or syntax sugar , e.g.
-    /// `let x = foo!();` or `if let Some(y) = x {}`
-    ///
-    /// This may recursively refer to other macro invocations, e.g. if
-    /// `foo!()` invoked `bar!()` internally, and there was an
-    /// expression inside `bar!`; the call_site of the expression in
-    /// the expansion would point to the `bar!` invocation; that
-    /// call_site span would have its own ExpnInfo, with the call_site
-    /// pointing to the `foo!` invocation.
-    pub call_site: Span,
-    /// Information about the expansion.
-    pub callee: NameAndSpan
-}
-
 // _____________________________________________________________________________
 // FileMap, MultiByteChar, FileName, FileLines
 //
@@ -161,7 +104,6 @@ impl FileLoader for RealFileLoader {
 
 pub struct CodeMap {
     pub files: RefCell<Vec<Rc<FileMap>>>,
-    expansions: RefCell<Vec<ExpnInfo>>,
     file_loader: Box<FileLoader>
 }
 
@@ -169,7 +111,6 @@ impl CodeMap {
     pub fn new() -> CodeMap {
         CodeMap {
             files: RefCell::new(Vec::new()),
-            expansions: RefCell::new(Vec::new()),
             file_loader: Box::new(RealFileLoader)
         }
     }
@@ -177,7 +118,6 @@ impl CodeMap {
     pub fn with_file_loader(file_loader: Box<FileLoader>) -> CodeMap {
         CodeMap {
             files: RefCell::new(Vec::new()),
-            expansions: RefCell::new(Vec::new()),
             file_loader: file_loader
         }
     }
@@ -353,14 +293,14 @@ 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 ctxt 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 {
+        if sp_lhs.ctxt != sp_rhs.ctxt {
             return None;
         }
 
@@ -383,7 +323,7 @@ impl CodeMap {
             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,
+                ctxt: sp_lhs.ctxt,
             })
         } else {
             None
@@ -391,10 +331,6 @@ impl CodeMap {
     }
 
     pub fn span_to_string(&self, sp: Span) -> String {
-        if sp == COMMAND_LINE_SP {
-            return "<command line option>".to_string();
-        }
-
         if self.files.borrow().is_empty() && sp.source_equal(&DUMMY_SP) {
             return "no-location".to_string();
         }
@@ -409,157 +345,6 @@ impl CodeMap {
                         hi.col.to_usize() + 1)).to_string()
     }
 
-    // Returns true if two spans have the same callee
-    // (Assumes the same ExpnFormat implies same callee)
-    fn match_callees(&self, sp_a: &Span, sp_b: &Span) -> bool {
-        let fmt_a = self
-            .with_expn_info(sp_a.expn_id,
-                            |ei| ei.map(|ei| ei.callee.format.clone()));
-
-        let fmt_b = self
-            .with_expn_info(sp_b.expn_id,
-                            |ei| ei.map(|ei| ei.callee.format.clone()));
-        fmt_a == fmt_b
-    }
-
-    /// Returns a formatted string showing the expansion chain of a span
-    ///
-    /// Spans are printed in the following format:
-    ///
-    /// filename:start_line:col: end_line:col
-    /// snippet
-    ///   Callee:
-    ///   Callee span
-    ///   Callsite:
-    ///   Callsite span
-    ///
-    /// Callees and callsites are printed recursively (if available, otherwise header
-    /// and span is omitted), expanding into their own callee/callsite spans.
-    /// Each layer of recursion has an increased indent, and snippets are truncated
-    /// to at most 50 characters. Finally, recursive calls to the same macro are squashed,
-    /// with '...' used to represent any number of recursive calls.
-    pub fn span_to_expanded_string(&self, sp: Span) -> String {
-        self.span_to_expanded_string_internal(sp, "")
-    }
-
-    fn span_to_expanded_string_internal(&self, sp:Span, indent: &str) -> String {
-        let mut indent = indent.to_owned();
-        let mut output = "".to_owned();
-        let span_str = self.span_to_string(sp);
-        let mut span_snip = self.span_to_snippet(sp)
-            .unwrap_or("Snippet unavailable".to_owned());
-
-        // Truncate by code points - in worst case this will be more than 50 characters,
-        // but ensures at least 50 characters and respects byte boundaries.
-        let char_vec: Vec<(usize, char)> = span_snip.char_indices().collect();
-        if char_vec.len() > 50 {
-            span_snip.truncate(char_vec[49].0);
-            span_snip.push_str("...");
-        }
-
-        output.push_str(&format!("{}{}\n{}`{}`\n", indent, span_str, indent, span_snip));
-
-        if sp.expn_id == NO_EXPANSION || sp.expn_id == COMMAND_LINE_EXPN {
-            return output;
-        }
-
-        let mut callee = self.with_expn_info(sp.expn_id,
-                                             |ei| ei.and_then(|ei| ei.callee.span.clone()));
-        let mut callsite = self.with_expn_info(sp.expn_id,
-                                               |ei| ei.map(|ei| ei.call_site.clone()));
-
-        indent.push_str("  ");
-        let mut is_recursive = false;
-
-        while callee.is_some() && self.match_callees(&sp, &callee.unwrap()) {
-            callee = self.with_expn_info(callee.unwrap().expn_id,
-                                         |ei| ei.and_then(|ei| ei.callee.span.clone()));
-            is_recursive = true;
-        }
-        if let Some(span) = callee {
-            output.push_str(&indent);
-            output.push_str("Callee:\n");
-            if is_recursive {
-                output.push_str(&indent);
-                output.push_str("...\n");
-            }
-            output.push_str(&(self.span_to_expanded_string_internal(span, &indent)));
-        }
-
-        is_recursive = false;
-        while callsite.is_some() && self.match_callees(&sp, &callsite.unwrap()) {
-            callsite = self.with_expn_info(callsite.unwrap().expn_id,
-                                           |ei| ei.map(|ei| ei.call_site.clone()));
-            is_recursive = true;
-        }
-        if let Some(span) = callsite {
-            output.push_str(&indent);
-            output.push_str("Callsite:\n");
-            if is_recursive {
-                output.push_str(&indent);
-                output.push_str("...\n");
-            }
-            output.push_str(&(self.span_to_expanded_string_internal(span, &indent)));
-        }
-        output
-    }
-
-    /// Return the source span - this is either the supplied span, or the span for
-    /// the macro callsite that expanded to it.
-    pub fn source_callsite(&self, sp: Span) -> Span {
-        let mut span = sp;
-        // Special case - if a macro is parsed as an argument to another macro, the source
-        // callsite is the first callsite, which is also source-equivalent to the span.
-        let mut first = true;
-        while span.expn_id != NO_EXPANSION && span.expn_id != COMMAND_LINE_EXPN {
-            if let Some(callsite) = self.with_expn_info(span.expn_id,
-                                               |ei| ei.map(|ei| ei.call_site.clone())) {
-                if first && span.source_equal(&callsite) {
-                    if self.lookup_char_pos(span.lo).file.is_real_file() {
-                        return Span { expn_id: NO_EXPANSION, .. span };
-                    }
-                }
-                first = false;
-                span = callsite;
-            }
-            else {
-                break;
-            }
-        }
-        span
-    }
-
-    /// Return the source callee.
-    ///
-    /// Returns None if the supplied span has no expansion trace,
-    /// else returns the NameAndSpan for the macro definition
-    /// corresponding to the source callsite.
-    pub fn source_callee(&self, sp: Span) -> Option<NameAndSpan> {
-        let mut span = sp;
-        // Special case - if a macro is parsed as an argument to another macro, the source
-        // callsite is source-equivalent to the span, and the source callee is the first callee.
-        let mut first = true;
-        while let Some(callsite) = self.with_expn_info(span.expn_id,
-                                            |ei| ei.map(|ei| ei.call_site.clone())) {
-            if first && span.source_equal(&callsite) {
-                if self.lookup_char_pos(span.lo).file.is_real_file() {
-                    return self.with_expn_info(span.expn_id,
-                                               |ei| ei.map(|ei| ei.callee.clone()));
-                }
-            }
-            first = false;
-            if let Some(_) = self.with_expn_info(callsite.expn_id,
-                                                 |ei| ei.map(|ei| ei.call_site.clone())) {
-                span = callsite;
-            }
-            else {
-                return self.with_expn_info(span.expn_id,
-                                           |ei| ei.map(|ei| ei.callee.clone()));
-            }
-        }
-        None
-    }
-
     pub fn span_to_filename(&self, sp: Span) -> FileName {
         self.lookup_char_pos(sp.lo).file.name.to_string()
     }
@@ -723,111 +508,9 @@ impl CodeMap {
         return a;
     }
 
-    pub fn record_expansion(&self, expn_info: ExpnInfo) -> ExpnId {
-        let mut expansions = self.expansions.borrow_mut();
-        expansions.push(expn_info);
-        let len = expansions.len();
-        if len > u32::max_value() as usize {
-            panic!("too many ExpnInfo's!");
-        }
-        ExpnId(len as u32 - 1)
-    }
-
-    pub fn with_expn_info<T, F>(&self, id: ExpnId, f: F) -> T where
-        F: FnOnce(Option<&ExpnInfo>) -> T,
-    {
-        match id {
-            NO_EXPANSION | COMMAND_LINE_EXPN => f(None),
-            ExpnId(i) => f(Some(&(*self.expansions.borrow())[i as usize]))
-        }
-    }
-
-    /// Check if a span is "internal" to a macro in which #[unstable]
-    /// items can be used (that is, a macro marked with
-    /// `#[allow_internal_unstable]`).
-    pub fn span_allows_unstable(&self, span: Span) -> bool {
-        debug!("span_allows_unstable(span = {:?})", span);
-        let mut allows_unstable = false;
-        let mut expn_id = span.expn_id;
-        loop {
-            let quit = self.with_expn_info(expn_id, |expninfo| {
-                debug!("span_allows_unstable: expninfo = {:?}", expninfo);
-                expninfo.map_or(/* hit the top level */ true, |info| {
-
-                    let span_comes_from_this_expansion =
-                        info.callee.span.map_or(span.source_equal(&info.call_site), |mac_span| {
-                            mac_span.contains(span)
-                        });
-
-                    debug!("span_allows_unstable: span: {:?} call_site: {:?} callee: {:?}",
-                           (span.lo, span.hi),
-                           (info.call_site.lo, info.call_site.hi),
-                           info.callee.span.map(|x| (x.lo, x.hi)));
-                    debug!("span_allows_unstable: from this expansion? {}, allows unstable? {}",
-                           span_comes_from_this_expansion,
-                           info.callee.allow_internal_unstable);
-                    if span_comes_from_this_expansion {
-                        allows_unstable = info.callee.allow_internal_unstable;
-                        // we've found the right place, stop looking
-                        true
-                    } else {
-                        // not the right place, keep looking
-                        expn_id = info.call_site.expn_id;
-                        false
-                    }
-                })
-            });
-            if quit {
-                break
-            }
-        }
-        debug!("span_allows_unstable? {}", allows_unstable);
-        allows_unstable
-    }
-
     pub fn count_lines(&self) -> usize {
         self.files.borrow().iter().fold(0, |a, f| a + f.count_lines())
     }
-
-    pub fn macro_backtrace(&self, span: Span) -> Vec<MacroBacktrace> {
-        let mut prev_span = DUMMY_SP;
-        let mut span = span;
-        let mut result = vec![];
-        loop {
-            let span_name_span = self.with_expn_info(span.expn_id, |expn_info| {
-                expn_info.map(|ei| {
-                    let (pre, post) = match ei.callee.format {
-                        MacroAttribute(..) => ("#[", "]"),
-                        MacroBang(..) => ("", "!"),
-                        CompilerDesugaring(..) => ("desugaring of `", "`"),
-                    };
-                    let macro_decl_name = format!("{}{}{}",
-                                                  pre,
-                                                  ei.callee.name(),
-                                                  post);
-                    let def_site_span = ei.callee.span;
-                    (ei.call_site, macro_decl_name, def_site_span)
-                })
-            });
-
-            match span_name_span {
-                None => break,
-                Some((call_site, macro_decl_name, def_site_span)) => {
-                    // Don't print recursive invocations
-                    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,
-                        });
-                    }
-                    prev_span = span;
-                    span = call_site;
-                }
-            }
-        }
-        result
-    }
 }
 
 impl CodeMapper for CodeMap {
@@ -843,9 +526,6 @@ impl CodeMapper for CodeMap {
     fn span_to_filename(&self, sp: Span) -> FileName {
         self.span_to_filename(sp)
     }
-    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)
     }
@@ -858,7 +538,6 @@ impl CodeMapper for CodeMap {
 #[cfg(test)]
 mod tests {
     use super::*;
-    use symbol::keywords;
     use std::rc::Rc;
 
     #[test]
@@ -1007,7 +686,7 @@ mod tests {
     fn t7() {
         // Test span_to_lines for a span ending at the end of filemap
         let cm = init_code_map();
-        let span = Span {lo: BytePos(12), hi: BytePos(23), expn_id: NO_EXPANSION};
+        let span = Span {lo: BytePos(12), hi: BytePos(23), ctxt: NO_EXPANSION};
         let file_lines = cm.span_to_lines(span).unwrap();
 
         assert_eq!(file_lines.file.name, "blork.rs");
@@ -1023,7 +702,7 @@ mod tests {
         assert_eq!(input.len(), selection.len());
         let left_index = selection.find('~').unwrap() as u32;
         let right_index = selection.rfind('~').map(|x|x as u32).unwrap_or(left_index);
-        Span { lo: BytePos(left_index), hi: BytePos(right_index + 1), expn_id: NO_EXPANSION }
+        Span { lo: BytePos(left_index), hi: BytePos(right_index + 1), ctxt: NO_EXPANSION }
     }
 
     /// Test span_to_snippet and span_to_lines for a span coverting 3
@@ -1053,7 +732,7 @@ mod tests {
     fn t8() {
         // Test span_to_snippet for a span ending at the end of filemap
         let cm = init_code_map();
-        let span = Span {lo: BytePos(12), hi: BytePos(23), expn_id: NO_EXPANSION};
+        let span = Span {lo: BytePos(12), hi: BytePos(23), ctxt: NO_EXPANSION};
         let snippet = cm.span_to_snippet(span);
 
         assert_eq!(snippet, Ok("second line".to_string()));
@@ -1063,65 +742,12 @@ mod tests {
     fn t9() {
         // Test span_to_str for a span ending at the end of filemap
         let cm = init_code_map();
-        let span = Span {lo: BytePos(12), hi: BytePos(23), expn_id: NO_EXPANSION};
+        let span = Span {lo: BytePos(12), hi: BytePos(23), ctxt: NO_EXPANSION};
         let sstr =  cm.span_to_string(span);
 
         assert_eq!(sstr, "blork.rs:2:1: 2:12");
     }
 
-    #[test]
-    fn t10() {
-        // Test span_to_expanded_string works in base case (no expansion)
-        let cm = init_code_map();
-        let span = Span { lo: BytePos(0), hi: BytePos(11), expn_id: NO_EXPANSION };
-        let sstr = cm.span_to_expanded_string(span);
-        assert_eq!(sstr, "blork.rs:1:1: 1:12\n`first line.`\n");
-
-        let span = Span { lo: BytePos(12), hi: BytePos(23), expn_id: NO_EXPANSION };
-        let sstr =  cm.span_to_expanded_string(span);
-        assert_eq!(sstr, "blork.rs:2:1: 2:12\n`second line`\n");
-    }
-
-    #[test]
-    fn t11() {
-        // Test span_to_expanded_string works with expansion
-        let cm = init_code_map();
-        let root = Span { lo: BytePos(0), hi: BytePos(11), expn_id: NO_EXPANSION };
-        let format = ExpnFormat::MacroBang(keywords::Invalid.name());
-        let callee = NameAndSpan { format: format,
-                                   allow_internal_unstable: false,
-                                   span: None };
-
-        let info = ExpnInfo { call_site: root, callee: callee };
-        let id = cm.record_expansion(info);
-        let sp = Span { lo: BytePos(12), hi: BytePos(23), expn_id: id };
-
-        let sstr = cm.span_to_expanded_string(sp);
-        assert_eq!(sstr,
-                   "blork.rs:2:1: 2:12\n`second line`\n  Callsite:\n  \
-                    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() {
@@ -1170,7 +796,7 @@ mod tests {
                     let span = Span {
                         lo: BytePos(lo as u32 + file.start_pos.0),
                         hi: BytePos(hi as u32 + file.start_pos.0),
-                        expn_id: NO_EXPANSION,
+                        ctxt: NO_EXPANSION,
                     };
                     assert_eq!(&self.span_to_snippet(span).unwrap()[..],
                             substring);
@@ -1180,82 +806,4 @@ mod tests {
             }
         }
     }
-
-    fn init_expansion_chain(cm: &CodeMap) -> Span {
-        // Creates an expansion chain containing two recursive calls
-        // root -> expA -> expA -> expB -> expB -> end
-        let root = Span { lo: BytePos(0), hi: BytePos(11), expn_id: NO_EXPANSION };
-
-        let format_root = ExpnFormat::MacroBang(keywords::Invalid.name());
-        let callee_root = NameAndSpan { format: format_root,
-                                        allow_internal_unstable: false,
-                                        span: Some(root) };
-
-        let info_a1 = ExpnInfo { call_site: root, callee: callee_root };
-        let id_a1 = cm.record_expansion(info_a1);
-        let span_a1 = Span { lo: BytePos(12), hi: BytePos(23), expn_id: id_a1 };
-
-        let format_a = ExpnFormat::MacroBang(keywords::As.name());
-        let callee_a = NameAndSpan { format: format_a,
-                                      allow_internal_unstable: false,
-                                      span: Some(span_a1) };
-
-        let info_a2 = ExpnInfo { call_site: span_a1, callee: callee_a.clone() };
-        let id_a2 = cm.record_expansion(info_a2);
-        let span_a2 = Span { lo: BytePos(12), hi: BytePos(23), expn_id: id_a2 };
-
-        let info_b1 = ExpnInfo { call_site: span_a2, callee: callee_a };
-        let id_b1 = cm.record_expansion(info_b1);
-        let span_b1 = Span { lo: BytePos(25), hi: BytePos(36), expn_id: id_b1 };
-
-        let format_b = ExpnFormat::MacroBang(keywords::Box.name());
-        let callee_b = NameAndSpan { format: format_b,
-                                     allow_internal_unstable: false,
-                                     span: None };
-
-        let info_b2 = ExpnInfo { call_site: span_b1, callee: callee_b.clone() };
-        let id_b2 = cm.record_expansion(info_b2);
-        let span_b2 = Span { lo: BytePos(25), hi: BytePos(36), expn_id: id_b2 };
-
-        let info_end = ExpnInfo { call_site: span_b2, callee: callee_b };
-        let id_end = cm.record_expansion(info_end);
-        Span { lo: BytePos(37), hi: BytePos(48), expn_id: id_end }
-    }
-
-    #[test]
-    fn t12() {
-        // Test span_to_expanded_string collapses recursive macros and handles
-        // recursive callsite and callee expansions
-        let cm = init_code_map();
-        let end = init_expansion_chain(&cm);
-        let sstr = cm.span_to_expanded_string(end);
-        let res_str =
-r"blork2.rs:2:1: 2:12
-`second line`
-  Callsite:
-  ...
-  blork2.rs:1:1: 1:12
-  `first line.`
-    Callee:
-    blork.rs:2:1: 2:12
-    `second line`
-      Callee:
-      blork.rs:1:1: 1:12
-      `first line.`
-      Callsite:
-      blork.rs:1:1: 1:12
-      `first line.`
-    Callsite:
-    ...
-    blork.rs:2:1: 2:12
-    `second line`
-      Callee:
-      blork.rs:1:1: 1:12
-      `first line.`
-      Callsite:
-      blork.rs:1:1: 1:12
-      `first line.`
-";
-        assert_eq!(sstr, res_str);
-    }
 }
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index dc7e7673eb0..fda026fec64 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -12,11 +12,11 @@ pub use self::SyntaxExtension::{MultiDecorator, MultiModifier, NormalTT, IdentTT
 
 use ast::{self, Attribute, Name, PatKind, MetaItem};
 use attr::HasAttrs;
-use codemap::{self, CodeMap, ExpnInfo, Spanned, respan};
-use syntax_pos::{Span, ExpnId, NO_EXPANSION};
-use errors::{DiagnosticBuilder, FatalError};
+use codemap::{self, CodeMap, Spanned, respan};
+use syntax_pos::{Span, DUMMY_SP};
+use errors::DiagnosticBuilder;
 use ext::expand::{self, Expansion, Invocation};
-use ext::hygiene::Mark;
+use ext::hygiene::{Mark, SyntaxContext};
 use fold::{self, Folder};
 use parse::{self, parser, DirectoryOwnership};
 use parse::token;
@@ -56,6 +56,14 @@ impl HasAttrs for Annotatable {
 }
 
 impl Annotatable {
+    pub fn span(&self) -> Span {
+        match *self {
+            Annotatable::Item(ref item) => item.span,
+            Annotatable::TraitItem(ref trait_item) => trait_item.span,
+            Annotatable::ImplItem(ref impl_item) => impl_item.span,
+        }
+    }
+
     pub fn expect_item(self) -> P<ast::Item> {
         match self {
             Annotatable::Item(i) => i,
@@ -201,7 +209,26 @@ impl<F> TTMacroExpander for F
 {
     fn expand<'cx>(&self, ecx: &'cx mut ExtCtxt, span: Span, input: TokenStream)
                    -> Box<MacResult+'cx> {
-        (*self)(ecx, span, &input.trees().collect::<Vec<_>>())
+        struct AvoidInterpolatedIdents;
+
+        impl Folder for AvoidInterpolatedIdents {
+            fn fold_tt(&mut self, tt: tokenstream::TokenTree) -> tokenstream::TokenTree {
+                if let tokenstream::TokenTree::Token(_, token::Interpolated(ref nt)) = tt {
+                    if let token::NtIdent(ident) = **nt {
+                        return tokenstream::TokenTree::Token(ident.span, token::Ident(ident.node));
+                    }
+                }
+                fold::noop_fold_tt(tt, self)
+            }
+
+            fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
+                fold::noop_fold_mac(mac, self)
+            }
+        }
+
+        let input: Vec<_> =
+            input.trees().map(|tt| AvoidInterpolatedIdents.fold_tt(tt)).collect();
+        (*self)(ecx, span, &input)
     }
 }
 
@@ -602,7 +629,6 @@ pub struct ModuleData {
 pub struct ExpansionData {
     pub mark: Mark,
     pub depth: usize,
-    pub backtrace: ExpnId,
     pub module: Rc<ModuleData>,
     pub directory_ownership: DirectoryOwnership,
 }
@@ -633,7 +659,6 @@ impl<'a> ExtCtxt<'a> {
             current_expansion: ExpansionData {
                 mark: Mark::root(),
                 depth: 0,
-                backtrace: NO_EXPANSION,
                 module: Rc::new(ModuleData { mod_path: Vec::new(), directory: PathBuf::new() }),
                 directory_ownership: DirectoryOwnership::Owned,
             },
@@ -658,30 +683,30 @@ impl<'a> ExtCtxt<'a> {
     pub fn parse_sess(&self) -> &'a parse::ParseSess { self.parse_sess }
     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 {
+        match self.current_expansion.mark.expn_info() {
             Some(expn_info) => expn_info.call_site,
-            None => self.bug("missing top span")
-        })
+            None => DUMMY_SP,
+        }
+    }
+    pub fn backtrace(&self) -> SyntaxContext {
+        SyntaxContext::empty().apply_mark(self.current_expansion.mark)
     }
-    pub fn backtrace(&self) -> ExpnId { self.current_expansion.backtrace }
 
     /// Returns span for the macro which originally caused the current expansion to happen.
     ///
     /// Stops backtracing at include! boundary.
     pub fn expansion_cause(&self) -> Span {
-        let mut expn_id = self.backtrace();
+        let mut ctxt = self.backtrace();
         let mut last_macro = None;
         loop {
-            if self.codemap().with_expn_info(expn_id, |info| {
-                info.map_or(None, |i| {
-                    if i.callee.name() == "include" {
-                        // Stop going up the backtrace once include! is encountered
-                        return None;
-                    }
-                    expn_id = i.call_site.expn_id;
-                    last_macro = Some(i.call_site);
-                    return Some(());
-                })
+            if ctxt.outer().expn_info().map_or(None, |info| {
+                if info.callee.name() == "include" {
+                    // Stop going up the backtrace once include! is encountered
+                    return None;
+                }
+                ctxt = info.call_site.ctxt;
+                last_macro = Some(info.call_site);
+                return Some(());
             }).is_none() {
                 break
             }
@@ -689,28 +714,6 @@ impl<'a> ExtCtxt<'a> {
         last_macro.expect("missing expansion backtrace")
     }
 
-    pub fn bt_push(&mut self, ei: ExpnInfo) {
-        if self.current_expansion.depth > self.ecfg.recursion_limit {
-            let suggested_limit = self.ecfg.recursion_limit * 2;
-            let mut err = self.struct_span_fatal(ei.call_site,
-                &format!("recursion limit reached while expanding the macro `{}`",
-                         ei.callee.name()));
-            err.help(&format!(
-                "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate",
-                suggested_limit));
-            err.emit();
-            panic!(FatalError);
-        }
-
-        let mut call_site = ei.call_site;
-        call_site.expn_id = self.backtrace();
-        self.current_expansion.backtrace = self.codemap().record_expansion(ExpnInfo {
-            call_site: call_site,
-            callee: ei.callee
-        });
-    }
-    pub fn bt_pop(&mut self) {}
-
     pub fn struct_span_warn(&self,
                             sp: Span,
                             msg: &str)
@@ -792,9 +795,9 @@ impl<'a> ExtCtxt<'a> {
 /// compilation on error, merely emits a non-fatal error and returns None.
 pub fn expr_to_spanned_string(cx: &mut ExtCtxt, expr: P<ast::Expr>, err_msg: &str)
                               -> Option<Spanned<(Symbol, ast::StrStyle)>> {
-    // Update `expr.span`'s expn_id now in case expr is an `include!` macro invocation.
+    // Update `expr.span`'s ctxt now in case expr is an `include!` macro invocation.
     let expr = expr.map(|mut expr| {
-        expr.span.expn_id = cx.backtrace();
+        expr.span.ctxt = expr.span.ctxt.apply_mark(cx.current_expansion.mark);
         expr
     });
 
diff --git a/src/libsyntax/ext/derive.rs b/src/libsyntax/ext/derive.rs
index 1569d9f540b..c79040424f6 100644
--- a/src/libsyntax/ext/derive.rs
+++ b/src/libsyntax/ext/derive.rs
@@ -9,13 +9,16 @@
 // except according to those terms.
 
 use attr::HasAttrs;
-use {ast, codemap};
+use ast;
+use codemap::{ExpnInfo, NameAndSpan, ExpnFormat};
 use ext::base::ExtCtxt;
 use ext::build::AstBuilder;
 use parse::parser::PathStyle;
 use symbol::Symbol;
 use syntax_pos::Span;
 
+use std::collections::HashSet;
+
 pub fn collect_derives(cx: &mut ExtCtxt, attrs: &mut Vec<ast::Attribute>) -> Vec<ast::Path> {
     let mut result = Vec::new();
     attrs.retain(|attr| {
@@ -41,36 +44,35 @@ pub fn collect_derives(cx: &mut ExtCtxt, attrs: &mut Vec<ast::Attribute>) -> Vec
     result
 }
 
-fn allow_unstable(cx: &mut ExtCtxt, span: Span, attr_name: &str) -> Span {
-    Span {
-        expn_id: cx.codemap().record_expansion(codemap::ExpnInfo {
-            call_site: span,
-            callee: codemap::NameAndSpan {
-                format: codemap::MacroAttribute(Symbol::intern(attr_name)),
-                span: Some(span),
-                allow_internal_unstable: true,
-            },
-        }),
-        ..span
+pub fn add_derived_markers<T>(cx: &mut ExtCtxt, span: Span, traits: &[ast::Path], item: T) -> T
+    where T: HasAttrs,
+{
+    let (mut names, mut pretty_name) = (HashSet::new(), "derive(".to_owned());
+    for (i, path) in traits.iter().enumerate() {
+        if i > 0 {
+            pretty_name.push_str(", ");
+        }
+        pretty_name.push_str(&path.to_string());
+        names.insert(unwrap_or!(path.segments.get(0), continue).identifier.name);
     }
-}
+    pretty_name.push(')');
 
-pub fn add_derived_markers<T: HasAttrs>(cx: &mut ExtCtxt, traits: &[ast::Path], item: T) -> T {
-    let span = match traits.get(0) {
-        Some(path) => path.span,
-        None => return item,
-    };
+    cx.current_expansion.mark.set_expn_info(ExpnInfo {
+        call_site: span,
+        callee: NameAndSpan {
+            format: ExpnFormat::MacroAttribute(Symbol::intern(&pretty_name)),
+            span: None,
+            allow_internal_unstable: true,
+        },
+    });
 
+    let span = Span { ctxt: cx.backtrace(), ..span };
     item.map_attrs(|mut attrs| {
-        if traits.iter().any(|path| *path == "PartialEq") &&
-           traits.iter().any(|path| *path == "Eq") {
-            let span = allow_unstable(cx, span, "derive(PartialEq, Eq)");
+        if names.contains(&Symbol::intern("Eq")) && names.contains(&Symbol::intern("PartialEq")) {
             let meta = cx.meta_word(span, Symbol::intern("structural_match"));
             attrs.push(cx.attribute(span, meta));
         }
-        if traits.iter().any(|path| *path == "Copy") &&
-           traits.iter().any(|path| *path == "Clone") {
-            let span = allow_unstable(cx, span, "derive(Copy, Clone)");
+        if names.contains(&Symbol::intern("Copy")) && names.contains(&Symbol::intern("Clone")) {
             let meta = cx.meta_word(span, Symbol::intern("rustc_copy_clone_marker"));
             attrs.push(cx.attribute(span, meta));
         }
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 6abeb4b0b28..1b3352f73ad 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -8,11 +8,12 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use ast::{self, Block, Ident, PatKind, Path};
+use ast::{self, Block, Ident, NodeId, PatKind, Path};
 use ast::{MacStmtStyle, StmtKind, ItemKind};
 use attr::{self, HasAttrs};
 use codemap::{ExpnInfo, NameAndSpan, MacroBang, MacroAttribute};
 use config::{is_test_or_bench, StripUnconfigured};
+use errors::FatalError;
 use ext::base::*;
 use ext::derive::{add_derived_markers, collect_derives};
 use ext::hygiene::Mark;
@@ -27,7 +28,7 @@ use ptr::P;
 use std_inject;
 use symbol::Symbol;
 use symbol::keywords;
-use syntax_pos::{Span, ExpnId, DUMMY_SP};
+use syntax_pos::{Span, DUMMY_SP};
 use tokenstream::TokenStream;
 use util::small_vector::SmallVector;
 use visit::Visitor;
@@ -273,7 +274,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                     let item = item
                         .map_attrs(|mut attrs| { attrs.retain(|a| a.path != "derive"); attrs });
                     let item_with_markers =
-                        add_derived_markers(&mut self.cx, &traits, item.clone());
+                        add_derived_markers(&mut self.cx, item.span(), &traits, item.clone());
                     let derives = derives.entry(invoc.expansion_data.mark).or_insert_with(Vec::new);
 
                     for path in &traits {
@@ -321,7 +322,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         while let Some(expansions) = expansions.pop() {
             for (mark, expansion) in expansions.into_iter().rev() {
                 let derives = derives.remove(&mark).unwrap_or_else(Vec::new);
-                placeholder_expander.add(mark.as_placeholder_id(), expansion, derives);
+                placeholder_expander.add(NodeId::placeholder_from_mark(mark), expansion, derives);
             }
         }
 
@@ -363,11 +364,26 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
     }
 
     fn expand_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) -> Expansion {
-        match invoc.kind {
+        let result = match invoc.kind {
             InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc, ext),
             InvocationKind::Attr { .. } => self.expand_attr_invoc(invoc, ext),
             InvocationKind::Derive { .. } => self.expand_derive_invoc(invoc, ext),
+        };
+
+        if self.cx.current_expansion.depth > self.cx.ecfg.recursion_limit {
+            let info = self.cx.current_expansion.mark.expn_info().unwrap();
+            let suggested_limit = self.cx.ecfg.recursion_limit * 2;
+            let mut err = self.cx.struct_span_fatal(info.call_site,
+                &format!("recursion limit reached while expanding the macro `{}`",
+                         info.callee.name()));
+            err.help(&format!(
+                "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate",
+                suggested_limit));
+            err.emit();
+            panic!(FatalError);
         }
+
+        result
     }
 
     fn expand_attr_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) -> Expansion {
@@ -378,11 +394,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         };
 
         attr::mark_used(&attr);
-        self.cx.bt_push(ExpnInfo {
+        invoc.expansion_data.mark.set_expn_info(ExpnInfo {
             call_site: attr.span,
             callee: NameAndSpan {
                 format: MacroAttribute(Symbol::intern(&format!("{}", attr.path))),
-                span: Some(attr.span),
+                span: None,
                 allow_internal_unstable: false,
             }
         });
@@ -403,19 +419,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             SyntaxExtension::AttrProcMacro(ref mac) => {
                 let item_toks = stream_for_item(&item, &self.cx.parse_sess);
 
-                let span = Span {
-                    expn_id: self.cx.codemap().record_expansion(ExpnInfo {
-                        call_site: attr.span,
-                        callee: NameAndSpan {
-                            format: MacroAttribute(Symbol::intern(&format!("{}", attr.path))),
-                            span: None,
-                            allow_internal_unstable: false,
-                        },
-                    }),
-                    ..attr.span
-                };
-
-                let tok_result = mac.expand(self.cx, attr.span, attr.tokens.clone(), item_toks);
+                let span = Span { ctxt: self.cx.backtrace(), ..attr.span };
+                let tok_result = mac.expand(self.cx, attr.span, attr.tokens, item_toks);
                 self.parse_expansion(tok_result, kind, &attr.path, span)
             }
             SyntaxExtension::ProcMacroDerive(..) | SyntaxExtension::BuiltinDerive(..) => {
@@ -440,8 +445,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         let path = &mac.node.path;
 
         let ident = ident.unwrap_or(keywords::Invalid.ident());
-        let marked_tts =
-            noop_fold_tts(mac.node.stream(), &mut Marker { mark: mark, expn_id: None });
+        let marked_tts = noop_fold_tts(mac.node.stream(), &mut Marker(mark));
         let opt_expanded = match *ext {
             NormalTT(ref expandfun, exp_span, allow_internal_unstable) => {
                 if ident.name != keywords::Invalid.name() {
@@ -451,7 +455,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                     return kind.dummy(span);
                 }
 
-                self.cx.bt_push(ExpnInfo {
+                invoc.expansion_data.mark.set_expn_info(ExpnInfo {
                     call_site: span,
                     callee: NameAndSpan {
                         format: MacroBang(Symbol::intern(&format!("{}", path))),
@@ -470,7 +474,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                     return kind.dummy(span);
                 };
 
-                self.cx.bt_push(ExpnInfo {
+                invoc.expansion_data.mark.set_expn_info(ExpnInfo {
                     call_site: span,
                     callee: NameAndSpan {
                         format: MacroBang(Symbol::intern(&format!("{}", path))),
@@ -502,7 +506,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                     return kind.dummy(span);
                 }
 
-                self.cx.bt_push(ExpnInfo {
+                invoc.expansion_data.mark.set_expn_info(ExpnInfo {
                     call_site: span,
                     callee: NameAndSpan {
                         format: MacroBang(Symbol::intern(&format!("{}", path))),
@@ -528,10 +532,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             return kind.dummy(span);
         };
 
-        expanded.fold_with(&mut Marker {
-            mark: mark,
-            expn_id: Some(self.cx.backtrace()),
-        })
+        expanded.fold_with(&mut Marker(mark))
     }
 
     /// Expand a derive invocation. Returns the result of expansion.
@@ -550,50 +551,33 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             id: ast::AttrId(0), style: ast::AttrStyle::Outer, is_sugared_doc: false,
         };
 
-        self.cx.bt_push(ExpnInfo {
+        let mut expn_info = ExpnInfo {
             call_site: span,
             callee: NameAndSpan {
                 format: MacroAttribute(pretty_name),
                 span: None,
                 allow_internal_unstable: false,
             }
-        });
+        };
 
         match *ext {
             SyntaxExtension::ProcMacroDerive(ref ext, _) => {
-                let span = Span {
-                    expn_id: self.cx.codemap().record_expansion(ExpnInfo {
-                        call_site: span,
-                        callee: NameAndSpan {
-                            format: MacroAttribute(pretty_name),
-                            span: None,
-                            allow_internal_unstable: false,
-                        },
-                    }),
-                    ..span
-                };
+                invoc.expansion_data.mark.set_expn_info(expn_info);
+                let span = Span { ctxt: self.cx.backtrace(), ..span };
                 let dummy = ast::MetaItem { // FIXME(jseyfried) avoid this
                     name: keywords::Invalid.name(),
                     span: DUMMY_SP,
                     node: ast::MetaItemKind::Word,
                 };
-                return kind.expect_from_annotatables(ext.expand(self.cx, span, &dummy, item));
+                kind.expect_from_annotatables(ext.expand(self.cx, span, &dummy, item))
             }
             SyntaxExtension::BuiltinDerive(func) => {
-                let span = Span {
-                    expn_id: self.cx.codemap().record_expansion(ExpnInfo {
-                        call_site: span,
-                        callee: NameAndSpan {
-                            format: MacroAttribute(pretty_name),
-                            span: None,
-                            allow_internal_unstable: true,
-                        },
-                    }),
-                    ..span
-                };
+                expn_info.callee.allow_internal_unstable = true;
+                invoc.expansion_data.mark.set_expn_info(expn_info);
+                let span = Span { ctxt: self.cx.backtrace(), ..span };
                 let mut items = Vec::new();
                 func(self.cx, span, &attr.meta().unwrap(), &item, &mut |a| items.push(a));
-                return kind.expect_from_annotatables(items);
+                kind.expect_from_annotatables(items)
             }
             _ => {
                 let msg = &format!("macro `{}` may not be used for derive attributes", attr.path);
@@ -703,7 +687,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
                 ..self.cx.current_expansion.clone()
             },
         });
-        placeholder(expansion_kind, mark.as_placeholder_id())
+        placeholder(expansion_kind, NodeId::placeholder_from_mark(mark))
     }
 
     fn collect_bang(&mut self, mac: ast::Mac, span: Span, kind: ExpansionKind) -> Expansion {
@@ -753,10 +737,9 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
     // Detect use of feature-gated or invalid attributes on macro invocations
     // since they will not be detected after macro expansion.
     fn check_attributes(&mut self, attrs: &[ast::Attribute]) {
-        let codemap = &self.cx.parse_sess.codemap();
         let features = self.cx.ecfg.features.unwrap();
         for attr in attrs.iter() {
-            feature_gate::check_attribute(&attr, &self.cx.parse_sess, codemap, features);
+            feature_gate::check_attribute(&attr, &self.cx.parse_sess, features);
         }
     }
 }
@@ -1065,23 +1048,21 @@ impl<'feat> ExpansionConfig<'feat> {
     }
 }
 
-// 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> }
+// A Marker adds the given mark to the syntax context.
+struct Marker(Mark);
 
 impl Folder for Marker {
     fn fold_ident(&mut self, mut ident: Ident) -> Ident {
-        ident.ctxt = ident.ctxt.apply_mark(self.mark);
+        ident.ctxt = ident.ctxt.apply_mark(self.0);
         ident
     }
-    fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
-        noop_fold_mac(mac, self)
-    }
 
     fn new_span(&mut self, mut span: Span) -> Span {
-        if let Some(expn_id) = self.expn_id {
-            span.expn_id = expn_id;
-        }
+        span.ctxt = span.ctxt.apply_mark(self.0);
         span
     }
+
+    fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
+        noop_fold_mac(mac, self)
+    }
 }
diff --git a/src/libsyntax/ext/hygiene.rs b/src/libsyntax/ext/hygiene.rs
deleted file mode 100644
index 57f5ab73d37..00000000000
--- a/src/libsyntax/ext/hygiene.rs
+++ /dev/null
@@ -1,127 +0,0 @@
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Machinery for hygienic macros, inspired by the MTWT[1] paper.
-//!
-//! [1] Matthew Flatt, Ryan Culpepper, David Darais, and Robert Bruce Findler.
-//! 2012. *Macros that work together: Compile-time bindings, partial expansion,
-//! 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;
-
-/// A SyntaxContext represents a chain of macro expansions (represented by marks).
-#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Default)]
-pub struct SyntaxContext(u32);
-
-#[derive(Copy, Clone)]
-pub struct SyntaxContextData {
-    pub outer_mark: Mark,
-    pub prev_ctxt: SyntaxContext,
-}
-
-/// A mark is a unique id associated with a macro expansion.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default, RustcEncodable, RustcDecodable)]
-pub struct Mark(u32);
-
-impl Mark {
-    pub fn fresh() -> Self {
-        HygieneData::with(|data| {
-            let next_mark = Mark(data.next_mark.0 + 1);
-            ::std::mem::replace(&mut data.next_mark, next_mark)
-        })
-    }
-
-    /// The mark of the theoretical expansion that generates freshly parsed, unexpanded AST.
-    pub fn root() -> Self {
-        Mark(0)
-    }
-
-    pub fn from_placeholder_id(id: NodeId) -> Self {
-        Mark(id.as_u32())
-    }
-
-    pub fn as_placeholder_id(self) -> NodeId {
-        NodeId::from_u32(self.0)
-    }
-
-    pub fn as_u32(self) -> u32 {
-        self.0
-    }
-}
-
-struct HygieneData {
-    syntax_contexts: Vec<SyntaxContextData>,
-    markings: HashMap<(SyntaxContext, Mark), SyntaxContext>,
-    next_mark: Mark,
-}
-
-impl HygieneData {
-    fn new() -> Self {
-        HygieneData {
-            syntax_contexts: vec![SyntaxContextData {
-                outer_mark: Mark::root(),
-                prev_ctxt: SyntaxContext::empty(),
-            }],
-            markings: HashMap::new(),
-            next_mark: Mark(1),
-        }
-    }
-
-    fn with<T, F: FnOnce(&mut HygieneData) -> T>(f: F) -> T {
-        thread_local! {
-            static HYGIENE_DATA: RefCell<HygieneData> = RefCell::new(HygieneData::new());
-        }
-        HYGIENE_DATA.with(|data| f(&mut *data.borrow_mut()))
-    }
-}
-
-pub fn reset_hygiene_data() {
-    HygieneData::with(|data| *data = HygieneData::new())
-}
-
-impl SyntaxContext {
-    pub const fn empty() -> Self {
-        SyntaxContext(0)
-    }
-
-    pub fn data(self) -> SyntaxContextData {
-        HygieneData::with(|data| data.syntax_contexts[self.0 as usize])
-    }
-
-    /// Extend a syntax context with a given mark
-    pub fn apply_mark(self, mark: Mark) -> SyntaxContext {
-        // Applying the same mark twice is a no-op
-        let ctxt_data = self.data();
-        if mark == ctxt_data.outer_mark {
-            return ctxt_data.prev_ctxt;
-        }
-
-        HygieneData::with(|data| {
-            let syntax_contexts = &mut data.syntax_contexts;
-            *data.markings.entry((self, mark)).or_insert_with(|| {
-                syntax_contexts.push(SyntaxContextData {
-                    outer_mark: mark,
-                    prev_ctxt: self,
-                });
-                SyntaxContext(syntax_contexts.len() as u32 - 1)
-            })
-        })
-    }
-}
-
-impl fmt::Debug for SyntaxContext {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "#{}", self.0)
-    }
-}
diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs
index f60b1d17a5e..4fb138d506a 100644
--- a/src/libsyntax/ext/placeholders.rs
+++ b/src/libsyntax/ext/placeholders.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use ast;
+use ast::{self, NodeId};
 use codemap::{DUMMY_SP, dummy_spanned};
 use ext::base::ExtCtxt;
 use ext::expand::{Expansion, ExpansionKind};
@@ -88,7 +88,7 @@ impl<'a, 'b> PlaceholderExpander<'a, 'b> {
         let mut expansion = expansion.fold_with(self);
         if let Expansion::Items(mut items) = expansion {
             for derive in derives {
-                match self.remove(derive.as_placeholder_id()) {
+                match self.remove(NodeId::placeholder_from_mark(derive)) {
                     Expansion::Items(derived_items) => items.extend(derived_items),
                     _ => unreachable!(),
                 }
@@ -106,8 +106,8 @@ impl<'a, 'b> PlaceholderExpander<'a, 'b> {
 impl<'a, 'b> Folder for PlaceholderExpander<'a, 'b> {
     fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
         match item.node {
-            ast::ItemKind::Mac(ref mac) if !mac.node.path.segments.is_empty() => {}
             ast::ItemKind::Mac(_) => return self.remove(item.id).make_items(),
+            ast::ItemKind::MacroDef(_) => return SmallVector::one(item),
             _ => {}
         }
 
@@ -178,17 +178,9 @@ impl<'a, 'b> Folder for PlaceholderExpander<'a, 'b> {
             block.stmts = block.stmts.move_flat_map(|mut stmt| {
                 remaining_stmts -= 1;
 
-                match stmt.node {
-                    // Avoid wasting a node id on a trailing expression statement,
-                    // which shares a HIR node with the expression itself.
-                    ast::StmtKind::Expr(ref expr) if remaining_stmts == 0 => stmt.id = expr.id,
-
-                    _ if self.monotonic => {
-                        assert_eq!(stmt.id, ast::DUMMY_NODE_ID);
-                        stmt.id = self.cx.resolver.next_node_id();
-                    }
-
-                    _ => {}
+                if self.monotonic {
+                    assert_eq!(stmt.id, ast::DUMMY_NODE_ID);
+                    stmt.id = self.cx.resolver.next_node_id();
                 }
 
                 Some(stmt)
diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs
index 39b92c7d007..0103d6ea959 100644
--- a/src/libsyntax/ext/source_util.rs
+++ b/src/libsyntax/ext/source_util.rs
@@ -185,7 +185,7 @@ pub fn expand_include_bytes(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::Toke
 fn res_rel_file(cx: &mut ExtCtxt, sp: syntax_pos::Span, arg: &Path) -> PathBuf {
     // NB: relative paths are resolved relative to the compilation unit
     if !arg.is_absolute() {
-        let callsite = cx.codemap().source_callsite(sp);
+        let callsite = sp.source_callsite();
         let mut cu = PathBuf::from(&cx.codemap().span_to_filename(callsite));
         cu.pop();
         cu.push(arg);
diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs
index ed17f0f956c..6cd1fea2e75 100644
--- a/src/libsyntax/ext/tt/macro_parser.rs
+++ b/src/libsyntax/ext/tt/macro_parser.rs
@@ -79,7 +79,7 @@ pub use self::ParseResult::*;
 use self::TokenTreeOrTokenTreeVec::*;
 
 use ast::Ident;
-use syntax_pos::{self, BytePos, mk_sp, Span};
+use syntax_pos::{self, BytePos, Span};
 use codemap::Spanned;
 use errors::FatalError;
 use ext::tt::quoted::{self, TokenTree};
@@ -285,7 +285,7 @@ fn inner_parse_loop(sess: &ParseSess,
                     eof_eis: &mut SmallVector<Box<MatcherPos>>,
                     bb_eis: &mut SmallVector<Box<MatcherPos>>,
                     token: &Token,
-                    span: &syntax_pos::Span)
+                    span: syntax_pos::Span)
                     -> ParseResult<()> {
     while let Some(mut ei) = cur_eis.pop() {
         // When unzipped trees end, remove them
@@ -323,8 +323,7 @@ fn inner_parse_loop(sess: &ParseSess,
                     for idx in ei.match_lo..ei.match_hi {
                         let sub = ei.matches[idx].clone();
                         new_pos.matches[idx]
-                            .push(Rc::new(MatchedSeq(sub, mk_sp(ei.sp_lo,
-                                                                span.hi))));
+                            .push(Rc::new(MatchedSeq(sub, Span { lo: ei.sp_lo, ..span })));
                     }
 
                     new_pos.match_cur = ei.match_hi;
@@ -426,7 +425,7 @@ pub fn parse(sess: &ParseSess, tts: TokenStream, ms: &[TokenTree], directory: Op
         assert!(next_eis.is_empty());
 
         match inner_parse_loop(sess, &mut cur_eis, &mut next_eis, &mut eof_eis, &mut bb_eis,
-                               &parser.token, &parser.span) {
+                               &parser.token, parser.span) {
             Success(_) => {},
             Failure(sp, tok) => return Failure(sp, tok),
             Error(sp, msg) => return Error(sp, msg),
@@ -493,7 +492,7 @@ fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal {
         _ => {}
     }
     // check at the beginning and the parser checks after each bump
-    p.check_unknown_macro_variable();
+    p.process_potential_macro_variable();
     match name {
         "item" => match panictry!(p.parse_item()) {
             Some(i) => token::NtItem(i),
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs
index 021c5398a42..93348c8f083 100644
--- a/src/libsyntax/ext/tt/macro_rules.rs
+++ b/src/libsyntax/ext/tt/macro_rules.rs
@@ -119,9 +119,9 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
                 };
                 let mut p = Parser::new(cx.parse_sess(), tts, Some(directory), false);
                 p.root_module_name = cx.current_expansion.module.mod_path.last()
-                    .map(|id| (*id.name.as_str()).to_owned());
+                    .map(|id| id.name.as_str().to_string());
 
-                p.check_unknown_macro_variable();
+                p.process_potential_macro_variable();
                 // Let the context choose how to interpret the result.
                 // Weird, but useful for X-macros.
                 return Box::new(ParserAnyMacro {
diff --git a/src/libsyntax/ext/tt/quoted.rs b/src/libsyntax/ext/tt/quoted.rs
index d56859d805c..d216effbd45 100644
--- a/src/libsyntax/ext/tt/quoted.rs
+++ b/src/libsyntax/ext/tt/quoted.rs
@@ -34,17 +34,19 @@ impl Delimited {
     }
 
     pub fn open_tt(&self, span: Span) -> TokenTree {
-        let open_span = match span {
-            DUMMY_SP => DUMMY_SP,
-            _ => Span { hi: span.lo + BytePos(self.delim.len() as u32), ..span },
+        let open_span = if span == DUMMY_SP {
+            DUMMY_SP
+        } else {
+            Span { hi: span.lo + BytePos(self.delim.len() as u32), ..span }
         };
         TokenTree::Token(open_span, self.open_token())
     }
 
     pub fn close_tt(&self, span: Span) -> TokenTree {
-        let close_span = match span {
-            DUMMY_SP => DUMMY_SP,
-            _ => Span { lo: span.hi - BytePos(self.delim.len() as u32), ..span },
+        let close_span = if span == DUMMY_SP {
+            DUMMY_SP
+        } else {
+            Span { lo: span.hi - BytePos(self.delim.len() as u32), ..span }
         };
         TokenTree::Token(close_span, self.close_token())
     }
@@ -134,11 +136,14 @@ pub fn parse(input: tokenstream::TokenStream, expect_matchers: bool, sess: &Pars
             TokenTree::Token(start_sp, token::SubstNt(ident)) if expect_matchers => {
                 let span = match trees.next() {
                     Some(tokenstream::TokenTree::Token(span, token::Colon)) => match trees.next() {
-                        Some(tokenstream::TokenTree::Token(end_sp, token::Ident(kind))) => {
-                            let span = Span { lo: start_sp.lo, ..end_sp };
-                            result.push(TokenTree::MetaVarDecl(span, ident, kind));
-                            continue
-                        }
+                        Some(tokenstream::TokenTree::Token(end_sp, ref tok)) => match tok.ident() {
+                            Some(kind) => {
+                                let span = Span { lo: start_sp.lo, ..end_sp };
+                                result.push(TokenTree::MetaVarDecl(span, ident, kind));
+                                continue
+                            }
+                            _ => end_sp,
+                        },
                         tree @ _ => tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(span),
                     },
                     tree @ _ => tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(start_sp),
diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs
index 24004492be2..947089b0b9a 100644
--- a/src/libsyntax/ext/tt/transcribe.rs
+++ b/src/libsyntax/ext/tt/transcribe.rs
@@ -12,7 +12,7 @@ use ast::Ident;
 use errors::Handler;
 use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal};
 use ext::tt::quoted;
-use parse::token::{self, SubstNt, Token, NtIdent, NtTT};
+use parse::token::{self, SubstNt, Token, NtTT};
 use syntax_pos::{Span, DUMMY_SP};
 use tokenstream::{TokenStream, TokenTree, Delimited};
 use util::small_vector::SmallVector;
@@ -154,13 +154,6 @@ pub fn transcribe(sp_diag: &Handler,
                     None => result.push(TokenTree::Token(sp, SubstNt(ident)).into()),
                     Some(cur_matched) => if let MatchedNonterminal(ref nt) = *cur_matched {
                         match **nt {
-                            // sidestep the interpolation tricks for ident because
-                            // (a) idents can be in lots of places, so it'd be a pain
-                            // (b) we actually can, since it's a token.
-                            NtIdent(ref sn) => {
-                                let token = TokenTree::Token(sn.span, token::Ident(sn.node));
-                                result.push(token.into());
-                            }
                             NtTT(ref tt) => result.push(tt.clone().into()),
                             _ => {
                                 let token = TokenTree::Token(sp, token::Interpolated(nt.clone()));
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 7af432176cf..12d25ca4274 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -28,7 +28,7 @@ use self::AttributeGate::*;
 use abi::Abi;
 use ast::{self, NodeId, PatKind, RangeEnd};
 use attr;
-use codemap::{CodeMap, Spanned};
+use codemap::Spanned;
 use syntax_pos::Span;
 use errors::{DiagnosticBuilder, Handler, FatalError};
 use visit::{self, FnKind, Visitor};
@@ -818,7 +818,7 @@ pub struct GatedCfg {
 
 impl GatedCfg {
     pub fn gate(cfg: &ast::MetaItem) -> Option<GatedCfg> {
-        let name = &*cfg.name().as_str();
+        let name = cfg.name().as_str();
         GATED_CFGS.iter()
                   .position(|info| info.0 == name)
                   .map(|idx| {
@@ -831,7 +831,7 @@ 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) {
+        if !has_feature(features) && !self.span.allows_unstable() {
             let explain = format!("`cfg({})` is experimental and subject to change", cfg);
             emit_feature_err(sess, feature, self.span, GateIssue::Language, &explain);
         }
@@ -841,7 +841,6 @@ impl GatedCfg {
 struct Context<'a> {
     features: &'a Features,
     parse_sess: &'a ParseSess,
-    cm: &'a CodeMap,
     plugin_attributes: &'a [(String, AttributeType)],
 }
 
@@ -850,7 +849,7 @@ macro_rules! gate_feature_fn {
         let (cx, has_feature, span, name, explain) = ($cx, $has_feature, $span, $name, $explain);
         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) {
+        if !has_feature && !span.allows_unstable() {
             emit_feature_err(cx.parse_sess, name, span, GateIssue::Language, explain);
         }
     }}
@@ -865,8 +864,7 @@ macro_rules! gate_feature {
 impl<'a> Context<'a> {
     fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) {
         debug!("check_attribute(attr = {:?})", attr);
-        let name = unwrap_or!(attr.name(), return);
-
+        let name = unwrap_or!(attr.name(), return).as_str();
         for &(n, ty, ref gateage) in BUILTIN_ATTRIBUTES {
             if name == n {
                 if let &Gated(_, ref name, ref desc, ref has_feature) = gateage {
@@ -885,12 +883,12 @@ impl<'a> Context<'a> {
                 return;
             }
         }
-        if name.as_str().starts_with("rustc_") {
+        if name.starts_with("rustc_") {
             gate_feature!(self, rustc_attrs, attr.span,
                           "unless otherwise specified, attributes \
                            with the prefix `rustc_` \
                            are reserved for internal compiler diagnostics");
-        } else if name.as_str().starts_with("derive_") {
+        } else if name.starts_with("derive_") {
             gate_feature!(self, custom_derive, attr.span, EXPLAIN_DERIVE_UNDERSCORE);
         } else if !attr::is_known(attr) {
             // Only run the custom attribute lint during regular
@@ -909,12 +907,8 @@ impl<'a> Context<'a> {
     }
 }
 
-pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess,
-                       cm: &CodeMap, features: &Features) {
-    let cx = Context {
-        features: features, parse_sess: parse_sess,
-        cm: cm, plugin_attributes: &[]
-    };
+pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, features: &Features) {
+    let cx = Context { features: features, parse_sess: parse_sess, plugin_attributes: &[] };
     cx.check_attribute(attr, true);
 }
 
@@ -1017,7 +1011,7 @@ struct PostExpansionVisitor<'a> {
 macro_rules! gate_feature_post {
     ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {{
         let (cx, span) = ($cx, $span);
-        if !cx.context.cm.span_allows_unstable(span) {
+        if !span.allows_unstable() {
             gate_feature!(cx.context, $feature, span, $explain)
         }
     }}
@@ -1097,7 +1091,7 @@ fn starts_with_digit(s: &str) -> bool {
 
 impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
     fn visit_attribute(&mut self, attr: &ast::Attribute) {
-        if !self.context.cm.span_allows_unstable(attr.span) {
+        if !attr.span.allows_unstable() {
             // check for gated attributes
             self.context.check_attribute(attr, false);
         }
@@ -1531,7 +1525,6 @@ pub fn check_crate(krate: &ast::Crate,
     let ctx = Context {
         features: features,
         parse_sess: sess,
-        cm: sess.codemap(),
         plugin_attributes: plugin_attributes,
     };
     visit::walk_crate(&mut PostExpansionVisitor { context: &ctx }, krate);
diff --git a/src/libsyntax/json.rs b/src/libsyntax/json.rs
index fd762552248..dec1b7d1d87 100644
--- a/src/libsyntax/json.rs
+++ b/src/libsyntax/json.rs
@@ -202,7 +202,7 @@ impl DiagnosticSpan {
         // backtrace ourselves, but the `macro_backtrace` helper makes
         // some decision, such as dropping some frames, and I don't
         // want to duplicate that logic here.
-        let backtrace = je.cm.macro_backtrace(span).into_iter();
+        let backtrace = span.macro_backtrace().into_iter();
         DiagnosticSpan::from_span_full(span,
                                        is_primary,
                                        label,
diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs
index 4c9a5d512af..86ee1c5336d 100644
--- a/src/libsyntax/lib.rs
+++ b/src/libsyntax/lib.rs
@@ -125,7 +125,7 @@ pub mod ptr;
 pub mod show_span;
 pub mod std_inject;
 pub mod str;
-pub mod symbol;
+pub use syntax_pos::symbol;
 pub mod test;
 pub mod tokenstream;
 pub mod visit;
@@ -136,12 +136,12 @@ pub mod print {
 }
 
 pub mod ext {
+    pub use syntax_pos::hygiene;
     pub mod base;
     pub mod build;
     pub mod derive;
     pub mod expand;
     pub mod placeholders;
-    pub mod hygiene;
     pub mod quote;
     pub mod source_util;
 
diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs
index 53106214fa3..92cec462ffb 100644
--- a/src/libsyntax/parse/attr.rs
+++ b/src/libsyntax/parse/attr.rs
@@ -10,8 +10,7 @@
 
 use attr;
 use ast;
-use syntax_pos::{mk_sp, Span};
-use codemap::spanned;
+use codemap::respan;
 use parse::common::SeqSep;
 use parse::PResult;
 use parse::token::{self, Nonterminal};
@@ -49,8 +48,7 @@ impl<'a> Parser<'a> {
                     just_parsed_doc_comment = false;
                 }
                 token::DocComment(s) => {
-                    let Span { lo, hi, .. } = self.span;
-                    let attr = attr::mk_sugared_doc_attr(attr::mk_attr_id(), s, lo, hi);
+                    let attr = attr::mk_sugared_doc_attr(attr::mk_attr_id(), s, self.span);
                     if attr.style != ast::AttrStyle::Outer {
                         let mut err = self.fatal("expected outer doc comment");
                         err.note("inner doc comments like this (starting with \
@@ -94,7 +92,7 @@ impl<'a> Parser<'a> {
                self.token);
         let (span, path, tokens, mut style) = match self.token {
             token::Pound => {
-                let lo = self.span.lo;
+                let lo = self.span;
                 self.bump();
 
                 if inner_parse_policy == InnerAttributeParsePolicy::Permitted {
@@ -122,9 +120,9 @@ impl<'a> Parser<'a> {
                 self.expect(&token::OpenDelim(token::Bracket))?;
                 let (path, tokens) = self.parse_path_and_tokens()?;
                 self.expect(&token::CloseDelim(token::Bracket))?;
-                let hi = self.prev_span.hi;
+                let hi = self.prev_span;
 
-                (mk_sp(lo, hi), path, tokens, style)
+                (lo.to(hi), path, tokens, style)
             }
             _ => {
                 let token_str = self.this_token_to_string();
@@ -189,8 +187,7 @@ impl<'a> Parser<'a> {
                 }
                 token::DocComment(s) => {
                     // we need to get the position of this token before we bump.
-                    let Span { lo, hi, .. } = self.span;
-                    let attr = attr::mk_sugared_doc_attr(attr::mk_attr_id(), s, lo, hi);
+                    let attr = attr::mk_sugared_doc_attr(attr::mk_attr_id(), s, self.span);
                     if attr.style == ast::AttrStyle::Inner {
                         attrs.push(attr);
                         self.bump();
@@ -238,11 +235,10 @@ impl<'a> Parser<'a> {
             return Ok(meta);
         }
 
-        let lo = self.span.lo;
+        let lo = self.span;
         let ident = self.parse_ident()?;
         let node = self.parse_meta_item_kind()?;
-        let hi = self.prev_span.hi;
-        Ok(ast::MetaItem { name: ident.name, node: node, span: mk_sp(lo, hi) })
+        Ok(ast::MetaItem { name: ident.name, node: node, span: lo.to(self.prev_span) })
     }
 
     pub fn parse_meta_item_kind(&mut self) -> PResult<'a, ast::MetaItemKind> {
@@ -258,26 +254,25 @@ impl<'a> Parser<'a> {
 
     /// matches meta_item_inner : (meta_item | UNSUFFIXED_LIT) ;
     fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> {
-        let sp = self.span;
-        let lo = self.span.lo;
+        let lo = self.span;
 
         match self.parse_unsuffixed_lit() {
             Ok(lit) => {
-                return Ok(spanned(lo, self.prev_span.hi, ast::NestedMetaItemKind::Literal(lit)))
+                return Ok(respan(lo.to(self.prev_span), ast::NestedMetaItemKind::Literal(lit)))
             }
             Err(ref mut err) => self.diagnostic().cancel(err)
         }
 
         match self.parse_meta_item() {
             Ok(mi) => {
-                return Ok(spanned(lo, self.prev_span.hi, ast::NestedMetaItemKind::MetaItem(mi)))
+                return Ok(respan(lo.to(self.prev_span), ast::NestedMetaItemKind::MetaItem(mi)))
             }
             Err(ref mut err) => self.diagnostic().cancel(err)
         }
 
         let found = self.this_token_to_string();
         let msg = format!("expected unsuffixed literal or identifier, found {}", found);
-        Err(self.diagnostic().struct_span_err(sp, &msg))
+        Err(self.diagnostic().struct_span_err(lo, &msg))
     }
 
     /// matches meta_seq = ( COMMASEP(meta_item_inner) )
diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs
index d48cf6911ed..920b2c401e2 100644
--- a/src/libsyntax/parse/lexer/mod.rs
+++ b/src/libsyntax/parse/lexer/mod.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use ast::{self, Ident};
-use syntax_pos::{self, BytePos, CharPos, Pos, Span};
+use syntax_pos::{self, BytePos, CharPos, Pos, Span, NO_EXPANSION};
 use codemap::CodeMap;
 use errors::{FatalError, DiagnosticBuilder};
 use parse::{token, ParseSess};
@@ -68,6 +68,10 @@ pub struct StringReader<'a> {
     open_braces: Vec<(token::DelimToken, Span)>,
 }
 
+fn mk_sp(lo: BytePos, hi: BytePos) -> Span {
+    Span { lo: lo, hi: hi, ctxt: NO_EXPANSION }
+}
+
 impl<'a> StringReader<'a> {
     fn next_token(&mut self) -> TokenAndSpan where Self: Sized {
         let res = self.try_next_token();
@@ -225,12 +229,12 @@ impl<'a> StringReader<'a> {
 
     /// Report a fatal error spanning [`from_pos`, `to_pos`).
     fn fatal_span_(&self, from_pos: BytePos, to_pos: BytePos, m: &str) -> FatalError {
-        self.fatal_span(syntax_pos::mk_sp(from_pos, to_pos), m)
+        self.fatal_span(mk_sp(from_pos, to_pos), m)
     }
 
     /// Report a lexical error spanning [`from_pos`, `to_pos`).
     fn err_span_(&self, from_pos: BytePos, to_pos: BytePos, m: &str) {
-        self.err_span(syntax_pos::mk_sp(from_pos, to_pos), m)
+        self.err_span(mk_sp(from_pos, to_pos), m)
     }
 
     /// Report a lexical error spanning [`from_pos`, `to_pos`), appending an
@@ -254,7 +258,7 @@ impl<'a> StringReader<'a> {
         for c in c.escape_default() {
             m.push(c)
         }
-        self.sess.span_diagnostic.struct_span_fatal(syntax_pos::mk_sp(from_pos, to_pos), &m[..])
+        self.sess.span_diagnostic.struct_span_fatal(mk_sp(from_pos, to_pos), &m[..])
     }
 
     /// Report a lexical error spanning [`from_pos`, `to_pos`), appending an
@@ -278,7 +282,7 @@ impl<'a> StringReader<'a> {
         for c in c.escape_default() {
             m.push(c)
         }
-        self.sess.span_diagnostic.struct_span_err(syntax_pos::mk_sp(from_pos, to_pos), &m[..])
+        self.sess.span_diagnostic.struct_span_err(mk_sp(from_pos, to_pos), &m[..])
     }
 
     /// Report a lexical error spanning [`from_pos`, `to_pos`), appending the
@@ -302,11 +306,11 @@ impl<'a> StringReader<'a> {
             None => {
                 if self.is_eof() {
                     self.peek_tok = token::Eof;
-                    self.peek_span = syntax_pos::mk_sp(self.filemap.end_pos, self.filemap.end_pos);
+                    self.peek_span = mk_sp(self.filemap.end_pos, self.filemap.end_pos);
                 } else {
                     let start_bytepos = self.pos;
                     self.peek_tok = self.next_token_inner()?;
-                    self.peek_span = syntax_pos::mk_sp(start_bytepos, self.pos);
+                    self.peek_span = mk_sp(start_bytepos, self.pos);
                 };
             }
         }
@@ -489,7 +493,7 @@ impl<'a> StringReader<'a> {
         if let Some(c) = self.ch {
             if c.is_whitespace() {
                 let msg = "called consume_any_line_comment, but there was whitespace";
-                self.sess.span_diagnostic.span_err(syntax_pos::mk_sp(self.pos, self.pos), msg);
+                self.sess.span_diagnostic.span_err(mk_sp(self.pos, self.pos), msg);
             }
         }
 
@@ -532,13 +536,13 @@ impl<'a> StringReader<'a> {
 
                             Some(TokenAndSpan {
                                 tok: tok,
-                                sp: syntax_pos::mk_sp(start_bpos, self.pos),
+                                sp: mk_sp(start_bpos, self.pos),
                             })
                         })
                     } else {
                         Some(TokenAndSpan {
                             tok: token::Comment,
-                            sp: syntax_pos::mk_sp(start_bpos, self.pos),
+                            sp: mk_sp(start_bpos, self.pos),
                         })
                     };
                 }
@@ -571,7 +575,7 @@ impl<'a> StringReader<'a> {
                     }
                     return Some(TokenAndSpan {
                         tok: token::Shebang(self.name_from(start)),
-                        sp: syntax_pos::mk_sp(start, self.pos),
+                        sp: mk_sp(start, self.pos),
                     });
                 }
             }
@@ -599,7 +603,7 @@ impl<'a> StringReader<'a> {
                 }
                 let c = Some(TokenAndSpan {
                     tok: token::Whitespace,
-                    sp: syntax_pos::mk_sp(start_bpos, self.pos),
+                    sp: mk_sp(start_bpos, self.pos),
                 });
                 debug!("scanning whitespace: {:?}", c);
                 c
@@ -661,7 +665,7 @@ impl<'a> StringReader<'a> {
 
             Some(TokenAndSpan {
                 tok: tok,
-                sp: syntax_pos::mk_sp(start_bpos, self.pos),
+                sp: mk_sp(start_bpos, self.pos),
             })
         })
     }
@@ -858,7 +862,7 @@ impl<'a> StringReader<'a> {
                                 let valid = if self.ch_is('{') {
                                     self.scan_unicode_escape(delim) && !ascii_only
                                 } else {
-                                    let span = syntax_pos::mk_sp(start, self.pos);
+                                    let span = mk_sp(start, self.pos);
                                     self.sess.span_diagnostic
                                         .struct_span_err(span, "incorrect unicode escape sequence")
                                         .span_help(span,
@@ -896,13 +900,13 @@ impl<'a> StringReader<'a> {
                                                                         },
                                                                         c);
                                 if e == '\r' {
-                                    err.span_help(syntax_pos::mk_sp(escaped_pos, pos),
+                                    err.span_help(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, pos),
+                                    err.span_help(mk_sp(escaped_pos, pos),
                                                   "if used in a formatting string, curly braces \
                                                    are escaped with `{{` and `}}`");
                                 }
@@ -1735,7 +1739,7 @@ mod tests {
             sp: Span {
                 lo: BytePos(21),
                 hi: BytePos(23),
-                expn_id: NO_EXPANSION,
+                ctxt: NO_EXPANSION,
             },
         };
         assert_eq!(tok1, tok2);
@@ -1749,7 +1753,7 @@ mod tests {
             sp: Span {
                 lo: BytePos(24),
                 hi: BytePos(28),
-                expn_id: NO_EXPANSION,
+                ctxt: NO_EXPANSION,
             },
         };
         assert_eq!(tok3, tok4);
@@ -1908,7 +1912,7 @@ mod tests {
         let mut lexer = setup(&cm, &sh, "// test\r\n/// test\r\n".to_string());
         let comment = lexer.next_token();
         assert_eq!(comment.tok, token::Comment);
-        assert_eq!(comment.sp, ::syntax_pos::mk_sp(BytePos(0), BytePos(7)));
+        assert_eq!((comment.sp.lo, comment.sp.hi), (BytePos(0), BytePos(7)));
         assert_eq!(lexer.next_token().tok, token::Whitespace);
         assert_eq!(lexer.next_token().tok,
                    token::DocComment(Symbol::intern("/// test")));
diff --git a/src/libsyntax/parse/lexer/unicode_chars.rs b/src/libsyntax/parse/lexer/unicode_chars.rs
index 6da3e5de75c..4df23da3c9c 100644
--- a/src/libsyntax/parse/lexer/unicode_chars.rs
+++ b/src/libsyntax/parse/lexer/unicode_chars.rs
@@ -11,7 +11,7 @@
 // Characters and their corresponding confusables were collected from
 // http://www.unicode.org/Public/security/revision-06/confusables.txt
 
-use syntax_pos::mk_sp as make_span;
+use syntax_pos::{Span, NO_EXPANSION};
 use errors::DiagnosticBuilder;
 use super::StringReader;
 
@@ -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.pos, reader.next_pos);
+        let span = Span { lo: reader.pos, hi: reader.next_pos, ctxt: NO_EXPANSION };
         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 e188bcaf105..c63a6524f74 100644
--- a/src/libsyntax/parse/mod.rs
+++ b/src/libsyntax/parse/mod.rs
@@ -12,7 +12,7 @@
 
 use ast::{self, CrateConfig};
 use codemap::CodeMap;
-use syntax_pos::{self, Span, FileMap};
+use syntax_pos::{self, Span, FileMap, NO_EXPANSION};
 use errors::{Handler, ColorConfig, DiagnosticBuilder};
 use feature_gate::UnstableFeatures;
 use parse::parser::Parser;
@@ -178,7 +178,7 @@ pub fn filemap_to_parser<'a>(sess: &'a ParseSess, filemap: Rc<FileMap>, ) -> Par
     let mut parser = stream_to_parser(sess, filemap_to_stream(sess, filemap));
 
     if parser.token == token::Eof && parser.span == syntax_pos::DUMMY_SP {
-        parser.span = syntax_pos::mk_sp(end_pos, end_pos);
+        parser.span = Span { lo: end_pos, hi: end_pos, ctxt: NO_EXPANSION };
     }
 
     parser
@@ -218,9 +218,7 @@ pub fn filemap_to_stream(sess: &ParseSess, filemap: Rc<FileMap>) -> TokenStream
 
 /// Given stream and the ParseSess, produce a parser
 pub fn stream_to_parser<'a>(sess: &'a ParseSess, stream: TokenStream) -> Parser<'a> {
-    let mut p = Parser::new(sess, stream, None, false);
-    p.check_unknown_macro_variable();
-    p
+    Parser::new(sess, stream, None, false)
 }
 
 /// Parse a string representing a character literal into its final form.
@@ -665,7 +663,7 @@ mod tests {
 
     // produce a syntax_pos::span
     fn sp(a: u32, b: u32) -> Span {
-        Span {lo: BytePos(a), hi: BytePos(b), expn_id: NO_EXPANSION}
+        Span {lo: BytePos(a), hi: BytePos(b), ctxt: NO_EXPANSION}
     }
 
     fn str2seg(s: &str, lo: u32, hi: u32) -> ast::PathSegment {
diff --git a/src/libsyntax/parse/obsolete.rs b/src/libsyntax/parse/obsolete.rs
index a46a788ca08..d5baec675e4 100644
--- a/src/libsyntax/parse/obsolete.rs
+++ b/src/libsyntax/parse/obsolete.rs
@@ -36,6 +36,7 @@ pub trait ParserObsoleteMethods {
 impl<'a> ParserObsoleteMethods for parser::Parser<'a> {
     /// Reports an obsolete syntax non-fatal error.
     #[allow(unused_variables)]
+    #[allow(unreachable_code)]
     fn obsolete(&mut self, sp: Span, kind: ObsoleteSyntax) {
         let (kind_str, desc, error) = match kind {
             // Nothing here at the moment
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 8177d738dc8..a27fc070ebe 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -40,8 +40,8 @@ use ast::{Visibility, WhereClause};
 use ast::{BinOpKind, UnOp};
 use ast::RangeEnd;
 use {ast, attr};
-use codemap::{self, CodeMap, Spanned, spanned, respan};
-use syntax_pos::{self, Span, BytePos, mk_sp};
+use codemap::{self, CodeMap, Spanned, respan};
+use syntax_pos::{self, Span, BytePos};
 use errors::{self, DiagnosticBuilder};
 use parse::{self, classify, token};
 use parse::common::SeqSep;
@@ -59,7 +59,7 @@ use util::ThinVec;
 
 use std::collections::HashSet;
 use std::{cmp, mem, slice};
-use std::path::{Path, PathBuf};
+use std::path::{self, Path, PathBuf};
 
 bitflags! {
     flags Restrictions: u8 {
@@ -108,13 +108,13 @@ macro_rules! maybe_whole_expr {
                     $p.bump();
                     let span = $p.span;
                     let kind = ExprKind::Path(None, (*path).clone());
-                    return Ok($p.mk_expr(span.lo, span.hi, kind, ThinVec::new()));
+                    return Ok($p.mk_expr(span, kind, ThinVec::new()));
                 }
                 token::NtBlock(ref block) => {
                     $p.bump();
                     let span = $p.span;
                     let kind = ExprKind::Block((*block).clone());
-                    return Ok($p.mk_expr(span.lo, span.hi, kind, ThinVec::new()));
+                    return Ok($p.mk_expr(span, kind, ThinVec::new()));
                 }
                 _ => {},
             };
@@ -160,6 +160,7 @@ pub struct Parser<'a> {
     /// the span of the current token:
     pub span: Span,
     /// the span of the previous token:
+    pub meta_var_span: Option<Span>,
     pub prev_span: Span,
     /// the previous token kind
     prev_token_kind: PrevTokenKind,
@@ -417,6 +418,7 @@ impl<'a> Parser<'a> {
             token: token::Underscore,
             span: syntax_pos::DUMMY_SP,
             prev_span: syntax_pos::DUMMY_SP,
+            meta_var_span: None,
             prev_token_kind: PrevTokenKind::Other,
             restrictions: Restrictions::empty(),
             obsolete_set: HashSet::new(),
@@ -443,6 +445,7 @@ impl<'a> Parser<'a> {
             parser.directory.path = PathBuf::from(sess.codemap().span_to_filename(parser.span));
             parser.directory.path.pop();
         }
+        parser.process_potential_macro_variable();
         parser
     }
 
@@ -744,7 +747,7 @@ impl<'a> Parser<'a> {
             token::AndAnd => {
                 let span = self.span;
                 let lo = span.lo + BytePos(1);
-                Ok(self.bump_with(token::BinOp(token::And), lo, span.hi))
+                Ok(self.bump_with(token::BinOp(token::And), Span { lo: lo, ..span }))
             }
             _ => self.unexpected()
         }
@@ -778,7 +781,7 @@ impl<'a> Parser<'a> {
             token::BinOp(token::Shl) => {
                 let span = self.span;
                 let lo = span.lo + BytePos(1);
-                self.bump_with(token::Lt, lo, span.hi);
+                self.bump_with(token::Lt, Span { lo: lo, ..span });
                 true
             }
             _ => false,
@@ -806,17 +809,17 @@ impl<'a> Parser<'a> {
             token::BinOp(token::Shr) => {
                 let span = self.span;
                 let lo = span.lo + BytePos(1);
-                Ok(self.bump_with(token::Gt, lo, span.hi))
+                Ok(self.bump_with(token::Gt, Span { lo: lo, ..span }))
             }
             token::BinOpEq(token::Shr) => {
                 let span = self.span;
                 let lo = span.lo + BytePos(1);
-                Ok(self.bump_with(token::Ge, lo, span.hi))
+                Ok(self.bump_with(token::Ge, Span { lo: lo, ..span }))
             }
             token::Ge => {
                 let span = self.span;
                 let lo = span.lo + BytePos(1);
-                Ok(self.bump_with(token::Eq, lo, span.hi))
+                Ok(self.bump_with(token::Eq, Span { lo: lo, ..span }))
             }
             _ => self.unexpected()
         }
@@ -1010,12 +1013,12 @@ impl<'a> Parser<'a> {
                            -> PResult<'a, Spanned<Vec<T>>> where
         F: FnMut(&mut Parser<'a>) -> PResult<'a,  T>,
     {
-        let lo = self.span.lo;
+        let lo = self.span;
         self.expect(bra)?;
         let result = self.parse_seq_to_before_end(ket, sep, f);
-        let hi = self.span.hi;
+        let hi = self.span;
         self.bump();
-        Ok(spanned(lo, hi, result))
+        Ok(respan(lo.to(hi), result))
     }
 
     /// Advance the parser by one token
@@ -1025,7 +1028,7 @@ impl<'a> Parser<'a> {
             self.bug("attempted to bump the parser past EOF (may be stuck in a loop)");
         }
 
-        self.prev_span = self.span;
+        self.prev_span = self.meta_var_span.take().unwrap_or(self.span);
 
         // Record last token kind for possible error recovery.
         self.prev_token_kind = match self.token {
@@ -1041,21 +1044,18 @@ impl<'a> Parser<'a> {
         self.token = next.tok;
         self.expected_tokens.clear();
         // check after each token
-        self.check_unknown_macro_variable();
+        self.process_potential_macro_variable();
     }
 
     /// Advance the parser using provided token as a next one. Use this when
     /// consuming a part of a token. For example a single `<` from `<<`.
-    pub fn bump_with(&mut self,
-                     next: token::Token,
-                     lo: BytePos,
-                     hi: BytePos) {
-        self.prev_span = mk_sp(self.span.lo, lo);
+    pub fn bump_with(&mut self, next: token::Token, span: Span) {
+        self.prev_span = Span { hi: span.lo, ..self.span };
         // 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.span = span;
         self.token = next;
         self.expected_tokens.clear();
     }
@@ -1186,7 +1186,7 @@ impl<'a> Parser<'a> {
     pub fn parse_trait_item(&mut self) -> PResult<'a, TraitItem> {
         maybe_whole!(self, NtTraitItem, |x| x);
         let mut attrs = self.parse_outer_attributes()?;
-        let lo = self.span.lo;
+        let lo = self.span;
 
         let (name, node) = if self.eat_keyword(keywords::Type) {
             let TyParam {ident, bounds, default, ..} = self.parse_ty_param(vec![])?;
@@ -1210,7 +1210,7 @@ impl<'a> Parser<'a> {
         } 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 lo = self.span;
             let pth = self.parse_path(PathStyle::Mod)?;
             self.expect(&token::Not)?;
 
@@ -1220,7 +1220,7 @@ impl<'a> Parser<'a> {
                 self.expect(&token::Semi)?
             }
 
-            let mac = spanned(lo, self.prev_span.hi, Mac_ { path: pth, tts: tts });
+            let mac = respan(lo.to(self.prev_span), Mac_ { path: pth, tts: tts });
             (keywords::Invalid.ident(), ast::TraitItemKind::Macro(mac))
         } else {
             let (constness, unsafety, abi) = match self.parse_fn_front_matter() {
@@ -1290,7 +1290,7 @@ impl<'a> Parser<'a> {
             ident: name,
             attrs: attrs,
             node: node,
-            span: mk_sp(lo, self.prev_span.hi),
+            span: lo.to(self.prev_span),
         })
     }
 
@@ -1311,8 +1311,7 @@ impl<'a> Parser<'a> {
         if self.eat(&token::RArrow) {
             Ok(FunctionRetTy::Ty(self.parse_ty_no_plus()?))
         } else {
-            let pos = self.span.lo;
-            Ok(FunctionRetTy::Default(mk_sp(pos, pos)))
+            Ok(FunctionRetTy::Default(Span { hi: self.span.lo, ..self.span }))
         }
     }
 
@@ -1333,7 +1332,7 @@ impl<'a> Parser<'a> {
     fn parse_ty_common(&mut self, allow_plus: bool) -> PResult<'a, P<Ty>> {
         maybe_whole!(self, NtTy, |x| x);
 
-        let lo = self.span.lo;
+        let lo = self.span;
         let node = if self.eat(&token::OpenDelim(token::Paren)) {
             // `(TYPE)` is a parenthesized type.
             // `(TYPE,)` is a tuple with a single field of type TYPE.
@@ -1357,7 +1356,7 @@ impl<'a> Parser<'a> {
                     TyKind::Path(None, ref path)
                             if allow_plus && self.token == token::BinOp(token::Plus) => {
                         self.bump(); // `+`
-                        let pt = PolyTraitRef::new(Vec::new(), path.clone(), lo, self.prev_span.hi);
+                        let pt = PolyTraitRef::new(Vec::new(), path.clone(), lo.to(self.prev_span));
                         let mut bounds = vec![TraitTyParamBound(pt, TraitBoundModifier::None)];
                         bounds.append(&mut self.parse_ty_param_bounds()?);
                         TyKind::TraitObject(bounds)
@@ -1407,13 +1406,13 @@ impl<'a> Parser<'a> {
             if self.eat(&token::Not) {
                 // Macro invocation in type position
                 let (_, tts) = self.expect_delimited_token_tree()?;
-                TyKind::Mac(spanned(lo, self.span.hi, Mac_ { path: path, tts: tts }))
+                TyKind::Mac(respan(lo.to(self.span), Mac_ { path: path, tts: tts }))
             } else {
                 // Just a type path or bound list (trait object type) starting with a trait.
                 //   `Type`
                 //   `Trait1 + Trait2 + 'a`
                 if allow_plus && self.eat(&token::BinOp(token::Plus)) {
-                    let poly_trait = PolyTraitRef::new(Vec::new(), path, lo, self.prev_span.hi);
+                    let poly_trait = PolyTraitRef::new(Vec::new(), path, lo.to(self.prev_span));
                     let mut bounds = vec![TraitTyParamBound(poly_trait, TraitBoundModifier::None)];
                     bounds.append(&mut self.parse_ty_param_bounds()?);
                     TyKind::TraitObject(bounds)
@@ -1428,13 +1427,13 @@ impl<'a> Parser<'a> {
             // Function pointer type or bound list (trait object type) starting with a poly-trait.
             //   `for<'lt> [unsafe] [extern "ABI"] fn (&'lt S) -> T`
             //   `for<'lt> Trait1<'lt> + Trait2 + 'a`
-            let lo = self.span.lo;
+            let lo = self.span;
             let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
             if self.token_is_bare_fn_keyword() {
                 self.parse_ty_bare_fn(lifetime_defs)?
             } else {
                 let path = self.parse_path(PathStyle::Type)?;
-                let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo, self.prev_span.hi);
+                let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span));
                 let mut bounds = vec![TraitTyParamBound(poly_trait, TraitBoundModifier::None)];
                 if allow_plus && self.eat(&token::BinOp(token::Plus)) {
                     bounds.append(&mut self.parse_ty_param_bounds()?)
@@ -1453,7 +1452,7 @@ impl<'a> Parser<'a> {
             return Err(self.fatal(&msg));
         };
 
-        let span = mk_sp(lo, self.prev_span.hi);
+        let span = lo.to(self.prev_span);
         let ty = Ty { node: node, span: span, id: ast::DUMMY_NODE_ID };
 
         // Try to recover from use of `+` with incorrect priority.
@@ -1470,7 +1469,7 @@ impl<'a> Parser<'a> {
 
         self.bump(); // `+`
         let bounds = self.parse_ty_param_bounds()?;
-        let sum_span = mk_sp(ty.span.lo, self.prev_span.hi);
+        let sum_span = ty.span.to(self.prev_span);
 
         let mut err = struct_span_err!(self.sess.span_diagnostic, ty.span, E0178,
             "expected a path on the left-hand side of `+`, not `{}`", pprust::ty_to_string(&ty));
@@ -1590,7 +1589,7 @@ impl<'a> Parser<'a> {
             P(Ty {
                 id: ast::DUMMY_NODE_ID,
                 node: TyKind::Infer,
-                span: mk_sp(self.span.lo, self.span.hi),
+                span: self.span,
             })
         };
         Ok(Arg {
@@ -1638,7 +1637,7 @@ impl<'a> Parser<'a> {
 
     /// Matches lit = true | false | token_lit
     pub fn parse_lit(&mut self) -> PResult<'a, Lit> {
-        let lo = self.span.lo;
+        let lo = self.span;
         let lit = if self.eat_keyword(keywords::True) {
             LitKind::Bool(true)
         } else if self.eat_keyword(keywords::False) {
@@ -1647,22 +1646,22 @@ impl<'a> Parser<'a> {
             let lit = self.parse_lit_token()?;
             lit
         };
-        Ok(codemap::Spanned { node: lit, span: mk_sp(lo, self.prev_span.hi) })
+        Ok(codemap::Spanned { node: lit, span: lo.to(self.prev_span) })
     }
 
     /// matches '-' lit | lit
     pub fn parse_pat_literal_maybe_minus(&mut self) -> PResult<'a, P<Expr>> {
-        let minus_lo = self.span.lo;
+        let minus_lo = self.span;
         let minus_present = self.eat(&token::BinOp(token::Minus));
-        let lo = self.span.lo;
+        let lo = self.span;
         let literal = P(self.parse_lit()?);
-        let hi = self.prev_span.hi;
-        let expr = self.mk_expr(lo, hi, ExprKind::Lit(literal), ThinVec::new());
+        let hi = self.prev_span;
+        let expr = self.mk_expr(lo.to(hi), ExprKind::Lit(literal), ThinVec::new());
 
         if minus_present {
-            let minus_hi = self.prev_span.hi;
+            let minus_hi = self.prev_span;
             let unary = self.mk_unary(UnOp::Neg, expr);
-            Ok(self.mk_expr(minus_lo, minus_hi, unary, ThinVec::new()))
+            Ok(self.mk_expr(minus_lo.to(minus_hi), unary, ThinVec::new()))
         } else {
             Ok(expr)
         }
@@ -1739,7 +1738,7 @@ impl<'a> Parser<'a> {
     pub fn parse_path(&mut self, mode: PathStyle) -> PResult<'a, ast::Path> {
         maybe_whole!(self, NtPath, |x| x);
 
-        let lo = self.span.lo;
+        let lo = self.meta_var_span.unwrap_or(self.span);
         let is_global = self.eat(&token::ModSep);
 
         // Parse any number of segments and bound sets. A segment is an
@@ -1761,13 +1760,9 @@ impl<'a> Parser<'a> {
             segments.insert(0, PathSegment::crate_root());
         }
 
-        // Assemble the span.
-        // FIXME(#39450) This is bogus if part of the path is macro generated.
-        let span = mk_sp(lo, self.prev_span.hi);
-
         // Assemble the result.
         Ok(ast::Path {
-            span: span,
+            span: lo.to(self.prev_span),
             segments: segments,
         })
     }
@@ -1780,8 +1775,8 @@ impl<'a> Parser<'a> {
         let mut segments = Vec::new();
         loop {
             // First, parse an identifier.
+            let ident_span = self.span;
             let identifier = self.parse_path_segment_ident()?;
-            let ident_span = self.prev_span;
 
             if self.check(&token::ModSep) && self.look_ahead(1, |t| *t == token::Lt) {
                 self.bump();
@@ -1804,7 +1799,7 @@ impl<'a> Parser<'a> {
                     bindings: bindings,
                 }.into()
             } else if self.eat(&token::OpenDelim(token::Paren)) {
-                let lo = self.prev_span.lo;
+                let lo = self.prev_span;
 
                 let inputs = self.parse_seq_to_end(
                     &token::CloseDelim(token::Paren),
@@ -1817,10 +1812,10 @@ impl<'a> Parser<'a> {
                     None
                 };
 
-                let hi = self.prev_span.hi;
+                let hi = self.prev_span;
 
                 Some(P(ast::PathParameters::Parenthesized(ast::ParenthesizedParameterData {
-                    span: mk_sp(lo, hi),
+                    span: lo.to(hi),
                     inputs: inputs,
                     output: output_ty,
                 })))
@@ -1848,8 +1843,8 @@ impl<'a> Parser<'a> {
         let mut segments = Vec::new();
         loop {
             // First, parse an identifier.
+            let ident_span = self.span;
             let identifier = self.parse_path_segment_ident()?;
-            let ident_span = self.prev_span;
 
             // If we do not see a `::`, stop.
             if !self.eat(&token::ModSep) {
@@ -1890,10 +1885,11 @@ impl<'a> Parser<'a> {
         let mut segments = Vec::new();
         loop {
             // First, parse an identifier.
+            let ident_span = self.span;
             let identifier = self.parse_path_segment_ident()?;
 
             // Assemble and push the result.
-            segments.push(PathSegment::from_ident(identifier, self.prev_span));
+            segments.push(PathSegment::from_ident(identifier, ident_span));
 
             // If we do not see a `::` or see `::{`/`::*`, stop.
             if !self.check(&token::ModSep) || self.is_import_coupler() {
@@ -1913,8 +1909,9 @@ impl<'a> Parser<'a> {
     fn expect_lifetime(&mut self) -> Lifetime {
         match self.token {
             token::Lifetime(ident) => {
+                let ident_span = self.span;
                 self.bump();
-                Lifetime { name: ident.name, span: self.prev_span, id: ast::DUMMY_NODE_ID }
+                Lifetime { name: ident.name, span: ident_span, id: ast::DUMMY_NODE_ID }
             }
             _ => self.span_bug(self.span, "not a lifetime")
         }
@@ -1941,38 +1938,37 @@ impl<'a> Parser<'a> {
     /// Parse ident (COLON expr)?
     pub fn parse_field(&mut self) -> PResult<'a, Field> {
         let attrs = self.parse_outer_attributes()?;
-        let lo = self.span.lo;
+        let lo = self.span;
         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;
+            hi = self.prev_span;
             (fieldname, self.parse_expr()?, false)
         } else {
             let fieldname = self.parse_ident()?;
-            hi = self.prev_span.hi;
+            hi = self.prev_span;
 
             // 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)
+            let path = ast::Path::from_ident(lo.to(hi), fieldname);
+            (fieldname, self.mk_expr(lo.to(hi), ExprKind::Path(None, path), ThinVec::new()), true)
         };
         Ok(ast::Field {
-            ident: spanned(lo, hi, fieldname),
-            span: mk_sp(lo, expr.span.hi),
+            ident: respan(lo.to(hi), fieldname),
+            span: lo.to(expr.span),
             expr: expr,
             is_shorthand: is_shorthand,
             attrs: attrs.into(),
         })
     }
 
-    pub fn mk_expr(&mut self, lo: BytePos, hi: BytePos, node: ExprKind, attrs: ThinVec<Attribute>)
-                   -> P<Expr> {
+    pub fn mk_expr(&mut self, span: Span, node: ExprKind, attrs: ThinVec<Attribute>) -> P<Expr> {
         P(Expr {
             id: ast::DUMMY_NODE_ID,
             node: node,
-            span: mk_sp(lo, hi),
+            span: span,
             attrs: attrs.into(),
         })
     }
@@ -2026,12 +2022,11 @@ impl<'a> Parser<'a> {
         ExprKind::AssignOp(binop, lhs, rhs)
     }
 
-    pub fn mk_mac_expr(&mut self, lo: BytePos, hi: BytePos,
-                       m: Mac_, attrs: ThinVec<Attribute>) -> P<Expr> {
+    pub fn mk_mac_expr(&mut self, span: Span, m: Mac_, attrs: ThinVec<Attribute>) -> P<Expr> {
         P(Expr {
             id: ast::DUMMY_NODE_ID,
-            node: ExprKind::Mac(codemap::Spanned {node: m, span: mk_sp(lo, hi)}),
-            span: mk_sp(lo, hi),
+            node: ExprKind::Mac(codemap::Spanned {node: m, span: span}),
+            span: span,
             attrs: attrs,
         })
     }
@@ -2078,8 +2073,8 @@ impl<'a> Parser<'a> {
         // attributes by giving them a empty "already parsed" list.
         let mut attrs = ThinVec::new();
 
-        let lo = self.span.lo;
-        let mut hi = self.span.hi;
+        let lo = self.span;
+        let mut hi = self.span;
 
         let ex: ExprKind;
 
@@ -2108,18 +2103,19 @@ impl<'a> Parser<'a> {
                 }
                 self.bump();
 
-                hi = self.prev_span.hi;
+                hi = self.prev_span;
+                let span = lo.to(hi);
                 return if es.len() == 1 && !trailing_comma {
-                    Ok(self.mk_expr(lo, hi, ExprKind::Paren(es.into_iter().nth(0).unwrap()), attrs))
+                    Ok(self.mk_expr(span, ExprKind::Paren(es.into_iter().nth(0).unwrap()), attrs))
                 } else {
-                    Ok(self.mk_expr(lo, hi, ExprKind::Tup(es), attrs))
+                    Ok(self.mk_expr(span, ExprKind::Tup(es), attrs))
                 }
             },
             token::OpenDelim(token::Brace) => {
                 return self.parse_block_expr(lo, BlockCheckMode::Default, attrs);
             },
             token::BinOp(token::Or) |  token::OrOr => {
-                let lo = self.span.lo;
+                let lo = self.span;
                 return self.parse_lambda_expr(lo, CaptureBy::Ref, attrs);
             },
             token::OpenDelim(token::Bracket) => {
@@ -2157,34 +2153,34 @@ impl<'a> Parser<'a> {
                         ex = ExprKind::Array(vec![first_expr]);
                     }
                 }
-                hi = self.prev_span.hi;
+                hi = self.prev_span;
             }
             _ => {
                 if self.eat_lt() {
                     let (qself, path) =
                         self.parse_qualified_path(PathStyle::Expr)?;
-                    hi = path.span.hi;
-                    return Ok(self.mk_expr(lo, hi, ExprKind::Path(Some(qself), path), attrs));
+                    hi = path.span;
+                    return Ok(self.mk_expr(lo.to(hi), ExprKind::Path(Some(qself), path), attrs));
                 }
                 if self.eat_keyword(keywords::Move) {
-                    let lo = self.prev_span.lo;
+                    let lo = self.prev_span;
                     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.prev_span.lo;
+                    let lo = self.prev_span;
                     return self.parse_for_expr(None, lo, attrs);
                 }
                 if self.eat_keyword(keywords::While) {
-                    let lo = self.prev_span.lo;
+                    let lo = self.prev_span;
                     return self.parse_while_expr(None, lo, attrs);
                 }
                 if self.token.is_lifetime() {
                     let label = Spanned { node: self.get_label(),
                                           span: self.span };
-                    let lo = self.span.lo;
+                    let lo = self.span;
                     self.bump();
                     self.expect(&token::Colon)?;
                     if self.eat_keyword(keywords::While) {
@@ -2199,7 +2195,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.prev_span.lo;
+                    let lo = self.prev_span;
                     return self.parse_loop_expr(None, lo, attrs);
                 }
                 if self.eat_keyword(keywords::Continue) {
@@ -2213,8 +2209,8 @@ impl<'a> Parser<'a> {
                     } else {
                         ExprKind::Continue(None)
                     };
-                    let hi = self.prev_span.hi;
-                    return Ok(self.mk_expr(lo, hi, ex, attrs));
+                    let hi = self.prev_span;
+                    return Ok(self.mk_expr(lo.to(hi), ex, attrs));
                 }
                 if self.eat_keyword(keywords::Match) {
                     return self.parse_match_expr(attrs);
@@ -2228,13 +2224,13 @@ impl<'a> Parser<'a> {
                 if self.is_catch_expr() {
                     assert!(self.eat_keyword(keywords::Do));
                     assert!(self.eat_keyword(keywords::Catch));
-                    let lo = self.prev_span.lo;
+                    let lo = self.prev_span;
                     return self.parse_catch_expr(lo, attrs);
                 }
                 if self.eat_keyword(keywords::Return) {
                     if self.token.can_begin_expr() {
                         let e = self.parse_expr()?;
-                        hi = e.span.hi;
+                        hi = e.span;
                         ex = ExprKind::Ret(Some(e));
                     } else {
                         ex = ExprKind::Ret(None);
@@ -2259,7 +2255,7 @@ impl<'a> Parser<'a> {
                         None
                     };
                     ex = ExprKind::Break(lt, e);
-                    hi = self.prev_span.hi;
+                    hi = self.prev_span;
                 } 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
@@ -2273,8 +2269,8 @@ impl<'a> Parser<'a> {
                     if self.eat(&token::Not) {
                         // MACRO INVOCATION expression
                         let (_, tts) = self.expect_delimited_token_tree()?;
-                        let hi = self.prev_span.hi;
-                        return Ok(self.mk_mac_expr(lo, hi, Mac_ { path: pth, tts: tts }, attrs));
+                        let hi = self.prev_span;
+                        return Ok(self.mk_mac_expr(lo.to(hi), Mac_ { path: pth, tts: tts }, attrs));
                     }
                     if self.check(&token::OpenDelim(token::Brace)) {
                         // This is a struct literal, unless we're prohibited
@@ -2287,12 +2283,12 @@ impl<'a> Parser<'a> {
                         }
                     }
 
-                    hi = pth.span.hi;
+                    hi = pth.span;
                     ex = ExprKind::Path(None, pth);
                 } else {
                     match self.parse_lit() {
                         Ok(lit) => {
-                            hi = lit.span.hi;
+                            hi = lit.span;
                             ex = ExprKind::Lit(P(lit));
                         }
                         Err(mut err) => {
@@ -2306,10 +2302,10 @@ impl<'a> Parser<'a> {
             }
         }
 
-        return Ok(self.mk_expr(lo, hi, ex, attrs));
+        return Ok(self.mk_expr(lo.to(hi), ex, attrs));
     }
 
-    fn parse_struct_expr(&mut self, lo: BytePos, pth: ast::Path, mut attrs: ThinVec<Attribute>)
+    fn parse_struct_expr(&mut self, lo: Span, pth: ast::Path, mut attrs: ThinVec<Attribute>)
                          -> PResult<'a, P<Expr>> {
         self.bump();
         let mut fields = Vec::new();
@@ -2351,9 +2347,9 @@ impl<'a> Parser<'a> {
             }
         }
 
-        let hi = self.span.hi;
+        let span = lo.to(self.span);
         self.expect(&token::CloseDelim(token::Brace))?;
-        return Ok(self.mk_expr(lo, hi, ExprKind::Struct(pth, fields, base), attrs));
+        return Ok(self.mk_expr(span, ExprKind::Struct(pth, fields, base), attrs));
     }
 
     fn parse_or_use_outer_attributes(&mut self,
@@ -2367,7 +2363,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Parse a block or unsafe block
-    pub fn parse_block_expr(&mut self, lo: BytePos, blk_mode: BlockCheckMode,
+    pub fn parse_block_expr(&mut self, lo: Span, blk_mode: BlockCheckMode,
                             outer_attrs: ThinVec<Attribute>)
                             -> PResult<'a, P<Expr>> {
 
@@ -2377,7 +2373,7 @@ impl<'a> Parser<'a> {
         attrs.extend(self.parse_inner_attributes()?);
 
         let blk = self.parse_block_tail(lo, blk_mode)?;
-        return Ok(self.mk_expr(blk.span.lo, blk.span.hi, ExprKind::Block(blk), attrs));
+        return Ok(self.mk_expr(blk.span, ExprKind::Block(blk), attrs));
     }
 
     /// parse a.b or a(13) or a[4] or just a
@@ -2388,12 +2384,12 @@ impl<'a> Parser<'a> {
 
         let b = self.parse_bottom_expr();
         let (span, b) = self.interpolated_or_expr_span(b)?;
-        self.parse_dot_or_call_expr_with(b, span.lo, attrs)
+        self.parse_dot_or_call_expr_with(b, span, attrs)
     }
 
     pub fn parse_dot_or_call_expr_with(&mut self,
                                        e0: P<Expr>,
-                                       lo: BytePos,
+                                       lo: Span,
                                        mut attrs: ThinVec<Attribute>)
                                        -> PResult<'a, P<Expr>> {
         // Stitch the list of outer attributes onto the return value.
@@ -2424,11 +2420,7 @@ impl<'a> Parser<'a> {
 
     // Assuming we have just parsed `.foo` (i.e., a dot and an ident), continue
     // parsing into an expression.
-    fn parse_dot_suffix(&mut self,
-                        ident: Ident,
-                        ident_span: Span,
-                        self_value: P<Expr>,
-                        lo: BytePos)
+    fn parse_dot_suffix(&mut self, ident: Ident, ident_span: Span, self_value: P<Expr>, lo: Span)
                         -> PResult<'a, P<Expr>> {
         let (_, tys, bindings) = if self.eat(&token::ModSep) {
             self.expect_lt()?;
@@ -2453,12 +2445,12 @@ impl<'a> Parser<'a> {
                     SeqSep::trailing_allowed(token::Comma),
                     |p| Ok(p.parse_expr()?)
                 )?;
-                let hi = self.prev_span.hi;
+                let hi = self.prev_span;
 
                 es.insert(0, self_value);
-                let id = spanned(ident_span.lo, ident_span.hi, ident);
+                let id = respan(ident_span.to(ident_span), ident);
                 let nd = self.mk_method_call(id, tys, es);
-                self.mk_expr(lo, hi, nd, ThinVec::new())
+                self.mk_expr(lo.to(hi), nd, ThinVec::new())
             }
             // Field access.
             _ => {
@@ -2469,32 +2461,30 @@ impl<'a> Parser<'a> {
                                    have type parameters");
                 }
 
-                let id = spanned(ident_span.lo, ident_span.hi, ident);
+                let id = respan(ident_span.to(ident_span), ident);
                 let field = self.mk_field(self_value, id);
-                self.mk_expr(lo, ident_span.hi, field, ThinVec::new())
+                self.mk_expr(lo.to(ident_span), field, ThinVec::new())
             }
         })
     }
 
-    fn parse_dot_or_call_expr_with_(&mut self, e0: P<Expr>, lo: BytePos) -> PResult<'a, P<Expr>> {
+    fn parse_dot_or_call_expr_with_(&mut self, e0: P<Expr>, lo: Span) -> PResult<'a, P<Expr>> {
         let mut e = e0;
         let mut hi;
         loop {
             // expr?
             while self.eat(&token::Question) {
-                let hi = self.prev_span.hi;
-                e = self.mk_expr(lo, hi, ExprKind::Try(e), ThinVec::new());
+                let hi = self.prev_span;
+                e = self.mk_expr(lo.to(hi), ExprKind::Try(e), ThinVec::new());
             }
 
             // expr.f
             if self.eat(&token::Dot) {
                 match self.token {
                   token::Ident(i) => {
-                    let dot_pos = self.prev_span.hi;
-                    hi = self.span.hi;
+                    let ident_span = self.span;
                     self.bump();
-
-                    e = self.parse_dot_suffix(i, mk_sp(dot_pos, hi), e, lo)?;
+                    e = self.parse_dot_suffix(i, ident_span, e, lo)?;
                   }
                   token::Literal(token::Integer(n), suf) => {
                     let sp = self.span;
@@ -2502,16 +2492,16 @@ impl<'a> Parser<'a> {
                     // A tuple index may not have a suffix
                     self.expect_no_suffix(sp, "tuple index", suf);
 
-                    let dot = self.prev_span.hi;
-                    hi = self.span.hi;
+                    let dot_span = self.prev_span;
+                    hi = self.span;
                     self.bump();
 
                     let index = n.as_str().parse::<usize>().ok();
                     match index {
                         Some(n) => {
-                            let id = spanned(dot, hi, n);
+                            let id = respan(dot_span.to(hi), n);
                             let field = self.mk_tup_field(e, id);
-                            e = self.mk_expr(lo, hi, field, ThinVec::new());
+                            e = self.mk_expr(lo.to(hi), field, ThinVec::new());
                         }
                         None => {
                             let prev_span = self.prev_span;
@@ -2554,10 +2544,8 @@ impl<'a> Parser<'a> {
                     let actual = self.this_token_to_string();
                     self.span_err(self.span, &format!("unexpected token: `{}`", actual));
 
-                    let dot_pos = self.prev_span.hi;
-                    e = self.parse_dot_suffix(keywords::Invalid.ident(),
-                                              mk_sp(dot_pos, dot_pos),
-                                              e, lo)?;
+                    let dot_span = self.prev_span;
+                    e = self.parse_dot_suffix(keywords::Invalid.ident(), dot_span, e, lo)?;
                   }
                 }
                 continue;
@@ -2572,10 +2560,10 @@ impl<'a> Parser<'a> {
                     SeqSep::trailing_allowed(token::Comma),
                     |p| Ok(p.parse_expr()?)
                 )?;
-                hi = self.prev_span.hi;
+                hi = self.prev_span;
 
                 let nd = self.mk_call(e, es);
-                e = self.mk_expr(lo, hi, nd, ThinVec::new());
+                e = self.mk_expr(lo.to(hi), nd, ThinVec::new());
               }
 
               // expr[...]
@@ -2583,10 +2571,10 @@ impl<'a> Parser<'a> {
               token::OpenDelim(token::Bracket) => {
                 self.bump();
                 let ix = self.parse_expr()?;
-                hi = self.span.hi;
+                hi = self.span;
                 self.expect(&token::CloseDelim(token::Bracket))?;
                 let index = self.mk_index(e, ix);
-                e = self.mk_expr(lo, hi, index, ThinVec::new())
+                e = self.mk_expr(lo.to(hi), index, ThinVec::new())
               }
               _ => return Ok(e)
             }
@@ -2594,10 +2582,23 @@ impl<'a> Parser<'a> {
         return Ok(e);
     }
 
-    pub fn check_unknown_macro_variable(&mut self) {
-        if let token::SubstNt(name) = self.token {
-            self.fatal(&format!("unknown macro variable `{}`", name)).emit()
-        }
+    pub fn process_potential_macro_variable(&mut self) {
+        let ident = match self.token {
+            token::SubstNt(name) => {
+                self.fatal(&format!("unknown macro variable `{}`", name)).emit();
+                return
+            }
+            token::Interpolated(ref nt) => {
+                self.meta_var_span = Some(self.span);
+                match **nt {
+                    token::NtIdent(ident) => ident,
+                    _ => return,
+                }
+            }
+            _ => return,
+        };
+        self.token = token::Ident(ident.node);
+        self.span = ident.span;
     }
 
     /// parse a single token tree from the input.
@@ -2615,9 +2616,9 @@ impl<'a> Parser<'a> {
             },
             token::CloseDelim(_) | token::Eof => unreachable!(),
             _ => {
-                let token = mem::replace(&mut self.token, token::Underscore);
+                let (token, span) = (mem::replace(&mut self.token, token::Underscore), self.span);
                 self.bump();
-                TokenTree::Token(self.prev_span, token)
+                TokenTree::Token(span, token)
             }
         }
     }
@@ -2648,38 +2649,33 @@ impl<'a> Parser<'a> {
                              already_parsed_attrs: Option<ThinVec<Attribute>>)
                              -> PResult<'a, P<Expr>> {
         let attrs = self.parse_or_use_outer_attributes(already_parsed_attrs)?;
-        let lo = self.span.lo;
-        let hi;
+        let lo = self.span;
         // Note: when adding new unary operators, don't forget to adjust Token::can_begin_expr()
-        let ex = match self.token {
+        let (hi, ex) = match self.token {
             token::Not => {
                 self.bump();
                 let e = self.parse_prefix_expr(None);
                 let (span, e) = self.interpolated_or_expr_span(e)?;
-                hi = span.hi;
-                self.mk_unary(UnOp::Not, e)
+                (span, self.mk_unary(UnOp::Not, e))
             }
             token::BinOp(token::Minus) => {
                 self.bump();
                 let e = self.parse_prefix_expr(None);
                 let (span, e) = self.interpolated_or_expr_span(e)?;
-                hi = span.hi;
-                self.mk_unary(UnOp::Neg, e)
+                (span, self.mk_unary(UnOp::Neg, e))
             }
             token::BinOp(token::Star) => {
                 self.bump();
                 let e = self.parse_prefix_expr(None);
                 let (span, e) = self.interpolated_or_expr_span(e)?;
-                hi = span.hi;
-                self.mk_unary(UnOp::Deref, e)
+                (span, self.mk_unary(UnOp::Deref, e))
             }
             token::BinOp(token::And) | token::AndAnd => {
                 self.expect_and()?;
                 let m = self.parse_mutability();
                 let e = self.parse_prefix_expr(None);
                 let (span, e) = self.interpolated_or_expr_span(e)?;
-                hi = span.hi;
-                ExprKind::AddrOf(m, e)
+                (span, ExprKind::AddrOf(m, e))
             }
             token::Ident(..) if self.token.is_keyword(keywords::In) => {
                 self.bump();
@@ -2689,20 +2685,18 @@ impl<'a> Parser<'a> {
                 )?;
                 let blk = self.parse_block()?;
                 let span = blk.span;
-                hi = span.hi;
-                let blk_expr = self.mk_expr(span.lo, hi, ExprKind::Block(blk), ThinVec::new());
-                ExprKind::InPlace(place, blk_expr)
+                let blk_expr = self.mk_expr(span, ExprKind::Block(blk), ThinVec::new());
+                (span, ExprKind::InPlace(place, blk_expr))
             }
             token::Ident(..) if self.token.is_keyword(keywords::Box) => {
                 self.bump();
                 let e = self.parse_prefix_expr(None);
                 let (span, e) = self.interpolated_or_expr_span(e)?;
-                hi = span.hi;
-                ExprKind::Box(e)
+                (span, ExprKind::Box(e))
             }
             _ => return self.parse_dot_or_call_expr(Some(attrs))
         };
-        return Ok(self.mk_expr(lo, hi, ex, attrs));
+        return Ok(self.mk_expr(lo.to(hi), ex, attrs));
     }
 
     /// Parse an associative expression
@@ -2763,13 +2757,11 @@ impl<'a> Parser<'a> {
             // Special cases:
             if op == AssocOp::As {
                 let rhs = self.parse_ty_no_plus()?;
-                let (lo, hi) = (lhs_span.lo, rhs.span.hi);
-                lhs = self.mk_expr(lo, hi, ExprKind::Cast(lhs, rhs), ThinVec::new());
+                lhs = self.mk_expr(lhs_span.to(rhs.span), ExprKind::Cast(lhs, rhs), ThinVec::new());
                 continue
             } else if op == AssocOp::Colon {
                 let rhs = self.parse_ty_no_plus()?;
-                let (lo, hi) = (lhs_span.lo, rhs.span.hi);
-                lhs = self.mk_expr(lo, hi, ExprKind::Type(lhs, rhs), ThinVec::new());
+                lhs = self.mk_expr(lhs_span.to(rhs.span), ExprKind::Type(lhs, rhs), ThinVec::new());
                 continue
             } else if op == AssocOp::DotDot || op == AssocOp::DotDotDot {
                 // If we didn’t have to handle `x..`/`x...`, it would be pretty easy to
@@ -2795,7 +2787,7 @@ impl<'a> Parser<'a> {
                 };
 
                 let r = try!(self.mk_range(Some(lhs), rhs, limits));
-                lhs = self.mk_expr(lhs_span.lo, rhs_span.hi, r, ThinVec::new());
+                lhs = self.mk_expr(lhs_span.to(rhs_span), r, ThinVec::new());
                 break
             }
 
@@ -2822,7 +2814,7 @@ impl<'a> Parser<'a> {
                 }),
             }?;
 
-            let (lo, hi) = (lhs_span.lo, rhs.span.hi);
+            let span = lhs_span.to(rhs.span);
             lhs = match op {
                 AssocOp::Add | AssocOp::Subtract | AssocOp::Multiply | AssocOp::Divide |
                 AssocOp::Modulus | AssocOp::LAnd | AssocOp::LOr | AssocOp::BitXor |
@@ -2831,12 +2823,12 @@ impl<'a> Parser<'a> {
                 AssocOp::Greater | AssocOp::GreaterEqual => {
                     let ast_op = op.to_ast_binop().unwrap();
                     let binary = self.mk_binary(codemap::respan(cur_op_span, ast_op), lhs, rhs);
-                    self.mk_expr(lo, hi, binary, ThinVec::new())
+                    self.mk_expr(span, binary, ThinVec::new())
                 }
                 AssocOp::Assign =>
-                    self.mk_expr(lo, hi, ExprKind::Assign(lhs, rhs), ThinVec::new()),
+                    self.mk_expr(span, ExprKind::Assign(lhs, rhs), ThinVec::new()),
                 AssocOp::Inplace =>
-                    self.mk_expr(lo, hi, ExprKind::InPlace(lhs, rhs), ThinVec::new()),
+                    self.mk_expr(span, ExprKind::InPlace(lhs, rhs), ThinVec::new()),
                 AssocOp::AssignOp(k) => {
                     let aop = match k {
                         token::Plus =>    BinOpKind::Add,
@@ -2851,7 +2843,7 @@ impl<'a> Parser<'a> {
                         token::Shr =>     BinOpKind::Shr,
                     };
                     let aopexpr = self.mk_assign_op(codemap::respan(cur_op_span, aop), lhs, rhs);
-                    self.mk_expr(lo, hi, aopexpr, ThinVec::new())
+                    self.mk_expr(span, aopexpr, ThinVec::new())
                 }
                 AssocOp::As | AssocOp::Colon | AssocOp::DotDot | AssocOp::DotDotDot => {
                     self.bug("As, Colon, DotDot or DotDotDot branch reached")
@@ -2871,7 +2863,7 @@ impl<'a> Parser<'a> {
         match lhs.node {
             ExprKind::Binary(op, _, _) if op.node.is_comparison() => {
                 // respan to include both operators
-                let op_span = mk_sp(op.span.lo, self.span.hi);
+                let op_span = op.span.to(self.span);
                 let mut err = self.diagnostic().struct_span_err(op_span,
                     "chained comparison operators require parentheses");
                 if op.node == BinOpKind::Lt &&
@@ -2894,8 +2886,8 @@ impl<'a> Parser<'a> {
         debug_assert!(self.token == token::DotDot || self.token == token::DotDotDot);
         let tok = self.token.clone();
         let attrs = self.parse_or_use_outer_attributes(already_parsed_attrs)?;
-        let lo = self.span.lo;
-        let mut hi = self.span.hi;
+        let lo = self.span;
+        let mut hi = self.span;
         self.bump();
         let opt_end = if self.is_at_start_of_range_notation_rhs() {
             // RHS must be parsed with more associativity than the dots.
@@ -2903,7 +2895,7 @@ impl<'a> Parser<'a> {
             Some(self.parse_assoc_expr_with(next_prec,
                                             LhsExpr::NotYetParsed)
                 .map(|x|{
-                    hi = x.span.hi;
+                    hi = x.span;
                     x
                 })?)
          } else {
@@ -2918,7 +2910,7 @@ impl<'a> Parser<'a> {
         let r = try!(self.mk_range(None,
                                    opt_end,
                                    limits));
-        Ok(self.mk_expr(lo, hi, r, attrs))
+        Ok(self.mk_expr(lo.to(hi), r, attrs))
     }
 
     fn is_at_start_of_range_notation_rhs(&self) -> bool {
@@ -2938,23 +2930,23 @@ impl<'a> Parser<'a> {
         if self.check_keyword(keywords::Let) {
             return self.parse_if_let_expr(attrs);
         }
-        let lo = self.prev_span.lo;
+        let lo = self.prev_span;
         let cond = self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL, None)?;
         let thn = self.parse_block()?;
         let mut els: Option<P<Expr>> = None;
-        let mut hi = thn.span.hi;
+        let mut hi = thn.span;
         if self.eat_keyword(keywords::Else) {
             let elexpr = self.parse_else_expr()?;
-            hi = elexpr.span.hi;
+            hi = elexpr.span;
             els = Some(elexpr);
         }
-        Ok(self.mk_expr(lo, hi, ExprKind::If(cond, thn, els), attrs))
+        Ok(self.mk_expr(lo.to(hi), ExprKind::If(cond, thn, els), attrs))
     }
 
     /// 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.prev_span.lo;
+        let lo = self.prev_span;
         self.expect_keyword(keywords::Let)?;
         let pat = self.parse_pat()?;
         self.expect(&token::Eq)?;
@@ -2962,36 +2954,35 @@ impl<'a> Parser<'a> {
         let thn = self.parse_block()?;
         let (hi, els) = if self.eat_keyword(keywords::Else) {
             let expr = self.parse_else_expr()?;
-            (expr.span.hi, Some(expr))
+            (expr.span, Some(expr))
         } else {
-            (thn.span.hi, None)
+            (thn.span, None)
         };
-        Ok(self.mk_expr(lo, hi, ExprKind::IfLet(pat, expr, thn, els), attrs))
+        Ok(self.mk_expr(lo.to(hi), ExprKind::IfLet(pat, expr, thn, els), attrs))
     }
 
     // `move |args| expr`
     pub fn parse_lambda_expr(&mut self,
-                             lo: BytePos,
+                             lo: Span,
                              capture_clause: CaptureBy,
                              attrs: ThinVec<Attribute>)
                              -> PResult<'a, P<Expr>>
     {
         let decl = self.parse_fn_block_decl()?;
-        let decl_hi = self.prev_span.hi;
+        let decl_hi = self.prev_span;
         let body = match decl.output {
             FunctionRetTy::Default(_) => self.parse_expr()?,
             _ => {
                 // If an explicit return type is given, require a
                 // block to appear (RFC 968).
-                let body_lo = self.span.lo;
+                let body_lo = self.span;
                 self.parse_block_expr(body_lo, BlockCheckMode::Default, ThinVec::new())?
             }
         };
 
         Ok(self.mk_expr(
-            lo,
-            body.span.hi,
-            ExprKind::Closure(capture_clause, decl, body, mk_sp(lo, decl_hi)),
+            lo.to(body.span),
+            ExprKind::Closure(capture_clause, decl, body, lo.to(decl_hi)),
             attrs))
     }
 
@@ -3001,13 +2992,13 @@ impl<'a> Parser<'a> {
             return self.parse_if_expr(ThinVec::new());
         } else {
             let blk = self.parse_block()?;
-            return Ok(self.mk_expr(blk.span.lo, blk.span.hi, ExprKind::Block(blk), ThinVec::new()));
+            return Ok(self.mk_expr(blk.span, ExprKind::Block(blk), ThinVec::new()));
         }
     }
 
     /// Parse a 'for' .. 'in' expression ('for' token already eaten)
     pub fn parse_for_expr(&mut self, opt_ident: Option<ast::SpannedIdent>,
-                          span_lo: BytePos,
+                          span_lo: Span,
                           mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
         // Parse: `for <src_pat> in <src_expr> <src_loop_block>`
 
@@ -3017,16 +3008,13 @@ impl<'a> Parser<'a> {
         let (iattrs, loop_block) = self.parse_inner_attrs_and_block()?;
         attrs.extend(iattrs);
 
-        let hi = self.prev_span.hi;
-
-        Ok(self.mk_expr(span_lo, hi,
-                        ExprKind::ForLoop(pat, expr, loop_block, opt_ident),
-                        attrs))
+        let hi = self.prev_span;
+        Ok(self.mk_expr(span_lo.to(hi), ExprKind::ForLoop(pat, expr, loop_block, opt_ident), attrs))
     }
 
     /// Parse a 'while' or 'while let' expression ('while' token already eaten)
     pub fn parse_while_expr(&mut self, opt_ident: Option<ast::SpannedIdent>,
-                            span_lo: BytePos,
+                            span_lo: Span,
                             mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
         if self.token.is_keyword(keywords::Let) {
             return self.parse_while_let_expr(opt_ident, span_lo, attrs);
@@ -3034,14 +3022,13 @@ impl<'a> Parser<'a> {
         let cond = self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL, None)?;
         let (iattrs, body) = self.parse_inner_attrs_and_block()?;
         attrs.extend(iattrs);
-        let hi = body.span.hi;
-        return Ok(self.mk_expr(span_lo, hi, ExprKind::While(cond, body, opt_ident),
-                               attrs));
+        let span = span_lo.to(body.span);
+        return Ok(self.mk_expr(span, ExprKind::While(cond, body, opt_ident), attrs));
     }
 
     /// Parse a 'while let' expression ('while' token already eaten)
     pub fn parse_while_let_expr(&mut self, opt_ident: Option<ast::SpannedIdent>,
-                                span_lo: BytePos,
+                                span_lo: Span,
                                 mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
         self.expect_keyword(keywords::Let)?;
         let pat = self.parse_pat()?;
@@ -3049,34 +3036,33 @@ impl<'a> Parser<'a> {
         let expr = self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL, None)?;
         let (iattrs, body) = self.parse_inner_attrs_and_block()?;
         attrs.extend(iattrs);
-        let hi = body.span.hi;
-        return Ok(self.mk_expr(span_lo, hi, ExprKind::WhileLet(pat, expr, body, opt_ident), attrs));
+        let span = span_lo.to(body.span);
+        return Ok(self.mk_expr(span, ExprKind::WhileLet(pat, expr, body, opt_ident), attrs));
     }
 
     // parse `loop {...}`, `loop` token already eaten
     pub fn parse_loop_expr(&mut self, opt_ident: Option<ast::SpannedIdent>,
-                           span_lo: BytePos,
+                           span_lo: Span,
                            mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
         let (iattrs, body) = self.parse_inner_attrs_and_block()?;
         attrs.extend(iattrs);
-        let hi = body.span.hi;
-        Ok(self.mk_expr(span_lo, hi, ExprKind::Loop(body, opt_ident), attrs))
+        let span = span_lo.to(body.span);
+        Ok(self.mk_expr(span, ExprKind::Loop(body, opt_ident), attrs))
     }
 
     /// Parse a `do catch {...}` expression (`do catch` token already eaten)
-    pub fn parse_catch_expr(&mut self, span_lo: BytePos, mut attrs: ThinVec<Attribute>)
+    pub fn parse_catch_expr(&mut self, span_lo: Span, mut attrs: ThinVec<Attribute>)
         -> PResult<'a, P<Expr>>
     {
         let (iattrs, body) = self.parse_inner_attrs_and_block()?;
         attrs.extend(iattrs);
-        let hi = body.span.hi;
-        Ok(self.mk_expr(span_lo, hi, ExprKind::Catch(body), attrs))
+        Ok(self.mk_expr(span_lo.to(body.span), ExprKind::Catch(body), attrs))
     }
 
     // `match` token already eaten
     fn parse_match_expr(&mut self, mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
         let match_span = self.prev_span;
-        let lo = self.prev_span.lo;
+        let lo = self.prev_span;
         let discriminant = self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL,
                                                None)?;
         if let Err(mut e) = self.expect(&token::OpenDelim(token::Brace)) {
@@ -3095,17 +3081,17 @@ impl<'a> Parser<'a> {
                     // Recover by skipping to the end of the block.
                     e.emit();
                     self.recover_stmt();
-                    let hi = self.span.hi;
+                    let span = lo.to(self.span);
                     if self.token == token::CloseDelim(token::Brace) {
                         self.bump();
                     }
-                    return Ok(self.mk_expr(lo, hi, ExprKind::Match(discriminant, arms), attrs));
+                    return Ok(self.mk_expr(span, ExprKind::Match(discriminant, arms), attrs));
                 }
             }
         }
-        let hi = self.span.hi;
+        let hi = self.span;
         self.bump();
-        return Ok(self.mk_expr(lo, hi, ExprKind::Match(discriminant, arms), attrs));
+        return Ok(self.mk_expr(lo.to(hi), ExprKind::Match(discriminant, arms), attrs));
     }
 
     pub fn parse_arm(&mut self) -> PResult<'a, Arm> {
@@ -3279,7 +3265,7 @@ impl<'a> Parser<'a> {
             }
 
             let attrs = self.parse_outer_attributes()?;
-            let lo = self.span.lo;
+            let lo = self.span;
             let hi;
 
             if self.check(&token::DotDot) {
@@ -3299,16 +3285,16 @@ impl<'a> Parser<'a> {
                 let fieldname = self.parse_field_name()?;
                 self.bump();
                 let pat = self.parse_pat()?;
-                hi = pat.span.hi;
+                hi = pat.span;
                 (pat, fieldname, false)
             } else {
                 // Parsing a pattern of the form "(box) (ref) (mut) fieldname"
                 let is_box = self.eat_keyword(keywords::Box);
-                let boxed_span_lo = self.span.lo;
+                let boxed_span = self.span;
                 let is_ref = self.eat_keyword(keywords::Ref);
                 let is_mut = self.eat_keyword(keywords::Mut);
                 let fieldname = self.parse_ident()?;
-                hi = self.prev_span.hi;
+                hi = self.prev_span;
 
                 let bind_type = match (is_ref, is_mut) {
                     (true, true) => BindingMode::ByRef(Mutability::Mutable),
@@ -3320,14 +3306,14 @@ impl<'a> Parser<'a> {
                 let fieldpat = P(ast::Pat{
                     id: ast::DUMMY_NODE_ID,
                     node: PatKind::Ident(bind_type, fieldpath, None),
-                    span: mk_sp(boxed_span_lo, hi),
+                    span: boxed_span.to(hi),
                 });
 
                 let subpat = if is_box {
                     P(ast::Pat{
                         id: ast::DUMMY_NODE_ID,
                         node: PatKind::Box(fieldpat),
-                        span: mk_sp(lo, hi),
+                        span: lo.to(hi),
                     })
                 } else {
                     fieldpat
@@ -3335,7 +3321,7 @@ impl<'a> Parser<'a> {
                 (subpat, fieldname, true)
             };
 
-            fields.push(codemap::Spanned { span: mk_sp(lo, hi),
+            fields.push(codemap::Spanned { span: lo.to(hi),
                                            node: ast::FieldPat {
                                                ident: fieldname,
                                                pat: subpat,
@@ -3349,7 +3335,7 @@ impl<'a> Parser<'a> {
 
     fn parse_pat_range_end(&mut self) -> PResult<'a, P<Expr>> {
         if self.token.is_path_start() {
-            let lo = self.span.lo;
+            let lo = self.span;
             let (qself, path) = if self.eat_lt() {
                 // Parse a qualified path
                 let (qself, path) =
@@ -3359,8 +3345,8 @@ impl<'a> Parser<'a> {
                 // Parse an unqualified path
                 (None, self.parse_path(PathStyle::Expr)?)
             };
-            let hi = self.prev_span.hi;
-            Ok(self.mk_expr(lo, hi, ExprKind::Path(qself, path), ThinVec::new()))
+            let hi = self.prev_span;
+            Ok(self.mk_expr(lo.to(hi), ExprKind::Path(qself, path), ThinVec::new()))
         } else {
             self.parse_pat_literal_maybe_minus()
         }
@@ -3386,7 +3372,7 @@ impl<'a> Parser<'a> {
     pub fn parse_pat(&mut self) -> PResult<'a, P<Pat>> {
         maybe_whole!(self, NtPat, |x| x);
 
-        let lo = self.span.lo;
+        let lo = self.span;
         let pat;
         match self.token {
             token::Underscore => {
@@ -3452,7 +3438,7 @@ impl<'a> Parser<'a> {
                         // Parse macro invocation
                         self.bump();
                         let (_, tts) = self.expect_delimited_token_tree()?;
-                        let mac = spanned(lo, self.prev_span.hi, Mac_ { path: path, tts: tts });
+                        let mac = respan(lo.to(self.prev_span), Mac_ { path: path, tts: tts });
                         pat = PatKind::Mac(mac);
                     }
                     token::DotDotDot | token::DotDot => {
@@ -3462,9 +3448,8 @@ impl<'a> Parser<'a> {
                             _ => panic!("can only parse `..` or `...` for ranges (checked above)"),
                         };
                         // Parse range
-                        let hi = self.prev_span.hi;
-                        let begin =
-                              self.mk_expr(lo, hi, ExprKind::Path(qself, path), ThinVec::new());
+                        let span = lo.to(self.prev_span);
+                        let begin = self.mk_expr(span, ExprKind::Path(qself, path), ThinVec::new());
                         self.bump();
                         let end = self.parse_pat_range_end()?;
                         pat = PatKind::Range(begin, end, end_kind);
@@ -3518,11 +3503,10 @@ impl<'a> Parser<'a> {
             }
         }
 
-        let hi = self.prev_span.hi;
         Ok(P(ast::Pat {
             id: ast::DUMMY_NODE_ID,
             node: pat,
-            span: mk_sp(lo, hi),
+            span: lo.to(self.prev_span),
         }))
     }
 
@@ -3532,9 +3516,9 @@ impl<'a> Parser<'a> {
     fn parse_pat_ident(&mut self,
                        binding_mode: ast::BindingMode)
                        -> PResult<'a, PatKind> {
+        let ident_span = self.span;
         let ident = self.parse_ident()?;
-        let prev_span = self.prev_span;
-        let name = codemap::Spanned{span: prev_span, node: ident};
+        let name = codemap::Spanned{span: ident_span, node: ident};
         let sub = if self.eat(&token::At) {
             Some(self.parse_pat()?)
         } else {
@@ -3558,7 +3542,7 @@ impl<'a> Parser<'a> {
 
     /// Parse a local variable declaration
     fn parse_local(&mut self, attrs: ThinVec<Attribute>) -> PResult<'a, P<Local>> {
-        let lo = self.span.lo;
+        let lo = self.span;
         let pat = self.parse_pat()?;
 
         let mut ty = None;
@@ -3571,14 +3555,14 @@ impl<'a> Parser<'a> {
             pat: pat,
             init: init,
             id: ast::DUMMY_NODE_ID,
-            span: mk_sp(lo, self.prev_span.hi),
+            span: lo.to(self.prev_span),
             attrs: attrs,
         }))
     }
 
     /// Parse a structure field
     fn parse_name_and_ty(&mut self,
-                         lo: BytePos,
+                         lo: Span,
                          vis: Visibility,
                          attrs: Vec<Attribute>)
                          -> PResult<'a, StructField> {
@@ -3586,7 +3570,7 @@ impl<'a> Parser<'a> {
         self.expect(&token::Colon)?;
         let ty = self.parse_ty()?;
         Ok(StructField {
-            span: mk_sp(lo, self.prev_span.hi),
+            span: lo.to(self.prev_span),
             ident: Some(name),
             vis: vis,
             id: ast::DUMMY_NODE_ID,
@@ -3696,7 +3680,7 @@ impl<'a> Parser<'a> {
 
     fn eat_macro_def(&mut self, attrs: &[Attribute], vis: &Visibility)
                      -> PResult<'a, Option<P<Item>>> {
-        let lo = self.span.lo;
+        let lo = self.span;
         match self.token {
             token::Ident(ident) if ident.name == "macro_rules" => {
                 if self.look_ahead(1, |t| *t == token::Not) {
@@ -3719,9 +3703,9 @@ impl<'a> Parser<'a> {
             }
         }
 
-        let hi = self.prev_span.hi;
+        let span = lo.to(self.prev_span);
         let kind = ItemKind::MacroDef(tts);
-        Ok(Some(self.mk_item(lo, hi, id, kind, Visibility::Inherited, attrs.to_owned())))
+        Ok(Some(self.mk_item(span, id, kind, Visibility::Inherited, attrs.to_owned())))
     }
 
     fn parse_stmt_without_recovery(&mut self,
@@ -3730,19 +3714,19 @@ impl<'a> Parser<'a> {
         maybe_whole!(self, NtStmt, |x| Some(x));
 
         let attrs = self.parse_outer_attributes()?;
-        let lo = self.span.lo;
+        let lo = self.span;
 
         Ok(Some(if self.eat_keyword(keywords::Let) {
             Stmt {
                 id: ast::DUMMY_NODE_ID,
                 node: StmtKind::Local(self.parse_local(attrs.into())?),
-                span: mk_sp(lo, self.prev_span.hi),
+                span: lo.to(self.prev_span),
             }
         } else if let Some(macro_def) = self.eat_macro_def(&attrs, &Visibility::Inherited)? {
             Stmt {
                 id: ast::DUMMY_NODE_ID,
                 node: StmtKind::Item(macro_def),
-                span: mk_sp(lo, self.prev_span.hi),
+                span: lo.to(self.prev_span),
             }
         // Starts like a simple path, but not a union item.
         } else if self.token.is_path_start() &&
@@ -3754,8 +3738,8 @@ impl<'a> Parser<'a> {
                 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 hi = self.prev_span;
+                    self.mk_expr(lo.to(hi), ExprKind::Path(None, pth), ThinVec::new())
                 };
 
                 let expr = self.with_res(Restrictions::RESTRICTION_STMT_EXPR, |this| {
@@ -3766,7 +3750,7 @@ impl<'a> Parser<'a> {
                 return Ok(Some(Stmt {
                     id: ast::DUMMY_NODE_ID,
                     node: StmtKind::Expr(expr),
-                    span: mk_sp(lo, self.prev_span.hi),
+                    span: lo.to(self.prev_span),
                 }));
             }
 
@@ -3797,7 +3781,7 @@ impl<'a> Parser<'a> {
             };
 
             let (_, tts) = self.expect_delimited_token_tree()?;
-            let hi = self.prev_span.hi;
+            let hi = self.prev_span;
 
             let style = if delim == token::Brace {
                 MacStmtStyle::Braces
@@ -3806,7 +3790,7 @@ impl<'a> Parser<'a> {
             };
 
             if id.name == keywords::Invalid.name() {
-                let mac = spanned(lo, hi, Mac_ { path: pth, tts: tts });
+                let mac = respan(lo.to(hi), Mac_ { path: pth, tts: tts });
                 let node = if delim == token::Brace ||
                               self.token == token::Semi || self.token == token::Eof {
                     StmtKind::Mac(P((mac, style, attrs.into())))
@@ -3826,14 +3810,14 @@ impl<'a> Parser<'a> {
                     self.warn_missing_semicolon();
                     StmtKind::Mac(P((mac, style, attrs.into())))
                 } else {
-                    let e = self.mk_mac_expr(lo, hi, mac.node, ThinVec::new());
+                    let e = self.mk_mac_expr(lo.to(hi), mac.node, ThinVec::new());
                     let e = self.parse_dot_or_call_expr_with(e, lo, attrs.into())?;
                     let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?;
                     StmtKind::Expr(e)
                 };
                 Stmt {
                     id: ast::DUMMY_NODE_ID,
-                    span: mk_sp(lo, hi),
+                    span: lo.to(hi),
                     node: node,
                 }
             } else {
@@ -3848,13 +3832,14 @@ impl<'a> Parser<'a> {
                                        followed by a semicolon");
                     }
                 }
+                let span = lo.to(hi);
                 Stmt {
                     id: ast::DUMMY_NODE_ID,
-                    span: mk_sp(lo, hi),
+                    span: span,
                     node: StmtKind::Item({
                         self.mk_item(
-                            lo, hi, id /*id is good here*/,
-                            ItemKind::Mac(spanned(lo, hi, Mac_ { path: pth, tts: tts })),
+                            span, id /*id is good here*/,
+                            ItemKind::Mac(respan(span, Mac_ { path: pth, tts: tts })),
                             Visibility::Inherited,
                             attrs)
                     }),
@@ -3869,7 +3854,7 @@ impl<'a> Parser<'a> {
             match item {
                 Some(i) => Stmt {
                     id: ast::DUMMY_NODE_ID,
-                    span: mk_sp(lo, i.span.hi),
+                    span: lo.to(i.span),
                     node: StmtKind::Item(i),
                 },
                 None => {
@@ -3900,7 +3885,7 @@ impl<'a> Parser<'a> {
                         Restrictions::RESTRICTION_STMT_EXPR, Some(attrs.into()))?;
                     Stmt {
                         id: ast::DUMMY_NODE_ID,
-                        span: mk_sp(lo, e.span.hi),
+                        span: lo.to(e.span),
                         node: StmtKind::Expr(e),
                     }
                 }
@@ -3918,7 +3903,7 @@ impl<'a> Parser<'a> {
     pub fn parse_block(&mut self) -> PResult<'a, P<Block>> {
         maybe_whole!(self, NtBlock, |x| x);
 
-        let lo = self.span.lo;
+        let lo = self.span;
 
         if !self.eat(&token::OpenDelim(token::Brace)) {
             let sp = self.span;
@@ -3963,7 +3948,7 @@ impl<'a> Parser<'a> {
     fn parse_inner_attrs_and_block(&mut self) -> PResult<'a, (Vec<Attribute>, P<Block>)> {
         maybe_whole!(self, NtBlock, |x| (Vec::new(), x));
 
-        let lo = self.span.lo;
+        let lo = self.span;
         self.expect(&token::OpenDelim(token::Brace))?;
         Ok((self.parse_inner_attributes()?,
             self.parse_block_tail(lo, BlockCheckMode::Default)?))
@@ -3971,7 +3956,7 @@ impl<'a> Parser<'a> {
 
     /// Parse the rest of a block expression or function body
     /// Precondition: already parsed the '{'.
-    fn parse_block_tail(&mut self, lo: BytePos, s: BlockCheckMode) -> PResult<'a, P<Block>> {
+    fn parse_block_tail(&mut self, lo: Span, s: BlockCheckMode) -> PResult<'a, P<Block>> {
         let mut stmts = vec![];
 
         while !self.eat(&token::CloseDelim(token::Brace)) {
@@ -3989,7 +3974,7 @@ impl<'a> Parser<'a> {
             stmts: stmts,
             id: ast::DUMMY_NODE_ID,
             rules: s,
-            span: mk_sp(lo, self.prev_span.hi),
+            span: lo.to(self.prev_span),
         }))
     }
 
@@ -4055,10 +4040,10 @@ impl<'a> Parser<'a> {
                 }
                 bounds.push(RegionTyParamBound(self.expect_lifetime()));
             } else if self.check_keyword(keywords::For) || self.check_path() {
-                let lo = self.span.lo;
+                let lo = self.span;
                 let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
                 let path = self.parse_path(PathStyle::Type)?;
-                let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo, self.prev_span.hi);
+                let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span));
                 let modifier = if question.is_some() {
                     TraitBoundModifier::Maybe
                 } else {
@@ -4179,7 +4164,7 @@ impl<'a> Parser<'a> {
     pub fn parse_generics(&mut self) -> PResult<'a, ast::Generics> {
         maybe_whole!(self, NtGenerics, |x| x);
 
-        let span_lo = self.span.lo;
+        let span_lo = self.span;
         if self.eat_lt() {
             let (lifetime_defs, ty_params) = self.parse_generic_params()?;
             self.expect_gt()?;
@@ -4190,7 +4175,7 @@ impl<'a> Parser<'a> {
                     id: ast::DUMMY_NODE_ID,
                     predicates: Vec::new(),
                 },
-                span: mk_sp(span_lo, self.prev_span.hi),
+                span: span_lo.to(self.prev_span),
             })
         } else {
             Ok(ast::Generics::default())
@@ -4215,7 +4200,7 @@ impl<'a> Parser<'a> {
                 }
             } else if self.check_ident() && self.look_ahead(1, |t| t == &token::Eq) {
                 // Parse associated type binding.
-                let lo = self.span.lo;
+                let lo = self.span;
                 let ident = self.parse_ident()?;
                 self.bump();
                 let ty = self.parse_ty()?;
@@ -4223,7 +4208,7 @@ impl<'a> Parser<'a> {
                     id: ast::DUMMY_NODE_ID,
                     ident: ident,
                     ty: ty,
-                    span: mk_sp(lo, self.prev_span.hi),
+                    span: lo.to(self.prev_span),
                 });
                 seen_binding = true;
             } else if self.check_type() {
@@ -4280,7 +4265,7 @@ impl<'a> Parser<'a> {
         }
 
         loop {
-            let lo = self.span.lo;
+            let lo = self.span;
             if self.check_lifetime() && self.look_ahead(1, |t| t != &token::BinOp(token::Plus)) {
                 let lifetime = self.expect_lifetime();
                 // Bounds starting with a colon are mandatory, but possibly empty.
@@ -4288,7 +4273,7 @@ impl<'a> Parser<'a> {
                 let bounds = self.parse_lt_param_bounds();
                 where_clause.predicates.push(ast::WherePredicate::RegionPredicate(
                     ast::WhereRegionPredicate {
-                        span: mk_sp(lo, self.prev_span.hi),
+                        span: lo.to(self.prev_span),
                         lifetime: lifetime,
                         bounds: bounds,
                     }
@@ -4309,7 +4294,7 @@ impl<'a> Parser<'a> {
                     let bounds = self.parse_ty_param_bounds()?;
                     where_clause.predicates.push(ast::WherePredicate::BoundPredicate(
                         ast::WhereBoundPredicate {
-                            span: mk_sp(lo, self.prev_span.hi),
+                            span: lo.to(self.prev_span),
                             bound_lifetimes: lifetime_defs,
                             bounded_ty: ty,
                             bounds: bounds,
@@ -4320,7 +4305,7 @@ impl<'a> Parser<'a> {
                     let rhs_ty = self.parse_ty()?;
                     where_clause.predicates.push(ast::WherePredicate::EqPredicate(
                         ast::WhereEqPredicate {
-                            span: mk_sp(lo, self.prev_span.hi),
+                            span: lo.to(self.prev_span),
                             lhs_ty: ty,
                             rhs_ty: rhs_ty,
                             id: ast::DUMMY_NODE_ID,
@@ -4406,7 +4391,7 @@ 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.prev_span, ident) }
+            token::Ident(ident) => { let sp = this.span; this.bump(); codemap::respan(sp, ident) }
             _ => unreachable!()
         };
         let isolated_self = |this: &mut Self, n| {
@@ -4417,7 +4402,7 @@ impl<'a> Parser<'a> {
         // Parse optional self parameter of a method.
         // Only a limited set of initial token sequences is considered self parameters, anything
         // else is parsed as a normal function parameter list, so some lookahead is required.
-        let eself_lo = self.span.lo;
+        let eself_lo = self.span;
         let (eself, eself_ident) = match self.token {
             token::BinOp(token::And) => {
                 // &self
@@ -4499,7 +4484,7 @@ impl<'a> Parser<'a> {
             _ => return Ok(None),
         };
 
-        let eself = codemap::respan(mk_sp(eself_lo, self.prev_span.hi), eself);
+        let eself = codemap::respan(eself_lo.to(self.prev_span), eself);
         Ok(Some(Arg::from_self(eself, eself_ident)))
     }
 
@@ -4571,8 +4556,7 @@ impl<'a> Parser<'a> {
         Ok((id, generics))
     }
 
-    fn mk_item(&mut self, lo: BytePos, hi: BytePos, ident: Ident,
-               node: ItemKind, vis: Visibility,
+    fn mk_item(&mut self, span: Span, ident: Ident, node: ItemKind, vis: Visibility,
                attrs: Vec<Attribute>) -> P<Item> {
         P(Item {
             ident: ident,
@@ -4580,7 +4564,7 @@ impl<'a> Parser<'a> {
             id: ast::DUMMY_NODE_ID,
             node: node,
             vis: vis,
-            span: mk_sp(lo, hi)
+            span: span,
         })
     }
 
@@ -4638,8 +4622,8 @@ impl<'a> Parser<'a> {
         maybe_whole!(self, NtImplItem, |x| x);
 
         let mut attrs = self.parse_outer_attributes()?;
-        let lo = self.span.lo;
-        let vis = self.parse_visibility()?;
+        let lo = self.span;
+        let vis = self.parse_visibility(false)?;
         let defaultness = self.parse_defaultness()?;
         let (name, node) = if self.eat_keyword(keywords::Type) {
             let name = self.parse_ident()?;
@@ -4664,7 +4648,7 @@ impl<'a> Parser<'a> {
 
         Ok(ImplItem {
             id: ast::DUMMY_NODE_ID,
-            span: mk_sp(lo, self.prev_span.hi),
+            span: lo.to(self.prev_span),
             ident: name,
             vis: vis,
             defaultness: defaultness,
@@ -4707,7 +4691,7 @@ impl<'a> Parser<'a> {
             let prev_span = self.prev_span;
             self.complain_if_pub_macro(&vis, prev_span);
 
-            let lo = self.span.lo;
+            let lo = self.span;
             let pth = self.parse_path(PathStyle::Mod)?;
             self.expect(&token::Not)?;
 
@@ -4717,7 +4701,7 @@ impl<'a> Parser<'a> {
                 self.expect(&token::Semi)?
             }
 
-            let mac = spanned(lo, self.prev_span.hi, Mac_ { path: pth, tts: tts });
+            let mac = respan(lo.to(self.prev_span), Mac_ { path: pth, tts: tts });
             Ok((keywords::Invalid.ident(), vec![], ast::ImplItemKind::Macro(mac)))
         } else {
             let (constness, unsafety, abi) = self.parse_fn_front_matter()?;
@@ -4951,28 +4935,11 @@ impl<'a> Parser<'a> {
             SeqSep::trailing_allowed(token::Comma),
             |p| {
                 let attrs = p.parse_outer_attributes()?;
-                let lo = p.span.lo;
-                let mut vis = p.parse_visibility()?;
-                let ty_is_interpolated =
-                    p.token.is_interpolated() || p.look_ahead(1, |t| t.is_interpolated());
-                let mut ty = p.parse_ty()?;
-
-                // Handle `pub(path) type`, in which `vis` will be `pub` and `ty` will be `(path)`.
-                if vis == Visibility::Public && !ty_is_interpolated &&
-                   p.token != token::Comma && p.token != token::CloseDelim(token::Paren) {
-                    ty = if let TyKind::Paren(ref path_ty) = ty.node {
-                        if let TyKind::Path(None, ref path) = path_ty.node {
-                            vis = Visibility::Restricted { path: P(path.clone()), id: path_ty.id };
-                            Some(p.parse_ty()?)
-                        } else {
-                            None
-                        }
-                    } else {
-                        None
-                    }.unwrap_or(ty);
-                }
+                let lo = p.span;
+                let vis = p.parse_visibility(true)?;
+                let ty = p.parse_ty()?;
                 Ok(StructField {
-                    span: mk_sp(lo, p.span.hi),
+                    span: lo.to(p.span),
                     vis: vis,
                     ident: None,
                     id: ast::DUMMY_NODE_ID,
@@ -4986,7 +4953,7 @@ impl<'a> Parser<'a> {
 
     /// Parse a structure field declaration
     pub fn parse_single_struct_field(&mut self,
-                                     lo: BytePos,
+                                     lo: Span,
                                      vis: Visibility,
                                      attrs: Vec<Attribute> )
                                      -> PResult<'a, StructField> {
@@ -5008,19 +4975,26 @@ impl<'a> Parser<'a> {
     /// Parse an element of a struct definition
     fn parse_struct_decl_field(&mut self) -> PResult<'a, StructField> {
         let attrs = self.parse_outer_attributes()?;
-        let lo = self.span.lo;
-        let vis = self.parse_visibility()?;
+        let lo = self.span;
+        let vis = self.parse_visibility(false)?;
         self.parse_single_struct_field(lo, vis, attrs)
     }
 
-    // Parse `pub`, `pub(crate)` and `pub(in path)` plus shortcuts
-    // `pub(self)` for `pub(in self)` and `pub(super)` for `pub(in super)`.
-    fn parse_visibility(&mut self) -> PResult<'a, Visibility> {
+    /// Parse `pub`, `pub(crate)` and `pub(in path)` plus shortcuts `pub(self)` for `pub(in self)`
+    /// and `pub(super)` for `pub(in super)`.  If the following element can't be a tuple (i.e. it's
+    /// a function definition, it's not a tuple struct field) and the contents within the parens
+    /// isn't valid, emit a proper diagnostic.
+    fn parse_visibility(&mut self, can_take_tuple: bool) -> PResult<'a, Visibility> {
         if !self.eat_keyword(keywords::Pub) {
             return Ok(Visibility::Inherited)
         }
 
         if self.check(&token::OpenDelim(token::Paren)) {
+            let start_span = self.span;
+            // We don't `self.bump()` the `(` yet because this might be a struct definition where
+            // `()` or a tuple might be allowed. For example, `struct Struct(pub (), pub (usize));`.
+            // Because of this, we only `bump` the `(` if we're assured it is appropriate to do so
+            // by the following tokens.
             if self.look_ahead(1, |t| t.is_keyword(keywords::Crate)) {
                 // `pub(crate)`
                 self.bump(); // `(`
@@ -5045,6 +5019,24 @@ impl<'a> Parser<'a> {
                 let vis = Visibility::Restricted { path: P(path), id: ast::DUMMY_NODE_ID };
                 self.expect(&token::CloseDelim(token::Paren))?; // `)`
                 return Ok(vis)
+            } else if !can_take_tuple {  // Provide this diagnostic if this is not a tuple struct
+                // `pub(something) fn ...` or `struct X { pub(something) y: Z }`
+                self.bump(); // `(`
+                let msg = "incorrect visibility restriction";
+                let suggestion = r##"some possible visibility restrictions are:
+`pub(crate)`: visible only on the current crate
+`pub(super)`: visible only in the current module's parent
+`pub(in path::to::module)`: visible only on the specified path"##;
+                let path = self.parse_path(PathStyle::Mod)?;
+                let path_span = self.prev_span;
+                let help_msg = format!("to make this visible only to module `{}`, add `in` before \
+                                       the path:",
+                                       path);
+                self.expect(&token::CloseDelim(token::Paren))?;  // `)`
+                let sp = start_span.to(self.prev_span);
+                let mut err = self.span_fatal_help(sp, &msg, &suggestion);
+                err.span_suggestion(path_span, &help_msg, format!("in {}", path));
+                err.emit();  // emit diagnostic, but continue with public visibility
             }
         }
 
@@ -5061,7 +5053,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Given a termination token, parse all of the items in a module
-    fn parse_mod_items(&mut self, term: &token::Token, inner_lo: BytePos) -> PResult<'a, Mod> {
+    fn parse_mod_items(&mut self, term: &token::Token, inner_lo: Span) -> PResult<'a, Mod> {
         let mut items = vec![];
         while let Some(item) = self.parse_item()? {
             items.push(item);
@@ -5075,11 +5067,11 @@ impl<'a> Parser<'a> {
         let hi = if self.span == syntax_pos::DUMMY_SP {
             inner_lo
         } else {
-            self.prev_span.hi
+            self.prev_span
         };
 
         Ok(ast::Mod {
-            inner: mk_sp(inner_lo, hi),
+            inner: inner_lo.to(hi),
             items: items
         })
     }
@@ -5142,7 +5134,7 @@ impl<'a> Parser<'a> {
             let old_directory = self.directory.clone();
             self.push_directory(id, &outer_attrs);
             self.expect(&token::OpenDelim(token::Brace))?;
-            let mod_inner_lo = self.span.lo;
+            let mod_inner_lo = self.span;
             let attrs = self.parse_inner_attributes()?;
             let module = self.parse_mod_items(&token::CloseDelim(token::Brace), mod_inner_lo)?;
             self.directory = old_directory;
@@ -5152,22 +5144,22 @@ impl<'a> Parser<'a> {
 
     fn push_directory(&mut self, id: Ident, attrs: &[Attribute]) {
         if let Some(path) = attr::first_attr_value_str_by_name(attrs, "path") {
-            self.directory.path.push(&*path.as_str());
+            self.directory.path.push(&path.as_str());
             self.directory.ownership = DirectoryOwnership::Owned;
         } else {
-            self.directory.path.push(&*id.name.as_str());
+            self.directory.path.push(&id.name.as_str());
         }
     }
 
     pub fn submod_path_from_attr(attrs: &[ast::Attribute], dir_path: &Path) -> Option<PathBuf> {
-        attr::first_attr_value_str_by_name(attrs, "path").map(|d| dir_path.join(&*d.as_str()))
+        attr::first_attr_value_str_by_name(attrs, "path").map(|d| dir_path.join(&d.as_str()))
     }
 
     /// Returns either a path to a module, or .
     pub fn default_submod_path(id: ast::Ident, dir_path: &Path, codemap: &CodeMap) -> ModulePath {
         let mod_name = id.to_string();
         let default_path_str = format!("{}.rs", mod_name);
-        let secondary_path_str = format!("{}/mod.rs", mod_name);
+        let secondary_path_str = format!("{}{}mod.rs", mod_name, path::MAIN_SEPARATOR);
         let default_path = dir_path.join(&default_path_str);
         let secondary_path = dir_path.join(&secondary_path_str);
         let default_exists = codemap.file_exists(&default_path);
@@ -5245,8 +5237,9 @@ impl<'a> Parser<'a> {
             };
             err.span_note(id_sp,
                           &format!("maybe move this module `{0}` to its own directory \
-                                     via `{0}/mod.rs`",
-                                    this_module));
+                                    via `{0}{1}mod.rs`",
+                                   this_module,
+                                   path::MAIN_SEPARATOR));
             if paths.path_exists {
                 err.span_note(id_sp,
                               &format!("... or maybe `use` the module `{}` instead \
@@ -5285,7 +5278,7 @@ impl<'a> Parser<'a> {
         let mut p0 =
             new_sub_parser_from_file(self.sess, &path, directory_ownership, Some(name), id_sp);
         p0.cfg_mods = self.cfg_mods;
-        let mod_inner_lo = p0.span.lo;
+        let mod_inner_lo = p0.span;
         let mod_attrs = p0.parse_inner_attributes()?;
         let m0 = p0.parse_mod_items(&token::Eof, mod_inner_lo)?;
         self.sess.included_mod_stack.borrow_mut().pop();
@@ -5293,42 +5286,42 @@ impl<'a> Parser<'a> {
     }
 
     /// Parse a function declaration from a foreign module
-    fn parse_item_foreign_fn(&mut self, vis: ast::Visibility, lo: BytePos,
-                             attrs: Vec<Attribute>) -> PResult<'a, ForeignItem> {
+    fn parse_item_foreign_fn(&mut self, vis: ast::Visibility, lo: Span, attrs: Vec<Attribute>)
+                             -> PResult<'a, ForeignItem> {
         self.expect_keyword(keywords::Fn)?;
 
         let (ident, mut generics) = self.parse_fn_header()?;
         let decl = self.parse_fn_decl(true)?;
         generics.where_clause = self.parse_where_clause()?;
-        let hi = self.span.hi;
+        let hi = self.span;
         self.expect(&token::Semi)?;
         Ok(ast::ForeignItem {
             ident: ident,
             attrs: attrs,
             node: ForeignItemKind::Fn(decl, generics),
             id: ast::DUMMY_NODE_ID,
-            span: mk_sp(lo, hi),
+            span: lo.to(hi),
             vis: vis
         })
     }
 
     /// Parse a static item from a foreign module
-    fn parse_item_foreign_static(&mut self, vis: ast::Visibility, lo: BytePos,
-                                 attrs: Vec<Attribute>) -> PResult<'a, ForeignItem> {
+    fn parse_item_foreign_static(&mut self, vis: ast::Visibility, lo: Span, attrs: Vec<Attribute>)
+                                 -> PResult<'a, ForeignItem> {
         self.expect_keyword(keywords::Static)?;
         let mutbl = self.eat_keyword(keywords::Mut);
 
         let ident = self.parse_ident()?;
         self.expect(&token::Colon)?;
         let ty = self.parse_ty()?;
-        let hi = self.span.hi;
+        let hi = self.span;
         self.expect(&token::Semi)?;
         Ok(ForeignItem {
             ident: ident,
             attrs: attrs,
             node: ForeignItemKind::Static(ty, mutbl),
             id: ast::DUMMY_NODE_ID,
-            span: mk_sp(lo, hi),
+            span: lo.to(hi),
             vis: vis
         })
     }
@@ -5340,7 +5333,7 @@ impl<'a> Parser<'a> {
     /// extern crate foo;
     /// extern crate bar as foo;
     fn parse_item_extern_crate(&mut self,
-                               lo: BytePos,
+                               lo: Span,
                                visibility: Visibility,
                                attrs: Vec<Attribute>)
                                 -> PResult<'a, P<Item>> {
@@ -5354,8 +5347,7 @@ impl<'a> Parser<'a> {
         self.expect(&token::Semi)?;
 
         let prev_span = self.prev_span;
-        Ok(self.mk_item(lo,
-                        prev_span.hi,
+        Ok(self.mk_item(lo.to(prev_span),
                         ident,
                         ItemKind::ExternCrate(maybe_path),
                         visibility,
@@ -5373,7 +5365,7 @@ impl<'a> Parser<'a> {
     /// extern "C" {}
     /// extern {}
     fn parse_item_foreign_mod(&mut self,
-                              lo: BytePos,
+                              lo: Span,
                               opt_abi: Option<abi::Abi>,
                               visibility: Visibility,
                               mut attrs: Vec<Attribute>)
@@ -5395,12 +5387,8 @@ impl<'a> Parser<'a> {
             abi: abi,
             items: foreign_items
         };
-        Ok(self.mk_item(lo,
-                     prev_span.hi,
-                     keywords::Invalid.ident(),
-                     ItemKind::ForeignMod(m),
-                     visibility,
-                     attrs))
+        let invalid = keywords::Invalid.ident();
+        Ok(self.mk_item(lo.to(prev_span), invalid, ItemKind::ForeignMod(m), visibility, attrs))
     }
 
     /// Parse type Foo = Bar;
@@ -5421,7 +5409,7 @@ impl<'a> Parser<'a> {
         let mut any_disr = None;
         while self.token != token::CloseDelim(token::Brace) {
             let variant_attrs = self.parse_outer_attributes()?;
-            let vlo = self.span.lo;
+            let vlo = self.span;
 
             let struct_def;
             let mut disr_expr = None;
@@ -5449,7 +5437,7 @@ impl<'a> Parser<'a> {
                 data: struct_def,
                 disr_expr: disr_expr,
             };
-            variants.push(spanned(vlo, self.prev_span.hi, vr));
+            variants.push(respan(vlo.to(self.prev_span), vr));
 
             if !self.eat(&token::Comma) { break; }
         }
@@ -5519,9 +5507,9 @@ impl<'a> Parser<'a> {
             Some(P(item))
         });
 
-        let lo = self.span.lo;
+        let lo = self.span;
 
-        let visibility = self.parse_visibility()?;
+        let visibility = self.parse_visibility(false)?;
 
         if self.eat_keyword(keywords::Use) {
             // USE ITEM
@@ -5529,12 +5517,8 @@ impl<'a> Parser<'a> {
             self.expect(&token::Semi)?;
 
             let prev_span = self.prev_span;
-            let item = self.mk_item(lo,
-                                    prev_span.hi,
-                                    keywords::Invalid.ident(),
-                                    item_,
-                                    visibility,
-                                    attrs);
+            let invalid = keywords::Invalid.ident();
+            let item = self.mk_item(lo.to(prev_span), invalid, item_, visibility, attrs);
             return Ok(Some(item));
         }
 
@@ -5554,8 +5538,7 @@ impl<'a> Parser<'a> {
                                        respan(fn_span, Constness::NotConst),
                                        abi)?;
                 let prev_span = self.prev_span;
-                let item = self.mk_item(lo,
-                                        prev_span.hi,
+                let item = self.mk_item(lo.to(prev_span),
                                         ident,
                                         item_,
                                         visibility,
@@ -5577,8 +5560,7 @@ impl<'a> Parser<'a> {
             };
             let (ident, item_, extra_attrs) = self.parse_item_const(Some(m))?;
             let prev_span = self.prev_span;
-            let item = self.mk_item(lo,
-                                    prev_span.hi,
+            let item = self.mk_item(lo.to(prev_span),
                                     ident,
                                     item_,
                                     visibility,
@@ -5602,8 +5584,7 @@ impl<'a> Parser<'a> {
                                        respan(const_span, Constness::Const),
                                        Abi::Rust)?;
                 let prev_span = self.prev_span;
-                let item = self.mk_item(lo,
-                                        prev_span.hi,
+                let item = self.mk_item(lo.to(prev_span),
                                         ident,
                                         item_,
                                         visibility,
@@ -5620,8 +5601,7 @@ impl<'a> Parser<'a> {
             }
             let (ident, item_, extra_attrs) = self.parse_item_const(None)?;
             let prev_span = self.prev_span;
-            let item = self.mk_item(lo,
-                                    prev_span.hi,
+            let item = self.mk_item(lo.to(prev_span),
                                     ident,
                                     item_,
                                     visibility,
@@ -5637,8 +5617,7 @@ impl<'a> Parser<'a> {
             let (ident, item_, extra_attrs) =
                 self.parse_item_trait(ast::Unsafety::Unsafe)?;
             let prev_span = self.prev_span;
-            let item = self.mk_item(lo,
-                                    prev_span.hi,
+            let item = self.mk_item(lo.to(prev_span),
                                     ident,
                                     item_,
                                     visibility,
@@ -5653,8 +5632,7 @@ impl<'a> Parser<'a> {
             self.expect_keyword(keywords::Impl)?;
             let (ident, item_, extra_attrs) = self.parse_item_impl(ast::Unsafety::Unsafe)?;
             let prev_span = self.prev_span;
-            let item = self.mk_item(lo,
-                                    prev_span.hi,
+            let item = self.mk_item(lo.to(prev_span),
                                     ident,
                                     item_,
                                     visibility,
@@ -5670,8 +5648,7 @@ impl<'a> Parser<'a> {
                                    respan(fn_span, Constness::NotConst),
                                    Abi::Rust)?;
             let prev_span = self.prev_span;
-            let item = self.mk_item(lo,
-                                    prev_span.hi,
+            let item = self.mk_item(lo.to(prev_span),
                                     ident,
                                     item_,
                                     visibility,
@@ -5694,8 +5671,7 @@ impl<'a> Parser<'a> {
                                    respan(fn_span, Constness::NotConst),
                                    abi)?;
             let prev_span = self.prev_span;
-            let item = self.mk_item(lo,
-                                    prev_span.hi,
+            let item = self.mk_item(lo.to(prev_span),
                                     ident,
                                     item_,
                                     visibility,
@@ -5707,8 +5683,7 @@ impl<'a> Parser<'a> {
             let (ident, item_, extra_attrs) =
                 self.parse_item_mod(&attrs[..])?;
             let prev_span = self.prev_span;
-            let item = self.mk_item(lo,
-                                    prev_span.hi,
+            let item = self.mk_item(lo.to(prev_span),
                                     ident,
                                     item_,
                                     visibility,
@@ -5719,8 +5694,7 @@ impl<'a> Parser<'a> {
             // TYPE ITEM
             let (ident, item_, extra_attrs) = self.parse_item_type()?;
             let prev_span = self.prev_span;
-            let item = self.mk_item(lo,
-                                    prev_span.hi,
+            let item = self.mk_item(lo.to(prev_span),
                                     ident,
                                     item_,
                                     visibility,
@@ -5731,8 +5705,7 @@ impl<'a> Parser<'a> {
             // ENUM ITEM
             let (ident, item_, extra_attrs) = self.parse_item_enum()?;
             let prev_span = self.prev_span;
-            let item = self.mk_item(lo,
-                                    prev_span.hi,
+            let item = self.mk_item(lo.to(prev_span),
                                     ident,
                                     item_,
                                     visibility,
@@ -5744,8 +5717,7 @@ impl<'a> Parser<'a> {
             let (ident, item_, extra_attrs) =
                 self.parse_item_trait(ast::Unsafety::Normal)?;
             let prev_span = self.prev_span;
-            let item = self.mk_item(lo,
-                                    prev_span.hi,
+            let item = self.mk_item(lo.to(prev_span),
                                     ident,
                                     item_,
                                     visibility,
@@ -5756,8 +5728,7 @@ impl<'a> Parser<'a> {
             // IMPL ITEM
             let (ident, item_, extra_attrs) = self.parse_item_impl(ast::Unsafety::Normal)?;
             let prev_span = self.prev_span;
-            let item = self.mk_item(lo,
-                                    prev_span.hi,
+            let item = self.mk_item(lo.to(prev_span),
                                     ident,
                                     item_,
                                     visibility,
@@ -5768,8 +5739,7 @@ impl<'a> Parser<'a> {
             // STRUCT ITEM
             let (ident, item_, extra_attrs) = self.parse_item_struct()?;
             let prev_span = self.prev_span;
-            let item = self.mk_item(lo,
-                                    prev_span.hi,
+            let item = self.mk_item(lo.to(prev_span),
                                     ident,
                                     item_,
                                     visibility,
@@ -5781,8 +5751,7 @@ impl<'a> Parser<'a> {
             self.bump();
             let (ident, item_, extra_attrs) = self.parse_item_union()?;
             let prev_span = self.prev_span;
-            let item = self.mk_item(lo,
-                                    prev_span.hi,
+            let item = self.mk_item(lo.to(prev_span),
                                     ident,
                                     item_,
                                     visibility,
@@ -5799,8 +5768,8 @@ impl<'a> Parser<'a> {
     /// Parse a foreign item.
     fn parse_foreign_item(&mut self) -> PResult<'a, Option<ForeignItem>> {
         let attrs = self.parse_outer_attributes()?;
-        let lo = self.span.lo;
-        let visibility = self.parse_visibility()?;
+        let lo = self.span;
+        let visibility = self.parse_visibility(false)?;
 
         if self.check_keyword(keywords::Static) {
             // FOREIGN STATIC ITEM
@@ -5826,7 +5795,7 @@ impl<'a> Parser<'a> {
         attrs: Vec<Attribute> ,
         macros_allowed: bool,
         attributes_allowed: bool,
-        lo: BytePos,
+        lo: Span,
         visibility: Visibility
     ) -> PResult<'a, Option<P<Item>>> {
         if macros_allowed && self.token.is_path_start() {
@@ -5835,7 +5804,7 @@ impl<'a> Parser<'a> {
             let prev_span = self.prev_span;
             self.complain_if_pub_macro(&visibility, prev_span);
 
-            let mac_lo = self.span.lo;
+            let mac_lo = self.span;
 
             // item macro.
             let pth = self.parse_path(PathStyle::Mod)?;
@@ -5861,9 +5830,9 @@ impl<'a> Parser<'a> {
                 }
             }
 
-            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);
+            let hi = self.prev_span;
+            let mac = respan(mac_lo.to(hi), Mac_ { path: pth, tts: tts });
+            let item = self.mk_item(lo.to(hi), id, ItemKind::Mac(mac), visibility, attrs);
             return Ok(Some(item));
         }
 
@@ -5891,7 +5860,7 @@ impl<'a> Parser<'a> {
         self.parse_unspanned_seq(&token::OpenDelim(token::Brace),
                                  &token::CloseDelim(token::Brace),
                                  SeqSep::trailing_allowed(token::Comma), |this| {
-            let lo = this.span.lo;
+            let lo = this.span;
             let ident = if this.eat_keyword(keywords::SelfValue) {
                 keywords::SelfValue.ident()
             } else {
@@ -5903,8 +5872,7 @@ impl<'a> Parser<'a> {
                 rename: rename,
                 id: ast::DUMMY_NODE_ID
             };
-            let hi = this.prev_span.hi;
-            Ok(spanned(lo, hi, node))
+            Ok(respan(lo.to(this.prev_span), node))
         })
     }
 
@@ -5922,21 +5890,21 @@ impl<'a> Parser<'a> {
     /// MOD_SEP? non_global_path MOD_SEP LBRACE item_seq RBRACE
     /// MOD_SEP? LBRACE item_seq RBRACE
     fn parse_view_path(&mut self) -> PResult<'a, P<ViewPath>> {
-        let lo = self.span.lo;
+        let lo = self.span;
         if self.check(&token::OpenDelim(token::Brace)) || self.check(&token::BinOp(token::Star)) ||
            self.is_import_coupler() {
             // `{foo, bar}`, `::{foo, bar}`, `*`, or `::*`.
             self.eat(&token::ModSep);
             let prefix = ast::Path {
                 segments: vec![PathSegment::crate_root()],
-                span: mk_sp(lo, self.span.hi),
+                span: lo.to(self.span),
             };
             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)))
+            Ok(P(respan(lo.to(self.span), view_path_kind)))
         } else {
             let prefix = self.parse_path(PathStyle::Mod)?.default_to_global();
             if self.is_import_coupler() {
@@ -5944,16 +5912,16 @@ impl<'a> Parser<'a> {
                 self.bump();
                 if self.check(&token::BinOp(token::Star)) {
                     self.bump();
-                    Ok(P(spanned(lo, self.span.hi, ViewPathGlob(prefix))))
+                    Ok(P(respan(lo.to(self.span), ViewPathGlob(prefix))))
                 } else {
                     let items = self.parse_path_list_items()?;
-                    Ok(P(spanned(lo, self.span.hi, ViewPathList(prefix, items))))
+                    Ok(P(respan(lo.to(self.span), ViewPathList(prefix, items))))
                 }
             } else {
                 // `foo::bar` or `foo::bar as baz`
                 let rename = self.parse_rename()?.
                                   unwrap_or(prefix.segments.last().unwrap().identifier);
-                Ok(P(spanned(lo, self.prev_span.hi, ViewPathSimple(rename, prefix))))
+                Ok(P(respan(lo.to(self.prev_span), ViewPathSimple(rename, prefix))))
             }
         }
     }
@@ -5969,11 +5937,11 @@ impl<'a> Parser<'a> {
     /// Parses a source module as a crate. This is the main
     /// entry point for the parser.
     pub fn parse_crate_mod(&mut self) -> PResult<'a, Crate> {
-        let lo = self.span.lo;
+        let lo = self.span;
         Ok(ast::Crate {
             attrs: self.parse_inner_attributes()?,
             module: self.parse_mod_items(&token::Eof, lo)?,
-            span: mk_sp(lo, self.span.lo),
+            span: lo.to(self.span),
         })
     }
 
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index 519d5bd98e4..74aa3984a9a 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -211,9 +211,7 @@ impl Token {
             ModSep                      => true, // global path
             Pound                       => true, // expression attributes
             Interpolated(ref nt) => match **nt {
-                NtExpr(..) => true,
-                NtBlock(..) => true,
-                NtPath(..) => true,
+                NtIdent(..) | NtExpr(..) | NtBlock(..) | NtPath(..) => true,
                 _ => false,
             },
             _ => false,
@@ -236,8 +234,7 @@ impl Token {
             Lt | BinOp(Shl)             => true, // associated path
             ModSep                      => true, // global path
             Interpolated(ref nt) => match **nt {
-                NtTy(..) => true,
-                NtPath(..) => true,
+                NtIdent(..) | NtTy(..) | NtPath(..) => true,
                 _ => false,
             },
             _ => false,
@@ -252,14 +249,22 @@ impl Token {
         }
     }
 
-    /// Returns `true` if the token is an identifier.
-    pub fn is_ident(&self) -> bool {
+    pub fn ident(&self) -> Option<ast::Ident> {
         match *self {
-            Ident(..)   => true,
-            _           => false,
+            Ident(ident) => Some(ident),
+            Interpolated(ref nt) => match **nt {
+                NtIdent(ident) => Some(ident.node),
+                _ => None,
+            },
+            _ => None,
         }
     }
 
+    /// Returns `true` if the token is an identifier.
+    pub fn is_ident(&self) -> bool {
+        self.ident().is_some()
+    }
+
     /// Returns `true` if the token is a documentation comment.
     pub fn is_doc_comment(&self) -> bool {
         match *self {
@@ -311,18 +316,15 @@ impl Token {
 
     /// Returns `true` if the token is a given keyword, `kw`.
     pub fn is_keyword(&self, kw: keywords::Keyword) -> bool {
-        match *self {
-            Ident(id) => id.name == kw.name(),
-            _ => false,
-        }
+        self.ident().map(|ident| ident.name == kw.name()).unwrap_or(false)
     }
 
     pub fn is_path_segment_keyword(&self) -> bool {
-        match *self {
-            Ident(id) => id.name == keywords::Super.name() ||
-                         id.name == keywords::SelfValue.name() ||
-                         id.name == keywords::SelfType.name(),
-            _ => false,
+        match self.ident() {
+            Some(id) => id.name == keywords::Super.name() ||
+                        id.name == keywords::SelfValue.name() ||
+                        id.name == keywords::SelfType.name(),
+            None => false,
         }
     }
 
@@ -333,18 +335,16 @@ impl Token {
 
     /// Returns `true` if the token is a strict keyword.
     pub fn is_strict_keyword(&self) -> bool {
-        match *self {
-            Ident(id) => id.name >= keywords::As.name() &&
-                         id.name <= keywords::While.name(),
+        match self.ident() {
+            Some(id) => id.name >= keywords::As.name() && id.name <= keywords::While.name(),
             _ => false,
         }
     }
 
     /// Returns `true` if the token is a keyword reserved for possible future use.
     pub fn is_reserved_keyword(&self) -> bool {
-        match *self {
-            Ident(id) => id.name >= keywords::Abstract.name() &&
-                         id.name <= keywords::Yield.name(),
+        match self.ident() {
+            Some(id) => id.name >= keywords::Abstract.name() && id.name <= keywords::Yield.name(),
             _ => false,
         }
     }
diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs
index c541df9230a..c7820a15fb3 100644
--- a/src/libsyntax/std_inject.rs
+++ b/src/libsyntax/std_inject.rs
@@ -10,29 +10,27 @@
 
 use ast;
 use attr;
+use ext::hygiene::{Mark, SyntaxContext};
 use symbol::{Symbol, keywords};
 use syntax_pos::{DUMMY_SP, Span};
 use codemap::{self, ExpnInfo, NameAndSpan, MacroAttribute};
-use parse::ParseSess;
 use ptr::P;
 use tokenstream::TokenStream;
 
 /// Craft a span that will be ignored by the stability lint's
 /// call to codemap's is_internal check.
 /// The expanded code uses the unstable `#[prelude_import]` attribute.
-fn ignored_span(sess: &ParseSess, sp: Span) -> Span {
-    let info = ExpnInfo {
+fn ignored_span(sp: Span) -> Span {
+    let mark = Mark::fresh();
+    mark.set_expn_info(ExpnInfo {
         call_site: DUMMY_SP,
         callee: NameAndSpan {
             format: MacroAttribute(Symbol::intern("std_inject")),
             span: None,
             allow_internal_unstable: true,
         }
-    };
-    let expn_id = sess.codemap().record_expansion(info);
-    let mut sp = sp;
-    sp.expn_id = expn_id;
-    return sp;
+    });
+    Span { ctxt: SyntaxContext::empty().apply_mark(mark), ..sp }
 }
 
 pub fn injected_crate_name(krate: &ast::Crate) -> Option<&'static str> {
@@ -45,10 +43,7 @@ pub fn injected_crate_name(krate: &ast::Crate) -> Option<&'static str> {
     }
 }
 
-pub fn maybe_inject_crates_ref(sess: &ParseSess,
-                               mut krate: ast::Crate,
-                               alt_std_name: Option<String>)
-                               -> ast::Crate {
+pub fn maybe_inject_crates_ref(mut krate: ast::Crate, alt_std_name: Option<String>) -> ast::Crate {
     let name = match injected_crate_name(&krate) {
         Some(name) => name,
         None => return krate,
@@ -67,7 +62,7 @@ pub fn maybe_inject_crates_ref(sess: &ParseSess,
         span: DUMMY_SP,
     }));
 
-    let span = ignored_span(sess, DUMMY_SP);
+    let span = ignored_span(DUMMY_SP);
     krate.module.items.insert(0, P(ast::Item {
         attrs: vec![ast::Attribute {
             style: ast::AttrStyle::Outer,
diff --git a/src/libsyntax/symbol.rs b/src/libsyntax/symbol.rs
deleted file mode 100644
index 6642c60d256..00000000000
--- a/src/libsyntax/symbol.rs
+++ /dev/null
@@ -1,306 +0,0 @@
-// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! An "interner" is a data structure that associates values with usize tags and
-//! allows bidirectional lookup; i.e. given a value, one can easily find the
-//! type, and vice versa.
-
-use serialize::{Decodable, Decoder, Encodable, Encoder};
-use std::cell::RefCell;
-use std::collections::HashMap;
-use std::fmt;
-
-/// A symbol is an interned or gensymed string.
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub struct Symbol(u32);
-
-// The interner in thread-local, so `Symbol` shouldn't move between threads.
-impl !Send for Symbol { }
-
-impl Symbol {
-    /// Maps a string to its interned representation.
-    pub fn intern(string: &str) -> Self {
-        with_interner(|interner| interner.intern(string))
-    }
-
-    /// gensym's a new usize, using the current interner.
-    pub fn gensym(string: &str) -> Self {
-        with_interner(|interner| interner.gensym(string))
-    }
-
-    pub fn as_str(self) -> InternedString {
-        with_interner(|interner| unsafe {
-            InternedString {
-                string: ::std::mem::transmute::<&str, &str>(interner.get(self))
-            }
-        })
-    }
-
-    pub fn as_u32(self) -> u32 {
-        self.0
-    }
-}
-
-impl fmt::Debug for Symbol {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}({})", self, self.0)
-    }
-}
-
-impl fmt::Display for Symbol {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        fmt::Display::fmt(&self.as_str(), f)
-    }
-}
-
-impl Encodable for Symbol {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_str(&self.as_str())
-    }
-}
-
-impl Decodable for Symbol {
-    fn decode<D: Decoder>(d: &mut D) -> Result<Symbol, D::Error> {
-        Ok(Symbol::intern(&d.read_str()?))
-    }
-}
-
-impl<'a> PartialEq<&'a str> for Symbol {
-    fn eq(&self, other: &&str) -> bool {
-        *self.as_str() == **other
-    }
-}
-
-#[derive(Default)]
-pub struct Interner {
-    names: HashMap<Box<str>, Symbol>,
-    strings: Vec<Box<str>>,
-}
-
-impl Interner {
-    pub fn new() -> Self {
-        Interner::default()
-    }
-
-    fn prefill(init: &[&str]) -> Self {
-        let mut this = Interner::new();
-        for &string in init {
-            this.intern(string);
-        }
-        this
-    }
-
-    pub fn intern(&mut self, string: &str) -> Symbol {
-        if let Some(&name) = self.names.get(string) {
-            return name;
-        }
-
-        let name = Symbol(self.strings.len() as u32);
-        let string = string.to_string().into_boxed_str();
-        self.strings.push(string.clone());
-        self.names.insert(string, name);
-        name
-    }
-
-    fn gensym(&mut self, string: &str) -> Symbol {
-        let gensym = Symbol(self.strings.len() as u32);
-        // leave out of `names` to avoid colliding
-        self.strings.push(string.to_string().into_boxed_str());
-        gensym
-    }
-
-    pub fn get(&self, name: Symbol) -> &str {
-        &self.strings[name.0 as usize]
-    }
-}
-
-// In this macro, there is the requirement that the name (the number) must be monotonically
-// increasing by one in the special identifiers, starting at 0; the same holds for the keywords,
-// except starting from the next number instead of zero.
-macro_rules! declare_keywords {(
-    $( ($index: expr, $konst: ident, $string: expr) )*
-) => {
-    pub mod keywords {
-        use ast;
-        #[derive(Clone, Copy, PartialEq, Eq)]
-        pub struct Keyword {
-            ident: ast::Ident,
-        }
-        impl Keyword {
-            #[inline] pub fn ident(self) -> ast::Ident { self.ident }
-            #[inline] pub fn name(self) -> ast::Name { self.ident.name }
-        }
-        $(
-            #[allow(non_upper_case_globals)]
-            pub const $konst: Keyword = Keyword {
-                ident: ast::Ident::with_empty_ctxt(super::Symbol($index))
-            };
-        )*
-    }
-
-    impl Interner {
-        fn fresh() -> Self {
-            Interner::prefill(&[$($string,)*])
-        }
-    }
-}}
-
-// NB: leaving holes in the ident table is bad! a different ident will get
-// interned with the id from the hole, but it will be between the min and max
-// of the reserved words, and thus tagged as "reserved".
-// After modifying this list adjust `is_strict_keyword`/`is_reserved_keyword`,
-// this should be rarely necessary though if the keywords are kept in alphabetic order.
-declare_keywords! {
-    // Invalid identifier
-    (0,  Invalid,        "")
-
-    // Strict keywords used in the language.
-    (1,  As,             "as")
-    (2,  Box,            "box")
-    (3,  Break,          "break")
-    (4,  Const,          "const")
-    (5,  Continue,       "continue")
-    (6,  Crate,          "crate")
-    (7,  Else,           "else")
-    (8,  Enum,           "enum")
-    (9,  Extern,         "extern")
-    (10, False,          "false")
-    (11, Fn,             "fn")
-    (12, For,            "for")
-    (13, If,             "if")
-    (14, Impl,           "impl")
-    (15, In,             "in")
-    (16, Let,            "let")
-    (17, Loop,           "loop")
-    (18, Match,          "match")
-    (19, Mod,            "mod")
-    (20, Move,           "move")
-    (21, Mut,            "mut")
-    (22, Pub,            "pub")
-    (23, Ref,            "ref")
-    (24, Return,         "return")
-    (25, SelfValue,      "self")
-    (26, SelfType,       "Self")
-    (27, Static,         "static")
-    (28, Struct,         "struct")
-    (29, Super,          "super")
-    (30, Trait,          "trait")
-    (31, True,           "true")
-    (32, Type,           "type")
-    (33, Unsafe,         "unsafe")
-    (34, Use,            "use")
-    (35, Where,          "where")
-    (36, While,          "while")
-
-    // Keywords reserved for future use.
-    (37, Abstract,       "abstract")
-    (38, Alignof,        "alignof")
-    (39, Become,         "become")
-    (40, Do,             "do")
-    (41, Final,          "final")
-    (42, Macro,          "macro")
-    (43, Offsetof,       "offsetof")
-    (44, Override,       "override")
-    (45, Priv,           "priv")
-    (46, Proc,           "proc")
-    (47, Pure,           "pure")
-    (48, Sizeof,         "sizeof")
-    (49, Typeof,         "typeof")
-    (50, Unsized,        "unsized")
-    (51, Virtual,        "virtual")
-    (52, Yield,          "yield")
-
-    // Weak keywords, have special meaning only in specific contexts.
-    (53, Default,        "default")
-    (54, StaticLifetime, "'static")
-    (55, Union,          "union")
-    (56, Catch,          "catch")
-
-    // A virtual keyword that resolves to the crate root when used in a lexical scope.
-    (57, CrateRoot, "{{root}}")
-}
-
-// If an interner exists in TLS, return it. Otherwise, prepare a fresh one.
-fn with_interner<T, F: FnOnce(&mut Interner) -> T>(f: F) -> T {
-    thread_local!(static INTERNER: RefCell<Interner> = {
-        RefCell::new(Interner::fresh())
-    });
-    INTERNER.with(|interner| f(&mut *interner.borrow_mut()))
-}
-
-/// Represents a string stored in the thread-local interner. Because the
-/// interner lives for the life of the thread, this can be safely treated as an
-/// immortal string, as long as it never crosses between threads.
-///
-/// FIXME(pcwalton): You must be careful about what you do in the destructors
-/// of objects stored in TLS, because they may run after the interner is
-/// destroyed. In particular, they must not access string contents. This can
-/// be fixed in the future by just leaking all strings until thread death
-/// somehow.
-#[derive(Clone, PartialEq, Hash, PartialOrd, Eq, Ord)]
-pub struct InternedString {
-    string: &'static str,
-}
-
-impl !Send for InternedString { }
-
-impl ::std::ops::Deref for InternedString {
-    type Target = str;
-    fn deref(&self) -> &str { self.string }
-}
-
-impl fmt::Debug for InternedString {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        fmt::Debug::fmt(self.string, f)
-    }
-}
-
-impl fmt::Display for InternedString {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        fmt::Display::fmt(self.string, f)
-    }
-}
-
-impl Decodable for InternedString {
-    fn decode<D: Decoder>(d: &mut D) -> Result<InternedString, D::Error> {
-        Ok(Symbol::intern(&d.read_str()?).as_str())
-    }
-}
-
-impl Encodable for InternedString {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_str(self.string)
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn interner_tests() {
-        let mut i: Interner = Interner::new();
-        // first one is zero:
-        assert_eq!(i.intern("dog"), Symbol(0));
-        // re-use gets the same entry:
-        assert_eq!(i.intern ("dog"), Symbol(0));
-        // different string gets a different #:
-        assert_eq!(i.intern("cat"), Symbol(1));
-        assert_eq!(i.intern("cat"), Symbol(1));
-        // dog is still at zero
-        assert_eq!(i.intern("dog"), Symbol(0));
-        // gensym gets 3
-        assert_eq!(i.gensym("zebra"), Symbol(2));
-        // gensym of same string gets new number :
-        assert_eq!(i.gensym("zebra"), Symbol(3));
-        // gensym of *existing* string gets new number:
-        assert_eq!(i.gensym("dog"), Symbol(4));
-    }
-}
diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs
index e052d2cda3a..50380626d7f 100644
--- a/src/libsyntax/test.rs
+++ b/src/libsyntax/test.rs
@@ -31,6 +31,7 @@ use entry::{self, EntryPointType};
 use ext::base::{ExtCtxt, Resolver};
 use ext::build::AstBuilder;
 use ext::expand::ExpansionConfig;
+use ext::hygiene::{Mark, SyntaxContext};
 use fold::Folder;
 use util::move_map::MoveMap;
 use fold;
@@ -62,6 +63,7 @@ struct TestCtxt<'a> {
     testfns: Vec<Test>,
     reexport_test_harness_main: Option<Symbol>,
     is_test_crate: bool,
+    ctxt: SyntaxContext,
 
     // top-level re-export submodule, filled out after folding is finished
     toplevel_reexport: Option<Ident>,
@@ -275,6 +277,7 @@ fn generate_test_harness(sess: &ParseSess,
     let mut cleaner = EntryPointCleaner { depth: 0 };
     let krate = cleaner.fold_crate(krate);
 
+    let mark = Mark::fresh();
     let mut cx: TestCtxt = TestCtxt {
         sess: sess,
         span_diagnostic: sd,
@@ -284,15 +287,16 @@ fn generate_test_harness(sess: &ParseSess,
         reexport_test_harness_main: reexport_test_harness_main,
         is_test_crate: is_test_crate(&krate),
         toplevel_reexport: None,
+        ctxt: SyntaxContext::empty().apply_mark(mark),
     };
     cx.ext_cx.crate_root = Some("std");
 
-    cx.ext_cx.bt_push(ExpnInfo {
+    mark.set_expn_info(ExpnInfo {
         call_site: DUMMY_SP,
         callee: NameAndSpan {
             format: MacroAttribute(Symbol::intern("test")),
             span: None,
-            allow_internal_unstable: false,
+            allow_internal_unstable: true,
         }
     });
 
@@ -307,18 +311,7 @@ fn generate_test_harness(sess: &ParseSess,
 /// call to codemap's is_internal check.
 /// The expanded code calls some unstable functions in the test crate.
 fn ignored_span(cx: &TestCtxt, sp: Span) -> Span {
-    let info = ExpnInfo {
-        call_site: sp,
-        callee: NameAndSpan {
-            format: MacroAttribute(Symbol::intern("test")),
-            span: None,
-            allow_internal_unstable: true,
-        }
-    };
-    let expn_id = cx.sess.codemap().record_expansion(info);
-    let mut sp = sp;
-    sp.expn_id = expn_id;
-    return sp;
+    Span { ctxt: cx.ctxt, ..sp }
 }
 
 #[derive(PartialEq)]
@@ -616,7 +609,7 @@ fn mk_tests(cx: &TestCtxt) -> P<ast::Item> {
 
 fn is_test_crate(krate: &ast::Crate) -> bool {
     match attr::find_crate_name(&krate.attrs) {
-        Some(s) if "test" == &*s.as_str() => true,
+        Some(s) if "test" == s.as_str() => true,
         _ => false
     }
 }
diff --git a/src/libsyntax/test_snippet.rs b/src/libsyntax/test_snippet.rs
index c6d6e6237f2..c537a0ee166 100644
--- a/src/libsyntax/test_snippet.rs
+++ b/src/libsyntax/test_snippet.rs
@@ -83,7 +83,7 @@ fn make_span(file_text: &str, start: &Position, end: &Position) -> Span {
     Span {
         lo: BytePos(start as u32),
         hi: BytePos(end as u32),
-        expn_id: NO_EXPANSION,
+        ctxt: NO_EXPANSION,
     }
 }
 
diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs
index b75b3efda36..86bfdebe42b 100644
--- a/src/libsyntax/tokenstream.rs
+++ b/src/libsyntax/tokenstream.rs
@@ -56,18 +56,20 @@ impl Delimited {
 
     /// Returns the opening delimiter as a token tree.
     pub fn open_tt(&self, span: Span) -> TokenTree {
-        let open_span = match span {
-            DUMMY_SP => DUMMY_SP,
-            _ => Span { hi: span.lo + BytePos(self.delim.len() as u32), ..span },
+        let open_span = if span == DUMMY_SP {
+            DUMMY_SP
+        } else {
+            Span { hi: span.lo + BytePos(self.delim.len() as u32), ..span }
         };
         TokenTree::Token(open_span, self.open_token())
     }
 
     /// Returns the closing delimiter as a token tree.
     pub fn close_tt(&self, span: Span) -> TokenTree {
-        let close_span = match span {
-            DUMMY_SP => DUMMY_SP,
-            _ => Span { lo: span.hi - BytePos(self.delim.len() as u32), ..span },
+        let close_span = if span == DUMMY_SP {
+            DUMMY_SP
+        } else {
+            Span { lo: span.hi - BytePos(self.delim.len() as u32), ..span }
         };
         TokenTree::Token(close_span, self.close_token())
     }
@@ -425,7 +427,7 @@ mod tests {
         Span {
             lo: BytePos(a),
             hi: BytePos(b),
-            expn_id: NO_EXPANSION,
+            ctxt: NO_EXPANSION,
         }
     }