about summary refs log tree commit diff
path: root/compiler/rustc_ast/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-08-30 15:57:57 +0000
committerbors <bors@rust-lang.org>2020-08-30 15:57:57 +0000
commit85fbf49ce0e2274d0acf798f6e703747674feec3 (patch)
tree158a05eb3f204a8e72939b58427d0c2787a4eade /compiler/rustc_ast/src
parentdb534b3ac286cf45688c3bbae6aa6e77439e52d2 (diff)
parent9e5f7d5631b8f4009ac1c693e585d4b7108d4275 (diff)
downloadrust-85fbf49ce0e2274d0acf798f6e703747674feec3.tar.gz
rust-85fbf49ce0e2274d0acf798f6e703747674feec3.zip
Auto merge of #74862 - mark-i-m:mv-compiler, r=petrochenkov
Move almost all compiler crates to compiler/

This PR implements https://github.com/rust-lang/compiler-team/issues/336 and moves all `rustc_*` crates from `src` to the new `compiler` directory.

`librustc_foo` directories are renamed to `rustc_foo`.
`src` directories are introduced inside `rustc_*` directories to mirror the scheme already use for `library` crates.
Diffstat (limited to 'compiler/rustc_ast/src')
-rw-r--r--compiler/rustc_ast/src/ast.rs2846
-rw-r--r--compiler/rustc_ast/src/ast/tests.rs11
-rw-r--r--compiler/rustc_ast/src/attr/mod.rs684
-rw-r--r--compiler/rustc_ast/src/crate_disambiguator.rs35
-rw-r--r--compiler/rustc_ast/src/entry.rs7
-rw-r--r--compiler/rustc_ast/src/expand/allocator.rs53
-rw-r--r--compiler/rustc_ast/src/expand/mod.rs3
-rw-r--r--compiler/rustc_ast/src/lib.rs69
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs1325
-rw-r--r--compiler/rustc_ast/src/node_id.rs34
-rw-r--r--compiler/rustc_ast/src/ptr.rs219
-rw-r--r--compiler/rustc_ast/src/token.rs884
-rw-r--r--compiler/rustc_ast/src/tokenstream.rs433
-rw-r--r--compiler/rustc_ast/src/util/classify.rs25
-rw-r--r--compiler/rustc_ast/src/util/comments.rs222
-rw-r--r--compiler/rustc_ast/src/util/comments/tests.rs43
-rw-r--r--compiler/rustc_ast/src/util/lev_distance.rs108
-rw-r--r--compiler/rustc_ast/src/util/lev_distance/tests.rs59
-rw-r--r--compiler/rustc_ast/src/util/literal.rs320
-rw-r--r--compiler/rustc_ast/src/util/parser.rs403
-rw-r--r--compiler/rustc_ast/src/visit.rs913
21 files changed, 8696 insertions, 0 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
new file mode 100644
index 00000000000..127a53cad2b
--- /dev/null
+++ b/compiler/rustc_ast/src/ast.rs
@@ -0,0 +1,2846 @@
+//! The Rust abstract syntax tree module.
+//!
+//! This module contains common structures forming the language AST.
+//! Two main entities in the module are [`Item`] (which represents an AST element with
+//! additional metadata), and [`ItemKind`] (which represents a concrete type and contains
+//! information specific to the type of the item).
+//!
+//! Other module items worth mentioning:
+//! - [`Ty`] and [`TyKind`]: A parsed Rust type.
+//! - [`Expr`] and [`ExprKind`]: A parsed Rust expression.
+//! - [`Pat`] and [`PatKind`]: A parsed Rust pattern. Patterns are often dual to expressions.
+//! - [`Stmt`] and [`StmtKind`]: An executable action that does not return a value.
+//! - [`FnDecl`], [`FnHeader`] and [`Param`]: Metadata associated with a function declaration.
+//! - [`Generics`], [`GenericParam`], [`WhereClause`]: Metadata associated with generic parameters.
+//! - [`EnumDef`] and [`Variant`]: Enum declaration.
+//! - [`Lit`] and [`LitKind`]: Literal expressions.
+//! - [`MacroDef`], [`MacStmtStyle`], [`MacCall`], [`MacDelimiter`]: Macro definition and invocation.
+//! - [`Attribute`]: Metadata associated with item.
+//! - [`UnOp`], [`BinOp`], and [`BinOpKind`]: Unary and binary operators.
+
+pub use crate::util::parser::ExprPrecedence;
+pub use GenericArgs::*;
+pub use UnsafeSource::*;
+
+use crate::ptr::P;
+use crate::token::{self, CommentKind, DelimToken};
+use crate::tokenstream::{DelimSpan, TokenStream, TokenTree};
+
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::sync::Lrc;
+use rustc_data_structures::thin_vec::ThinVec;
+use rustc_macros::HashStable_Generic;
+use rustc_serialize::{self, Decoder, Encoder};
+use rustc_span::source_map::{respan, Spanned};
+use rustc_span::symbol::{kw, sym, Ident, Symbol};
+use rustc_span::{Span, DUMMY_SP};
+
+use std::cmp::Ordering;
+use std::convert::TryFrom;
+use std::fmt;
+use std::iter;
+
+#[cfg(test)]
+mod tests;
+
+/// A "Label" is an identifier of some point in sources,
+/// e.g. in the following code:
+///
+/// ```rust
+/// 'outer: loop {
+///     break 'outer;
+/// }
+/// ```
+///
+/// `'outer` is a label.
+#[derive(Clone, Encodable, Decodable, Copy, HashStable_Generic)]
+pub struct Label {
+    pub ident: Ident,
+}
+
+impl fmt::Debug for Label {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "label({:?})", self.ident)
+    }
+}
+
+/// A "Lifetime" is an annotation of the scope in which variable
+/// can be used, e.g. `'a` in `&'a i32`.
+#[derive(Clone, Encodable, Decodable, Copy)]
+pub struct Lifetime {
+    pub id: NodeId,
+    pub ident: Ident,
+}
+
+impl fmt::Debug for Lifetime {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "lifetime({}: {})", self.id, self)
+    }
+}
+
+impl fmt::Display for Lifetime {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{}", self.ident.name)
+    }
+}
+
+/// A "Path" is essentially Rust's notion of a name.
+///
+/// It's represented as a sequence of identifiers,
+/// along with a bunch of supporting information.
+///
+/// E.g., `std::cmp::PartialEq`.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct Path {
+    pub span: Span,
+    /// The segments in the path: the things separated by `::`.
+    /// Global paths begin with `kw::PathRoot`.
+    pub segments: Vec<PathSegment>,
+}
+
+impl PartialEq<Symbol> for Path {
+    fn eq(&self, symbol: &Symbol) -> bool {
+        self.segments.len() == 1 && { self.segments[0].ident.name == *symbol }
+    }
+}
+
+impl<CTX> HashStable<CTX> for Path {
+    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
+        self.segments.len().hash_stable(hcx, hasher);
+        for segment in &self.segments {
+            segment.ident.name.hash_stable(hcx, hasher);
+        }
+    }
+}
+
+impl Path {
+    // Convert a span and an identifier to the corresponding
+    // one-segment path.
+    pub fn from_ident(ident: Ident) -> Path {
+        Path { segments: vec![PathSegment::from_ident(ident)], span: ident.span }
+    }
+
+    pub fn is_global(&self) -> bool {
+        !self.segments.is_empty() && self.segments[0].ident.name == kw::PathRoot
+    }
+}
+
+/// A segment of a path: an identifier, an optional lifetime, and a set of types.
+///
+/// E.g., `std`, `String` or `Box<T>`.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct PathSegment {
+    /// The identifier portion of this path segment.
+    pub ident: Ident,
+
+    pub id: NodeId,
+
+    /// Type/lifetime parameters attached to this path. They come in
+    /// two flavors: `Path<A,B,C>` and `Path(A,B) -> C`.
+    /// `None` means that no parameter list is supplied (`Path`),
+    /// `Some` means that parameter list is supplied (`Path<X, Y>`)
+    /// but it can be empty (`Path<>`).
+    /// `P` is used as a size optimization for the common case with no parameters.
+    pub args: Option<P<GenericArgs>>,
+}
+
+impl PathSegment {
+    pub fn from_ident(ident: Ident) -> Self {
+        PathSegment { ident, id: DUMMY_NODE_ID, args: None }
+    }
+    pub fn path_root(span: Span) -> Self {
+        PathSegment::from_ident(Ident::new(kw::PathRoot, span))
+    }
+}
+
+/// The arguments of a path segment.
+///
+/// E.g., `<A, B>` as in `Foo<A, B>` or `(A, B)` as in `Foo(A, B)`.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub enum GenericArgs {
+    /// The `<'a, A, B, C>` in `foo::bar::baz::<'a, A, B, C>`.
+    AngleBracketed(AngleBracketedArgs),
+    /// The `(A, B)` and `C` in `Foo(A, B) -> C`.
+    Parenthesized(ParenthesizedArgs),
+}
+
+impl GenericArgs {
+    pub fn is_parenthesized(&self) -> bool {
+        match *self {
+            Parenthesized(..) => true,
+            _ => false,
+        }
+    }
+
+    pub fn is_angle_bracketed(&self) -> bool {
+        match *self {
+            AngleBracketed(..) => true,
+            _ => false,
+        }
+    }
+
+    pub fn span(&self) -> Span {
+        match *self {
+            AngleBracketed(ref data) => data.span,
+            Parenthesized(ref data) => data.span,
+        }
+    }
+}
+
+/// Concrete argument in the sequence of generic args.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub enum GenericArg {
+    /// `'a` in `Foo<'a>`
+    Lifetime(Lifetime),
+    /// `Bar` in `Foo<Bar>`
+    Type(P<Ty>),
+    /// `1` in `Foo<1>`
+    Const(AnonConst),
+}
+
+impl GenericArg {
+    pub fn span(&self) -> Span {
+        match self {
+            GenericArg::Lifetime(lt) => lt.ident.span,
+            GenericArg::Type(ty) => ty.span,
+            GenericArg::Const(ct) => ct.value.span,
+        }
+    }
+}
+
+/// A path like `Foo<'a, T>`.
+#[derive(Clone, Encodable, Decodable, Debug, Default)]
+pub struct AngleBracketedArgs {
+    /// The overall span.
+    pub span: Span,
+    /// The comma separated parts in the `<...>`.
+    pub args: Vec<AngleBracketedArg>,
+}
+
+/// Either an argument for a parameter e.g., `'a`, `Vec<u8>`, `0`,
+/// or a constraint on an associated item, e.g., `Item = String` or `Item: Bound`.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub enum AngleBracketedArg {
+    /// Argument for a generic parameter.
+    Arg(GenericArg),
+    /// Constraint for an associated item.
+    Constraint(AssocTyConstraint),
+}
+
+impl Into<Option<P<GenericArgs>>> for AngleBracketedArgs {
+    fn into(self) -> Option<P<GenericArgs>> {
+        Some(P(GenericArgs::AngleBracketed(self)))
+    }
+}
+
+impl Into<Option<P<GenericArgs>>> for ParenthesizedArgs {
+    fn into(self) -> Option<P<GenericArgs>> {
+        Some(P(GenericArgs::Parenthesized(self)))
+    }
+}
+
+/// A path like `Foo(A, B) -> C`.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct ParenthesizedArgs {
+    /// Overall span
+    pub span: Span,
+
+    /// `(A, B)`
+    pub inputs: Vec<P<Ty>>,
+
+    /// `C`
+    pub output: FnRetTy,
+}
+
+impl ParenthesizedArgs {
+    pub fn as_angle_bracketed_args(&self) -> AngleBracketedArgs {
+        let args = self
+            .inputs
+            .iter()
+            .cloned()
+            .map(|input| AngleBracketedArg::Arg(GenericArg::Type(input)))
+            .collect();
+        AngleBracketedArgs { span: self.span, args }
+    }
+}
+
+pub use crate::node_id::{NodeId, CRATE_NODE_ID, DUMMY_NODE_ID};
+
+/// A modifier on a bound, e.g., `?Sized` or `?const Trait`.
+///
+/// Negative bounds should also be handled here.
+#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)]
+pub enum TraitBoundModifier {
+    /// No modifiers
+    None,
+
+    /// `?Trait`
+    Maybe,
+
+    /// `?const Trait`
+    MaybeConst,
+
+    /// `?const ?Trait`
+    //
+    // This parses but will be rejected during AST validation.
+    MaybeConstMaybe,
+}
+
+/// The AST represents all type param bounds as types.
+/// `typeck::collect::compute_bounds` matches these against
+/// the "special" built-in traits (see `middle::lang_items`) and
+/// detects `Copy`, `Send` and `Sync`.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub enum GenericBound {
+    Trait(PolyTraitRef, TraitBoundModifier),
+    Outlives(Lifetime),
+}
+
+impl GenericBound {
+    pub fn span(&self) -> Span {
+        match self {
+            GenericBound::Trait(ref t, ..) => t.span,
+            GenericBound::Outlives(ref l) => l.ident.span,
+        }
+    }
+}
+
+pub type GenericBounds = Vec<GenericBound>;
+
+/// Specifies the enforced ordering for generic parameters. In the future,
+/// if we wanted to relax this order, we could override `PartialEq` and
+/// `PartialOrd`, to allow the kinds to be unordered.
+#[derive(Hash, Clone, Copy)]
+pub enum ParamKindOrd {
+    Lifetime,
+    Type,
+    // `unordered` is only `true` if `sess.has_features().const_generics`
+    // is active. Specifically, if it's only `min_const_generics`, it will still require
+    // ordering consts after types.
+    Const { unordered: bool },
+}
+
+impl Ord for ParamKindOrd {
+    fn cmp(&self, other: &Self) -> Ordering {
+        use ParamKindOrd::*;
+        let to_int = |v| match v {
+            Lifetime => 0,
+            Type | Const { unordered: true } => 1,
+            // technically both consts should be ordered equally,
+            // but only one is ever encountered at a time, so this is
+            // fine.
+            Const { unordered: false } => 2,
+        };
+
+        to_int(*self).cmp(&to_int(*other))
+    }
+}
+impl PartialOrd for ParamKindOrd {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+impl PartialEq for ParamKindOrd {
+    fn eq(&self, other: &Self) -> bool {
+        self.cmp(other) == Ordering::Equal
+    }
+}
+impl Eq for ParamKindOrd {}
+
+impl fmt::Display for ParamKindOrd {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            ParamKindOrd::Lifetime => "lifetime".fmt(f),
+            ParamKindOrd::Type => "type".fmt(f),
+            ParamKindOrd::Const { .. } => "const".fmt(f),
+        }
+    }
+}
+
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub enum GenericParamKind {
+    /// A lifetime definition (e.g., `'a: 'b + 'c + 'd`).
+    Lifetime,
+    Type {
+        default: Option<P<Ty>>,
+    },
+    Const {
+        ty: P<Ty>,
+        /// Span of the `const` keyword.
+        kw_span: Span,
+    },
+}
+
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct GenericParam {
+    pub id: NodeId,
+    pub ident: Ident,
+    pub attrs: AttrVec,
+    pub bounds: GenericBounds,
+    pub is_placeholder: bool,
+    pub kind: GenericParamKind,
+}
+
+/// Represents lifetime, type and const parameters attached to a declaration of
+/// a function, enum, trait, etc.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct Generics {
+    pub params: Vec<GenericParam>,
+    pub where_clause: WhereClause,
+    pub span: Span,
+}
+
+impl Default for Generics {
+    /// Creates an instance of `Generics`.
+    fn default() -> Generics {
+        Generics {
+            params: Vec::new(),
+            where_clause: WhereClause {
+                has_where_token: false,
+                predicates: Vec::new(),
+                span: DUMMY_SP,
+            },
+            span: DUMMY_SP,
+        }
+    }
+}
+
+/// A where-clause in a definition.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct WhereClause {
+    /// `true` if we ate a `where` token: this can happen
+    /// if we parsed no predicates (e.g. `struct Foo where {}`).
+    /// This allows us to accurately pretty-print
+    /// in `nt_to_tokenstream`
+    pub has_where_token: bool,
+    pub predicates: Vec<WherePredicate>,
+    pub span: Span,
+}
+
+/// A single predicate in a where-clause.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub enum WherePredicate {
+    /// A type binding (e.g., `for<'c> Foo: Send + Clone + 'c`).
+    BoundPredicate(WhereBoundPredicate),
+    /// A lifetime predicate (e.g., `'a: 'b + 'c`).
+    RegionPredicate(WhereRegionPredicate),
+    /// An equality predicate (unsupported).
+    EqPredicate(WhereEqPredicate),
+}
+
+impl WherePredicate {
+    pub fn span(&self) -> Span {
+        match self {
+            &WherePredicate::BoundPredicate(ref p) => p.span,
+            &WherePredicate::RegionPredicate(ref p) => p.span,
+            &WherePredicate::EqPredicate(ref p) => p.span,
+        }
+    }
+}
+
+/// A type bound.
+///
+/// E.g., `for<'c> Foo: Send + Clone + 'c`.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct WhereBoundPredicate {
+    pub span: Span,
+    /// Any generics from a `for` binding.
+    pub bound_generic_params: Vec<GenericParam>,
+    /// The type being bounded.
+    pub bounded_ty: P<Ty>,
+    /// Trait and lifetime bounds (`Clone + Send + 'static`).
+    pub bounds: GenericBounds,
+}
+
+/// A lifetime predicate.
+///
+/// E.g., `'a: 'b + 'c`.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct WhereRegionPredicate {
+    pub span: Span,
+    pub lifetime: Lifetime,
+    pub bounds: GenericBounds,
+}
+
+/// An equality predicate (unsupported).
+///
+/// E.g., `T = int`.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct WhereEqPredicate {
+    pub id: NodeId,
+    pub span: Span,
+    pub lhs_ty: P<Ty>,
+    pub rhs_ty: P<Ty>,
+}
+
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct Crate {
+    pub module: Mod,
+    pub attrs: Vec<Attribute>,
+    pub span: Span,
+    /// The order of items in the HIR is unrelated to the order of
+    /// items in the AST. However, we generate proc macro harnesses
+    /// based on the AST order, and later refer to these harnesses
+    /// from the HIR. This field keeps track of the order in which
+    /// we generated proc macros harnesses, so that we can map
+    /// HIR proc macros items back to their harness items.
+    pub proc_macros: Vec<NodeId>,
+}
+
+/// Possible values inside of compile-time attribute lists.
+///
+/// E.g., the '..' in `#[name(..)]`.
+#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
+pub enum NestedMetaItem {
+    /// A full MetaItem, for recursive meta items.
+    MetaItem(MetaItem),
+    /// A literal.
+    ///
+    /// E.g., `"foo"`, `64`, `true`.
+    Literal(Lit),
+}
+
+/// A spanned compile-time attribute item.
+///
+/// E.g., `#[test]`, `#[derive(..)]`, `#[rustfmt::skip]` or `#[feature = "foo"]`.
+#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
+pub struct MetaItem {
+    pub path: Path,
+    pub kind: MetaItemKind,
+    pub span: Span,
+}
+
+/// A compile-time attribute item.
+///
+/// E.g., `#[test]`, `#[derive(..)]` or `#[feature = "foo"]`.
+#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
+pub enum MetaItemKind {
+    /// Word meta item.
+    ///
+    /// E.g., `test` as in `#[test]`.
+    Word,
+    /// List meta item.
+    ///
+    /// E.g., `derive(..)` as in `#[derive(..)]`.
+    List(Vec<NestedMetaItem>),
+    /// Name value meta item.
+    ///
+    /// E.g., `feature = "foo"` as in `#[feature = "foo"]`.
+    NameValue(Lit),
+}
+
+/// A block (`{ .. }`).
+///
+/// E.g., `{ .. }` as in `fn foo() { .. }`.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct Block {
+    /// The statements in the block.
+    pub stmts: Vec<Stmt>,
+    pub id: NodeId,
+    /// Distinguishes between `unsafe { ... }` and `{ ... }`.
+    pub rules: BlockCheckMode,
+    pub span: Span,
+}
+
+/// A match pattern.
+///
+/// Patterns appear in match statements and some other contexts, such as `let` and `if let`.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct Pat {
+    pub id: NodeId,
+    pub kind: PatKind,
+    pub span: Span,
+    pub tokens: Option<TokenStream>,
+}
+
+impl Pat {
+    /// Attempt reparsing the pattern as a type.
+    /// This is intended for use by diagnostics.
+    pub fn to_ty(&self) -> Option<P<Ty>> {
+        let kind = match &self.kind {
+            // In a type expression `_` is an inference variable.
+            PatKind::Wild => TyKind::Infer,
+            // An IDENT pattern with no binding mode would be valid as path to a type. E.g. `u32`.
+            PatKind::Ident(BindingMode::ByValue(Mutability::Not), ident, None) => {
+                TyKind::Path(None, Path::from_ident(*ident))
+            }
+            PatKind::Path(qself, path) => TyKind::Path(qself.clone(), path.clone()),
+            PatKind::MacCall(mac) => TyKind::MacCall(mac.clone()),
+            // `&mut? P` can be reinterpreted as `&mut? T` where `T` is `P` reparsed as a type.
+            PatKind::Ref(pat, mutbl) => {
+                pat.to_ty().map(|ty| TyKind::Rptr(None, MutTy { ty, mutbl: *mutbl }))?
+            }
+            // A slice/array pattern `[P]` can be reparsed as `[T]`, an unsized array,
+            // when `P` can be reparsed as a type `T`.
+            PatKind::Slice(pats) if pats.len() == 1 => pats[0].to_ty().map(TyKind::Slice)?,
+            // A tuple pattern `(P0, .., Pn)` can be reparsed as `(T0, .., Tn)`
+            // assuming `T0` to `Tn` are all syntactically valid as types.
+            PatKind::Tuple(pats) => {
+                let mut tys = Vec::with_capacity(pats.len());
+                // FIXME(#48994) - could just be collected into an Option<Vec>
+                for pat in pats {
+                    tys.push(pat.to_ty()?);
+                }
+                TyKind::Tup(tys)
+            }
+            _ => return None,
+        };
+
+        Some(P(Ty { kind, id: self.id, span: self.span }))
+    }
+
+    /// Walk top-down and call `it` in each place where a pattern occurs
+    /// starting with the root pattern `walk` is called on. If `it` returns
+    /// false then we will descend no further but siblings will be processed.
+    pub fn walk(&self, it: &mut impl FnMut(&Pat) -> bool) {
+        if !it(self) {
+            return;
+        }
+
+        match &self.kind {
+            // Walk into the pattern associated with `Ident` (if any).
+            PatKind::Ident(_, _, Some(p)) => p.walk(it),
+
+            // Walk into each field of struct.
+            PatKind::Struct(_, fields, _) => fields.iter().for_each(|field| field.pat.walk(it)),
+
+            // Sequence of patterns.
+            PatKind::TupleStruct(_, s) | PatKind::Tuple(s) | PatKind::Slice(s) | PatKind::Or(s) => {
+                s.iter().for_each(|p| p.walk(it))
+            }
+
+            // Trivial wrappers over inner patterns.
+            PatKind::Box(s) | PatKind::Ref(s, _) | PatKind::Paren(s) => s.walk(it),
+
+            // These patterns do not contain subpatterns, skip.
+            PatKind::Wild
+            | PatKind::Rest
+            | PatKind::Lit(_)
+            | PatKind::Range(..)
+            | PatKind::Ident(..)
+            | PatKind::Path(..)
+            | PatKind::MacCall(_) => {}
+        }
+    }
+
+    /// Is this a `..` pattern?
+    pub fn is_rest(&self) -> bool {
+        match self.kind {
+            PatKind::Rest => true,
+            _ => false,
+        }
+    }
+}
+
+/// A single field in a struct pattern
+///
+/// Patterns like the fields of Foo `{ x, ref y, ref mut z }`
+/// are treated the same as` x: x, y: ref y, z: ref mut z`,
+/// except is_shorthand is true
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct FieldPat {
+    /// The identifier for the field
+    pub ident: Ident,
+    /// The pattern the field is destructured to
+    pub pat: P<Pat>,
+    pub is_shorthand: bool,
+    pub attrs: AttrVec,
+    pub id: NodeId,
+    pub span: Span,
+    pub is_placeholder: bool,
+}
+
+#[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy)]
+pub enum BindingMode {
+    ByRef(Mutability),
+    ByValue(Mutability),
+}
+
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub enum RangeEnd {
+    Included(RangeSyntax),
+    Excluded,
+}
+
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub enum RangeSyntax {
+    /// `...`
+    DotDotDot,
+    /// `..=`
+    DotDotEq,
+}
+
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub enum PatKind {
+    /// Represents a wildcard pattern (`_`).
+    Wild,
+
+    /// A `PatKind::Ident` may either be a new bound variable (`ref mut binding @ OPT_SUBPATTERN`),
+    /// or a unit struct/variant pattern, or a const pattern (in the last two cases the third
+    /// field must be `None`). Disambiguation cannot be done with parser alone, so it happens
+    /// during name resolution.
+    Ident(BindingMode, Ident, Option<P<Pat>>),
+
+    /// A struct or struct variant pattern (e.g., `Variant {x, y, ..}`).
+    /// The `bool` is `true` in the presence of a `..`.
+    Struct(Path, Vec<FieldPat>, /* recovered */ bool),
+
+    /// A tuple struct/variant pattern (`Variant(x, y, .., z)`).
+    TupleStruct(Path, Vec<P<Pat>>),
+
+    /// An or-pattern `A | B | C`.
+    /// Invariant: `pats.len() >= 2`.
+    Or(Vec<P<Pat>>),
+
+    /// A possibly qualified path pattern.
+    /// Unqualified path patterns `A::B::C` can legally refer to variants, structs, constants
+    /// or associated constants. Qualified path patterns `<A>::B::C`/`<A as Trait>::B::C` can
+    /// only legally refer to associated constants.
+    Path(Option<QSelf>, Path),
+
+    /// A tuple pattern (`(a, b)`).
+    Tuple(Vec<P<Pat>>),
+
+    /// A `box` pattern.
+    Box(P<Pat>),
+
+    /// A reference pattern (e.g., `&mut (a, b)`).
+    Ref(P<Pat>, Mutability),
+
+    /// A literal.
+    Lit(P<Expr>),
+
+    /// A range pattern (e.g., `1...2`, `1..=2` or `1..2`).
+    Range(Option<P<Expr>>, Option<P<Expr>>, Spanned<RangeEnd>),
+
+    /// A slice pattern `[a, b, c]`.
+    Slice(Vec<P<Pat>>),
+
+    /// A rest pattern `..`.
+    ///
+    /// Syntactically it is valid anywhere.
+    ///
+    /// Semantically however, it only has meaning immediately inside:
+    /// - a slice pattern: `[a, .., b]`,
+    /// - a binding pattern immediately inside a slice pattern: `[a, r @ ..]`,
+    /// - a tuple pattern: `(a, .., b)`,
+    /// - a tuple struct/variant pattern: `$path(a, .., b)`.
+    ///
+    /// In all of these cases, an additional restriction applies,
+    /// only one rest pattern may occur in the pattern sequences.
+    Rest,
+
+    /// Parentheses in patterns used for grouping (i.e., `(PAT)`).
+    Paren(P<Pat>),
+
+    /// A macro pattern; pre-expansion.
+    MacCall(MacCall),
+}
+
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Copy)]
+#[derive(HashStable_Generic, Encodable, Decodable)]
+pub enum Mutability {
+    Mut,
+    Not,
+}
+
+impl Mutability {
+    /// Returns `MutMutable` only if both `self` and `other` are mutable.
+    pub fn and(self, other: Self) -> Self {
+        match self {
+            Mutability::Mut => other,
+            Mutability::Not => Mutability::Not,
+        }
+    }
+
+    pub fn invert(self) -> Self {
+        match self {
+            Mutability::Mut => Mutability::Not,
+            Mutability::Not => Mutability::Mut,
+        }
+    }
+
+    pub fn prefix_str(&self) -> &'static str {
+        match self {
+            Mutability::Mut => "mut ",
+            Mutability::Not => "",
+        }
+    }
+}
+
+/// The kind of borrow in an `AddrOf` expression,
+/// e.g., `&place` or `&raw const place`.
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+#[derive(Encodable, Decodable, HashStable_Generic)]
+pub enum BorrowKind {
+    /// A normal borrow, `&$expr` or `&mut $expr`.
+    /// The resulting type is either `&'a T` or `&'a mut T`
+    /// where `T = typeof($expr)` and `'a` is some lifetime.
+    Ref,
+    /// A raw borrow, `&raw const $expr` or `&raw mut $expr`.
+    /// The resulting type is either `*const T` or `*mut T`
+    /// where `T = typeof($expr)`.
+    Raw,
+}
+
+#[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy)]
+pub enum BinOpKind {
+    /// The `+` operator (addition)
+    Add,
+    /// The `-` operator (subtraction)
+    Sub,
+    /// The `*` operator (multiplication)
+    Mul,
+    /// The `/` operator (division)
+    Div,
+    /// The `%` operator (modulus)
+    Rem,
+    /// The `&&` operator (logical and)
+    And,
+    /// The `||` operator (logical or)
+    Or,
+    /// The `^` operator (bitwise xor)
+    BitXor,
+    /// The `&` operator (bitwise and)
+    BitAnd,
+    /// The `|` operator (bitwise or)
+    BitOr,
+    /// The `<<` operator (shift left)
+    Shl,
+    /// The `>>` operator (shift right)
+    Shr,
+    /// The `==` operator (equality)
+    Eq,
+    /// The `<` operator (less than)
+    Lt,
+    /// The `<=` operator (less than or equal to)
+    Le,
+    /// The `!=` operator (not equal to)
+    Ne,
+    /// The `>=` operator (greater than or equal to)
+    Ge,
+    /// The `>` operator (greater than)
+    Gt,
+}
+
+impl BinOpKind {
+    pub fn to_string(&self) -> &'static str {
+        use BinOpKind::*;
+        match *self {
+            Add => "+",
+            Sub => "-",
+            Mul => "*",
+            Div => "/",
+            Rem => "%",
+            And => "&&",
+            Or => "||",
+            BitXor => "^",
+            BitAnd => "&",
+            BitOr => "|",
+            Shl => "<<",
+            Shr => ">>",
+            Eq => "==",
+            Lt => "<",
+            Le => "<=",
+            Ne => "!=",
+            Ge => ">=",
+            Gt => ">",
+        }
+    }
+    pub fn lazy(&self) -> bool {
+        match *self {
+            BinOpKind::And | BinOpKind::Or => true,
+            _ => false,
+        }
+    }
+
+    pub fn is_shift(&self) -> bool {
+        match *self {
+            BinOpKind::Shl | BinOpKind::Shr => true,
+            _ => false,
+        }
+    }
+
+    pub fn is_comparison(&self) -> bool {
+        use BinOpKind::*;
+        // Note for developers: please keep this as is;
+        // we want compilation to fail if another variant is added.
+        match *self {
+            Eq | Lt | Le | Ne | Gt | Ge => true,
+            And | Or | Add | Sub | Mul | Div | Rem | BitXor | BitAnd | BitOr | Shl | Shr => false,
+        }
+    }
+
+    /// Returns `true` if the binary operator takes its arguments by value
+    pub fn is_by_value(&self) -> bool {
+        !self.is_comparison()
+    }
+}
+
+pub type BinOp = Spanned<BinOpKind>;
+
+/// Unary operator.
+///
+/// Note that `&data` is not an operator, it's an `AddrOf` expression.
+#[derive(Clone, Encodable, Decodable, Debug, Copy)]
+pub enum UnOp {
+    /// The `*` operator for dereferencing
+    Deref,
+    /// The `!` operator for logical inversion
+    Not,
+    /// The `-` operator for negation
+    Neg,
+}
+
+impl UnOp {
+    /// Returns `true` if the unary operator takes its argument by value
+    pub fn is_by_value(u: UnOp) -> bool {
+        match u {
+            UnOp::Neg | UnOp::Not => true,
+            _ => false,
+        }
+    }
+
+    pub fn to_string(op: UnOp) -> &'static str {
+        match op {
+            UnOp::Deref => "*",
+            UnOp::Not => "!",
+            UnOp::Neg => "-",
+        }
+    }
+}
+
+/// A statement
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct Stmt {
+    pub id: NodeId,
+    pub kind: StmtKind,
+    pub span: Span,
+}
+
+impl Stmt {
+    pub fn add_trailing_semicolon(mut self) -> Self {
+        self.kind = match self.kind {
+            StmtKind::Expr(expr) => StmtKind::Semi(expr),
+            StmtKind::MacCall(mac) => StmtKind::MacCall(
+                mac.map(|(mac, _style, attrs)| (mac, MacStmtStyle::Semicolon, attrs)),
+            ),
+            kind => kind,
+        };
+        self
+    }
+
+    pub fn is_item(&self) -> bool {
+        match self.kind {
+            StmtKind::Item(_) => true,
+            _ => false,
+        }
+    }
+
+    pub fn is_expr(&self) -> bool {
+        match self.kind {
+            StmtKind::Expr(_) => true,
+            _ => false,
+        }
+    }
+}
+
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub enum StmtKind {
+    /// A local (let) binding.
+    Local(P<Local>),
+    /// An item definition.
+    Item(P<Item>),
+    /// Expr without trailing semi-colon.
+    Expr(P<Expr>),
+    /// Expr with a trailing semi-colon.
+    Semi(P<Expr>),
+    /// Just a trailing semi-colon.
+    Empty,
+    /// Macro.
+    MacCall(P<(MacCall, MacStmtStyle, AttrVec)>),
+}
+
+#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug)]
+pub enum MacStmtStyle {
+    /// The macro statement had a trailing semicolon (e.g., `foo! { ... };`
+    /// `foo!(...);`, `foo![...];`).
+    Semicolon,
+    /// The macro statement had braces (e.g., `foo! { ... }`).
+    Braces,
+    /// The macro statement had parentheses or brackets and no semicolon (e.g.,
+    /// `foo!(...)`). All of these will end up being converted into macro
+    /// expressions.
+    NoBraces,
+}
+
+/// Local represents a `let` statement, e.g., `let <pat>:<ty> = <expr>;`.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct Local {
+    pub id: NodeId,
+    pub pat: P<Pat>,
+    pub ty: Option<P<Ty>>,
+    /// Initializer expression to set the value, if any.
+    pub init: Option<P<Expr>>,
+    pub span: Span,
+    pub attrs: AttrVec,
+}
+
+/// An arm of a 'match'.
+///
+/// E.g., `0..=10 => { println!("match!") }` as in
+///
+/// ```
+/// match 123 {
+///     0..=10 => { println!("match!") },
+///     _ => { println!("no match!") },
+/// }
+/// ```
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct Arm {
+    pub attrs: Vec<Attribute>,
+    /// Match arm pattern, e.g. `10` in `match foo { 10 => {}, _ => {} }`
+    pub pat: P<Pat>,
+    /// Match arm guard, e.g. `n > 10` in `match foo { n if n > 10 => {}, _ => {} }`
+    pub guard: Option<P<Expr>>,
+    /// Match arm body.
+    pub body: P<Expr>,
+    pub span: Span,
+    pub id: NodeId,
+    pub is_placeholder: bool,
+}
+
+/// Access of a named (e.g., `obj.foo`) or unnamed (e.g., `obj.0`) struct field.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct Field {
+    pub attrs: AttrVec,
+    pub id: NodeId,
+    pub span: Span,
+    pub ident: Ident,
+    pub expr: P<Expr>,
+    pub is_shorthand: bool,
+    pub is_placeholder: bool,
+}
+
+#[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy)]
+pub enum BlockCheckMode {
+    Default,
+    Unsafe(UnsafeSource),
+}
+
+#[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy)]
+pub enum UnsafeSource {
+    CompilerGenerated,
+    UserProvided,
+}
+
+/// A constant (expression) that's not an item or associated item,
+/// but needs its own `DefId` for type-checking, const-eval, etc.
+/// These are usually found nested inside types (e.g., array lengths)
+/// or expressions (e.g., repeat counts), and also used to define
+/// explicit discriminant values for enum variants.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct AnonConst {
+    pub id: NodeId,
+    pub value: P<Expr>,
+}
+
+/// An expression.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct Expr {
+    pub id: NodeId,
+    pub kind: ExprKind,
+    pub span: Span,
+    pub attrs: AttrVec,
+    pub tokens: Option<TokenStream>,
+}
+
+// `Expr` is used a lot. Make sure it doesn't unintentionally get bigger.
+#[cfg(target_arch = "x86_64")]
+rustc_data_structures::static_assert_size!(Expr, 104);
+
+impl Expr {
+    /// Returns `true` if this expression would be valid somewhere that expects a value;
+    /// for example, an `if` condition.
+    pub fn returns(&self) -> bool {
+        if let ExprKind::Block(ref block, _) = self.kind {
+            match block.stmts.last().map(|last_stmt| &last_stmt.kind) {
+                // Implicit return
+                Some(&StmtKind::Expr(_)) => true,
+                Some(&StmtKind::Semi(ref expr)) => {
+                    if let ExprKind::Ret(_) = expr.kind {
+                        // Last statement is explicit return.
+                        true
+                    } else {
+                        false
+                    }
+                }
+                // This is a block that doesn't end in either an implicit or explicit return.
+                _ => false,
+            }
+        } else {
+            // This is not a block, it is a value.
+            true
+        }
+    }
+
+    /// Is this expr either `N`, or `{ N }`.
+    ///
+    /// If this is not the case, name resolution does not resolve `N` when using
+    /// `feature(min_const_generics)` as more complex expressions are not supported.
+    pub fn is_potential_trivial_const_param(&self) -> bool {
+        let this = if let ExprKind::Block(ref block, None) = self.kind {
+            if block.stmts.len() == 1 {
+                if let StmtKind::Expr(ref expr) = block.stmts[0].kind { expr } else { self }
+            } else {
+                self
+            }
+        } else {
+            self
+        };
+
+        if let ExprKind::Path(None, ref path) = this.kind {
+            if path.segments.len() == 1 && path.segments[0].args.is_none() {
+                return true;
+            }
+        }
+
+        false
+    }
+
+    pub fn to_bound(&self) -> Option<GenericBound> {
+        match &self.kind {
+            ExprKind::Path(None, path) => Some(GenericBound::Trait(
+                PolyTraitRef::new(Vec::new(), path.clone(), self.span),
+                TraitBoundModifier::None,
+            )),
+            _ => None,
+        }
+    }
+
+    /// Attempts to reparse as `Ty` (for diagnostic purposes).
+    pub fn to_ty(&self) -> Option<P<Ty>> {
+        let kind = match &self.kind {
+            // Trivial conversions.
+            ExprKind::Path(qself, path) => TyKind::Path(qself.clone(), path.clone()),
+            ExprKind::MacCall(mac) => TyKind::MacCall(mac.clone()),
+
+            ExprKind::Paren(expr) => expr.to_ty().map(TyKind::Paren)?,
+
+            ExprKind::AddrOf(BorrowKind::Ref, mutbl, expr) => {
+                expr.to_ty().map(|ty| TyKind::Rptr(None, MutTy { ty, mutbl: *mutbl }))?
+            }
+
+            ExprKind::Repeat(expr, expr_len) => {
+                expr.to_ty().map(|ty| TyKind::Array(ty, expr_len.clone()))?
+            }
+
+            ExprKind::Array(exprs) if exprs.len() == 1 => exprs[0].to_ty().map(TyKind::Slice)?,
+
+            ExprKind::Tup(exprs) => {
+                let tys = exprs.iter().map(|expr| expr.to_ty()).collect::<Option<Vec<_>>>()?;
+                TyKind::Tup(tys)
+            }
+
+            // If binary operator is `Add` and both `lhs` and `rhs` are trait bounds,
+            // then type of result is trait object.
+            // Otherwise we don't assume the result type.
+            ExprKind::Binary(binop, lhs, rhs) if binop.node == BinOpKind::Add => {
+                if let (Some(lhs), Some(rhs)) = (lhs.to_bound(), rhs.to_bound()) {
+                    TyKind::TraitObject(vec![lhs, rhs], TraitObjectSyntax::None)
+                } else {
+                    return None;
+                }
+            }
+
+            // This expression doesn't look like a type syntactically.
+            _ => return None,
+        };
+
+        Some(P(Ty { kind, id: self.id, span: self.span }))
+    }
+
+    pub fn precedence(&self) -> ExprPrecedence {
+        match self.kind {
+            ExprKind::Box(_) => ExprPrecedence::Box,
+            ExprKind::Array(_) => ExprPrecedence::Array,
+            ExprKind::Call(..) => ExprPrecedence::Call,
+            ExprKind::MethodCall(..) => ExprPrecedence::MethodCall,
+            ExprKind::Tup(_) => ExprPrecedence::Tup,
+            ExprKind::Binary(op, ..) => ExprPrecedence::Binary(op.node),
+            ExprKind::Unary(..) => ExprPrecedence::Unary,
+            ExprKind::Lit(_) => ExprPrecedence::Lit,
+            ExprKind::Type(..) | ExprKind::Cast(..) => ExprPrecedence::Cast,
+            ExprKind::Let(..) => ExprPrecedence::Let,
+            ExprKind::If(..) => ExprPrecedence::If,
+            ExprKind::While(..) => ExprPrecedence::While,
+            ExprKind::ForLoop(..) => ExprPrecedence::ForLoop,
+            ExprKind::Loop(..) => ExprPrecedence::Loop,
+            ExprKind::Match(..) => ExprPrecedence::Match,
+            ExprKind::Closure(..) => ExprPrecedence::Closure,
+            ExprKind::Block(..) => ExprPrecedence::Block,
+            ExprKind::TryBlock(..) => ExprPrecedence::TryBlock,
+            ExprKind::Async(..) => ExprPrecedence::Async,
+            ExprKind::Await(..) => ExprPrecedence::Await,
+            ExprKind::Assign(..) => ExprPrecedence::Assign,
+            ExprKind::AssignOp(..) => ExprPrecedence::AssignOp,
+            ExprKind::Field(..) => ExprPrecedence::Field,
+            ExprKind::Index(..) => ExprPrecedence::Index,
+            ExprKind::Range(..) => ExprPrecedence::Range,
+            ExprKind::Path(..) => ExprPrecedence::Path,
+            ExprKind::AddrOf(..) => ExprPrecedence::AddrOf,
+            ExprKind::Break(..) => ExprPrecedence::Break,
+            ExprKind::Continue(..) => ExprPrecedence::Continue,
+            ExprKind::Ret(..) => ExprPrecedence::Ret,
+            ExprKind::InlineAsm(..) | ExprKind::LlvmInlineAsm(..) => ExprPrecedence::InlineAsm,
+            ExprKind::MacCall(..) => ExprPrecedence::Mac,
+            ExprKind::Struct(..) => ExprPrecedence::Struct,
+            ExprKind::Repeat(..) => ExprPrecedence::Repeat,
+            ExprKind::Paren(..) => ExprPrecedence::Paren,
+            ExprKind::Try(..) => ExprPrecedence::Try,
+            ExprKind::Yield(..) => ExprPrecedence::Yield,
+            ExprKind::Err => ExprPrecedence::Err,
+        }
+    }
+}
+
+/// Limit types of a range (inclusive or exclusive)
+#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug)]
+pub enum RangeLimits {
+    /// Inclusive at the beginning, exclusive at the end
+    HalfOpen,
+    /// Inclusive at the beginning and end
+    Closed,
+}
+
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub enum ExprKind {
+    /// A `box x` expression.
+    Box(P<Expr>),
+    /// An array (`[a, b, c, d]`)
+    Array(Vec<P<Expr>>),
+    /// A function call
+    ///
+    /// The first field resolves to the function itself,
+    /// and the second field is the list of arguments.
+    /// This also represents calling the constructor of
+    /// tuple-like ADTs such as tuple structs and enum variants.
+    Call(P<Expr>, Vec<P<Expr>>),
+    /// A method call (`x.foo::<'static, Bar, Baz>(a, b, c, d)`)
+    ///
+    /// The `PathSegment` represents the method name and its generic arguments
+    /// (within the angle brackets).
+    /// The first element of the vector of an `Expr` is the expression that evaluates
+    /// to the object on which the method is being called on (the receiver),
+    /// and the remaining elements are the rest of the arguments.
+    /// Thus, `x.foo::<Bar, Baz>(a, b, c, d)` is represented as
+    /// `ExprKind::MethodCall(PathSegment { foo, [Bar, Baz] }, [x, a, b, c, d])`.
+    /// This `Span` is the span of the function, without the dot and receiver
+    /// (e.g. `foo(a, b)` in `x.foo(a, b)`
+    MethodCall(PathSegment, Vec<P<Expr>>, Span),
+    /// A tuple (e.g., `(a, b, c, d)`).
+    Tup(Vec<P<Expr>>),
+    /// A binary operation (e.g., `a + b`, `a * b`).
+    Binary(BinOp, P<Expr>, P<Expr>),
+    /// A unary operation (e.g., `!x`, `*x`).
+    Unary(UnOp, P<Expr>),
+    /// A literal (e.g., `1`, `"foo"`).
+    Lit(Lit),
+    /// A cast (e.g., `foo as f64`).
+    Cast(P<Expr>, P<Ty>),
+    /// A type ascription (e.g., `42: usize`).
+    Type(P<Expr>, P<Ty>),
+    /// A `let pat = expr` expression that is only semantically allowed in the condition
+    /// of `if` / `while` expressions. (e.g., `if let 0 = x { .. }`).
+    Let(P<Pat>, P<Expr>),
+    /// An `if` block, with an optional `else` block.
+    ///
+    /// `if expr { block } else { expr }`
+    If(P<Expr>, P<Block>, Option<P<Expr>>),
+    /// A while loop, with an optional label.
+    ///
+    /// `'label: while expr { block }`
+    While(P<Expr>, P<Block>, Option<Label>),
+    /// A `for` loop, with an optional label.
+    ///
+    /// `'label: for pat in expr { block }`
+    ///
+    /// This is desugared to a combination of `loop` and `match` expressions.
+    ForLoop(P<Pat>, P<Expr>, P<Block>, Option<Label>),
+    /// Conditionless loop (can be exited with `break`, `continue`, or `return`).
+    ///
+    /// `'label: loop { block }`
+    Loop(P<Block>, Option<Label>),
+    /// A `match` block.
+    Match(P<Expr>, Vec<Arm>),
+    /// A closure (e.g., `move |a, b, c| a + b + c`).
+    ///
+    /// The final span is the span of the argument block `|...|`.
+    Closure(CaptureBy, Async, Movability, P<FnDecl>, P<Expr>, Span),
+    /// A block (`'label: { ... }`).
+    Block(P<Block>, Option<Label>),
+    /// An async block (`async move { ... }`).
+    ///
+    /// The `NodeId` is the `NodeId` for the closure that results from
+    /// desugaring an async block, just like the NodeId field in the
+    /// `Async::Yes` variant. This is necessary in order to create a def for the
+    /// closure which can be used as a parent of any child defs. Defs
+    /// created during lowering cannot be made the parent of any other
+    /// preexisting defs.
+    Async(CaptureBy, NodeId, P<Block>),
+    /// An await expression (`my_future.await`).
+    Await(P<Expr>),
+
+    /// A try block (`try { ... }`).
+    TryBlock(P<Block>),
+
+    /// An assignment (`a = foo()`).
+    /// The `Span` argument is the span of the `=` token.
+    Assign(P<Expr>, P<Expr>, Span),
+    /// An assignment with an operator.
+    ///
+    /// E.g., `a += 1`.
+    AssignOp(BinOp, P<Expr>, P<Expr>),
+    /// Access of a named (e.g., `obj.foo`) or unnamed (e.g., `obj.0`) struct field.
+    Field(P<Expr>, Ident),
+    /// An indexing operation (e.g., `foo[2]`).
+    Index(P<Expr>, P<Expr>),
+    /// A range (e.g., `1..2`, `1..`, `..2`, `1..=2`, `..=2`).
+    Range(Option<P<Expr>>, Option<P<Expr>>, RangeLimits),
+
+    /// Variable reference, possibly containing `::` and/or type
+    /// parameters (e.g., `foo::bar::<baz>`).
+    ///
+    /// Optionally "qualified" (e.g., `<Vec<T> as SomeTrait>::SomeType`).
+    Path(Option<QSelf>, Path),
+
+    /// A referencing operation (`&a`, `&mut a`, `&raw const a` or `&raw mut a`).
+    AddrOf(BorrowKind, Mutability, P<Expr>),
+    /// A `break`, with an optional label to break, and an optional expression.
+    Break(Option<Label>, Option<P<Expr>>),
+    /// A `continue`, with an optional label.
+    Continue(Option<Label>),
+    /// A `return`, with an optional value to be returned.
+    Ret(Option<P<Expr>>),
+
+    /// Output of the `asm!()` macro.
+    InlineAsm(P<InlineAsm>),
+    /// Output of the `llvm_asm!()` macro.
+    LlvmInlineAsm(P<LlvmInlineAsm>),
+
+    /// A macro invocation; pre-expansion.
+    MacCall(MacCall),
+
+    /// A struct literal expression.
+    ///
+    /// E.g., `Foo {x: 1, y: 2}`, or `Foo {x: 1, .. base}`,
+    /// where `base` is the `Option<Expr>`.
+    Struct(Path, Vec<Field>, Option<P<Expr>>),
+
+    /// An array literal constructed from one repeated element.
+    ///
+    /// E.g., `[1; 5]`. The expression is the element to be
+    /// repeated; the constant is the number of times to repeat it.
+    Repeat(P<Expr>, AnonConst),
+
+    /// No-op: used solely so we can pretty-print faithfully.
+    Paren(P<Expr>),
+
+    /// A try expression (`expr?`).
+    Try(P<Expr>),
+
+    /// A `yield`, with an optional value to be yielded.
+    Yield(Option<P<Expr>>),
+
+    /// Placeholder for an expression that wasn't syntactically well formed in some way.
+    Err,
+}
+
+/// The explicit `Self` type in a "qualified path". The actual
+/// path, including the trait and the associated item, is stored
+/// separately. `position` represents the index of the associated
+/// item qualified with this `Self` type.
+///
+/// ```ignore (only-for-syntax-highlight)
+/// <Vec<T> as a::b::Trait>::AssociatedItem
+///  ^~~~~     ~~~~~~~~~~~~~~^
+///  ty        position = 3
+///
+/// <Vec<T>>::AssociatedItem
+///  ^~~~~    ^
+///  ty       position = 0
+/// ```
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct QSelf {
+    pub ty: P<Ty>,
+
+    /// The span of `a::b::Trait` in a path like `<Vec<T> as
+    /// a::b::Trait>::AssociatedItem`; in the case where `position ==
+    /// 0`, this is an empty span.
+    pub path_span: Span,
+    pub position: usize,
+}
+
+/// A capture clause used in closures and `async` blocks.
+#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
+pub enum CaptureBy {
+    /// `move |x| y + x`.
+    Value,
+    /// `move` keyword was not specified.
+    Ref,
+}
+
+/// The movability of a generator / closure literal:
+/// whether a generator contains self-references, causing it to be `!Unpin`.
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable, Debug, Copy)]
+#[derive(HashStable_Generic)]
+pub enum Movability {
+    /// May contain self-references, `!Unpin`.
+    Static,
+    /// Must not contain self-references, `Unpin`.
+    Movable,
+}
+
+/// Represents a macro invocation. The `path` indicates which macro
+/// is being invoked, and the `args` are arguments passed to it.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct MacCall {
+    pub path: Path,
+    pub args: P<MacArgs>,
+    pub prior_type_ascription: Option<(Span, bool)>,
+}
+
+impl MacCall {
+    pub fn span(&self) -> Span {
+        self.path.span.to(self.args.span().unwrap_or(self.path.span))
+    }
+}
+
+/// Arguments passed to an attribute or a function-like macro.
+#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
+pub enum MacArgs {
+    /// No arguments - `#[attr]`.
+    Empty,
+    /// Delimited arguments - `#[attr()/[]/{}]` or `mac!()/[]/{}`.
+    Delimited(DelimSpan, MacDelimiter, TokenStream),
+    /// Arguments of a key-value attribute - `#[attr = "value"]`.
+    Eq(
+        /// Span of the `=` token.
+        Span,
+        /// Token stream of the "value".
+        TokenStream,
+    ),
+}
+
+impl MacArgs {
+    pub fn delim(&self) -> DelimToken {
+        match self {
+            MacArgs::Delimited(_, delim, _) => delim.to_token(),
+            MacArgs::Empty | MacArgs::Eq(..) => token::NoDelim,
+        }
+    }
+
+    pub fn span(&self) -> Option<Span> {
+        match *self {
+            MacArgs::Empty => None,
+            MacArgs::Delimited(dspan, ..) => Some(dspan.entire()),
+            MacArgs::Eq(eq_span, ref tokens) => Some(eq_span.to(tokens.span().unwrap_or(eq_span))),
+        }
+    }
+
+    /// Tokens inside the delimiters or after `=`.
+    /// Proc macros see these tokens, for example.
+    pub fn inner_tokens(&self) -> TokenStream {
+        match self {
+            MacArgs::Empty => TokenStream::default(),
+            MacArgs::Delimited(.., tokens) | MacArgs::Eq(.., tokens) => tokens.clone(),
+        }
+    }
+
+    /// Tokens together with the delimiters or `=`.
+    /// Use of this method generally means that something suboptimal or hacky is happening.
+    pub fn outer_tokens(&self) -> TokenStream {
+        match *self {
+            MacArgs::Empty => TokenStream::default(),
+            MacArgs::Delimited(dspan, delim, ref tokens) => {
+                TokenTree::Delimited(dspan, delim.to_token(), tokens.clone()).into()
+            }
+            MacArgs::Eq(eq_span, ref tokens) => {
+                iter::once(TokenTree::token(token::Eq, eq_span)).chain(tokens.trees()).collect()
+            }
+        }
+    }
+
+    /// Whether a macro with these arguments needs a semicolon
+    /// when used as a standalone item or statement.
+    pub fn need_semicolon(&self) -> bool {
+        !matches!(self, MacArgs::Delimited(_, MacDelimiter::Brace, _))
+    }
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)]
+pub enum MacDelimiter {
+    Parenthesis,
+    Bracket,
+    Brace,
+}
+
+impl MacDelimiter {
+    pub fn to_token(self) -> DelimToken {
+        match self {
+            MacDelimiter::Parenthesis => DelimToken::Paren,
+            MacDelimiter::Bracket => DelimToken::Bracket,
+            MacDelimiter::Brace => DelimToken::Brace,
+        }
+    }
+
+    pub fn from_token(delim: DelimToken) -> Option<MacDelimiter> {
+        match delim {
+            token::Paren => Some(MacDelimiter::Parenthesis),
+            token::Bracket => Some(MacDelimiter::Bracket),
+            token::Brace => Some(MacDelimiter::Brace),
+            token::NoDelim => None,
+        }
+    }
+}
+
+/// Represents a macro definition.
+#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
+pub struct MacroDef {
+    pub body: P<MacArgs>,
+    /// `true` if macro was defined with `macro_rules`.
+    pub macro_rules: bool,
+}
+
+#[derive(Clone, Encodable, Decodable, Debug, Copy, Hash, Eq, PartialEq)]
+#[derive(HashStable_Generic)]
+pub enum StrStyle {
+    /// A regular string, like `"foo"`.
+    Cooked,
+    /// A raw string, like `r##"foo"##`.
+    ///
+    /// The value is the number of `#` symbols used.
+    Raw(u16),
+}
+
+/// An AST literal.
+#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
+pub struct Lit {
+    /// The original literal token as written in source code.
+    pub token: token::Lit,
+    /// The "semantic" representation of the literal lowered from the original tokens.
+    /// Strings are unescaped, hexadecimal forms are eliminated, etc.
+    /// FIXME: Remove this and only create the semantic representation during lowering to HIR.
+    pub kind: LitKind,
+    pub span: Span,
+}
+
+/// Same as `Lit`, but restricted to string literals.
+#[derive(Clone, Copy, Encodable, Decodable, Debug)]
+pub struct StrLit {
+    /// The original literal token as written in source code.
+    pub style: StrStyle,
+    pub symbol: Symbol,
+    pub suffix: Option<Symbol>,
+    pub span: Span,
+    /// The unescaped "semantic" representation of the literal lowered from the original token.
+    /// FIXME: Remove this and only create the semantic representation during lowering to HIR.
+    pub symbol_unescaped: Symbol,
+}
+
+impl StrLit {
+    pub fn as_lit(&self) -> Lit {
+        let token_kind = match self.style {
+            StrStyle::Cooked => token::Str,
+            StrStyle::Raw(n) => token::StrRaw(n),
+        };
+        Lit {
+            token: token::Lit::new(token_kind, self.symbol, self.suffix),
+            span: self.span,
+            kind: LitKind::Str(self.symbol_unescaped, self.style),
+        }
+    }
+}
+
+/// Type of the integer literal based on provided suffix.
+#[derive(Clone, Copy, Encodable, Decodable, Debug, Hash, Eq, PartialEq)]
+#[derive(HashStable_Generic)]
+pub enum LitIntType {
+    /// e.g. `42_i32`.
+    Signed(IntTy),
+    /// e.g. `42_u32`.
+    Unsigned(UintTy),
+    /// e.g. `42`.
+    Unsuffixed,
+}
+
+/// Type of the float literal based on provided suffix.
+#[derive(Clone, Copy, Encodable, Decodable, Debug, Hash, Eq, PartialEq)]
+#[derive(HashStable_Generic)]
+pub enum LitFloatType {
+    /// A float literal with a suffix (`1f32` or `1E10f32`).
+    Suffixed(FloatTy),
+    /// A float literal without a suffix (`1.0 or 1.0E10`).
+    Unsuffixed,
+}
+
+/// Literal kind.
+///
+/// E.g., `"foo"`, `42`, `12.34`, or `bool`.
+#[derive(Clone, Encodable, Decodable, Debug, Hash, Eq, PartialEq, HashStable_Generic)]
+pub enum LitKind {
+    /// A string literal (`"foo"`).
+    Str(Symbol, StrStyle),
+    /// A byte string (`b"foo"`).
+    ByteStr(Lrc<Vec<u8>>),
+    /// A byte char (`b'f'`).
+    Byte(u8),
+    /// A character literal (`'a'`).
+    Char(char),
+    /// An integer literal (`1`).
+    Int(u128, LitIntType),
+    /// A float literal (`1f64` or `1E10f64`).
+    Float(Symbol, LitFloatType),
+    /// A boolean literal.
+    Bool(bool),
+    /// Placeholder for a literal that wasn't well-formed in some way.
+    Err(Symbol),
+}
+
+impl LitKind {
+    /// Returns `true` if this literal is a string.
+    pub fn is_str(&self) -> bool {
+        match *self {
+            LitKind::Str(..) => true,
+            _ => false,
+        }
+    }
+
+    /// Returns `true` if this literal is byte literal string.
+    pub fn is_bytestr(&self) -> bool {
+        match self {
+            LitKind::ByteStr(_) => true,
+            _ => false,
+        }
+    }
+
+    /// Returns `true` if this is a numeric literal.
+    pub fn is_numeric(&self) -> bool {
+        match *self {
+            LitKind::Int(..) | LitKind::Float(..) => true,
+            _ => false,
+        }
+    }
+
+    /// Returns `true` if this literal has no suffix.
+    /// Note: this will return true for literals with prefixes such as raw strings and byte strings.
+    pub fn is_unsuffixed(&self) -> bool {
+        !self.is_suffixed()
+    }
+
+    /// Returns `true` if this literal has a suffix.
+    pub fn is_suffixed(&self) -> bool {
+        match *self {
+            // suffixed variants
+            LitKind::Int(_, LitIntType::Signed(..) | LitIntType::Unsigned(..))
+            | LitKind::Float(_, LitFloatType::Suffixed(..)) => true,
+            // unsuffixed variants
+            LitKind::Str(..)
+            | LitKind::ByteStr(..)
+            | LitKind::Byte(..)
+            | LitKind::Char(..)
+            | LitKind::Int(_, LitIntType::Unsuffixed)
+            | LitKind::Float(_, LitFloatType::Unsuffixed)
+            | LitKind::Bool(..)
+            | LitKind::Err(..) => false,
+        }
+    }
+}
+
+// N.B., If you change this, you'll probably want to change the corresponding
+// type structure in `middle/ty.rs` as well.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct MutTy {
+    pub ty: P<Ty>,
+    pub mutbl: Mutability,
+}
+
+/// Represents a function's signature in a trait declaration,
+/// trait implementation, or free function.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct FnSig {
+    pub header: FnHeader,
+    pub decl: P<FnDecl>,
+    pub span: Span,
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+#[derive(Encodable, Decodable, HashStable_Generic)]
+pub enum FloatTy {
+    F32,
+    F64,
+}
+
+impl FloatTy {
+    pub fn name_str(self) -> &'static str {
+        match self {
+            FloatTy::F32 => "f32",
+            FloatTy::F64 => "f64",
+        }
+    }
+
+    pub fn name(self) -> Symbol {
+        match self {
+            FloatTy::F32 => sym::f32,
+            FloatTy::F64 => sym::f64,
+        }
+    }
+
+    pub fn bit_width(self) -> u64 {
+        match self {
+            FloatTy::F32 => 32,
+            FloatTy::F64 => 64,
+        }
+    }
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+#[derive(Encodable, Decodable, HashStable_Generic)]
+pub enum IntTy {
+    Isize,
+    I8,
+    I16,
+    I32,
+    I64,
+    I128,
+}
+
+impl IntTy {
+    pub fn name_str(&self) -> &'static str {
+        match *self {
+            IntTy::Isize => "isize",
+            IntTy::I8 => "i8",
+            IntTy::I16 => "i16",
+            IntTy::I32 => "i32",
+            IntTy::I64 => "i64",
+            IntTy::I128 => "i128",
+        }
+    }
+
+    pub fn name(&self) -> Symbol {
+        match *self {
+            IntTy::Isize => sym::isize,
+            IntTy::I8 => sym::i8,
+            IntTy::I16 => sym::i16,
+            IntTy::I32 => sym::i32,
+            IntTy::I64 => sym::i64,
+            IntTy::I128 => sym::i128,
+        }
+    }
+
+    pub fn val_to_string(&self, val: i128) -> String {
+        // Cast to a `u128` so we can correctly print `INT128_MIN`. All integral types
+        // are parsed as `u128`, so we wouldn't want to print an extra negative
+        // sign.
+        format!("{}{}", val as u128, self.name_str())
+    }
+
+    pub fn bit_width(&self) -> Option<u64> {
+        Some(match *self {
+            IntTy::Isize => return None,
+            IntTy::I8 => 8,
+            IntTy::I16 => 16,
+            IntTy::I32 => 32,
+            IntTy::I64 => 64,
+            IntTy::I128 => 128,
+        })
+    }
+
+    pub fn normalize(&self, target_width: u32) -> Self {
+        match self {
+            IntTy::Isize => match target_width {
+                16 => IntTy::I16,
+                32 => IntTy::I32,
+                64 => IntTy::I64,
+                _ => unreachable!(),
+            },
+            _ => *self,
+        }
+    }
+}
+
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Debug)]
+#[derive(Encodable, Decodable, HashStable_Generic)]
+pub enum UintTy {
+    Usize,
+    U8,
+    U16,
+    U32,
+    U64,
+    U128,
+}
+
+impl UintTy {
+    pub fn name_str(&self) -> &'static str {
+        match *self {
+            UintTy::Usize => "usize",
+            UintTy::U8 => "u8",
+            UintTy::U16 => "u16",
+            UintTy::U32 => "u32",
+            UintTy::U64 => "u64",
+            UintTy::U128 => "u128",
+        }
+    }
+
+    pub fn name(&self) -> Symbol {
+        match *self {
+            UintTy::Usize => sym::usize,
+            UintTy::U8 => sym::u8,
+            UintTy::U16 => sym::u16,
+            UintTy::U32 => sym::u32,
+            UintTy::U64 => sym::u64,
+            UintTy::U128 => sym::u128,
+        }
+    }
+
+    pub fn val_to_string(&self, val: u128) -> String {
+        format!("{}{}", val, self.name_str())
+    }
+
+    pub fn bit_width(&self) -> Option<u64> {
+        Some(match *self {
+            UintTy::Usize => return None,
+            UintTy::U8 => 8,
+            UintTy::U16 => 16,
+            UintTy::U32 => 32,
+            UintTy::U64 => 64,
+            UintTy::U128 => 128,
+        })
+    }
+
+    pub fn normalize(&self, target_width: u32) -> Self {
+        match self {
+            UintTy::Usize => match target_width {
+                16 => UintTy::U16,
+                32 => UintTy::U32,
+                64 => UintTy::U64,
+                _ => unreachable!(),
+            },
+            _ => *self,
+        }
+    }
+}
+
+/// A constraint on an associated type (e.g., `A = Bar` in `Foo<A = Bar>` or
+/// `A: TraitA + TraitB` in `Foo<A: TraitA + TraitB>`).
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct AssocTyConstraint {
+    pub id: NodeId,
+    pub ident: Ident,
+    pub kind: AssocTyConstraintKind,
+    pub span: Span,
+}
+
+/// The kinds of an `AssocTyConstraint`.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub enum AssocTyConstraintKind {
+    /// E.g., `A = Bar` in `Foo<A = Bar>`.
+    Equality { ty: P<Ty> },
+    /// E.g. `A: TraitA + TraitB` in `Foo<A: TraitA + TraitB>`.
+    Bound { bounds: GenericBounds },
+}
+
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct Ty {
+    pub id: NodeId,
+    pub kind: TyKind,
+    pub span: Span,
+}
+
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct BareFnTy {
+    pub unsafety: Unsafe,
+    pub ext: Extern,
+    pub generic_params: Vec<GenericParam>,
+    pub decl: P<FnDecl>,
+}
+
+/// The various kinds of type recognized by the compiler.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub enum TyKind {
+    /// A variable-length slice (`[T]`).
+    Slice(P<Ty>),
+    /// A fixed length array (`[T; n]`).
+    Array(P<Ty>, AnonConst),
+    /// A raw pointer (`*const T` or `*mut T`).
+    Ptr(MutTy),
+    /// A reference (`&'a T` or `&'a mut T`).
+    Rptr(Option<Lifetime>, MutTy),
+    /// A bare function (e.g., `fn(usize) -> bool`).
+    BareFn(P<BareFnTy>),
+    /// The never type (`!`).
+    Never,
+    /// A tuple (`(A, B, C, D,...)`).
+    Tup(Vec<P<Ty>>),
+    /// A path (`module::module::...::Type`), optionally
+    /// "qualified", e.g., `<Vec<T> as SomeTrait>::SomeType`.
+    ///
+    /// Type parameters are stored in the `Path` itself.
+    Path(Option<QSelf>, Path),
+    /// A trait object type `Bound1 + Bound2 + Bound3`
+    /// where `Bound` is a trait or a lifetime.
+    TraitObject(GenericBounds, TraitObjectSyntax),
+    /// An `impl Bound1 + Bound2 + Bound3` type
+    /// where `Bound` is a trait or a lifetime.
+    ///
+    /// The `NodeId` exists to prevent lowering from having to
+    /// generate `NodeId`s on the fly, which would complicate
+    /// the generation of opaque `type Foo = impl Trait` items significantly.
+    ImplTrait(NodeId, GenericBounds),
+    /// No-op; kept solely so that we can pretty-print faithfully.
+    Paren(P<Ty>),
+    /// Unused for now.
+    Typeof(AnonConst),
+    /// This means the type should be inferred instead of it having been
+    /// specified. This can appear anywhere in a type.
+    Infer,
+    /// Inferred type of a `self` or `&self` argument in a method.
+    ImplicitSelf,
+    /// A macro in the type position.
+    MacCall(MacCall),
+    /// Placeholder for a kind that has failed to be defined.
+    Err,
+    /// Placeholder for a `va_list`.
+    CVarArgs,
+}
+
+impl TyKind {
+    pub fn is_implicit_self(&self) -> bool {
+        if let TyKind::ImplicitSelf = *self { true } else { false }
+    }
+
+    pub fn is_unit(&self) -> bool {
+        if let TyKind::Tup(ref tys) = *self { tys.is_empty() } else { false }
+    }
+}
+
+/// Syntax used to declare a trait object.
+#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug)]
+pub enum TraitObjectSyntax {
+    Dyn,
+    None,
+}
+
+/// Inline assembly operand explicit register or register class.
+///
+/// E.g., `"eax"` as in `asm!("mov eax, 2", out("eax") result)`.
+#[derive(Clone, Copy, Encodable, Decodable, Debug)]
+pub enum InlineAsmRegOrRegClass {
+    Reg(Symbol),
+    RegClass(Symbol),
+}
+
+bitflags::bitflags! {
+    #[derive(Encodable, Decodable, HashStable_Generic)]
+    pub struct InlineAsmOptions: u8 {
+        const PURE = 1 << 0;
+        const NOMEM = 1 << 1;
+        const READONLY = 1 << 2;
+        const PRESERVES_FLAGS = 1 << 3;
+        const NORETURN = 1 << 4;
+        const NOSTACK = 1 << 5;
+        const ATT_SYNTAX = 1 << 6;
+    }
+}
+
+#[derive(Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
+pub enum InlineAsmTemplatePiece {
+    String(String),
+    Placeholder { operand_idx: usize, modifier: Option<char>, span: Span },
+}
+
+impl fmt::Display for InlineAsmTemplatePiece {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Self::String(s) => {
+                for c in s.chars() {
+                    match c {
+                        '{' => f.write_str("{{")?,
+                        '}' => f.write_str("}}")?,
+                        _ => c.fmt(f)?,
+                    }
+                }
+                Ok(())
+            }
+            Self::Placeholder { operand_idx, modifier: Some(modifier), .. } => {
+                write!(f, "{{{}:{}}}", operand_idx, modifier)
+            }
+            Self::Placeholder { operand_idx, modifier: None, .. } => {
+                write!(f, "{{{}}}", operand_idx)
+            }
+        }
+    }
+}
+
+impl InlineAsmTemplatePiece {
+    /// Rebuilds the asm template string from its pieces.
+    pub fn to_string(s: &[Self]) -> String {
+        use fmt::Write;
+        let mut out = String::new();
+        for p in s.iter() {
+            let _ = write!(out, "{}", p);
+        }
+        out
+    }
+}
+
+/// Inline assembly operand.
+///
+/// E.g., `out("eax") result` as in `asm!("mov eax, 2", out("eax") result)`.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub enum InlineAsmOperand {
+    In {
+        reg: InlineAsmRegOrRegClass,
+        expr: P<Expr>,
+    },
+    Out {
+        reg: InlineAsmRegOrRegClass,
+        late: bool,
+        expr: Option<P<Expr>>,
+    },
+    InOut {
+        reg: InlineAsmRegOrRegClass,
+        late: bool,
+        expr: P<Expr>,
+    },
+    SplitInOut {
+        reg: InlineAsmRegOrRegClass,
+        late: bool,
+        in_expr: P<Expr>,
+        out_expr: Option<P<Expr>>,
+    },
+    Const {
+        expr: P<Expr>,
+    },
+    Sym {
+        expr: P<Expr>,
+    },
+}
+
+/// Inline assembly.
+///
+/// E.g., `asm!("NOP");`.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct InlineAsm {
+    pub template: Vec<InlineAsmTemplatePiece>,
+    pub operands: Vec<(InlineAsmOperand, Span)>,
+    pub options: InlineAsmOptions,
+    pub line_spans: Vec<Span>,
+}
+
+/// Inline assembly dialect.
+///
+/// E.g., `"intel"` as in `llvm_asm!("mov eax, 2" : "={eax}"(result) : : : "intel")`.
+#[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy, HashStable_Generic)]
+pub enum LlvmAsmDialect {
+    Att,
+    Intel,
+}
+
+/// LLVM-style inline assembly.
+///
+/// E.g., `"={eax}"(result)` as in `llvm_asm!("mov eax, 2" : "={eax}"(result) : : : "intel")`.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct LlvmInlineAsmOutput {
+    pub constraint: Symbol,
+    pub expr: P<Expr>,
+    pub is_rw: bool,
+    pub is_indirect: bool,
+}
+
+/// LLVM-style inline assembly.
+///
+/// E.g., `llvm_asm!("NOP");`.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct LlvmInlineAsm {
+    pub asm: Symbol,
+    pub asm_str_style: StrStyle,
+    pub outputs: Vec<LlvmInlineAsmOutput>,
+    pub inputs: Vec<(Symbol, P<Expr>)>,
+    pub clobbers: Vec<Symbol>,
+    pub volatile: bool,
+    pub alignstack: bool,
+    pub dialect: LlvmAsmDialect,
+}
+
+/// A parameter in a function header.
+///
+/// E.g., `bar: usize` as in `fn foo(bar: usize)`.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct Param {
+    pub attrs: AttrVec,
+    pub ty: P<Ty>,
+    pub pat: P<Pat>,
+    pub id: NodeId,
+    pub span: Span,
+    pub is_placeholder: bool,
+}
+
+/// Alternative representation for `Arg`s describing `self` parameter of methods.
+///
+/// E.g., `&mut self` as in `fn foo(&mut self)`.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub enum SelfKind {
+    /// `self`, `mut self`
+    Value(Mutability),
+    /// `&'lt self`, `&'lt mut self`
+    Region(Option<Lifetime>, Mutability),
+    /// `self: TYPE`, `mut self: TYPE`
+    Explicit(P<Ty>, Mutability),
+}
+
+pub type ExplicitSelf = Spanned<SelfKind>;
+
+impl Param {
+    /// Attempts to cast parameter to `ExplicitSelf`.
+    pub fn to_self(&self) -> Option<ExplicitSelf> {
+        if let PatKind::Ident(BindingMode::ByValue(mutbl), ident, _) = self.pat.kind {
+            if ident.name == kw::SelfLower {
+                return match self.ty.kind {
+                    TyKind::ImplicitSelf => Some(respan(self.pat.span, SelfKind::Value(mutbl))),
+                    TyKind::Rptr(lt, MutTy { ref ty, mutbl }) if ty.kind.is_implicit_self() => {
+                        Some(respan(self.pat.span, SelfKind::Region(lt, mutbl)))
+                    }
+                    _ => Some(respan(
+                        self.pat.span.to(self.ty.span),
+                        SelfKind::Explicit(self.ty.clone(), mutbl),
+                    )),
+                };
+            }
+        }
+        None
+    }
+
+    /// Returns `true` if parameter is `self`.
+    pub fn is_self(&self) -> bool {
+        if let PatKind::Ident(_, ident, _) = self.pat.kind {
+            ident.name == kw::SelfLower
+        } else {
+            false
+        }
+    }
+
+    /// Builds a `Param` object from `ExplicitSelf`.
+    pub fn from_self(attrs: AttrVec, eself: ExplicitSelf, eself_ident: Ident) -> Param {
+        let span = eself.span.to(eself_ident.span);
+        let infer_ty = P(Ty { id: DUMMY_NODE_ID, kind: TyKind::ImplicitSelf, span });
+        let param = |mutbl, ty| Param {
+            attrs,
+            pat: P(Pat {
+                id: DUMMY_NODE_ID,
+                kind: PatKind::Ident(BindingMode::ByValue(mutbl), eself_ident, None),
+                span,
+                tokens: None,
+            }),
+            span,
+            ty,
+            id: DUMMY_NODE_ID,
+            is_placeholder: false,
+        };
+        match eself.node {
+            SelfKind::Explicit(ty, mutbl) => param(mutbl, ty),
+            SelfKind::Value(mutbl) => param(mutbl, infer_ty),
+            SelfKind::Region(lt, mutbl) => param(
+                Mutability::Not,
+                P(Ty {
+                    id: DUMMY_NODE_ID,
+                    kind: TyKind::Rptr(lt, MutTy { ty: infer_ty, mutbl }),
+                    span,
+                }),
+            ),
+        }
+    }
+}
+
+/// A signature (not the body) of a function declaration.
+///
+/// E.g., `fn foo(bar: baz)`.
+///
+/// Please note that it's different from `FnHeader` structure
+/// which contains metadata about function safety, asyncness, constness and ABI.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct FnDecl {
+    pub inputs: Vec<Param>,
+    pub output: FnRetTy,
+}
+
+impl FnDecl {
+    pub fn get_self(&self) -> Option<ExplicitSelf> {
+        self.inputs.get(0).and_then(Param::to_self)
+    }
+    pub fn has_self(&self) -> bool {
+        self.inputs.get(0).map_or(false, Param::is_self)
+    }
+    pub fn c_variadic(&self) -> bool {
+        self.inputs.last().map_or(false, |arg| match arg.ty.kind {
+            TyKind::CVarArgs => true,
+            _ => false,
+        })
+    }
+}
+
+/// Is the trait definition an auto trait?
+#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
+pub enum IsAuto {
+    Yes,
+    No,
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable, Debug)]
+#[derive(HashStable_Generic)]
+pub enum Unsafe {
+    Yes(Span),
+    No,
+}
+
+#[derive(Copy, Clone, Encodable, Decodable, Debug)]
+pub enum Async {
+    Yes { span: Span, closure_id: NodeId, return_impl_trait_id: NodeId },
+    No,
+}
+
+impl Async {
+    pub fn is_async(self) -> bool {
+        if let Async::Yes { .. } = self { true } else { false }
+    }
+
+    /// In this case this is an `async` return, the `NodeId` for the generated `impl Trait` item.
+    pub fn opt_return_id(self) -> Option<NodeId> {
+        match self {
+            Async::Yes { return_impl_trait_id, .. } => Some(return_impl_trait_id),
+            Async::No => None,
+        }
+    }
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Encodable, Decodable, Debug)]
+#[derive(HashStable_Generic)]
+pub enum Const {
+    Yes(Span),
+    No,
+}
+
+/// Item defaultness.
+/// For details see the [RFC #2532](https://github.com/rust-lang/rfcs/pull/2532).
+#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
+pub enum Defaultness {
+    Default(Span),
+    Final,
+}
+
+#[derive(Copy, Clone, PartialEq, Encodable, Decodable, HashStable_Generic)]
+pub enum ImplPolarity {
+    /// `impl Trait for Type`
+    Positive,
+    /// `impl !Trait for Type`
+    Negative(Span),
+}
+
+impl fmt::Debug for ImplPolarity {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match *self {
+            ImplPolarity::Positive => "positive".fmt(f),
+            ImplPolarity::Negative(_) => "negative".fmt(f),
+        }
+    }
+}
+
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub enum FnRetTy {
+    /// Returns type is not specified.
+    ///
+    /// Functions default to `()` and closures default to inference.
+    /// Span points to where return type would be inserted.
+    Default(Span),
+    /// Everything else.
+    Ty(P<Ty>),
+}
+
+impl FnRetTy {
+    pub fn span(&self) -> Span {
+        match *self {
+            FnRetTy::Default(span) => span,
+            FnRetTy::Ty(ref ty) => ty.span,
+        }
+    }
+}
+
+/// Module declaration.
+///
+/// E.g., `mod foo;` or `mod foo { .. }`.
+#[derive(Clone, Encodable, Decodable, Debug, Default)]
+pub struct Mod {
+    /// A span from the first token past `{` to the last token until `}`.
+    /// For `mod foo;`, the inner span ranges from the first token
+    /// to the last token in the external file.
+    pub inner: Span,
+    pub items: Vec<P<Item>>,
+    /// `true` for `mod foo { .. }`; `false` for `mod foo;`.
+    pub inline: bool,
+}
+
+/// Foreign module declaration.
+///
+/// E.g., `extern { .. }` or `extern C { .. }`.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct ForeignMod {
+    pub abi: Option<StrLit>,
+    pub items: Vec<P<ForeignItem>>,
+}
+
+/// Global inline assembly.
+///
+/// Also known as "module-level assembly" or "file-scoped assembly".
+#[derive(Clone, Encodable, Decodable, Debug, Copy)]
+pub struct GlobalAsm {
+    pub asm: Symbol,
+}
+
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct EnumDef {
+    pub variants: Vec<Variant>,
+}
+/// Enum variant.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct Variant {
+    /// Attributes of the variant.
+    pub attrs: Vec<Attribute>,
+    /// Id of the variant (not the constructor, see `VariantData::ctor_id()`).
+    pub id: NodeId,
+    /// Span
+    pub span: Span,
+    /// The visibility of the variant. Syntactically accepted but not semantically.
+    pub vis: Visibility,
+    /// Name of the variant.
+    pub ident: Ident,
+
+    /// Fields and constructor id of the variant.
+    pub data: VariantData,
+    /// Explicit discriminant, e.g., `Foo = 1`.
+    pub disr_expr: Option<AnonConst>,
+    /// Is a macro placeholder
+    pub is_placeholder: bool,
+}
+
+/// Part of `use` item to the right of its prefix.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub enum UseTreeKind {
+    /// `use prefix` or `use prefix as rename`
+    ///
+    /// The extra `NodeId`s are for HIR lowering, when additional statements are created for each
+    /// namespace.
+    Simple(Option<Ident>, NodeId, NodeId),
+    /// `use prefix::{...}`
+    Nested(Vec<(UseTree, NodeId)>),
+    /// `use prefix::*`
+    Glob,
+}
+
+/// A tree of paths sharing common prefixes.
+/// Used in `use` items both at top-level and inside of braces in import groups.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct UseTree {
+    pub prefix: Path,
+    pub kind: UseTreeKind,
+    pub span: Span,
+}
+
+impl UseTree {
+    pub fn ident(&self) -> Ident {
+        match self.kind {
+            UseTreeKind::Simple(Some(rename), ..) => rename,
+            UseTreeKind::Simple(None, ..) => {
+                self.prefix.segments.last().expect("empty prefix in a simple import").ident
+            }
+            _ => panic!("`UseTree::ident` can only be used on a simple import"),
+        }
+    }
+}
+
+/// Distinguishes between `Attribute`s that decorate items and Attributes that
+/// are contained as statements within items. These two cases need to be
+/// distinguished for pretty-printing.
+#[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy, HashStable_Generic)]
+pub enum AttrStyle {
+    Outer,
+    Inner,
+}
+
+rustc_index::newtype_index! {
+    pub struct AttrId {
+        ENCODABLE = custom
+        DEBUG_FORMAT = "AttrId({})"
+    }
+}
+
+impl<S: Encoder> rustc_serialize::Encodable<S> for AttrId {
+    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
+        s.emit_unit()
+    }
+}
+
+impl<D: Decoder> rustc_serialize::Decodable<D> for AttrId {
+    fn decode(d: &mut D) -> Result<AttrId, D::Error> {
+        d.read_nil().map(|_| crate::attr::mk_attr_id())
+    }
+}
+
+#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
+pub struct AttrItem {
+    pub path: Path,
+    pub args: MacArgs,
+}
+
+/// A list of attributes.
+pub type AttrVec = ThinVec<Attribute>;
+
+/// Metadata associated with an item.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct Attribute {
+    pub kind: AttrKind,
+    pub id: AttrId,
+    /// Denotes if the attribute decorates the following construct (outer)
+    /// or the construct this attribute is contained within (inner).
+    pub style: AttrStyle,
+    pub span: Span,
+}
+
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub enum AttrKind {
+    /// A normal attribute.
+    Normal(AttrItem),
+
+    /// A doc comment (e.g. `/// ...`, `//! ...`, `/** ... */`, `/*! ... */`).
+    /// Doc attributes (e.g. `#[doc="..."]`) are represented with the `Normal`
+    /// variant (which is much less compact and thus more expensive).
+    DocComment(CommentKind, Symbol),
+}
+
+/// `TraitRef`s appear in impls.
+///
+/// Resolution maps each `TraitRef`'s `ref_id` to its defining trait; that's all
+/// that the `ref_id` is for. The `impl_id` maps to the "self type" of this impl.
+/// If this impl is an `ItemKind::Impl`, the `impl_id` is redundant (it could be the
+/// same as the impl's `NodeId`).
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct TraitRef {
+    pub path: Path,
+    pub ref_id: NodeId,
+}
+
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct PolyTraitRef {
+    /// The `'a` in `<'a> Foo<&'a T>`.
+    pub bound_generic_params: Vec<GenericParam>,
+
+    /// The `Foo<&'a T>` in `<'a> Foo<&'a T>`.
+    pub trait_ref: TraitRef,
+
+    pub span: Span,
+}
+
+impl PolyTraitRef {
+    pub fn new(generic_params: Vec<GenericParam>, path: Path, span: Span) -> Self {
+        PolyTraitRef {
+            bound_generic_params: generic_params,
+            trait_ref: TraitRef { path, ref_id: DUMMY_NODE_ID },
+            span,
+        }
+    }
+}
+
+#[derive(Copy, Clone, Encodable, Decodable, Debug, HashStable_Generic)]
+pub enum CrateSugar {
+    /// Source is `pub(crate)`.
+    PubCrate,
+
+    /// Source is (just) `crate`.
+    JustCrate,
+}
+
+pub type Visibility = Spanned<VisibilityKind>;
+
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub enum VisibilityKind {
+    Public,
+    Crate(CrateSugar),
+    Restricted { path: P<Path>, id: NodeId },
+    Inherited,
+}
+
+impl VisibilityKind {
+    pub fn is_pub(&self) -> bool {
+        if let VisibilityKind::Public = *self { true } else { false }
+    }
+}
+
+/// Field of a struct.
+///
+/// E.g., `bar: usize` as in `struct Foo { bar: usize }`.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct StructField {
+    pub attrs: Vec<Attribute>,
+    pub id: NodeId,
+    pub span: Span,
+    pub vis: Visibility,
+    pub ident: Option<Ident>,
+
+    pub ty: P<Ty>,
+    pub is_placeholder: bool,
+}
+
+/// Fields and constructor ids of enum variants and structs.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub enum VariantData {
+    /// Struct variant.
+    ///
+    /// E.g., `Bar { .. }` as in `enum Foo { Bar { .. } }`.
+    Struct(Vec<StructField>, bool),
+    /// Tuple variant.
+    ///
+    /// E.g., `Bar(..)` as in `enum Foo { Bar(..) }`.
+    Tuple(Vec<StructField>, NodeId),
+    /// Unit variant.
+    ///
+    /// E.g., `Bar = ..` as in `enum Foo { Bar = .. }`.
+    Unit(NodeId),
+}
+
+impl VariantData {
+    /// Return the fields of this variant.
+    pub fn fields(&self) -> &[StructField] {
+        match *self {
+            VariantData::Struct(ref fields, ..) | VariantData::Tuple(ref fields, _) => fields,
+            _ => &[],
+        }
+    }
+
+    /// Return the `NodeId` of this variant's constructor, if it has one.
+    pub fn ctor_id(&self) -> Option<NodeId> {
+        match *self {
+            VariantData::Struct(..) => None,
+            VariantData::Tuple(_, id) | VariantData::Unit(id) => Some(id),
+        }
+    }
+}
+
+/// An item definition.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct Item<K = ItemKind> {
+    pub attrs: Vec<Attribute>,
+    pub id: NodeId,
+    pub span: Span,
+    pub vis: Visibility,
+    /// The name of the item.
+    /// It might be a dummy name in case of anonymous items.
+    pub ident: Ident,
+
+    pub kind: K,
+
+    /// Original tokens this item was parsed from. This isn't necessarily
+    /// available for all items, although over time more and more items should
+    /// have this be `Some`. Right now this is primarily used for procedural
+    /// macros, notably custom attributes.
+    ///
+    /// Note that the tokens here do not include the outer attributes, but will
+    /// include inner attributes.
+    pub tokens: Option<TokenStream>,
+}
+
+impl Item {
+    /// Return the span that encompasses the attributes.
+    pub fn span_with_attributes(&self) -> Span {
+        self.attrs.iter().fold(self.span, |acc, attr| acc.to(attr.span))
+    }
+}
+
+impl<K: Into<ItemKind>> Item<K> {
+    pub fn into_item(self) -> Item {
+        let Item { attrs, id, span, vis, ident, kind, tokens } = self;
+        Item { attrs, id, span, vis, ident, kind: kind.into(), tokens }
+    }
+}
+
+/// `extern` qualifier on a function item or function type.
+#[derive(Clone, Copy, Encodable, Decodable, Debug)]
+pub enum Extern {
+    None,
+    Implicit,
+    Explicit(StrLit),
+}
+
+impl Extern {
+    pub fn from_abi(abi: Option<StrLit>) -> Extern {
+        abi.map_or(Extern::Implicit, Extern::Explicit)
+    }
+}
+
+/// A function header.
+///
+/// All the information between the visibility and the name of the function is
+/// included in this struct (e.g., `async unsafe fn` or `const extern "C" fn`).
+#[derive(Clone, Copy, Encodable, Decodable, Debug)]
+pub struct FnHeader {
+    pub unsafety: Unsafe,
+    pub asyncness: Async,
+    pub constness: Const,
+    pub ext: Extern,
+}
+
+impl FnHeader {
+    /// Does this function header have any qualifiers or is it empty?
+    pub fn has_qualifiers(&self) -> bool {
+        let Self { unsafety, asyncness, constness, ext } = self;
+        matches!(unsafety, Unsafe::Yes(_))
+            || asyncness.is_async()
+            || matches!(constness, Const::Yes(_))
+            || !matches!(ext, Extern::None)
+    }
+}
+
+impl Default for FnHeader {
+    fn default() -> FnHeader {
+        FnHeader {
+            unsafety: Unsafe::No,
+            asyncness: Async::No,
+            constness: Const::No,
+            ext: Extern::None,
+        }
+    }
+}
+
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub enum ItemKind {
+    /// An `extern crate` item, with the optional *original* crate name if the crate was renamed.
+    ///
+    /// E.g., `extern crate foo` or `extern crate foo_bar as foo`.
+    ExternCrate(Option<Symbol>),
+    /// A use declaration item (`use`).
+    ///
+    /// E.g., `use foo;`, `use foo::bar;` or `use foo::bar as FooBar;`.
+    Use(P<UseTree>),
+    /// A static item (`static`).
+    ///
+    /// E.g., `static FOO: i32 = 42;` or `static FOO: &'static str = "bar";`.
+    Static(P<Ty>, Mutability, Option<P<Expr>>),
+    /// A constant item (`const`).
+    ///
+    /// E.g., `const FOO: i32 = 42;`.
+    Const(Defaultness, P<Ty>, Option<P<Expr>>),
+    /// A function declaration (`fn`).
+    ///
+    /// E.g., `fn foo(bar: usize) -> usize { .. }`.
+    Fn(Defaultness, FnSig, Generics, Option<P<Block>>),
+    /// A module declaration (`mod`).
+    ///
+    /// E.g., `mod foo;` or `mod foo { .. }`.
+    Mod(Mod),
+    /// An external module (`extern`).
+    ///
+    /// E.g., `extern {}` or `extern "C" {}`.
+    ForeignMod(ForeignMod),
+    /// Module-level inline assembly (from `global_asm!()`).
+    GlobalAsm(P<GlobalAsm>),
+    /// A type alias (`type`).
+    ///
+    /// E.g., `type Foo = Bar<u8>;`.
+    TyAlias(Defaultness, Generics, GenericBounds, Option<P<Ty>>),
+    /// An enum definition (`enum`).
+    ///
+    /// E.g., `enum Foo<A, B> { C<A>, D<B> }`.
+    Enum(EnumDef, Generics),
+    /// A struct definition (`struct`).
+    ///
+    /// E.g., `struct Foo<A> { x: A }`.
+    Struct(VariantData, Generics),
+    /// A union definition (`union`).
+    ///
+    /// E.g., `union Foo<A, B> { x: A, y: B }`.
+    Union(VariantData, Generics),
+    /// A trait declaration (`trait`).
+    ///
+    /// E.g., `trait Foo { .. }`, `trait Foo<T> { .. }` or `auto trait Foo {}`.
+    Trait(IsAuto, Unsafe, Generics, GenericBounds, Vec<P<AssocItem>>),
+    /// Trait alias
+    ///
+    /// E.g., `trait Foo = Bar + Quux;`.
+    TraitAlias(Generics, GenericBounds),
+    /// An implementation.
+    ///
+    /// E.g., `impl<A> Foo<A> { .. }` or `impl<A> Trait for Foo<A> { .. }`.
+    Impl {
+        unsafety: Unsafe,
+        polarity: ImplPolarity,
+        defaultness: Defaultness,
+        constness: Const,
+        generics: Generics,
+
+        /// The trait being implemented, if any.
+        of_trait: Option<TraitRef>,
+
+        self_ty: P<Ty>,
+        items: Vec<P<AssocItem>>,
+    },
+    /// A macro invocation.
+    ///
+    /// E.g., `foo!(..)`.
+    MacCall(MacCall),
+
+    /// A macro definition.
+    MacroDef(MacroDef),
+}
+
+impl ItemKind {
+    pub fn article(&self) -> &str {
+        use ItemKind::*;
+        match self {
+            Use(..) | Static(..) | Const(..) | Fn(..) | Mod(..) | GlobalAsm(..) | TyAlias(..)
+            | Struct(..) | Union(..) | Trait(..) | TraitAlias(..) | MacroDef(..) => "a",
+            ExternCrate(..) | ForeignMod(..) | MacCall(..) | Enum(..) | Impl { .. } => "an",
+        }
+    }
+
+    pub fn descr(&self) -> &str {
+        match self {
+            ItemKind::ExternCrate(..) => "extern crate",
+            ItemKind::Use(..) => "`use` import",
+            ItemKind::Static(..) => "static item",
+            ItemKind::Const(..) => "constant item",
+            ItemKind::Fn(..) => "function",
+            ItemKind::Mod(..) => "module",
+            ItemKind::ForeignMod(..) => "extern block",
+            ItemKind::GlobalAsm(..) => "global asm item",
+            ItemKind::TyAlias(..) => "type alias",
+            ItemKind::Enum(..) => "enum",
+            ItemKind::Struct(..) => "struct",
+            ItemKind::Union(..) => "union",
+            ItemKind::Trait(..) => "trait",
+            ItemKind::TraitAlias(..) => "trait alias",
+            ItemKind::MacCall(..) => "item macro invocation",
+            ItemKind::MacroDef(..) => "macro definition",
+            ItemKind::Impl { .. } => "implementation",
+        }
+    }
+
+    pub fn generics(&self) -> Option<&Generics> {
+        match self {
+            Self::Fn(_, _, generics, _)
+            | Self::TyAlias(_, generics, ..)
+            | Self::Enum(_, generics)
+            | Self::Struct(_, generics)
+            | Self::Union(_, generics)
+            | Self::Trait(_, _, generics, ..)
+            | Self::TraitAlias(generics, _)
+            | Self::Impl { generics, .. } => Some(generics),
+            _ => None,
+        }
+    }
+}
+
+/// Represents associated items.
+/// These include items in `impl` and `trait` definitions.
+pub type AssocItem = Item<AssocItemKind>;
+
+/// Represents associated item kinds.
+///
+/// The term "provided" in the variants below refers to the item having a default
+/// definition / body. Meanwhile, a "required" item lacks a definition / body.
+/// In an implementation, all items must be provided.
+/// The `Option`s below denote the bodies, where `Some(_)`
+/// means "provided" and conversely `None` means "required".
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub enum AssocItemKind {
+    /// An associated constant, `const $ident: $ty $def?;` where `def ::= "=" $expr? ;`.
+    /// If `def` is parsed, then the constant is provided, and otherwise required.
+    Const(Defaultness, P<Ty>, Option<P<Expr>>),
+    /// An associated function.
+    Fn(Defaultness, FnSig, Generics, Option<P<Block>>),
+    /// An associated type.
+    TyAlias(Defaultness, Generics, GenericBounds, Option<P<Ty>>),
+    /// A macro expanding to associated items.
+    MacCall(MacCall),
+}
+
+impl AssocItemKind {
+    pub fn defaultness(&self) -> Defaultness {
+        match *self {
+            Self::Const(def, ..) | Self::Fn(def, ..) | Self::TyAlias(def, ..) => def,
+            Self::MacCall(..) => Defaultness::Final,
+        }
+    }
+}
+
+impl From<AssocItemKind> for ItemKind {
+    fn from(assoc_item_kind: AssocItemKind) -> ItemKind {
+        match assoc_item_kind {
+            AssocItemKind::Const(a, b, c) => ItemKind::Const(a, b, c),
+            AssocItemKind::Fn(a, b, c, d) => ItemKind::Fn(a, b, c, d),
+            AssocItemKind::TyAlias(a, b, c, d) => ItemKind::TyAlias(a, b, c, d),
+            AssocItemKind::MacCall(a) => ItemKind::MacCall(a),
+        }
+    }
+}
+
+impl TryFrom<ItemKind> for AssocItemKind {
+    type Error = ItemKind;
+
+    fn try_from(item_kind: ItemKind) -> Result<AssocItemKind, ItemKind> {
+        Ok(match item_kind {
+            ItemKind::Const(a, b, c) => AssocItemKind::Const(a, b, c),
+            ItemKind::Fn(a, b, c, d) => AssocItemKind::Fn(a, b, c, d),
+            ItemKind::TyAlias(a, b, c, d) => AssocItemKind::TyAlias(a, b, c, d),
+            ItemKind::MacCall(a) => AssocItemKind::MacCall(a),
+            _ => return Err(item_kind),
+        })
+    }
+}
+
+/// An item in `extern` block.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub enum ForeignItemKind {
+    /// A foreign static item (`static FOO: u8`).
+    Static(P<Ty>, Mutability, Option<P<Expr>>),
+    /// A foreign function.
+    Fn(Defaultness, FnSig, Generics, Option<P<Block>>),
+    /// A foreign type.
+    TyAlias(Defaultness, Generics, GenericBounds, Option<P<Ty>>),
+    /// A macro expanding to foreign items.
+    MacCall(MacCall),
+}
+
+impl From<ForeignItemKind> for ItemKind {
+    fn from(foreign_item_kind: ForeignItemKind) -> ItemKind {
+        match foreign_item_kind {
+            ForeignItemKind::Static(a, b, c) => ItemKind::Static(a, b, c),
+            ForeignItemKind::Fn(a, b, c, d) => ItemKind::Fn(a, b, c, d),
+            ForeignItemKind::TyAlias(a, b, c, d) => ItemKind::TyAlias(a, b, c, d),
+            ForeignItemKind::MacCall(a) => ItemKind::MacCall(a),
+        }
+    }
+}
+
+impl TryFrom<ItemKind> for ForeignItemKind {
+    type Error = ItemKind;
+
+    fn try_from(item_kind: ItemKind) -> Result<ForeignItemKind, ItemKind> {
+        Ok(match item_kind {
+            ItemKind::Static(a, b, c) => ForeignItemKind::Static(a, b, c),
+            ItemKind::Fn(a, b, c, d) => ForeignItemKind::Fn(a, b, c, d),
+            ItemKind::TyAlias(a, b, c, d) => ForeignItemKind::TyAlias(a, b, c, d),
+            ItemKind::MacCall(a) => ForeignItemKind::MacCall(a),
+            _ => return Err(item_kind),
+        })
+    }
+}
+
+pub type ForeignItem = Item<ForeignItemKind>;
diff --git a/compiler/rustc_ast/src/ast/tests.rs b/compiler/rustc_ast/src/ast/tests.rs
new file mode 100644
index 00000000000..8ba55bf037b
--- /dev/null
+++ b/compiler/rustc_ast/src/ast/tests.rs
@@ -0,0 +1,11 @@
+use super::*;
+
+// Are ASTs encodable?
+#[test]
+fn check_asts_encodable() {
+    fn assert_encodable<
+        T: for<'a> rustc_serialize::Encodable<rustc_serialize::json::Encoder<'a>>,
+    >() {
+    }
+    assert_encodable::<Crate>();
+}
diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs
new file mode 100644
index 00000000000..edcbce3e2cf
--- /dev/null
+++ b/compiler/rustc_ast/src/attr/mod.rs
@@ -0,0 +1,684 @@
+//! Functions dealing with attributes and meta items.
+
+use crate::ast;
+use crate::ast::{AttrId, AttrItem, AttrKind, AttrStyle, AttrVec, Attribute};
+use crate::ast::{Expr, GenericParam, Item, Lit, LitKind, Local, Stmt, StmtKind};
+use crate::ast::{MacArgs, MacDelimiter, MetaItem, MetaItemKind, NestedMetaItem};
+use crate::ast::{Path, PathSegment};
+use crate::mut_visit::visit_clobber;
+use crate::ptr::P;
+use crate::token::{self, CommentKind, Token};
+use crate::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndJoint};
+
+use rustc_index::bit_set::GrowableBitSet;
+use rustc_span::source_map::{BytePos, Spanned};
+use rustc_span::symbol::{sym, Ident, Symbol};
+use rustc_span::Span;
+
+use std::iter;
+use std::ops::DerefMut;
+
+pub struct MarkedAttrs(GrowableBitSet<AttrId>);
+
+impl MarkedAttrs {
+    // We have no idea how many attributes there will be, so just
+    // initiate the vectors with 0 bits. We'll grow them as necessary.
+    pub fn new() -> Self {
+        MarkedAttrs(GrowableBitSet::new_empty())
+    }
+
+    pub fn mark(&mut self, attr: &Attribute) {
+        self.0.insert(attr.id);
+    }
+
+    pub fn is_marked(&self, attr: &Attribute) -> bool {
+        self.0.contains(attr.id)
+    }
+}
+
+pub fn is_known_lint_tool(m_item: Ident) -> bool {
+    [sym::clippy, sym::rustc].contains(&m_item.name)
+}
+
+impl NestedMetaItem {
+    /// Returns the `MetaItem` if `self` is a `NestedMetaItem::MetaItem`.
+    pub fn meta_item(&self) -> Option<&MetaItem> {
+        match *self {
+            NestedMetaItem::MetaItem(ref item) => Some(item),
+            _ => None,
+        }
+    }
+
+    /// Returns the `Lit` if `self` is a `NestedMetaItem::Literal`s.
+    pub fn literal(&self) -> Option<&Lit> {
+        match *self {
+            NestedMetaItem::Literal(ref lit) => Some(lit),
+            _ => None,
+        }
+    }
+
+    /// Returns `true` if this list item is a MetaItem with a name of `name`.
+    pub fn has_name(&self, name: Symbol) -> bool {
+        self.meta_item().map_or(false, |meta_item| meta_item.has_name(name))
+    }
+
+    /// For a single-segment meta item, returns its name; otherwise, returns `None`.
+    pub fn ident(&self) -> Option<Ident> {
+        self.meta_item().and_then(|meta_item| meta_item.ident())
+    }
+    pub fn name_or_empty(&self) -> Symbol {
+        self.ident().unwrap_or(Ident::invalid()).name
+    }
+
+    /// Gets the string value if `self` is a `MetaItem` and the `MetaItem` is a
+    /// `MetaItemKind::NameValue` variant containing a string, otherwise `None`.
+    pub fn value_str(&self) -> Option<Symbol> {
+        self.meta_item().and_then(|meta_item| meta_item.value_str())
+    }
+
+    /// Returns a name and single literal value tuple of the `MetaItem`.
+    pub fn name_value_literal(&self) -> Option<(Symbol, &Lit)> {
+        self.meta_item().and_then(|meta_item| {
+            meta_item.meta_item_list().and_then(|meta_item_list| {
+                if meta_item_list.len() == 1 {
+                    if let Some(ident) = meta_item.ident() {
+                        if let Some(lit) = meta_item_list[0].literal() {
+                            return Some((ident.name, lit));
+                        }
+                    }
+                }
+                None
+            })
+        })
+    }
+
+    /// Gets a list of inner meta items from a list `MetaItem` type.
+    pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> {
+        self.meta_item().and_then(|meta_item| meta_item.meta_item_list())
+    }
+
+    /// Returns `true` if the variant is `MetaItem`.
+    pub fn is_meta_item(&self) -> bool {
+        self.meta_item().is_some()
+    }
+
+    /// Returns `true` if the variant is `Literal`.
+    pub fn is_literal(&self) -> bool {
+        self.literal().is_some()
+    }
+
+    /// Returns `true` if `self` is a `MetaItem` and the meta item is a word.
+    pub fn is_word(&self) -> bool {
+        self.meta_item().map_or(false, |meta_item| meta_item.is_word())
+    }
+
+    /// Returns `true` if `self` is a `MetaItem` and the meta item is a `ValueString`.
+    pub fn is_value_str(&self) -> bool {
+        self.value_str().is_some()
+    }
+
+    /// Returns `true` if `self` is a `MetaItem` and the meta item is a list.
+    pub fn is_meta_item_list(&self) -> bool {
+        self.meta_item_list().is_some()
+    }
+}
+
+impl Attribute {
+    pub fn has_name(&self, name: Symbol) -> bool {
+        match self.kind {
+            AttrKind::Normal(ref item) => item.path == name,
+            AttrKind::DocComment(..) => false,
+        }
+    }
+
+    /// For a single-segment attribute, returns its name; otherwise, returns `None`.
+    pub fn ident(&self) -> Option<Ident> {
+        match self.kind {
+            AttrKind::Normal(ref item) => {
+                if item.path.segments.len() == 1 {
+                    Some(item.path.segments[0].ident)
+                } else {
+                    None
+                }
+            }
+            AttrKind::DocComment(..) => None,
+        }
+    }
+    pub fn name_or_empty(&self) -> Symbol {
+        self.ident().unwrap_or(Ident::invalid()).name
+    }
+
+    pub fn value_str(&self) -> Option<Symbol> {
+        match self.kind {
+            AttrKind::Normal(ref item) => item.meta(self.span).and_then(|meta| meta.value_str()),
+            AttrKind::DocComment(..) => None,
+        }
+    }
+
+    pub fn meta_item_list(&self) -> Option<Vec<NestedMetaItem>> {
+        match self.kind {
+            AttrKind::Normal(ref item) => match item.meta(self.span) {
+                Some(MetaItem { kind: MetaItemKind::List(list), .. }) => Some(list),
+                _ => None,
+            },
+            AttrKind::DocComment(..) => None,
+        }
+    }
+
+    pub fn is_word(&self) -> bool {
+        if let AttrKind::Normal(item) = &self.kind {
+            matches!(item.args, MacArgs::Empty)
+        } else {
+            false
+        }
+    }
+
+    pub fn is_meta_item_list(&self) -> bool {
+        self.meta_item_list().is_some()
+    }
+
+    /// Indicates if the attribute is a `ValueString`.
+    pub fn is_value_str(&self) -> bool {
+        self.value_str().is_some()
+    }
+}
+
+impl MetaItem {
+    /// For a single-segment meta item, returns its name; otherwise, returns `None`.
+    pub fn ident(&self) -> Option<Ident> {
+        if self.path.segments.len() == 1 { Some(self.path.segments[0].ident) } else { None }
+    }
+    pub fn name_or_empty(&self) -> Symbol {
+        self.ident().unwrap_or(Ident::invalid()).name
+    }
+
+    // Example:
+    //     #[attribute(name = "value")]
+    //                 ^^^^^^^^^^^^^^
+    pub fn name_value_literal(&self) -> Option<&Lit> {
+        match &self.kind {
+            MetaItemKind::NameValue(v) => Some(v),
+            _ => None,
+        }
+    }
+
+    pub fn value_str(&self) -> Option<Symbol> {
+        match self.kind {
+            MetaItemKind::NameValue(ref v) => match v.kind {
+                LitKind::Str(ref s, _) => Some(*s),
+                _ => None,
+            },
+            _ => None,
+        }
+    }
+
+    pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> {
+        match self.kind {
+            MetaItemKind::List(ref l) => Some(&l[..]),
+            _ => None,
+        }
+    }
+
+    pub fn is_word(&self) -> bool {
+        match self.kind {
+            MetaItemKind::Word => true,
+            _ => false,
+        }
+    }
+
+    pub fn has_name(&self, name: Symbol) -> bool {
+        self.path == name
+    }
+
+    pub fn is_value_str(&self) -> bool {
+        self.value_str().is_some()
+    }
+
+    pub fn is_meta_item_list(&self) -> bool {
+        self.meta_item_list().is_some()
+    }
+}
+
+impl AttrItem {
+    pub fn span(&self) -> Span {
+        self.args.span().map_or(self.path.span, |args_span| self.path.span.to(args_span))
+    }
+
+    pub fn meta(&self, span: Span) -> Option<MetaItem> {
+        Some(MetaItem {
+            path: self.path.clone(),
+            kind: MetaItemKind::from_mac_args(&self.args)?,
+            span,
+        })
+    }
+}
+
+impl Attribute {
+    pub fn is_doc_comment(&self) -> bool {
+        match self.kind {
+            AttrKind::Normal(_) => false,
+            AttrKind::DocComment(..) => true,
+        }
+    }
+
+    pub fn doc_str(&self) -> Option<Symbol> {
+        match self.kind {
+            AttrKind::DocComment(.., data) => Some(data),
+            AttrKind::Normal(ref item) if item.path == sym::doc => {
+                item.meta(self.span).and_then(|meta| meta.value_str())
+            }
+            _ => None,
+        }
+    }
+
+    pub fn get_normal_item(&self) -> &AttrItem {
+        match self.kind {
+            AttrKind::Normal(ref item) => item,
+            AttrKind::DocComment(..) => panic!("unexpected doc comment"),
+        }
+    }
+
+    pub fn unwrap_normal_item(self) -> AttrItem {
+        match self.kind {
+            AttrKind::Normal(item) => item,
+            AttrKind::DocComment(..) => panic!("unexpected doc comment"),
+        }
+    }
+
+    /// Extracts the MetaItem from inside this Attribute.
+    pub fn meta(&self) -> Option<MetaItem> {
+        match self.kind {
+            AttrKind::Normal(ref item) => item.meta(self.span),
+            AttrKind::DocComment(..) => None,
+        }
+    }
+}
+
+/* Constructors */
+
+pub fn mk_name_value_item_str(ident: Ident, str: Symbol, str_span: Span) -> MetaItem {
+    let lit_kind = LitKind::Str(str, ast::StrStyle::Cooked);
+    mk_name_value_item(ident, lit_kind, str_span)
+}
+
+pub fn mk_name_value_item(ident: Ident, lit_kind: LitKind, lit_span: Span) -> MetaItem {
+    let lit = Lit::from_lit_kind(lit_kind, lit_span);
+    let span = ident.span.to(lit_span);
+    MetaItem { path: Path::from_ident(ident), span, kind: MetaItemKind::NameValue(lit) }
+}
+
+pub fn mk_list_item(ident: Ident, items: Vec<NestedMetaItem>) -> MetaItem {
+    MetaItem { path: Path::from_ident(ident), span: ident.span, kind: MetaItemKind::List(items) }
+}
+
+pub fn mk_word_item(ident: Ident) -> MetaItem {
+    MetaItem { path: Path::from_ident(ident), span: ident.span, kind: MetaItemKind::Word }
+}
+
+pub fn mk_nested_word_item(ident: Ident) -> NestedMetaItem {
+    NestedMetaItem::MetaItem(mk_word_item(ident))
+}
+
+crate fn mk_attr_id() -> AttrId {
+    use std::sync::atomic::AtomicU32;
+    use std::sync::atomic::Ordering;
+
+    static NEXT_ATTR_ID: AtomicU32 = AtomicU32::new(0);
+
+    let id = NEXT_ATTR_ID.fetch_add(1, Ordering::SeqCst);
+    assert!(id != u32::MAX);
+    AttrId::from_u32(id)
+}
+
+pub fn mk_attr(style: AttrStyle, path: Path, args: MacArgs, span: Span) -> Attribute {
+    mk_attr_from_item(style, AttrItem { path, args }, span)
+}
+
+pub fn mk_attr_from_item(style: AttrStyle, item: AttrItem, span: Span) -> Attribute {
+    Attribute { kind: AttrKind::Normal(item), id: mk_attr_id(), style, span }
+}
+
+/// Returns an inner attribute with the given value and span.
+pub fn mk_attr_inner(item: MetaItem) -> Attribute {
+    mk_attr(AttrStyle::Inner, item.path, item.kind.mac_args(item.span), item.span)
+}
+
+/// Returns an outer attribute with the given value and span.
+pub fn mk_attr_outer(item: MetaItem) -> Attribute {
+    mk_attr(AttrStyle::Outer, item.path, item.kind.mac_args(item.span), item.span)
+}
+
+pub fn mk_doc_comment(
+    comment_kind: CommentKind,
+    style: AttrStyle,
+    data: Symbol,
+    span: Span,
+) -> Attribute {
+    Attribute { kind: AttrKind::DocComment(comment_kind, data), id: mk_attr_id(), style, span }
+}
+
+pub fn list_contains_name(items: &[NestedMetaItem], name: Symbol) -> bool {
+    items.iter().any(|item| item.has_name(name))
+}
+
+impl MetaItem {
+    fn token_trees_and_joints(&self) -> Vec<TreeAndJoint> {
+        let mut idents = vec![];
+        let mut last_pos = BytePos(0 as u32);
+        for (i, segment) in self.path.segments.iter().enumerate() {
+            let is_first = i == 0;
+            if !is_first {
+                let mod_sep_span =
+                    Span::new(last_pos, segment.ident.span.lo(), segment.ident.span.ctxt());
+                idents.push(TokenTree::token(token::ModSep, mod_sep_span).into());
+            }
+            idents.push(TokenTree::Token(Token::from_ast_ident(segment.ident)).into());
+            last_pos = segment.ident.span.hi();
+        }
+        idents.extend(self.kind.token_trees_and_joints(self.span));
+        idents
+    }
+
+    fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<MetaItem>
+    where
+        I: Iterator<Item = TokenTree>,
+    {
+        // FIXME: Share code with `parse_path`.
+        let path = match tokens.next().map(TokenTree::uninterpolate) {
+            Some(TokenTree::Token(Token {
+                kind: kind @ (token::Ident(..) | token::ModSep),
+                span,
+            })) => 'arm: {
+                let mut segments = if let token::Ident(name, _) = kind {
+                    if let Some(TokenTree::Token(Token { kind: token::ModSep, .. })) = tokens.peek()
+                    {
+                        tokens.next();
+                        vec![PathSegment::from_ident(Ident::new(name, span))]
+                    } else {
+                        break 'arm Path::from_ident(Ident::new(name, span));
+                    }
+                } else {
+                    vec![PathSegment::path_root(span)]
+                };
+                loop {
+                    if let Some(TokenTree::Token(Token { kind: token::Ident(name, _), span })) =
+                        tokens.next().map(TokenTree::uninterpolate)
+                    {
+                        segments.push(PathSegment::from_ident(Ident::new(name, span)));
+                    } else {
+                        return None;
+                    }
+                    if let Some(TokenTree::Token(Token { kind: token::ModSep, .. })) = tokens.peek()
+                    {
+                        tokens.next();
+                    } else {
+                        break;
+                    }
+                }
+                let span = span.with_hi(segments.last().unwrap().ident.span.hi());
+                Path { span, segments }
+            }
+            Some(TokenTree::Token(Token { kind: token::Interpolated(nt), .. })) => match *nt {
+                token::Nonterminal::NtMeta(ref item) => return item.meta(item.path.span),
+                token::Nonterminal::NtPath(ref path) => path.clone(),
+                _ => return None,
+            },
+            _ => return None,
+        };
+        let list_closing_paren_pos = tokens.peek().map(|tt| tt.span().hi());
+        let kind = MetaItemKind::from_tokens(tokens)?;
+        let hi = match kind {
+            MetaItemKind::NameValue(ref lit) => lit.span.hi(),
+            MetaItemKind::List(..) => list_closing_paren_pos.unwrap_or(path.span.hi()),
+            _ => path.span.hi(),
+        };
+        let span = path.span.with_hi(hi);
+        Some(MetaItem { path, kind, span })
+    }
+}
+
+impl MetaItemKind {
+    pub fn mac_args(&self, span: Span) -> MacArgs {
+        match self {
+            MetaItemKind::Word => MacArgs::Empty,
+            MetaItemKind::NameValue(lit) => MacArgs::Eq(span, lit.token_tree().into()),
+            MetaItemKind::List(list) => {
+                let mut tts = Vec::new();
+                for (i, item) in list.iter().enumerate() {
+                    if i > 0 {
+                        tts.push(TokenTree::token(token::Comma, span).into());
+                    }
+                    tts.extend(item.token_trees_and_joints())
+                }
+                MacArgs::Delimited(
+                    DelimSpan::from_single(span),
+                    MacDelimiter::Parenthesis,
+                    TokenStream::new(tts),
+                )
+            }
+        }
+    }
+
+    fn token_trees_and_joints(&self, span: Span) -> Vec<TreeAndJoint> {
+        match *self {
+            MetaItemKind::Word => vec![],
+            MetaItemKind::NameValue(ref lit) => {
+                vec![TokenTree::token(token::Eq, span).into(), lit.token_tree().into()]
+            }
+            MetaItemKind::List(ref list) => {
+                let mut tokens = Vec::new();
+                for (i, item) in list.iter().enumerate() {
+                    if i > 0 {
+                        tokens.push(TokenTree::token(token::Comma, span).into());
+                    }
+                    tokens.extend(item.token_trees_and_joints())
+                }
+                vec![
+                    TokenTree::Delimited(
+                        DelimSpan::from_single(span),
+                        token::Paren,
+                        TokenStream::new(tokens),
+                    )
+                    .into(),
+                ]
+            }
+        }
+    }
+
+    fn list_from_tokens(tokens: TokenStream) -> Option<MetaItemKind> {
+        let mut tokens = tokens.into_trees().peekable();
+        let mut result = Vec::new();
+        while let Some(..) = tokens.peek() {
+            let item = NestedMetaItem::from_tokens(&mut tokens)?;
+            result.push(item);
+            match tokens.next() {
+                None | Some(TokenTree::Token(Token { kind: token::Comma, .. })) => {}
+                _ => return None,
+            }
+        }
+        Some(MetaItemKind::List(result))
+    }
+
+    fn name_value_from_tokens(
+        tokens: &mut impl Iterator<Item = TokenTree>,
+    ) -> Option<MetaItemKind> {
+        match tokens.next() {
+            Some(TokenTree::Delimited(_, token::NoDelim, inner_tokens)) => {
+                MetaItemKind::name_value_from_tokens(&mut inner_tokens.trees())
+            }
+            Some(TokenTree::Token(token)) => {
+                Lit::from_token(&token).ok().map(MetaItemKind::NameValue)
+            }
+            _ => None,
+        }
+    }
+
+    fn from_mac_args(args: &MacArgs) -> Option<MetaItemKind> {
+        match args {
+            MacArgs::Delimited(_, MacDelimiter::Parenthesis, tokens) => {
+                MetaItemKind::list_from_tokens(tokens.clone())
+            }
+            MacArgs::Delimited(..) => None,
+            MacArgs::Eq(_, tokens) => {
+                assert!(tokens.len() == 1);
+                MetaItemKind::name_value_from_tokens(&mut tokens.trees())
+            }
+            MacArgs::Empty => Some(MetaItemKind::Word),
+        }
+    }
+
+    fn from_tokens(
+        tokens: &mut iter::Peekable<impl Iterator<Item = TokenTree>>,
+    ) -> Option<MetaItemKind> {
+        match tokens.peek() {
+            Some(TokenTree::Delimited(_, token::Paren, inner_tokens)) => {
+                let inner_tokens = inner_tokens.clone();
+                tokens.next();
+                MetaItemKind::list_from_tokens(inner_tokens)
+            }
+            Some(TokenTree::Delimited(..)) => None,
+            Some(TokenTree::Token(Token { kind: token::Eq, .. })) => {
+                tokens.next();
+                MetaItemKind::name_value_from_tokens(tokens)
+            }
+            _ => Some(MetaItemKind::Word),
+        }
+    }
+}
+
+impl NestedMetaItem {
+    pub fn span(&self) -> Span {
+        match *self {
+            NestedMetaItem::MetaItem(ref item) => item.span,
+            NestedMetaItem::Literal(ref lit) => lit.span,
+        }
+    }
+
+    fn token_trees_and_joints(&self) -> Vec<TreeAndJoint> {
+        match *self {
+            NestedMetaItem::MetaItem(ref item) => item.token_trees_and_joints(),
+            NestedMetaItem::Literal(ref lit) => vec![lit.token_tree().into()],
+        }
+    }
+
+    fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<NestedMetaItem>
+    where
+        I: Iterator<Item = TokenTree>,
+    {
+        match tokens.peek() {
+            Some(TokenTree::Token(token)) => {
+                if let Ok(lit) = Lit::from_token(token) {
+                    tokens.next();
+                    return Some(NestedMetaItem::Literal(lit));
+                }
+            }
+            Some(TokenTree::Delimited(_, token::NoDelim, inner_tokens)) => {
+                let inner_tokens = inner_tokens.clone();
+                tokens.next();
+                return NestedMetaItem::from_tokens(&mut inner_tokens.into_trees().peekable());
+            }
+            _ => {}
+        }
+        MetaItem::from_tokens(tokens).map(NestedMetaItem::MetaItem)
+    }
+}
+
+pub trait HasAttrs: Sized {
+    fn attrs(&self) -> &[Attribute];
+    fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>));
+}
+
+impl<T: HasAttrs> HasAttrs for Spanned<T> {
+    fn attrs(&self) -> &[Attribute] {
+        self.node.attrs()
+    }
+    fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
+        self.node.visit_attrs(f);
+    }
+}
+
+impl HasAttrs for Vec<Attribute> {
+    fn attrs(&self) -> &[Attribute] {
+        self
+    }
+    fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
+        f(self)
+    }
+}
+
+impl HasAttrs for AttrVec {
+    fn attrs(&self) -> &[Attribute] {
+        self
+    }
+    fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
+        visit_clobber(self, |this| {
+            let mut vec = this.into();
+            f(&mut vec);
+            vec.into()
+        });
+    }
+}
+
+impl<T: HasAttrs + 'static> HasAttrs for P<T> {
+    fn attrs(&self) -> &[Attribute] {
+        (**self).attrs()
+    }
+    fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
+        (**self).visit_attrs(f);
+    }
+}
+
+impl HasAttrs for StmtKind {
+    fn attrs(&self) -> &[Attribute] {
+        match *self {
+            StmtKind::Local(ref local) => local.attrs(),
+            StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => expr.attrs(),
+            StmtKind::Empty | StmtKind::Item(..) => &[],
+            StmtKind::MacCall(ref mac) => {
+                let (_, _, ref attrs) = **mac;
+                attrs.attrs()
+            }
+        }
+    }
+
+    fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
+        match self {
+            StmtKind::Local(local) => local.visit_attrs(f),
+            StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.visit_attrs(f),
+            StmtKind::Empty | StmtKind::Item(..) => {}
+            StmtKind::MacCall(mac) => {
+                let (_mac, _style, attrs) = mac.deref_mut();
+                attrs.visit_attrs(f);
+            }
+        }
+    }
+}
+
+impl HasAttrs for Stmt {
+    fn attrs(&self) -> &[ast::Attribute] {
+        self.kind.attrs()
+    }
+
+    fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
+        self.kind.visit_attrs(f);
+    }
+}
+
+macro_rules! derive_has_attrs {
+    ($($ty:path),*) => { $(
+        impl HasAttrs for $ty {
+            fn attrs(&self) -> &[Attribute] {
+                &self.attrs
+            }
+
+            fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
+                self.attrs.visit_attrs(f);
+            }
+        }
+    )* }
+}
+
+derive_has_attrs! {
+    Item, Expr, Local, ast::AssocItem, ast::ForeignItem, ast::StructField, ast::Arm,
+    ast::Field, ast::FieldPat, ast::Variant, ast::Param, GenericParam
+}
diff --git a/compiler/rustc_ast/src/crate_disambiguator.rs b/compiler/rustc_ast/src/crate_disambiguator.rs
new file mode 100644
index 00000000000..bd7d8516714
--- /dev/null
+++ b/compiler/rustc_ast/src/crate_disambiguator.rs
@@ -0,0 +1,35 @@
+// This is here because `rustc_session` wants to refer to it,
+// and so does `rustc_hir`, but `rustc_hir` shouldn't refer to `rustc_session`.
+
+use rustc_data_structures::fingerprint::Fingerprint;
+use rustc_data_structures::{base_n, impl_stable_hash_via_hash};
+
+use std::fmt;
+
+/// Hash value constructed out of all the `-C metadata` arguments passed to the
+/// compiler. Together with the crate-name forms a unique global identifier for
+/// the crate.
+#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Clone, Copy, Encodable, Decodable)]
+pub struct CrateDisambiguator(Fingerprint);
+
+impl CrateDisambiguator {
+    pub fn to_fingerprint(self) -> Fingerprint {
+        self.0
+    }
+}
+
+impl fmt::Display for CrateDisambiguator {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
+        let (a, b) = self.0.as_value();
+        let as_u128 = a as u128 | ((b as u128) << 64);
+        f.write_str(&base_n::encode(as_u128, base_n::CASE_INSENSITIVE))
+    }
+}
+
+impl From<Fingerprint> for CrateDisambiguator {
+    fn from(fingerprint: Fingerprint) -> CrateDisambiguator {
+        CrateDisambiguator(fingerprint)
+    }
+}
+
+impl_stable_hash_via_hash!(CrateDisambiguator);
diff --git a/compiler/rustc_ast/src/entry.rs b/compiler/rustc_ast/src/entry.rs
new file mode 100644
index 00000000000..290f6006de0
--- /dev/null
+++ b/compiler/rustc_ast/src/entry.rs
@@ -0,0 +1,7 @@
+pub enum EntryPointType {
+    None,
+    MainNamed,
+    MainAttr,
+    Start,
+    OtherMain, // Not an entry point, but some other function named main
+}
diff --git a/compiler/rustc_ast/src/expand/allocator.rs b/compiler/rustc_ast/src/expand/allocator.rs
new file mode 100644
index 00000000000..cd27f958e46
--- /dev/null
+++ b/compiler/rustc_ast/src/expand/allocator.rs
@@ -0,0 +1,53 @@
+use rustc_span::symbol::{sym, Symbol};
+
+#[derive(Clone, Copy)]
+pub enum AllocatorKind {
+    Global,
+    Default,
+}
+
+impl AllocatorKind {
+    pub fn fn_name(&self, base: Symbol) -> String {
+        match *self {
+            AllocatorKind::Global => format!("__rg_{}", base),
+            AllocatorKind::Default => format!("__rdl_{}", base),
+        }
+    }
+}
+
+pub enum AllocatorTy {
+    Layout,
+    Ptr,
+    ResultPtr,
+    Unit,
+    Usize,
+}
+
+pub struct AllocatorMethod {
+    pub name: Symbol,
+    pub inputs: &'static [AllocatorTy],
+    pub output: AllocatorTy,
+}
+
+pub static ALLOCATOR_METHODS: &[AllocatorMethod] = &[
+    AllocatorMethod {
+        name: sym::alloc,
+        inputs: &[AllocatorTy::Layout],
+        output: AllocatorTy::ResultPtr,
+    },
+    AllocatorMethod {
+        name: sym::dealloc,
+        inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout],
+        output: AllocatorTy::Unit,
+    },
+    AllocatorMethod {
+        name: sym::realloc,
+        inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout, AllocatorTy::Usize],
+        output: AllocatorTy::ResultPtr,
+    },
+    AllocatorMethod {
+        name: sym::alloc_zeroed,
+        inputs: &[AllocatorTy::Layout],
+        output: AllocatorTy::ResultPtr,
+    },
+];
diff --git a/compiler/rustc_ast/src/expand/mod.rs b/compiler/rustc_ast/src/expand/mod.rs
new file mode 100644
index 00000000000..eebfc38bdf4
--- /dev/null
+++ b/compiler/rustc_ast/src/expand/mod.rs
@@ -0,0 +1,3 @@
+//! Definitions shared by macros / syntax extensions and e.g. librustc_middle.
+
+pub mod allocator;
diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs
new file mode 100644
index 00000000000..b556c1a446b
--- /dev/null
+++ b/compiler/rustc_ast/src/lib.rs
@@ -0,0 +1,69 @@
+//! The Rust parser and macro expander.
+//!
+//! # Note
+//!
+//! This API is completely unstable and subject to change.
+
+#![doc(html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(deny(warnings))))]
+#![feature(bool_to_option)]
+#![feature(box_syntax)]
+#![feature(const_fn)] // For the `transmute` in `P::new`
+#![feature(const_panic)]
+#![feature(const_fn_transmute)]
+#![feature(crate_visibility_modifier)]
+#![feature(label_break_value)]
+#![feature(nll)]
+#![feature(or_patterns)]
+#![feature(try_trait)]
+#![feature(unicode_internals)]
+#![recursion_limit = "256"]
+
+#[macro_use]
+extern crate rustc_macros;
+
+#[macro_export]
+macro_rules! unwrap_or {
+    ($opt:expr, $default:expr) => {
+        match $opt {
+            Some(x) => x,
+            None => $default,
+        }
+    };
+}
+
+pub mod util {
+    pub mod classify;
+    pub mod comments;
+    pub mod lev_distance;
+    pub mod literal;
+    pub mod parser;
+}
+
+pub mod ast;
+pub mod attr;
+pub mod crate_disambiguator;
+pub mod entry;
+pub mod expand;
+pub mod mut_visit;
+pub mod node_id;
+pub mod ptr;
+pub mod token;
+pub mod tokenstream;
+pub mod visit;
+
+pub use self::ast::*;
+
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+
+/// Requirements for a `StableHashingContext` to be used in this crate.
+/// This is a hack to allow using the `HashStable_Generic` derive macro
+/// instead of implementing everything in librustc_middle.
+pub trait HashStableContext: rustc_span::HashStableContext {
+    fn hash_attr(&mut self, _: &ast::Attribute, hasher: &mut StableHasher);
+}
+
+impl<AstCtx: crate::HashStableContext> HashStable<AstCtx> for ast::Attribute {
+    fn hash_stable(&self, hcx: &mut AstCtx, hasher: &mut StableHasher) {
+        hcx.hash_attr(self, hasher)
+    }
+}
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
new file mode 100644
index 00000000000..965571aaa54
--- /dev/null
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -0,0 +1,1325 @@
+//! A `MutVisitor` represents an AST modification; it accepts an AST piece and
+//! and mutates it in place. So, for instance, macro expansion is a `MutVisitor`
+//! that walks over an AST and modifies it.
+//!
+//! Note: using a `MutVisitor` (other than the `MacroExpander` `MutVisitor`) on
+//! an AST before macro expansion is probably a bad idea. For instance,
+//! a `MutVisitor` renaming item names in a module will miss all of those
+//! that are created by the expansion of a macro.
+
+use crate::ast::*;
+use crate::ptr::P;
+use crate::token::{self, Token};
+use crate::tokenstream::*;
+
+use rustc_data_structures::map_in_place::MapInPlace;
+use rustc_data_structures::sync::Lrc;
+use rustc_span::source_map::{respan, Spanned};
+use rustc_span::symbol::Ident;
+use rustc_span::Span;
+
+use smallvec::{smallvec, Array, SmallVec};
+use std::ops::DerefMut;
+use std::{panic, process, ptr};
+
+pub trait ExpectOne<A: Array> {
+    fn expect_one(self, err: &'static str) -> A::Item;
+}
+
+impl<A: Array> ExpectOne<A> for SmallVec<A> {
+    fn expect_one(self, err: &'static str) -> A::Item {
+        assert!(self.len() == 1, err);
+        self.into_iter().next().unwrap()
+    }
+}
+
+pub trait MutVisitor: Sized {
+    // Methods in this trait have one of three forms:
+    //
+    //   fn visit_t(&mut self, t: &mut T);                      // common
+    //   fn flat_map_t(&mut self, t: T) -> SmallVec<[T; 1]>;    // rare
+    //   fn filter_map_t(&mut self, t: T) -> Option<T>;         // rarest
+    //
+    // Any additions to this trait should happen in form of a call to a public
+    // `noop_*` function that only calls out to the visitor again, not other
+    // `noop_*` functions. This is a necessary API workaround to the problem of
+    // not being able to call out to the super default method in an overridden
+    // default method.
+    //
+    // When writing these methods, it is better to use destructuring like this:
+    //
+    //   fn visit_abc(&mut self, ABC { a, b, c: _ }: &mut ABC) {
+    //       visit_a(a);
+    //       visit_b(b);
+    //   }
+    //
+    // than to use field access like this:
+    //
+    //   fn visit_abc(&mut self, abc: &mut ABC) {
+    //       visit_a(&mut abc.a);
+    //       visit_b(&mut abc.b);
+    //       // ignore abc.c
+    //   }
+    //
+    // As well as being more concise, the former is explicit about which fields
+    // are skipped. Furthermore, if a new field is added, the destructuring
+    // version will cause a compile error, which is good. In comparison, the
+    // field access version will continue working and it would be easy to
+    // forget to add handling for it.
+
+    fn visit_crate(&mut self, c: &mut Crate) {
+        noop_visit_crate(c, self)
+    }
+
+    fn visit_meta_list_item(&mut self, list_item: &mut NestedMetaItem) {
+        noop_visit_meta_list_item(list_item, self);
+    }
+
+    fn visit_meta_item(&mut self, meta_item: &mut MetaItem) {
+        noop_visit_meta_item(meta_item, self);
+    }
+
+    fn visit_use_tree(&mut self, use_tree: &mut UseTree) {
+        noop_visit_use_tree(use_tree, self);
+    }
+
+    fn flat_map_foreign_item(&mut self, ni: P<ForeignItem>) -> SmallVec<[P<ForeignItem>; 1]> {
+        noop_flat_map_foreign_item(ni, self)
+    }
+
+    fn flat_map_item(&mut self, i: P<Item>) -> SmallVec<[P<Item>; 1]> {
+        noop_flat_map_item(i, self)
+    }
+
+    fn visit_fn_header(&mut self, header: &mut FnHeader) {
+        noop_visit_fn_header(header, self);
+    }
+
+    fn flat_map_struct_field(&mut self, sf: StructField) -> SmallVec<[StructField; 1]> {
+        noop_flat_map_struct_field(sf, self)
+    }
+
+    fn visit_item_kind(&mut self, i: &mut ItemKind) {
+        noop_visit_item_kind(i, self);
+    }
+
+    fn flat_map_trait_item(&mut self, i: P<AssocItem>) -> SmallVec<[P<AssocItem>; 1]> {
+        noop_flat_map_assoc_item(i, self)
+    }
+
+    fn flat_map_impl_item(&mut self, i: P<AssocItem>) -> SmallVec<[P<AssocItem>; 1]> {
+        noop_flat_map_assoc_item(i, self)
+    }
+
+    fn visit_fn_decl(&mut self, d: &mut P<FnDecl>) {
+        noop_visit_fn_decl(d, self);
+    }
+
+    fn visit_asyncness(&mut self, a: &mut Async) {
+        noop_visit_asyncness(a, self);
+    }
+
+    fn visit_block(&mut self, b: &mut P<Block>) {
+        noop_visit_block(b, self);
+    }
+
+    fn flat_map_stmt(&mut self, s: Stmt) -> SmallVec<[Stmt; 1]> {
+        noop_flat_map_stmt(s, self)
+    }
+
+    fn flat_map_arm(&mut self, arm: Arm) -> SmallVec<[Arm; 1]> {
+        noop_flat_map_arm(arm, self)
+    }
+
+    fn visit_pat(&mut self, p: &mut P<Pat>) {
+        noop_visit_pat(p, self);
+    }
+
+    fn visit_anon_const(&mut self, c: &mut AnonConst) {
+        noop_visit_anon_const(c, self);
+    }
+
+    fn visit_expr(&mut self, e: &mut P<Expr>) {
+        noop_visit_expr(e, self);
+    }
+
+    fn filter_map_expr(&mut self, e: P<Expr>) -> Option<P<Expr>> {
+        noop_filter_map_expr(e, self)
+    }
+
+    fn visit_generic_arg(&mut self, arg: &mut GenericArg) {
+        noop_visit_generic_arg(arg, self);
+    }
+
+    fn visit_ty(&mut self, t: &mut P<Ty>) {
+        noop_visit_ty(t, self);
+    }
+
+    fn visit_lifetime(&mut self, l: &mut Lifetime) {
+        noop_visit_lifetime(l, self);
+    }
+
+    fn visit_ty_constraint(&mut self, t: &mut AssocTyConstraint) {
+        noop_visit_ty_constraint(t, self);
+    }
+
+    fn visit_mod(&mut self, m: &mut Mod) {
+        noop_visit_mod(m, self);
+    }
+
+    fn visit_foreign_mod(&mut self, nm: &mut ForeignMod) {
+        noop_visit_foreign_mod(nm, self);
+    }
+
+    fn flat_map_variant(&mut self, v: Variant) -> SmallVec<[Variant; 1]> {
+        noop_flat_map_variant(v, self)
+    }
+
+    fn visit_ident(&mut self, i: &mut Ident) {
+        noop_visit_ident(i, self);
+    }
+
+    fn visit_path(&mut self, p: &mut Path) {
+        noop_visit_path(p, self);
+    }
+
+    fn visit_qself(&mut self, qs: &mut Option<QSelf>) {
+        noop_visit_qself(qs, self);
+    }
+
+    fn visit_generic_args(&mut self, p: &mut GenericArgs) {
+        noop_visit_generic_args(p, self);
+    }
+
+    fn visit_angle_bracketed_parameter_data(&mut self, p: &mut AngleBracketedArgs) {
+        noop_visit_angle_bracketed_parameter_data(p, self);
+    }
+
+    fn visit_parenthesized_parameter_data(&mut self, p: &mut ParenthesizedArgs) {
+        noop_visit_parenthesized_parameter_data(p, self);
+    }
+
+    fn visit_local(&mut self, l: &mut P<Local>) {
+        noop_visit_local(l, self);
+    }
+
+    fn visit_mac(&mut self, _mac: &mut MacCall) {
+        panic!("visit_mac disabled by default");
+        // N.B., see note about macros above. If you really want a visitor that
+        // works on macros, use this definition in your trait impl:
+        //   mut_visit::noop_visit_mac(_mac, self);
+    }
+
+    fn visit_macro_def(&mut self, def: &mut MacroDef) {
+        noop_visit_macro_def(def, self);
+    }
+
+    fn visit_label(&mut self, label: &mut Label) {
+        noop_visit_label(label, self);
+    }
+
+    fn visit_attribute(&mut self, at: &mut Attribute) {
+        noop_visit_attribute(at, self);
+    }
+
+    fn flat_map_param(&mut self, param: Param) -> SmallVec<[Param; 1]> {
+        noop_flat_map_param(param, self)
+    }
+
+    fn visit_generics(&mut self, generics: &mut Generics) {
+        noop_visit_generics(generics, self);
+    }
+
+    fn visit_trait_ref(&mut self, tr: &mut TraitRef) {
+        noop_visit_trait_ref(tr, self);
+    }
+
+    fn visit_poly_trait_ref(&mut self, p: &mut PolyTraitRef) {
+        noop_visit_poly_trait_ref(p, self);
+    }
+
+    fn visit_variant_data(&mut self, vdata: &mut VariantData) {
+        noop_visit_variant_data(vdata, self);
+    }
+
+    fn flat_map_generic_param(&mut self, param: GenericParam) -> SmallVec<[GenericParam; 1]> {
+        noop_flat_map_generic_param(param, self)
+    }
+
+    fn visit_tt(&mut self, tt: &mut TokenTree) {
+        noop_visit_tt(tt, self);
+    }
+
+    fn visit_tts(&mut self, tts: &mut TokenStream) {
+        noop_visit_tts(tts, self);
+    }
+
+    fn visit_token(&mut self, t: &mut Token) {
+        noop_visit_token(t, self);
+    }
+
+    fn visit_interpolated(&mut self, nt: &mut token::Nonterminal) {
+        noop_visit_interpolated(nt, self);
+    }
+
+    fn visit_param_bound(&mut self, tpb: &mut GenericBound) {
+        noop_visit_param_bound(tpb, self);
+    }
+
+    fn visit_mt(&mut self, mt: &mut MutTy) {
+        noop_visit_mt(mt, self);
+    }
+
+    fn flat_map_field(&mut self, f: Field) -> SmallVec<[Field; 1]> {
+        noop_flat_map_field(f, self)
+    }
+
+    fn visit_where_clause(&mut self, where_clause: &mut WhereClause) {
+        noop_visit_where_clause(where_clause, self);
+    }
+
+    fn visit_where_predicate(&mut self, where_predicate: &mut WherePredicate) {
+        noop_visit_where_predicate(where_predicate, self);
+    }
+
+    fn visit_vis(&mut self, vis: &mut Visibility) {
+        noop_visit_vis(vis, self);
+    }
+
+    fn visit_id(&mut self, _id: &mut NodeId) {
+        // Do nothing.
+    }
+
+    fn visit_span(&mut self, _sp: &mut Span) {
+        // Do nothing.
+    }
+
+    fn flat_map_field_pattern(&mut self, fp: FieldPat) -> SmallVec<[FieldPat; 1]> {
+        noop_flat_map_field_pattern(fp, self)
+    }
+}
+
+/// Use a map-style function (`FnOnce(T) -> T`) to overwrite a `&mut T`. Useful
+/// when using a `flat_map_*` or `filter_map_*` method within a `visit_`
+/// method. Abort the program if the closure panics.
+//
+// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
+pub fn visit_clobber<T, F>(t: &mut T, f: F)
+where
+    F: FnOnce(T) -> T,
+{
+    unsafe {
+        // Safe because `t` is used in a read-only fashion by `read()` before
+        // being overwritten by `write()`.
+        let old_t = ptr::read(t);
+        let new_t = panic::catch_unwind(panic::AssertUnwindSafe(|| f(old_t)))
+            .unwrap_or_else(|_| process::abort());
+        ptr::write(t, new_t);
+    }
+}
+
+// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
+#[inline]
+pub fn visit_vec<T, F>(elems: &mut Vec<T>, mut visit_elem: F)
+where
+    F: FnMut(&mut T),
+{
+    for elem in elems {
+        visit_elem(elem);
+    }
+}
+
+// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
+#[inline]
+pub fn visit_opt<T, F>(opt: &mut Option<T>, mut visit_elem: F)
+where
+    F: FnMut(&mut T),
+{
+    if let Some(elem) = opt {
+        visit_elem(elem);
+    }
+}
+
+// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
+pub fn visit_attrs<T: MutVisitor>(attrs: &mut Vec<Attribute>, vis: &mut T) {
+    visit_vec(attrs, |attr| vis.visit_attribute(attr));
+}
+
+// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
+pub fn visit_thin_attrs<T: MutVisitor>(attrs: &mut AttrVec, vis: &mut T) {
+    for attr in attrs.iter_mut() {
+        vis.visit_attribute(attr);
+    }
+}
+
+// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
+pub fn visit_exprs<T: MutVisitor>(exprs: &mut Vec<P<Expr>>, vis: &mut T) {
+    exprs.flat_map_in_place(|expr| vis.filter_map_expr(expr))
+}
+
+// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
+pub fn visit_bounds<T: MutVisitor>(bounds: &mut GenericBounds, vis: &mut T) {
+    visit_vec(bounds, |bound| vis.visit_param_bound(bound));
+}
+
+// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
+pub fn visit_fn_sig<T: MutVisitor>(FnSig { header, decl, span }: &mut FnSig, vis: &mut T) {
+    vis.visit_fn_header(header);
+    vis.visit_fn_decl(decl);
+    vis.visit_span(span);
+}
+
+// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
+pub fn visit_mac_args<T: MutVisitor>(args: &mut MacArgs, vis: &mut T) {
+    match args {
+        MacArgs::Empty => {}
+        MacArgs::Delimited(dspan, _delim, tokens) => {
+            visit_delim_span(dspan, vis);
+            vis.visit_tts(tokens);
+        }
+        MacArgs::Eq(eq_span, tokens) => {
+            vis.visit_span(eq_span);
+            vis.visit_tts(tokens);
+        }
+    }
+}
+
+pub fn visit_delim_span<T: MutVisitor>(dspan: &mut DelimSpan, vis: &mut T) {
+    vis.visit_span(&mut dspan.open);
+    vis.visit_span(&mut dspan.close);
+}
+
+pub fn noop_flat_map_field_pattern<T: MutVisitor>(
+    mut fp: FieldPat,
+    vis: &mut T,
+) -> SmallVec<[FieldPat; 1]> {
+    let FieldPat { attrs, id, ident, is_placeholder: _, is_shorthand: _, pat, span } = &mut fp;
+    vis.visit_id(id);
+    vis.visit_ident(ident);
+    vis.visit_pat(pat);
+    vis.visit_span(span);
+    visit_thin_attrs(attrs, vis);
+    smallvec![fp]
+}
+
+pub fn noop_visit_use_tree<T: MutVisitor>(use_tree: &mut UseTree, vis: &mut T) {
+    let UseTree { prefix, kind, span } = use_tree;
+    vis.visit_path(prefix);
+    match kind {
+        UseTreeKind::Simple(rename, id1, id2) => {
+            visit_opt(rename, |rename| vis.visit_ident(rename));
+            vis.visit_id(id1);
+            vis.visit_id(id2);
+        }
+        UseTreeKind::Nested(items) => {
+            for (tree, id) in items {
+                vis.visit_use_tree(tree);
+                vis.visit_id(id);
+            }
+        }
+        UseTreeKind::Glob => {}
+    }
+    vis.visit_span(span);
+}
+
+pub fn noop_flat_map_arm<T: MutVisitor>(mut arm: Arm, vis: &mut T) -> SmallVec<[Arm; 1]> {
+    let Arm { attrs, pat, guard, body, span, id, is_placeholder: _ } = &mut arm;
+    visit_attrs(attrs, vis);
+    vis.visit_id(id);
+    vis.visit_pat(pat);
+    visit_opt(guard, |guard| vis.visit_expr(guard));
+    vis.visit_expr(body);
+    vis.visit_span(span);
+    smallvec![arm]
+}
+
+pub fn noop_visit_ty_constraint<T: MutVisitor>(
+    AssocTyConstraint { id, ident, kind, span }: &mut AssocTyConstraint,
+    vis: &mut T,
+) {
+    vis.visit_id(id);
+    vis.visit_ident(ident);
+    match kind {
+        AssocTyConstraintKind::Equality { ref mut ty } => {
+            vis.visit_ty(ty);
+        }
+        AssocTyConstraintKind::Bound { ref mut bounds } => {
+            visit_bounds(bounds, vis);
+        }
+    }
+    vis.visit_span(span);
+}
+
+pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) {
+    let Ty { id, kind, span } = ty.deref_mut();
+    vis.visit_id(id);
+    match kind {
+        TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err | TyKind::Never | TyKind::CVarArgs => {}
+        TyKind::Slice(ty) => vis.visit_ty(ty),
+        TyKind::Ptr(mt) => vis.visit_mt(mt),
+        TyKind::Rptr(lt, mt) => {
+            visit_opt(lt, |lt| noop_visit_lifetime(lt, vis));
+            vis.visit_mt(mt);
+        }
+        TyKind::BareFn(bft) => {
+            let BareFnTy { unsafety: _, ext: _, generic_params, decl } = bft.deref_mut();
+            generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param));
+            vis.visit_fn_decl(decl);
+        }
+        TyKind::Tup(tys) => visit_vec(tys, |ty| vis.visit_ty(ty)),
+        TyKind::Paren(ty) => vis.visit_ty(ty),
+        TyKind::Path(qself, path) => {
+            vis.visit_qself(qself);
+            vis.visit_path(path);
+        }
+        TyKind::Array(ty, length) => {
+            vis.visit_ty(ty);
+            vis.visit_anon_const(length);
+        }
+        TyKind::Typeof(expr) => vis.visit_anon_const(expr),
+        TyKind::TraitObject(bounds, _syntax) => {
+            visit_vec(bounds, |bound| vis.visit_param_bound(bound))
+        }
+        TyKind::ImplTrait(id, bounds) => {
+            vis.visit_id(id);
+            visit_vec(bounds, |bound| vis.visit_param_bound(bound));
+        }
+        TyKind::MacCall(mac) => vis.visit_mac(mac),
+    }
+    vis.visit_span(span);
+}
+
+pub fn noop_visit_foreign_mod<T: MutVisitor>(foreign_mod: &mut ForeignMod, vis: &mut T) {
+    let ForeignMod { abi: _, items } = foreign_mod;
+    items.flat_map_in_place(|item| vis.flat_map_foreign_item(item));
+}
+
+pub fn noop_flat_map_variant<T: MutVisitor>(
+    mut variant: Variant,
+    visitor: &mut T,
+) -> SmallVec<[Variant; 1]> {
+    let Variant { ident, vis, attrs, id, data, disr_expr, span, is_placeholder: _ } = &mut variant;
+    visitor.visit_ident(ident);
+    visitor.visit_vis(vis);
+    visit_attrs(attrs, visitor);
+    visitor.visit_id(id);
+    visitor.visit_variant_data(data);
+    visit_opt(disr_expr, |disr_expr| visitor.visit_anon_const(disr_expr));
+    visitor.visit_span(span);
+    smallvec![variant]
+}
+
+pub fn noop_visit_ident<T: MutVisitor>(Ident { name: _, span }: &mut Ident, vis: &mut T) {
+    vis.visit_span(span);
+}
+
+pub fn noop_visit_path<T: MutVisitor>(Path { segments, span }: &mut Path, vis: &mut T) {
+    vis.visit_span(span);
+    for PathSegment { ident, id, args } in segments {
+        vis.visit_ident(ident);
+        vis.visit_id(id);
+        visit_opt(args, |args| vis.visit_generic_args(args));
+    }
+}
+
+pub fn noop_visit_qself<T: MutVisitor>(qself: &mut Option<QSelf>, vis: &mut T) {
+    visit_opt(qself, |QSelf { ty, path_span, position: _ }| {
+        vis.visit_ty(ty);
+        vis.visit_span(path_span);
+    })
+}
+
+pub fn noop_visit_generic_args<T: MutVisitor>(generic_args: &mut GenericArgs, vis: &mut T) {
+    match generic_args {
+        GenericArgs::AngleBracketed(data) => vis.visit_angle_bracketed_parameter_data(data),
+        GenericArgs::Parenthesized(data) => vis.visit_parenthesized_parameter_data(data),
+    }
+}
+
+pub fn noop_visit_generic_arg<T: MutVisitor>(arg: &mut GenericArg, vis: &mut T) {
+    match arg {
+        GenericArg::Lifetime(lt) => vis.visit_lifetime(lt),
+        GenericArg::Type(ty) => vis.visit_ty(ty),
+        GenericArg::Const(ct) => vis.visit_anon_const(ct),
+    }
+}
+
+pub fn noop_visit_angle_bracketed_parameter_data<T: MutVisitor>(
+    data: &mut AngleBracketedArgs,
+    vis: &mut T,
+) {
+    let AngleBracketedArgs { args, span } = data;
+    visit_vec(args, |arg| match arg {
+        AngleBracketedArg::Arg(arg) => vis.visit_generic_arg(arg),
+        AngleBracketedArg::Constraint(constraint) => vis.visit_ty_constraint(constraint),
+    });
+    vis.visit_span(span);
+}
+
+pub fn noop_visit_parenthesized_parameter_data<T: MutVisitor>(
+    args: &mut ParenthesizedArgs,
+    vis: &mut T,
+) {
+    let ParenthesizedArgs { inputs, output, span } = args;
+    visit_vec(inputs, |input| vis.visit_ty(input));
+    noop_visit_fn_ret_ty(output, vis);
+    vis.visit_span(span);
+}
+
+pub fn noop_visit_local<T: MutVisitor>(local: &mut P<Local>, vis: &mut T) {
+    let Local { id, pat, ty, init, span, attrs } = local.deref_mut();
+    vis.visit_id(id);
+    vis.visit_pat(pat);
+    visit_opt(ty, |ty| vis.visit_ty(ty));
+    visit_opt(init, |init| vis.visit_expr(init));
+    vis.visit_span(span);
+    visit_thin_attrs(attrs, vis);
+}
+
+pub fn noop_visit_attribute<T: MutVisitor>(attr: &mut Attribute, vis: &mut T) {
+    let Attribute { kind, id: _, style: _, span } = attr;
+    match kind {
+        AttrKind::Normal(AttrItem { path, args }) => {
+            vis.visit_path(path);
+            visit_mac_args(args, vis);
+        }
+        AttrKind::DocComment(..) => {}
+    }
+    vis.visit_span(span);
+}
+
+pub fn noop_visit_mac<T: MutVisitor>(mac: &mut MacCall, vis: &mut T) {
+    let MacCall { path, args, prior_type_ascription: _ } = mac;
+    vis.visit_path(path);
+    visit_mac_args(args, vis);
+}
+
+pub fn noop_visit_macro_def<T: MutVisitor>(macro_def: &mut MacroDef, vis: &mut T) {
+    let MacroDef { body, macro_rules: _ } = macro_def;
+    visit_mac_args(body, vis);
+}
+
+pub fn noop_visit_meta_list_item<T: MutVisitor>(li: &mut NestedMetaItem, vis: &mut T) {
+    match li {
+        NestedMetaItem::MetaItem(mi) => vis.visit_meta_item(mi),
+        NestedMetaItem::Literal(_lit) => {}
+    }
+}
+
+pub fn noop_visit_meta_item<T: MutVisitor>(mi: &mut MetaItem, vis: &mut T) {
+    let MetaItem { path: _, kind, span } = mi;
+    match kind {
+        MetaItemKind::Word => {}
+        MetaItemKind::List(mis) => visit_vec(mis, |mi| vis.visit_meta_list_item(mi)),
+        MetaItemKind::NameValue(_s) => {}
+    }
+    vis.visit_span(span);
+}
+
+pub fn noop_flat_map_param<T: MutVisitor>(mut param: Param, vis: &mut T) -> SmallVec<[Param; 1]> {
+    let Param { attrs, id, pat, span, ty, is_placeholder: _ } = &mut param;
+    vis.visit_id(id);
+    visit_thin_attrs(attrs, vis);
+    vis.visit_pat(pat);
+    vis.visit_span(span);
+    vis.visit_ty(ty);
+    smallvec![param]
+}
+
+pub fn noop_visit_tt<T: MutVisitor>(tt: &mut TokenTree, vis: &mut T) {
+    match tt {
+        TokenTree::Token(token) => {
+            vis.visit_token(token);
+        }
+        TokenTree::Delimited(DelimSpan { open, close }, _delim, tts) => {
+            vis.visit_span(open);
+            vis.visit_span(close);
+            vis.visit_tts(tts);
+        }
+    }
+}
+
+pub fn noop_visit_tts<T: MutVisitor>(TokenStream(tts): &mut TokenStream, vis: &mut T) {
+    let tts = Lrc::make_mut(tts);
+    visit_vec(tts, |(tree, _is_joint)| vis.visit_tt(tree));
+}
+
+// Applies ident visitor if it's an ident; applies other visits to interpolated nodes.
+// In practice the ident part is not actually used by specific visitors right now,
+// but there's a test below checking that it works.
+pub fn noop_visit_token<T: MutVisitor>(t: &mut Token, vis: &mut T) {
+    let Token { kind, span } = t;
+    match kind {
+        token::Ident(name, _) | token::Lifetime(name) => {
+            let mut ident = Ident::new(*name, *span);
+            vis.visit_ident(&mut ident);
+            *name = ident.name;
+            *span = ident.span;
+            return; // Avoid visiting the span for the second time.
+        }
+        token::Interpolated(nt) => {
+            let mut nt = Lrc::make_mut(nt);
+            vis.visit_interpolated(&mut nt);
+        }
+        _ => {}
+    }
+    vis.visit_span(span);
+}
+
+/// Applies the visitor to elements of interpolated nodes.
+//
+// N.B., this can occur only when applying a visitor to partially expanded
+// code, where parsed pieces have gotten implanted ito *other* macro
+// invocations. This is relevant for macro hygiene, but possibly not elsewhere.
+//
+// One problem here occurs because the types for flat_map_item, flat_map_stmt,
+// etc., allow the visitor to return *multiple* items; this is a problem for the
+// nodes here, because they insist on having exactly one piece. One solution
+// would be to mangle the MutVisitor trait to include one-to-many and
+// one-to-one versions of these entry points, but that would probably confuse a
+// lot of people and help very few. Instead, I'm just going to put in dynamic
+// checks. I think the performance impact of this will be pretty much
+// nonexistent. The danger is that someone will apply a `MutVisitor` to a
+// partially expanded node, and will be confused by the fact that their
+// `flat_map_item` or `flat_map_stmt` isn't getting called on `NtItem` or `NtStmt`
+// nodes. Hopefully they'll wind up reading this comment, and doing something
+// appropriate.
+//
+// BTW, design choice: I considered just changing the type of, e.g., `NtItem` to
+// contain multiple items, but decided against it when I looked at
+// `parse_item_or_view_item` and tried to figure out what I would do with
+// multiple items there....
+pub fn noop_visit_interpolated<T: MutVisitor>(nt: &mut token::Nonterminal, vis: &mut T) {
+    match nt {
+        token::NtItem(item) => visit_clobber(item, |item| {
+            // This is probably okay, because the only visitors likely to
+            // peek inside interpolated nodes will be renamings/markings,
+            // which map single items to single items.
+            vis.flat_map_item(item).expect_one("expected visitor to produce exactly one item")
+        }),
+        token::NtBlock(block) => vis.visit_block(block),
+        token::NtStmt(stmt) => visit_clobber(stmt, |stmt| {
+            // See reasoning above.
+            vis.flat_map_stmt(stmt).expect_one("expected visitor to produce exactly one item")
+        }),
+        token::NtPat(pat) => vis.visit_pat(pat),
+        token::NtExpr(expr) => vis.visit_expr(expr),
+        token::NtTy(ty) => vis.visit_ty(ty),
+        token::NtIdent(ident, _is_raw) => vis.visit_ident(ident),
+        token::NtLifetime(ident) => vis.visit_ident(ident),
+        token::NtLiteral(expr) => vis.visit_expr(expr),
+        token::NtMeta(item) => {
+            let AttrItem { path, args } = item.deref_mut();
+            vis.visit_path(path);
+            visit_mac_args(args, vis);
+        }
+        token::NtPath(path) => vis.visit_path(path),
+        token::NtTT(tt) => vis.visit_tt(tt),
+        token::NtVis(visib) => vis.visit_vis(visib),
+    }
+}
+
+pub fn noop_visit_asyncness<T: MutVisitor>(asyncness: &mut Async, vis: &mut T) {
+    match asyncness {
+        Async::Yes { span: _, closure_id, return_impl_trait_id } => {
+            vis.visit_id(closure_id);
+            vis.visit_id(return_impl_trait_id);
+        }
+        Async::No => {}
+    }
+}
+
+pub fn noop_visit_fn_decl<T: MutVisitor>(decl: &mut P<FnDecl>, vis: &mut T) {
+    let FnDecl { inputs, output } = decl.deref_mut();
+    inputs.flat_map_in_place(|param| vis.flat_map_param(param));
+    noop_visit_fn_ret_ty(output, vis);
+}
+
+pub fn noop_visit_fn_ret_ty<T: MutVisitor>(fn_ret_ty: &mut FnRetTy, vis: &mut T) {
+    match fn_ret_ty {
+        FnRetTy::Default(span) => vis.visit_span(span),
+        FnRetTy::Ty(ty) => vis.visit_ty(ty),
+    }
+}
+
+pub fn noop_visit_param_bound<T: MutVisitor>(pb: &mut GenericBound, vis: &mut T) {
+    match pb {
+        GenericBound::Trait(ty, _modifier) => vis.visit_poly_trait_ref(ty),
+        GenericBound::Outlives(lifetime) => noop_visit_lifetime(lifetime, vis),
+    }
+}
+
+pub fn noop_flat_map_generic_param<T: MutVisitor>(
+    mut param: GenericParam,
+    vis: &mut T,
+) -> SmallVec<[GenericParam; 1]> {
+    let GenericParam { id, ident, attrs, bounds, kind, is_placeholder: _ } = &mut param;
+    vis.visit_id(id);
+    vis.visit_ident(ident);
+    visit_thin_attrs(attrs, vis);
+    visit_vec(bounds, |bound| noop_visit_param_bound(bound, vis));
+    match kind {
+        GenericParamKind::Lifetime => {}
+        GenericParamKind::Type { default } => {
+            visit_opt(default, |default| vis.visit_ty(default));
+        }
+        GenericParamKind::Const { ty, kw_span: _ } => {
+            vis.visit_ty(ty);
+        }
+    }
+    smallvec![param]
+}
+
+pub fn noop_visit_label<T: MutVisitor>(Label { ident }: &mut Label, vis: &mut T) {
+    vis.visit_ident(ident);
+}
+
+fn noop_visit_lifetime<T: MutVisitor>(Lifetime { id, ident }: &mut Lifetime, vis: &mut T) {
+    vis.visit_id(id);
+    vis.visit_ident(ident);
+}
+
+pub fn noop_visit_generics<T: MutVisitor>(generics: &mut Generics, vis: &mut T) {
+    let Generics { params, where_clause, span } = generics;
+    params.flat_map_in_place(|param| vis.flat_map_generic_param(param));
+    vis.visit_where_clause(where_clause);
+    vis.visit_span(span);
+}
+
+pub fn noop_visit_where_clause<T: MutVisitor>(wc: &mut WhereClause, vis: &mut T) {
+    let WhereClause { has_where_token: _, predicates, span } = wc;
+    visit_vec(predicates, |predicate| vis.visit_where_predicate(predicate));
+    vis.visit_span(span);
+}
+
+pub fn noop_visit_where_predicate<T: MutVisitor>(pred: &mut WherePredicate, vis: &mut T) {
+    match pred {
+        WherePredicate::BoundPredicate(bp) => {
+            let WhereBoundPredicate { span, bound_generic_params, bounded_ty, bounds } = bp;
+            vis.visit_span(span);
+            bound_generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param));
+            vis.visit_ty(bounded_ty);
+            visit_vec(bounds, |bound| vis.visit_param_bound(bound));
+        }
+        WherePredicate::RegionPredicate(rp) => {
+            let WhereRegionPredicate { span, lifetime, bounds } = rp;
+            vis.visit_span(span);
+            noop_visit_lifetime(lifetime, vis);
+            visit_vec(bounds, |bound| noop_visit_param_bound(bound, vis));
+        }
+        WherePredicate::EqPredicate(ep) => {
+            let WhereEqPredicate { id, span, lhs_ty, rhs_ty } = ep;
+            vis.visit_id(id);
+            vis.visit_span(span);
+            vis.visit_ty(lhs_ty);
+            vis.visit_ty(rhs_ty);
+        }
+    }
+}
+
+pub fn noop_visit_variant_data<T: MutVisitor>(vdata: &mut VariantData, vis: &mut T) {
+    match vdata {
+        VariantData::Struct(fields, ..) => {
+            fields.flat_map_in_place(|field| vis.flat_map_struct_field(field));
+        }
+        VariantData::Tuple(fields, id) => {
+            fields.flat_map_in_place(|field| vis.flat_map_struct_field(field));
+            vis.visit_id(id);
+        }
+        VariantData::Unit(id) => vis.visit_id(id),
+    }
+}
+
+pub fn noop_visit_trait_ref<T: MutVisitor>(TraitRef { path, ref_id }: &mut TraitRef, vis: &mut T) {
+    vis.visit_path(path);
+    vis.visit_id(ref_id);
+}
+
+pub fn noop_visit_poly_trait_ref<T: MutVisitor>(p: &mut PolyTraitRef, vis: &mut T) {
+    let PolyTraitRef { bound_generic_params, trait_ref, span } = p;
+    bound_generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param));
+    vis.visit_trait_ref(trait_ref);
+    vis.visit_span(span);
+}
+
+pub fn noop_flat_map_struct_field<T: MutVisitor>(
+    mut sf: StructField,
+    visitor: &mut T,
+) -> SmallVec<[StructField; 1]> {
+    let StructField { span, ident, vis, id, ty, attrs, is_placeholder: _ } = &mut sf;
+    visitor.visit_span(span);
+    visit_opt(ident, |ident| visitor.visit_ident(ident));
+    visitor.visit_vis(vis);
+    visitor.visit_id(id);
+    visitor.visit_ty(ty);
+    visit_attrs(attrs, visitor);
+    smallvec![sf]
+}
+
+pub fn noop_flat_map_field<T: MutVisitor>(mut f: Field, vis: &mut T) -> SmallVec<[Field; 1]> {
+    let Field { ident, expr, span, is_shorthand: _, attrs, id, is_placeholder: _ } = &mut f;
+    vis.visit_ident(ident);
+    vis.visit_expr(expr);
+    vis.visit_id(id);
+    vis.visit_span(span);
+    visit_thin_attrs(attrs, vis);
+    smallvec![f]
+}
+
+pub fn noop_visit_mt<T: MutVisitor>(MutTy { ty, mutbl: _ }: &mut MutTy, vis: &mut T) {
+    vis.visit_ty(ty);
+}
+
+pub fn noop_visit_block<T: MutVisitor>(block: &mut P<Block>, vis: &mut T) {
+    let Block { id, stmts, rules: _, span } = block.deref_mut();
+    vis.visit_id(id);
+    stmts.flat_map_in_place(|stmt| vis.flat_map_stmt(stmt));
+    vis.visit_span(span);
+}
+
+pub fn noop_visit_item_kind<T: MutVisitor>(kind: &mut ItemKind, vis: &mut T) {
+    match kind {
+        ItemKind::ExternCrate(_orig_name) => {}
+        ItemKind::Use(use_tree) => vis.visit_use_tree(use_tree),
+        ItemKind::Static(ty, _, expr) | ItemKind::Const(_, ty, expr) => {
+            vis.visit_ty(ty);
+            visit_opt(expr, |expr| vis.visit_expr(expr));
+        }
+        ItemKind::Fn(_, sig, generics, body) => {
+            visit_fn_sig(sig, vis);
+            vis.visit_generics(generics);
+            visit_opt(body, |body| vis.visit_block(body));
+        }
+        ItemKind::Mod(m) => vis.visit_mod(m),
+        ItemKind::ForeignMod(nm) => vis.visit_foreign_mod(nm),
+        ItemKind::GlobalAsm(_ga) => {}
+        ItemKind::TyAlias(_, generics, bounds, ty) => {
+            vis.visit_generics(generics);
+            visit_bounds(bounds, vis);
+            visit_opt(ty, |ty| vis.visit_ty(ty));
+        }
+        ItemKind::Enum(EnumDef { variants }, generics) => {
+            variants.flat_map_in_place(|variant| vis.flat_map_variant(variant));
+            vis.visit_generics(generics);
+        }
+        ItemKind::Struct(variant_data, generics) | ItemKind::Union(variant_data, generics) => {
+            vis.visit_variant_data(variant_data);
+            vis.visit_generics(generics);
+        }
+        ItemKind::Impl {
+            unsafety: _,
+            polarity: _,
+            defaultness: _,
+            constness: _,
+            generics,
+            of_trait,
+            self_ty,
+            items,
+        } => {
+            vis.visit_generics(generics);
+            visit_opt(of_trait, |trait_ref| vis.visit_trait_ref(trait_ref));
+            vis.visit_ty(self_ty);
+            items.flat_map_in_place(|item| vis.flat_map_impl_item(item));
+        }
+        ItemKind::Trait(_is_auto, _unsafety, generics, bounds, items) => {
+            vis.visit_generics(generics);
+            visit_bounds(bounds, vis);
+            items.flat_map_in_place(|item| vis.flat_map_trait_item(item));
+        }
+        ItemKind::TraitAlias(generics, bounds) => {
+            vis.visit_generics(generics);
+            visit_bounds(bounds, vis);
+        }
+        ItemKind::MacCall(m) => vis.visit_mac(m),
+        ItemKind::MacroDef(def) => vis.visit_macro_def(def),
+    }
+}
+
+pub fn noop_flat_map_assoc_item<T: MutVisitor>(
+    mut item: P<AssocItem>,
+    visitor: &mut T,
+) -> SmallVec<[P<AssocItem>; 1]> {
+    let Item { id, ident, vis, attrs, kind, span, tokens: _ } = item.deref_mut();
+    visitor.visit_id(id);
+    visitor.visit_ident(ident);
+    visitor.visit_vis(vis);
+    visit_attrs(attrs, visitor);
+    match kind {
+        AssocItemKind::Const(_, ty, expr) => {
+            visitor.visit_ty(ty);
+            visit_opt(expr, |expr| visitor.visit_expr(expr));
+        }
+        AssocItemKind::Fn(_, sig, generics, body) => {
+            visitor.visit_generics(generics);
+            visit_fn_sig(sig, visitor);
+            visit_opt(body, |body| visitor.visit_block(body));
+        }
+        AssocItemKind::TyAlias(_, generics, bounds, ty) => {
+            visitor.visit_generics(generics);
+            visit_bounds(bounds, visitor);
+            visit_opt(ty, |ty| visitor.visit_ty(ty));
+        }
+        AssocItemKind::MacCall(mac) => visitor.visit_mac(mac),
+    }
+    visitor.visit_span(span);
+    smallvec![item]
+}
+
+pub fn noop_visit_fn_header<T: MutVisitor>(header: &mut FnHeader, vis: &mut T) {
+    let FnHeader { unsafety: _, asyncness, constness: _, ext: _ } = header;
+    vis.visit_asyncness(asyncness);
+}
+
+pub fn noop_visit_mod<T: MutVisitor>(Mod { inner, items, inline: _ }: &mut Mod, vis: &mut T) {
+    vis.visit_span(inner);
+    items.flat_map_in_place(|item| vis.flat_map_item(item));
+}
+
+pub fn noop_visit_crate<T: MutVisitor>(krate: &mut Crate, vis: &mut T) {
+    visit_clobber(krate, |Crate { module, attrs, span, proc_macros }| {
+        let item = P(Item {
+            ident: Ident::invalid(),
+            attrs,
+            id: DUMMY_NODE_ID,
+            vis: respan(span.shrink_to_lo(), VisibilityKind::Public),
+            span,
+            kind: ItemKind::Mod(module),
+            tokens: None,
+        });
+        let items = vis.flat_map_item(item);
+
+        let len = items.len();
+        if len == 0 {
+            let module = Mod { inner: span, items: vec![], inline: true };
+            Crate { module, attrs: vec![], span, proc_macros }
+        } else if len == 1 {
+            let Item { attrs, span, kind, .. } = items.into_iter().next().unwrap().into_inner();
+            match kind {
+                ItemKind::Mod(module) => Crate { module, attrs, span, proc_macros },
+                _ => panic!("visitor converted a module to not a module"),
+            }
+        } else {
+            panic!("a crate cannot expand to more than one item");
+        }
+    });
+}
+
+// Mutates one item into possibly many items.
+pub fn noop_flat_map_item<T: MutVisitor>(
+    mut item: P<Item>,
+    visitor: &mut T,
+) -> SmallVec<[P<Item>; 1]> {
+    let Item { ident, attrs, id, kind, vis, span, tokens: _ } = item.deref_mut();
+    visitor.visit_ident(ident);
+    visit_attrs(attrs, visitor);
+    visitor.visit_id(id);
+    visitor.visit_item_kind(kind);
+    visitor.visit_vis(vis);
+    visitor.visit_span(span);
+
+    // FIXME: if `tokens` is modified with a call to `vis.visit_tts` it causes
+    //        an ICE during resolve... odd!
+
+    smallvec![item]
+}
+
+pub fn noop_flat_map_foreign_item<T: MutVisitor>(
+    mut item: P<ForeignItem>,
+    visitor: &mut T,
+) -> SmallVec<[P<ForeignItem>; 1]> {
+    let Item { ident, attrs, id, kind, vis, span, tokens: _ } = item.deref_mut();
+    visitor.visit_id(id);
+    visitor.visit_ident(ident);
+    visitor.visit_vis(vis);
+    visit_attrs(attrs, visitor);
+    match kind {
+        ForeignItemKind::Static(ty, _, expr) => {
+            visitor.visit_ty(ty);
+            visit_opt(expr, |expr| visitor.visit_expr(expr));
+        }
+        ForeignItemKind::Fn(_, sig, generics, body) => {
+            visitor.visit_generics(generics);
+            visit_fn_sig(sig, visitor);
+            visit_opt(body, |body| visitor.visit_block(body));
+        }
+        ForeignItemKind::TyAlias(_, generics, bounds, ty) => {
+            visitor.visit_generics(generics);
+            visit_bounds(bounds, visitor);
+            visit_opt(ty, |ty| visitor.visit_ty(ty));
+        }
+        ForeignItemKind::MacCall(mac) => visitor.visit_mac(mac),
+    }
+    visitor.visit_span(span);
+    smallvec![item]
+}
+
+pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) {
+    let Pat { id, kind, span, tokens: _ } = pat.deref_mut();
+    vis.visit_id(id);
+    match kind {
+        PatKind::Wild | PatKind::Rest => {}
+        PatKind::Ident(_binding_mode, ident, sub) => {
+            vis.visit_ident(ident);
+            visit_opt(sub, |sub| vis.visit_pat(sub));
+        }
+        PatKind::Lit(e) => vis.visit_expr(e),
+        PatKind::TupleStruct(path, elems) => {
+            vis.visit_path(path);
+            visit_vec(elems, |elem| vis.visit_pat(elem));
+        }
+        PatKind::Path(qself, path) => {
+            vis.visit_qself(qself);
+            vis.visit_path(path);
+        }
+        PatKind::Struct(path, fields, _etc) => {
+            vis.visit_path(path);
+            fields.flat_map_in_place(|field| vis.flat_map_field_pattern(field));
+        }
+        PatKind::Box(inner) => vis.visit_pat(inner),
+        PatKind::Ref(inner, _mutbl) => vis.visit_pat(inner),
+        PatKind::Range(e1, e2, Spanned { span: _, node: _ }) => {
+            visit_opt(e1, |e| vis.visit_expr(e));
+            visit_opt(e2, |e| vis.visit_expr(e));
+            vis.visit_span(span);
+        }
+        PatKind::Tuple(elems) | PatKind::Slice(elems) | PatKind::Or(elems) => {
+            visit_vec(elems, |elem| vis.visit_pat(elem))
+        }
+        PatKind::Paren(inner) => vis.visit_pat(inner),
+        PatKind::MacCall(mac) => vis.visit_mac(mac),
+    }
+    vis.visit_span(span);
+}
+
+pub fn noop_visit_anon_const<T: MutVisitor>(AnonConst { id, value }: &mut AnonConst, vis: &mut T) {
+    vis.visit_id(id);
+    vis.visit_expr(value);
+}
+
+pub fn noop_visit_expr<T: MutVisitor>(
+    Expr { kind, id, span, attrs, tokens: _ }: &mut Expr,
+    vis: &mut T,
+) {
+    match kind {
+        ExprKind::Box(expr) => vis.visit_expr(expr),
+        ExprKind::Array(exprs) => visit_exprs(exprs, vis),
+        ExprKind::Repeat(expr, count) => {
+            vis.visit_expr(expr);
+            vis.visit_anon_const(count);
+        }
+        ExprKind::Tup(exprs) => visit_exprs(exprs, vis),
+        ExprKind::Call(f, args) => {
+            vis.visit_expr(f);
+            visit_exprs(args, vis);
+        }
+        ExprKind::MethodCall(PathSegment { ident, id, args }, exprs, span) => {
+            vis.visit_ident(ident);
+            vis.visit_id(id);
+            visit_opt(args, |args| vis.visit_generic_args(args));
+            visit_exprs(exprs, vis);
+            vis.visit_span(span);
+        }
+        ExprKind::Binary(_binop, lhs, rhs) => {
+            vis.visit_expr(lhs);
+            vis.visit_expr(rhs);
+        }
+        ExprKind::Unary(_unop, ohs) => vis.visit_expr(ohs),
+        ExprKind::Cast(expr, ty) => {
+            vis.visit_expr(expr);
+            vis.visit_ty(ty);
+        }
+        ExprKind::Type(expr, ty) => {
+            vis.visit_expr(expr);
+            vis.visit_ty(ty);
+        }
+        ExprKind::AddrOf(_, _, ohs) => vis.visit_expr(ohs),
+        ExprKind::Let(pat, scrutinee) => {
+            vis.visit_pat(pat);
+            vis.visit_expr(scrutinee);
+        }
+        ExprKind::If(cond, tr, fl) => {
+            vis.visit_expr(cond);
+            vis.visit_block(tr);
+            visit_opt(fl, |fl| vis.visit_expr(fl));
+        }
+        ExprKind::While(cond, body, label) => {
+            vis.visit_expr(cond);
+            vis.visit_block(body);
+            visit_opt(label, |label| vis.visit_label(label));
+        }
+        ExprKind::ForLoop(pat, iter, body, label) => {
+            vis.visit_pat(pat);
+            vis.visit_expr(iter);
+            vis.visit_block(body);
+            visit_opt(label, |label| vis.visit_label(label));
+        }
+        ExprKind::Loop(body, label) => {
+            vis.visit_block(body);
+            visit_opt(label, |label| vis.visit_label(label));
+        }
+        ExprKind::Match(expr, arms) => {
+            vis.visit_expr(expr);
+            arms.flat_map_in_place(|arm| vis.flat_map_arm(arm));
+        }
+        ExprKind::Closure(_capture_by, asyncness, _movability, decl, body, span) => {
+            vis.visit_asyncness(asyncness);
+            vis.visit_fn_decl(decl);
+            vis.visit_expr(body);
+            vis.visit_span(span);
+        }
+        ExprKind::Block(blk, label) => {
+            vis.visit_block(blk);
+            visit_opt(label, |label| vis.visit_label(label));
+        }
+        ExprKind::Async(_capture_by, node_id, body) => {
+            vis.visit_id(node_id);
+            vis.visit_block(body);
+        }
+        ExprKind::Await(expr) => vis.visit_expr(expr),
+        ExprKind::Assign(el, er, _) => {
+            vis.visit_expr(el);
+            vis.visit_expr(er);
+        }
+        ExprKind::AssignOp(_op, el, er) => {
+            vis.visit_expr(el);
+            vis.visit_expr(er);
+        }
+        ExprKind::Field(el, ident) => {
+            vis.visit_expr(el);
+            vis.visit_ident(ident);
+        }
+        ExprKind::Index(el, er) => {
+            vis.visit_expr(el);
+            vis.visit_expr(er);
+        }
+        ExprKind::Range(e1, e2, _lim) => {
+            visit_opt(e1, |e1| vis.visit_expr(e1));
+            visit_opt(e2, |e2| vis.visit_expr(e2));
+        }
+        ExprKind::Path(qself, path) => {
+            vis.visit_qself(qself);
+            vis.visit_path(path);
+        }
+        ExprKind::Break(label, expr) => {
+            visit_opt(label, |label| vis.visit_label(label));
+            visit_opt(expr, |expr| vis.visit_expr(expr));
+        }
+        ExprKind::Continue(label) => {
+            visit_opt(label, |label| vis.visit_label(label));
+        }
+        ExprKind::Ret(expr) => {
+            visit_opt(expr, |expr| vis.visit_expr(expr));
+        }
+        ExprKind::InlineAsm(asm) => {
+            for (op, _) in &mut asm.operands {
+                match op {
+                    InlineAsmOperand::In { expr, .. }
+                    | InlineAsmOperand::InOut { expr, .. }
+                    | InlineAsmOperand::Const { expr, .. }
+                    | InlineAsmOperand::Sym { expr, .. } => vis.visit_expr(expr),
+                    InlineAsmOperand::Out { expr, .. } => {
+                        if let Some(expr) = expr {
+                            vis.visit_expr(expr);
+                        }
+                    }
+                    InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => {
+                        vis.visit_expr(in_expr);
+                        if let Some(out_expr) = out_expr {
+                            vis.visit_expr(out_expr);
+                        }
+                    }
+                }
+            }
+        }
+        ExprKind::LlvmInlineAsm(asm) => {
+            let LlvmInlineAsm {
+                asm: _,
+                asm_str_style: _,
+                outputs,
+                inputs,
+                clobbers: _,
+                volatile: _,
+                alignstack: _,
+                dialect: _,
+            } = asm.deref_mut();
+            for out in outputs {
+                let LlvmInlineAsmOutput { constraint: _, expr, is_rw: _, is_indirect: _ } = out;
+                vis.visit_expr(expr);
+            }
+            visit_vec(inputs, |(_c, expr)| vis.visit_expr(expr));
+        }
+        ExprKind::MacCall(mac) => vis.visit_mac(mac),
+        ExprKind::Struct(path, fields, expr) => {
+            vis.visit_path(path);
+            fields.flat_map_in_place(|field| vis.flat_map_field(field));
+            visit_opt(expr, |expr| vis.visit_expr(expr));
+        }
+        ExprKind::Paren(expr) => {
+            vis.visit_expr(expr);
+
+            // Nodes that are equal modulo `Paren` sugar no-ops should have the same IDs.
+            *id = expr.id;
+            vis.visit_span(span);
+            visit_thin_attrs(attrs, vis);
+            return;
+        }
+        ExprKind::Yield(expr) => {
+            visit_opt(expr, |expr| vis.visit_expr(expr));
+        }
+        ExprKind::Try(expr) => vis.visit_expr(expr),
+        ExprKind::TryBlock(body) => vis.visit_block(body),
+        ExprKind::Lit(_) | ExprKind::Err => {}
+    }
+    vis.visit_id(id);
+    vis.visit_span(span);
+    visit_thin_attrs(attrs, vis);
+}
+
+pub fn noop_filter_map_expr<T: MutVisitor>(mut e: P<Expr>, vis: &mut T) -> Option<P<Expr>> {
+    Some({
+        vis.visit_expr(&mut e);
+        e
+    })
+}
+
+pub fn noop_flat_map_stmt<T: MutVisitor>(
+    Stmt { kind, mut span, mut id }: Stmt,
+    vis: &mut T,
+) -> SmallVec<[Stmt; 1]> {
+    vis.visit_id(&mut id);
+    vis.visit_span(&mut span);
+    noop_flat_map_stmt_kind(kind, vis).into_iter().map(|kind| Stmt { id, kind, span }).collect()
+}
+
+pub fn noop_flat_map_stmt_kind<T: MutVisitor>(
+    kind: StmtKind,
+    vis: &mut T,
+) -> SmallVec<[StmtKind; 1]> {
+    match kind {
+        StmtKind::Local(mut local) => smallvec![StmtKind::Local({
+            vis.visit_local(&mut local);
+            local
+        })],
+        StmtKind::Item(item) => vis.flat_map_item(item).into_iter().map(StmtKind::Item).collect(),
+        StmtKind::Expr(expr) => vis.filter_map_expr(expr).into_iter().map(StmtKind::Expr).collect(),
+        StmtKind::Semi(expr) => vis.filter_map_expr(expr).into_iter().map(StmtKind::Semi).collect(),
+        StmtKind::Empty => smallvec![StmtKind::Empty],
+        StmtKind::MacCall(mut mac) => {
+            let (mac_, _semi, attrs) = mac.deref_mut();
+            vis.visit_mac(mac_);
+            visit_thin_attrs(attrs, vis);
+            smallvec![StmtKind::MacCall(mac)]
+        }
+    }
+}
+
+pub fn noop_visit_vis<T: MutVisitor>(Spanned { node, span }: &mut Visibility, vis: &mut T) {
+    match node {
+        VisibilityKind::Public | VisibilityKind::Crate(_) | VisibilityKind::Inherited => {}
+        VisibilityKind::Restricted { path, id } => {
+            vis.visit_path(path);
+            vis.visit_id(id);
+        }
+    }
+    vis.visit_span(span);
+}
diff --git a/compiler/rustc_ast/src/node_id.rs b/compiler/rustc_ast/src/node_id.rs
new file mode 100644
index 00000000000..1035e945538
--- /dev/null
+++ b/compiler/rustc_ast/src/node_id.rs
@@ -0,0 +1,34 @@
+use rustc_span::ExpnId;
+use std::fmt;
+
+rustc_index::newtype_index! {
+    pub struct NodeId {
+        DEBUG_FORMAT = "NodeId({})"
+    }
+}
+
+rustc_data_structures::define_id_collections!(NodeMap, NodeSet, NodeId);
+
+/// `NodeId` used to represent the root of the crate.
+pub const CRATE_NODE_ID: NodeId = NodeId::from_u32(0);
+
+/// When parsing and doing expansions, we initially give all AST nodes this AST
+/// node value. Then later, in the renumber pass, we renumber them to have
+/// small, positive ids.
+pub const DUMMY_NODE_ID: NodeId = NodeId::MAX;
+
+impl NodeId {
+    pub fn placeholder_from_expn_id(expn_id: ExpnId) -> Self {
+        NodeId::from_u32(expn_id.as_u32())
+    }
+
+    pub fn placeholder_to_expn_id(self) -> ExpnId {
+        ExpnId::from_u32(self.as_u32())
+    }
+}
+
+impl fmt::Display for NodeId {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Display::fmt(&self.as_u32(), f)
+    }
+}
diff --git a/compiler/rustc_ast/src/ptr.rs b/compiler/rustc_ast/src/ptr.rs
new file mode 100644
index 00000000000..e4a3cccb7ea
--- /dev/null
+++ b/compiler/rustc_ast/src/ptr.rs
@@ -0,0 +1,219 @@
+//! The AST pointer.
+//!
+//! Provides `P<T>`, a frozen owned smart pointer.
+//!
+//! # Motivations and benefits
+//!
+//! * **Identity**: sharing AST nodes is problematic for the various analysis
+//!   passes (e.g., one may be able to bypass the borrow checker with a shared
+//!   `ExprKind::AddrOf` node taking a mutable borrow).
+//!
+//! * **Immutability**: `P<T>` disallows mutating its inner `T`, unlike `Box<T>`
+//!   (unless it contains an `Unsafe` interior, but that may be denied later).
+//!   This mainly prevents mistakes, but can also enforces a kind of "purity".
+//!
+//! * **Efficiency**: folding can reuse allocation space for `P<T>` and `Vec<T>`,
+//!   the latter even when the input and output types differ (as it would be the
+//!   case with arenas or a GADT AST using type parameters to toggle features).
+//!
+//! * **Maintainability**: `P<T>` provides a fixed interface - `Deref`,
+//!   `and_then` and `map` - which can remain fully functional even if the
+//!   implementation changes (using a special thread-local heap, for example).
+//!   Moreover, a switch to, e.g., `P<'a, T>` would be easy and mostly automated.
+
+use std::fmt::{self, Debug, Display};
+use std::iter::FromIterator;
+use std::ops::{Deref, DerefMut};
+use std::{slice, vec};
+
+use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
+
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+/// An owned smart pointer.
+pub struct P<T: ?Sized> {
+    ptr: Box<T>,
+}
+
+/// Construct a `P<T>` from a `T` value.
+#[allow(non_snake_case)]
+pub fn P<T: 'static>(value: T) -> P<T> {
+    P { ptr: box value }
+}
+
+impl<T: 'static> P<T> {
+    /// Move out of the pointer.
+    /// Intended for chaining transformations not covered by `map`.
+    pub fn and_then<U, F>(self, f: F) -> U
+    where
+        F: FnOnce(T) -> U,
+    {
+        f(*self.ptr)
+    }
+
+    /// Equivalent to `and_then(|x| x)`.
+    pub fn into_inner(self) -> T {
+        *self.ptr
+    }
+
+    /// Produce a new `P<T>` from `self` without reallocating.
+    pub fn map<F>(mut self, f: F) -> P<T>
+    where
+        F: FnOnce(T) -> T,
+    {
+        let x = f(*self.ptr);
+        *self.ptr = x;
+
+        self
+    }
+
+    /// Optionally produce a new `P<T>` from `self` without reallocating.
+    pub fn filter_map<F>(mut self, f: F) -> Option<P<T>>
+    where
+        F: FnOnce(T) -> Option<T>,
+    {
+        *self.ptr = f(*self.ptr)?;
+        Some(self)
+    }
+}
+
+impl<T: ?Sized> Deref for P<T> {
+    type Target = T;
+
+    fn deref(&self) -> &T {
+        &self.ptr
+    }
+}
+
+impl<T: ?Sized> DerefMut for P<T> {
+    fn deref_mut(&mut self) -> &mut T {
+        &mut self.ptr
+    }
+}
+
+impl<T: 'static + Clone> Clone for P<T> {
+    fn clone(&self) -> P<T> {
+        P((**self).clone())
+    }
+}
+
+impl<T: ?Sized + Debug> Debug for P<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        Debug::fmt(&self.ptr, f)
+    }
+}
+
+impl<T: Display> Display for P<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        Display::fmt(&**self, f)
+    }
+}
+
+impl<T> fmt::Pointer for P<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Pointer::fmt(&self.ptr, f)
+    }
+}
+
+impl<D: Decoder, T: 'static + Decodable<D>> Decodable<D> for P<T> {
+    fn decode(d: &mut D) -> Result<P<T>, D::Error> {
+        Decodable::decode(d).map(P)
+    }
+}
+
+impl<S: Encoder, T: Encodable<S>> Encodable<S> for P<T> {
+    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
+        (**self).encode(s)
+    }
+}
+
+impl<T> P<[T]> {
+    pub const fn new() -> P<[T]> {
+        // HACK(eddyb) bypass the lack of a `const fn` to create an empty `Box<[T]>`
+        // (as trait methods, `default` in this case, can't be `const fn` yet).
+        P {
+            ptr: unsafe {
+                use std::ptr::NonNull;
+                std::mem::transmute(NonNull::<[T; 0]>::dangling() as NonNull<[T]>)
+            },
+        }
+    }
+
+    #[inline(never)]
+    pub fn from_vec(v: Vec<T>) -> P<[T]> {
+        P { ptr: v.into_boxed_slice() }
+    }
+
+    #[inline(never)]
+    pub fn into_vec(self) -> Vec<T> {
+        self.ptr.into_vec()
+    }
+}
+
+impl<T> Default for P<[T]> {
+    /// Creates an empty `P<[T]>`.
+    fn default() -> P<[T]> {
+        P::new()
+    }
+}
+
+impl<T: Clone> Clone for P<[T]> {
+    fn clone(&self) -> P<[T]> {
+        P::from_vec(self.to_vec())
+    }
+}
+
+impl<T> From<Vec<T>> for P<[T]> {
+    fn from(v: Vec<T>) -> Self {
+        P::from_vec(v)
+    }
+}
+
+impl<T> Into<Vec<T>> for P<[T]> {
+    fn into(self) -> Vec<T> {
+        self.into_vec()
+    }
+}
+
+impl<T> FromIterator<T> for P<[T]> {
+    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> P<[T]> {
+        P::from_vec(iter.into_iter().collect())
+    }
+}
+
+impl<T> IntoIterator for P<[T]> {
+    type Item = T;
+    type IntoIter = vec::IntoIter<T>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        self.into_vec().into_iter()
+    }
+}
+
+impl<'a, T> IntoIterator for &'a P<[T]> {
+    type Item = &'a T;
+    type IntoIter = slice::Iter<'a, T>;
+    fn into_iter(self) -> Self::IntoIter {
+        self.ptr.into_iter()
+    }
+}
+
+impl<S: Encoder, T: Encodable<S>> Encodable<S> for P<[T]> {
+    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
+        Encodable::encode(&**self, s)
+    }
+}
+
+impl<D: Decoder, T: Decodable<D>> Decodable<D> for P<[T]> {
+    fn decode(d: &mut D) -> Result<P<[T]>, D::Error> {
+        Ok(P::from_vec(Decodable::decode(d)?))
+    }
+}
+
+impl<CTX, T> HashStable<CTX> for P<T>
+where
+    T: ?Sized + HashStable<CTX>,
+{
+    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
+        (**self).hash_stable(hcx, hasher);
+    }
+}
diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs
new file mode 100644
index 00000000000..4a8bf6b4f19
--- /dev/null
+++ b/compiler/rustc_ast/src/token.rs
@@ -0,0 +1,884 @@
+pub use BinOpToken::*;
+pub use DelimToken::*;
+pub use LitKind::*;
+pub use Nonterminal::*;
+pub use TokenKind::*;
+
+use crate::ast;
+use crate::ptr::P;
+use crate::tokenstream::TokenTree;
+
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::sync::Lrc;
+use rustc_macros::HashStable_Generic;
+use rustc_span::hygiene::ExpnKind;
+use rustc_span::source_map::SourceMap;
+use rustc_span::symbol::{kw, sym};
+use rustc_span::symbol::{Ident, Symbol};
+use rustc_span::{self, FileName, RealFileName, Span, DUMMY_SP};
+use std::borrow::Cow;
+use std::{fmt, mem};
+
+#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
+pub enum CommentKind {
+    Line,
+    Block,
+}
+
+#[derive(Clone, PartialEq, Encodable, Decodable, Hash, Debug, Copy)]
+#[derive(HashStable_Generic)]
+pub enum BinOpToken {
+    Plus,
+    Minus,
+    Star,
+    Slash,
+    Percent,
+    Caret,
+    And,
+    Or,
+    Shl,
+    Shr,
+}
+
+/// A delimiter token.
+#[derive(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Debug, Copy)]
+#[derive(HashStable_Generic)]
+pub enum DelimToken {
+    /// A round parenthesis (i.e., `(` or `)`).
+    Paren,
+    /// A square bracket (i.e., `[` or `]`).
+    Bracket,
+    /// A curly brace (i.e., `{` or `}`).
+    Brace,
+    /// An empty delimiter.
+    NoDelim,
+}
+
+impl DelimToken {
+    pub fn len(self) -> usize {
+        if self == NoDelim { 0 } else { 1 }
+    }
+
+    pub fn is_empty(self) -> bool {
+        self == NoDelim
+    }
+}
+
+#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
+pub enum LitKind {
+    Bool, // AST only, must never appear in a `Token`
+    Byte,
+    Char,
+    Integer,
+    Float,
+    Str,
+    StrRaw(u16), // raw string delimited by `n` hash symbols
+    ByteStr,
+    ByteStrRaw(u16), // raw byte string delimited by `n` hash symbols
+    Err,
+}
+
+/// A literal token.
+#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
+pub struct Lit {
+    pub kind: LitKind,
+    pub symbol: Symbol,
+    pub suffix: Option<Symbol>,
+}
+
+impl fmt::Display for Lit {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let Lit { kind, symbol, suffix } = *self;
+        match kind {
+            Byte => write!(f, "b'{}'", symbol)?,
+            Char => write!(f, "'{}'", symbol)?,
+            Str => write!(f, "\"{}\"", symbol)?,
+            StrRaw(n) => write!(
+                f,
+                "r{delim}\"{string}\"{delim}",
+                delim = "#".repeat(n as usize),
+                string = symbol
+            )?,
+            ByteStr => write!(f, "b\"{}\"", symbol)?,
+            ByteStrRaw(n) => write!(
+                f,
+                "br{delim}\"{string}\"{delim}",
+                delim = "#".repeat(n as usize),
+                string = symbol
+            )?,
+            Integer | Float | Bool | Err => write!(f, "{}", symbol)?,
+        }
+
+        if let Some(suffix) = suffix {
+            write!(f, "{}", suffix)?;
+        }
+
+        Ok(())
+    }
+}
+
+impl LitKind {
+    /// An English article for the literal token kind.
+    pub fn article(self) -> &'static str {
+        match self {
+            Integer | Err => "an",
+            _ => "a",
+        }
+    }
+
+    pub fn descr(self) -> &'static str {
+        match self {
+            Bool => panic!("literal token contains `Lit::Bool`"),
+            Byte => "byte",
+            Char => "char",
+            Integer => "integer",
+            Float => "float",
+            Str | StrRaw(..) => "string",
+            ByteStr | ByteStrRaw(..) => "byte string",
+            Err => "error",
+        }
+    }
+
+    crate fn may_have_suffix(self) -> bool {
+        match self {
+            Integer | Float | Err => true,
+            _ => false,
+        }
+    }
+}
+
+impl Lit {
+    pub fn new(kind: LitKind, symbol: Symbol, suffix: Option<Symbol>) -> Lit {
+        Lit { kind, symbol, suffix }
+    }
+}
+
+pub fn ident_can_begin_expr(name: Symbol, span: Span, is_raw: bool) -> bool {
+    let ident_token = Token::new(Ident(name, is_raw), span);
+
+    !ident_token.is_reserved_ident()
+        || ident_token.is_path_segment_keyword()
+        || [
+            kw::Async,
+            kw::Do,
+            kw::Box,
+            kw::Break,
+            kw::Continue,
+            kw::False,
+            kw::For,
+            kw::If,
+            kw::Let,
+            kw::Loop,
+            kw::Match,
+            kw::Move,
+            kw::Return,
+            kw::True,
+            kw::Unsafe,
+            kw::While,
+            kw::Yield,
+            kw::Static,
+        ]
+        .contains(&name)
+}
+
+fn ident_can_begin_type(name: Symbol, span: Span, is_raw: bool) -> bool {
+    let ident_token = Token::new(Ident(name, is_raw), span);
+
+    !ident_token.is_reserved_ident()
+        || ident_token.is_path_segment_keyword()
+        || [kw::Underscore, kw::For, kw::Impl, kw::Fn, kw::Unsafe, kw::Extern, kw::Typeof, kw::Dyn]
+            .contains(&name)
+}
+
+#[derive(Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
+pub enum TokenKind {
+    /* Expression-operator symbols. */
+    Eq,
+    Lt,
+    Le,
+    EqEq,
+    Ne,
+    Ge,
+    Gt,
+    AndAnd,
+    OrOr,
+    Not,
+    Tilde,
+    BinOp(BinOpToken),
+    BinOpEq(BinOpToken),
+
+    /* Structural symbols */
+    At,
+    Dot,
+    DotDot,
+    DotDotDot,
+    DotDotEq,
+    Comma,
+    Semi,
+    Colon,
+    ModSep,
+    RArrow,
+    LArrow,
+    FatArrow,
+    Pound,
+    Dollar,
+    Question,
+    /// Used by proc macros for representing lifetimes, not generated by lexer right now.
+    SingleQuote,
+    /// An opening delimiter (e.g., `{`).
+    OpenDelim(DelimToken),
+    /// A closing delimiter (e.g., `}`).
+    CloseDelim(DelimToken),
+
+    /* Literals */
+    Literal(Lit),
+
+    /// Identifier token.
+    /// Do not forget about `NtIdent` when you want to match on identifiers.
+    /// It's recommended to use `Token::(ident,uninterpolate,uninterpolated_span)` to
+    /// treat regular and interpolated identifiers in the same way.
+    Ident(Symbol, /* is_raw */ bool),
+    /// Lifetime identifier token.
+    /// Do not forget about `NtLifetime` when you want to match on lifetime identifiers.
+    /// It's recommended to use `Token::(lifetime,uninterpolate,uninterpolated_span)` to
+    /// treat regular and interpolated lifetime identifiers in the same way.
+    Lifetime(Symbol),
+
+    Interpolated(Lrc<Nonterminal>),
+
+    /// A doc comment token.
+    /// `Symbol` is the doc comment's data excluding its "quotes" (`///`, `/**`, etc)
+    /// similarly to symbols in string literal tokens.
+    DocComment(CommentKind, ast::AttrStyle, Symbol),
+
+    // Junk. These carry no data because we don't really care about the data
+    // they *would* carry, and don't really want to allocate a new ident for
+    // them. Instead, users could extract that from the associated span.
+    /// Whitespace.
+    Whitespace,
+    /// A comment.
+    Comment,
+    Shebang(Symbol),
+    /// A completely invalid token which should be skipped.
+    Unknown(Symbol),
+
+    Eof,
+}
+
+// `TokenKind` is used a lot. Make sure it doesn't unintentionally get bigger.
+#[cfg(target_arch = "x86_64")]
+rustc_data_structures::static_assert_size!(TokenKind, 16);
+
+#[derive(Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
+pub struct Token {
+    pub kind: TokenKind,
+    pub span: Span,
+}
+
+impl TokenKind {
+    pub fn lit(kind: LitKind, symbol: Symbol, suffix: Option<Symbol>) -> TokenKind {
+        Literal(Lit::new(kind, symbol, suffix))
+    }
+
+    // An approximation to proc-macro-style single-character operators used by rustc parser.
+    // If the operator token can be broken into two tokens, the first of which is single-character,
+    // then this function performs that operation, otherwise it returns `None`.
+    pub fn break_two_token_op(&self) -> Option<(TokenKind, TokenKind)> {
+        Some(match *self {
+            Le => (Lt, Eq),
+            EqEq => (Eq, Eq),
+            Ne => (Not, Eq),
+            Ge => (Gt, Eq),
+            AndAnd => (BinOp(And), BinOp(And)),
+            OrOr => (BinOp(Or), BinOp(Or)),
+            BinOp(Shl) => (Lt, Lt),
+            BinOp(Shr) => (Gt, Gt),
+            BinOpEq(Plus) => (BinOp(Plus), Eq),
+            BinOpEq(Minus) => (BinOp(Minus), Eq),
+            BinOpEq(Star) => (BinOp(Star), Eq),
+            BinOpEq(Slash) => (BinOp(Slash), Eq),
+            BinOpEq(Percent) => (BinOp(Percent), Eq),
+            BinOpEq(Caret) => (BinOp(Caret), Eq),
+            BinOpEq(And) => (BinOp(And), Eq),
+            BinOpEq(Or) => (BinOp(Or), Eq),
+            BinOpEq(Shl) => (Lt, Le),
+            BinOpEq(Shr) => (Gt, Ge),
+            DotDot => (Dot, Dot),
+            DotDotDot => (Dot, DotDot),
+            ModSep => (Colon, Colon),
+            RArrow => (BinOp(Minus), Gt),
+            LArrow => (Lt, BinOp(Minus)),
+            FatArrow => (Eq, Gt),
+            _ => return None,
+        })
+    }
+
+    /// Returns tokens that are likely to be typed accidentally instead of the current token.
+    /// Enables better error recovery when the wrong token is found.
+    pub fn similar_tokens(&self) -> Option<Vec<TokenKind>> {
+        match *self {
+            Comma => Some(vec![Dot, Lt, Semi]),
+            Semi => Some(vec![Colon, Comma]),
+            _ => None,
+        }
+    }
+}
+
+impl Token {
+    pub fn new(kind: TokenKind, span: Span) -> Self {
+        Token { kind, span }
+    }
+
+    /// Some token that will be thrown away later.
+    pub fn dummy() -> Self {
+        Token::new(TokenKind::Whitespace, DUMMY_SP)
+    }
+
+    /// Recovers a `Token` from an `Ident`. This creates a raw identifier if necessary.
+    pub fn from_ast_ident(ident: Ident) -> Self {
+        Token::new(Ident(ident.name, ident.is_raw_guess()), ident.span)
+    }
+
+    /// Return this token by value and leave a dummy token in its place.
+    pub fn take(&mut self) -> Self {
+        mem::replace(self, Token::dummy())
+    }
+
+    /// For interpolated tokens, returns a span of the fragment to which the interpolated
+    /// token refers. For all other tokens this is just a regular span.
+    /// It is particularly important to use this for identifiers and lifetimes
+    /// for which spans affect name resolution and edition checks.
+    /// Note that keywords are also identifiers, so they should use this
+    /// if they keep spans or perform edition checks.
+    pub fn uninterpolated_span(&self) -> Span {
+        match &self.kind {
+            Interpolated(nt) => nt.span(),
+            _ => self.span,
+        }
+    }
+
+    pub fn is_op(&self) -> bool {
+        match self.kind {
+            OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | Ident(..)
+            | Lifetime(..) | Interpolated(..) | Whitespace | Comment | Shebang(..) | Eof => false,
+            _ => true,
+        }
+    }
+
+    pub fn is_like_plus(&self) -> bool {
+        match self.kind {
+            BinOp(Plus) | BinOpEq(Plus) => true,
+            _ => false,
+        }
+    }
+
+    /// Returns `true` if the token can appear at the start of an expression.
+    pub fn can_begin_expr(&self) -> bool {
+        match self.uninterpolate().kind {
+            Ident(name, is_raw)              =>
+                ident_can_begin_expr(name, self.span, is_raw), // value name or keyword
+            OpenDelim(..)                     | // tuple, array or block
+            Literal(..)                       | // literal
+            Not                               | // operator not
+            BinOp(Minus)                      | // unary minus
+            BinOp(Star)                       | // dereference
+            BinOp(Or) | OrOr                  | // closure
+            BinOp(And)                        | // reference
+            AndAnd                            | // double reference
+            // DotDotDot is no longer supported, but we need some way to display the error
+            DotDot | DotDotDot | DotDotEq     | // range notation
+            Lt | BinOp(Shl)                   | // associated path
+            ModSep                            | // global path
+            Lifetime(..)                      | // labeled loop
+            Pound                             => true, // expression attributes
+            Interpolated(ref nt) => match **nt {
+                NtLiteral(..) |
+                NtExpr(..)    |
+                NtBlock(..)   |
+                NtPath(..) => true,
+                _ => false,
+            },
+            _ => false,
+        }
+    }
+
+    /// Returns `true` if the token can appear at the start of a type.
+    pub fn can_begin_type(&self) -> bool {
+        match self.uninterpolate().kind {
+            Ident(name, is_raw)        =>
+                ident_can_begin_type(name, self.span, is_raw), // type name or keyword
+            OpenDelim(Paren)            | // tuple
+            OpenDelim(Bracket)          | // array
+            Not                         | // never
+            BinOp(Star)                 | // raw pointer
+            BinOp(And)                  | // reference
+            AndAnd                      | // double reference
+            Question                    | // maybe bound in trait object
+            Lifetime(..)                | // lifetime bound in trait object
+            Lt | BinOp(Shl)             | // associated path
+            ModSep                      => true, // global path
+            Interpolated(ref nt) => match **nt {
+                NtTy(..) | NtPath(..) => true,
+                _ => false,
+            },
+            _ => false,
+        }
+    }
+
+    /// Returns `true` if the token can appear at the start of a const param.
+    pub fn can_begin_const_arg(&self) -> bool {
+        match self.kind {
+            OpenDelim(Brace) => true,
+            Interpolated(ref nt) => match **nt {
+                NtExpr(..) | NtBlock(..) | NtLiteral(..) => true,
+                _ => false,
+            },
+            _ => self.can_begin_literal_maybe_minus(),
+        }
+    }
+
+    /// Returns `true` if the token can appear at the start of a generic bound.
+    pub fn can_begin_bound(&self) -> bool {
+        self.is_path_start()
+            || self.is_lifetime()
+            || self.is_keyword(kw::For)
+            || self == &Question
+            || self == &OpenDelim(Paren)
+    }
+
+    /// Returns `true` if the token is any literal
+    pub fn is_lit(&self) -> bool {
+        match self.kind {
+            Literal(..) => true,
+            _ => false,
+        }
+    }
+
+    /// Returns `true` if the token is any literal, a minus (which can prefix a literal,
+    /// for example a '-42', or one of the boolean idents).
+    ///
+    /// In other words, would this token be a valid start of `parse_literal_maybe_minus`?
+    ///
+    /// Keep this in sync with and `Lit::from_token`, excluding unary negation.
+    pub fn can_begin_literal_maybe_minus(&self) -> bool {
+        match self.uninterpolate().kind {
+            Literal(..) | BinOp(Minus) => true,
+            Ident(name, false) if name.is_bool_lit() => true,
+            Interpolated(ref nt) => match &**nt {
+                NtLiteral(_) => true,
+                NtExpr(e) => match &e.kind {
+                    ast::ExprKind::Lit(_) => true,
+                    ast::ExprKind::Unary(ast::UnOp::Neg, e) => {
+                        matches!(&e.kind, ast::ExprKind::Lit(_))
+                    }
+                    _ => false,
+                },
+                _ => false,
+            },
+            _ => false,
+        }
+    }
+
+    // A convenience function for matching on identifiers during parsing.
+    // Turns interpolated identifier (`$i: ident`) or lifetime (`$l: lifetime`) token
+    // into the regular identifier or lifetime token it refers to,
+    // otherwise returns the original token.
+    pub fn uninterpolate(&self) -> Cow<'_, Token> {
+        match &self.kind {
+            Interpolated(nt) => match **nt {
+                NtIdent(ident, is_raw) => {
+                    Cow::Owned(Token::new(Ident(ident.name, is_raw), ident.span))
+                }
+                NtLifetime(ident) => Cow::Owned(Token::new(Lifetime(ident.name), ident.span)),
+                _ => Cow::Borrowed(self),
+            },
+            _ => Cow::Borrowed(self),
+        }
+    }
+
+    /// Returns an identifier if this token is an identifier.
+    pub fn ident(&self) -> Option<(Ident, /* is_raw */ bool)> {
+        let token = self.uninterpolate();
+        match token.kind {
+            Ident(name, is_raw) => Some((Ident::new(name, token.span), is_raw)),
+            _ => None,
+        }
+    }
+
+    /// Returns a lifetime identifier if this token is a lifetime.
+    pub fn lifetime(&self) -> Option<Ident> {
+        let token = self.uninterpolate();
+        match token.kind {
+            Lifetime(name) => Some(Ident::new(name, token.span)),
+            _ => 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 lifetime.
+    pub fn is_lifetime(&self) -> bool {
+        self.lifetime().is_some()
+    }
+
+    /// Returns `true` if the token is a identifier whose name is the given
+    /// string slice.
+    pub fn is_ident_named(&self, name: Symbol) -> bool {
+        self.ident().map_or(false, |(ident, _)| ident.name == name)
+    }
+
+    /// Returns `true` if the token is an interpolated path.
+    fn is_path(&self) -> bool {
+        if let Interpolated(ref nt) = self.kind {
+            if let NtPath(..) = **nt {
+                return true;
+            }
+        }
+        false
+    }
+
+    /// Would `maybe_whole_expr` in `parser.rs` return `Ok(..)`?
+    /// That is, is this a pre-parsed expression dropped into the token stream
+    /// (which happens while parsing the result of macro expansion)?
+    pub fn is_whole_expr(&self) -> bool {
+        if let Interpolated(ref nt) = self.kind {
+            if let NtExpr(_) | NtLiteral(_) | NtPath(_) | NtIdent(..) | NtBlock(_) = **nt {
+                return true;
+            }
+        }
+
+        false
+    }
+
+    // Is the token an interpolated block (`$b:block`)?
+    pub fn is_whole_block(&self) -> bool {
+        if let Interpolated(ref nt) = self.kind {
+            if let NtBlock(..) = **nt {
+                return true;
+            }
+        }
+        false
+    }
+
+    /// Returns `true` if the token is either the `mut` or `const` keyword.
+    pub fn is_mutability(&self) -> bool {
+        self.is_keyword(kw::Mut) || self.is_keyword(kw::Const)
+    }
+
+    pub fn is_qpath_start(&self) -> bool {
+        self == &Lt || self == &BinOp(Shl)
+    }
+
+    pub fn is_path_start(&self) -> bool {
+        self == &ModSep
+            || self.is_qpath_start()
+            || self.is_path()
+            || self.is_path_segment_keyword()
+            || self.is_ident() && !self.is_reserved_ident()
+    }
+
+    /// Returns `true` if the token is a given keyword, `kw`.
+    pub fn is_keyword(&self, kw: Symbol) -> bool {
+        self.is_non_raw_ident_where(|id| id.name == kw)
+    }
+
+    pub fn is_path_segment_keyword(&self) -> bool {
+        self.is_non_raw_ident_where(Ident::is_path_segment_keyword)
+    }
+
+    // Returns true for reserved identifiers used internally for elided lifetimes,
+    // unnamed method parameters, crate root module, error recovery etc.
+    pub fn is_special_ident(&self) -> bool {
+        self.is_non_raw_ident_where(Ident::is_special)
+    }
+
+    /// Returns `true` if the token is a keyword used in the language.
+    pub fn is_used_keyword(&self) -> bool {
+        self.is_non_raw_ident_where(Ident::is_used_keyword)
+    }
+
+    /// Returns `true` if the token is a keyword reserved for possible future use.
+    pub fn is_unused_keyword(&self) -> bool {
+        self.is_non_raw_ident_where(Ident::is_unused_keyword)
+    }
+
+    /// Returns `true` if the token is either a special identifier or a keyword.
+    pub fn is_reserved_ident(&self) -> bool {
+        self.is_non_raw_ident_where(Ident::is_reserved)
+    }
+
+    /// Returns `true` if the token is the identifier `true` or `false`.
+    pub fn is_bool_lit(&self) -> bool {
+        self.is_non_raw_ident_where(|id| id.name.is_bool_lit())
+    }
+
+    /// Returns `true` if the token is a non-raw identifier for which `pred` holds.
+    pub fn is_non_raw_ident_where(&self, pred: impl FnOnce(Ident) -> bool) -> bool {
+        match self.ident() {
+            Some((id, false)) => pred(id),
+            _ => false,
+        }
+    }
+
+    pub fn glue(&self, joint: &Token) -> Option<Token> {
+        let kind = match self.kind {
+            Eq => match joint.kind {
+                Eq => EqEq,
+                Gt => FatArrow,
+                _ => return None,
+            },
+            Lt => match joint.kind {
+                Eq => Le,
+                Lt => BinOp(Shl),
+                Le => BinOpEq(Shl),
+                BinOp(Minus) => LArrow,
+                _ => return None,
+            },
+            Gt => match joint.kind {
+                Eq => Ge,
+                Gt => BinOp(Shr),
+                Ge => BinOpEq(Shr),
+                _ => return None,
+            },
+            Not => match joint.kind {
+                Eq => Ne,
+                _ => return None,
+            },
+            BinOp(op) => match joint.kind {
+                Eq => BinOpEq(op),
+                BinOp(And) if op == And => AndAnd,
+                BinOp(Or) if op == Or => OrOr,
+                Gt if op == Minus => RArrow,
+                _ => return None,
+            },
+            Dot => match joint.kind {
+                Dot => DotDot,
+                DotDot => DotDotDot,
+                _ => return None,
+            },
+            DotDot => match joint.kind {
+                Dot => DotDotDot,
+                Eq => DotDotEq,
+                _ => return None,
+            },
+            Colon => match joint.kind {
+                Colon => ModSep,
+                _ => return None,
+            },
+            SingleQuote => match joint.kind {
+                Ident(name, false) => Lifetime(Symbol::intern(&format!("'{}", name))),
+                _ => return None,
+            },
+
+            Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | BinOpEq(..) | At | DotDotDot
+            | DotDotEq | Comma | Semi | ModSep | RArrow | LArrow | FatArrow | Pound | Dollar
+            | Question | OpenDelim(..) | CloseDelim(..) | Literal(..) | Ident(..)
+            | Lifetime(..) | Interpolated(..) | DocComment(..) | Whitespace | Comment
+            | Shebang(..) | Unknown(..) | Eof => return None,
+        };
+
+        Some(Token::new(kind, self.span.to(joint.span)))
+    }
+}
+
+impl PartialEq<TokenKind> for Token {
+    fn eq(&self, rhs: &TokenKind) -> bool {
+        self.kind == *rhs
+    }
+}
+
+#[derive(Clone, Encodable, Decodable)]
+/// For interpolation during macro expansion.
+pub enum Nonterminal {
+    NtItem(P<ast::Item>),
+    NtBlock(P<ast::Block>),
+    NtStmt(ast::Stmt),
+    NtPat(P<ast::Pat>),
+    NtExpr(P<ast::Expr>),
+    NtTy(P<ast::Ty>),
+    NtIdent(Ident, /* is_raw */ bool),
+    NtLifetime(Ident),
+    NtLiteral(P<ast::Expr>),
+    /// Stuff inside brackets for attributes
+    NtMeta(P<ast::AttrItem>),
+    NtPath(ast::Path),
+    NtVis(ast::Visibility),
+    NtTT(TokenTree),
+}
+
+// `Nonterminal` is used a lot. Make sure it doesn't unintentionally get bigger.
+#[cfg(target_arch = "x86_64")]
+rustc_data_structures::static_assert_size!(Nonterminal, 40);
+
+#[derive(Debug, Copy, Clone, PartialEq, Encodable, Decodable)]
+pub enum NonterminalKind {
+    Item,
+    Block,
+    Stmt,
+    Pat,
+    Expr,
+    Ty,
+    Ident,
+    Lifetime,
+    Literal,
+    Meta,
+    Path,
+    Vis,
+    TT,
+}
+
+impl NonterminalKind {
+    pub fn from_symbol(symbol: Symbol) -> Option<NonterminalKind> {
+        Some(match symbol {
+            sym::item => NonterminalKind::Item,
+            sym::block => NonterminalKind::Block,
+            sym::stmt => NonterminalKind::Stmt,
+            sym::pat => NonterminalKind::Pat,
+            sym::expr => NonterminalKind::Expr,
+            sym::ty => NonterminalKind::Ty,
+            sym::ident => NonterminalKind::Ident,
+            sym::lifetime => NonterminalKind::Lifetime,
+            sym::literal => NonterminalKind::Literal,
+            sym::meta => NonterminalKind::Meta,
+            sym::path => NonterminalKind::Path,
+            sym::vis => NonterminalKind::Vis,
+            sym::tt => NonterminalKind::TT,
+            _ => return None,
+        })
+    }
+    fn symbol(self) -> Symbol {
+        match self {
+            NonterminalKind::Item => sym::item,
+            NonterminalKind::Block => sym::block,
+            NonterminalKind::Stmt => sym::stmt,
+            NonterminalKind::Pat => sym::pat,
+            NonterminalKind::Expr => sym::expr,
+            NonterminalKind::Ty => sym::ty,
+            NonterminalKind::Ident => sym::ident,
+            NonterminalKind::Lifetime => sym::lifetime,
+            NonterminalKind::Literal => sym::literal,
+            NonterminalKind::Meta => sym::meta,
+            NonterminalKind::Path => sym::path,
+            NonterminalKind::Vis => sym::vis,
+            NonterminalKind::TT => sym::tt,
+        }
+    }
+}
+
+impl fmt::Display for NonterminalKind {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{}", self.symbol())
+    }
+}
+
+impl Nonterminal {
+    fn span(&self) -> Span {
+        match self {
+            NtItem(item) => item.span,
+            NtBlock(block) => block.span,
+            NtStmt(stmt) => stmt.span,
+            NtPat(pat) => pat.span,
+            NtExpr(expr) | NtLiteral(expr) => expr.span,
+            NtTy(ty) => ty.span,
+            NtIdent(ident, _) | NtLifetime(ident) => ident.span,
+            NtMeta(attr_item) => attr_item.span(),
+            NtPath(path) => path.span,
+            NtVis(vis) => vis.span,
+            NtTT(tt) => tt.span(),
+        }
+    }
+
+    /// This nonterminal looks like some specific enums from
+    /// `proc-macro-hack` and `procedural-masquerade` crates.
+    /// We need to maintain some special pretty-printing behavior for them due to incorrect
+    /// asserts in old versions of those crates and their wide use in the ecosystem.
+    /// See issue #73345 for more details.
+    /// FIXME(#73933): Remove this eventually.
+    pub fn pretty_printing_compatibility_hack(&self) -> bool {
+        if let NtItem(item) = self {
+            let name = item.ident.name;
+            if name == sym::ProceduralMasqueradeDummyType || name == sym::ProcMacroHack {
+                if let ast::ItemKind::Enum(enum_def, _) = &item.kind {
+                    if let [variant] = &*enum_def.variants {
+                        return variant.ident.name == sym::Input;
+                    }
+                }
+            }
+        }
+        false
+    }
+
+    // See issue #74616 for details
+    pub fn ident_name_compatibility_hack(
+        &self,
+        orig_span: Span,
+        source_map: &SourceMap,
+    ) -> Option<(Ident, bool)> {
+        if let NtIdent(ident, is_raw) = self {
+            if let ExpnKind::Macro(_, macro_name) = orig_span.ctxt().outer_expn_data().kind {
+                let filename = source_map.span_to_filename(orig_span);
+                if let FileName::Real(RealFileName::Named(path)) = filename {
+                    if (path.ends_with("time-macros-impl/src/lib.rs")
+                        && macro_name == sym::impl_macros)
+                        || (path.ends_with("js-sys/src/lib.rs") && macro_name == sym::arrays)
+                    {
+                        let snippet = source_map.span_to_snippet(orig_span);
+                        if snippet.as_deref() == Ok("$name") {
+                            return Some((*ident, *is_raw));
+                        }
+                    }
+                }
+            }
+        }
+        None
+    }
+}
+
+impl PartialEq for Nonterminal {
+    fn eq(&self, rhs: &Self) -> bool {
+        match (self, rhs) {
+            (NtIdent(ident_lhs, is_raw_lhs), NtIdent(ident_rhs, is_raw_rhs)) => {
+                ident_lhs == ident_rhs && is_raw_lhs == is_raw_rhs
+            }
+            (NtLifetime(ident_lhs), NtLifetime(ident_rhs)) => ident_lhs == ident_rhs,
+            (NtTT(tt_lhs), NtTT(tt_rhs)) => tt_lhs == tt_rhs,
+            // FIXME: Assume that all "complex" nonterminal are not equal, we can't compare them
+            // correctly based on data from AST. This will prevent them from matching each other
+            // in macros. The comparison will become possible only when each nonterminal has an
+            // attached token stream from which it was parsed.
+            _ => false,
+        }
+    }
+}
+
+impl fmt::Debug for Nonterminal {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match *self {
+            NtItem(..) => f.pad("NtItem(..)"),
+            NtBlock(..) => f.pad("NtBlock(..)"),
+            NtStmt(..) => f.pad("NtStmt(..)"),
+            NtPat(..) => f.pad("NtPat(..)"),
+            NtExpr(..) => f.pad("NtExpr(..)"),
+            NtTy(..) => f.pad("NtTy(..)"),
+            NtIdent(..) => f.pad("NtIdent(..)"),
+            NtLiteral(..) => f.pad("NtLiteral(..)"),
+            NtMeta(..) => f.pad("NtMeta(..)"),
+            NtPath(..) => f.pad("NtPath(..)"),
+            NtTT(..) => f.pad("NtTT(..)"),
+            NtVis(..) => f.pad("NtVis(..)"),
+            NtLifetime(..) => f.pad("NtLifetime(..)"),
+        }
+    }
+}
+
+impl<CTX> HashStable<CTX> for Nonterminal
+where
+    CTX: crate::HashStableContext,
+{
+    fn hash_stable(&self, _hcx: &mut CTX, _hasher: &mut StableHasher) {
+        panic!("interpolated tokens should not be present in the HIR")
+    }
+}
diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs
new file mode 100644
index 00000000000..151acddae84
--- /dev/null
+++ b/compiler/rustc_ast/src/tokenstream.rs
@@ -0,0 +1,433 @@
+//! # Token Streams
+//!
+//! `TokenStream`s represent syntactic objects before they are converted into ASTs.
+//! A `TokenStream` is, roughly speaking, a sequence (eg stream) of `TokenTree`s,
+//! which are themselves a single `Token` or a `Delimited` subsequence of tokens.
+//!
+//! ## Ownership
+//!
+//! `TokenStream`s are persistent data structures constructed as ropes with reference
+//! counted-children. In general, this means that calling an operation on a `TokenStream`
+//! (such as `slice`) produces an entirely new `TokenStream` from the borrowed reference to
+//! the original. This essentially coerces `TokenStream`s into 'views' of their subparts,
+//! and a borrowed `TokenStream` is sufficient to build an owned `TokenStream` without taking
+//! ownership of the original.
+
+use crate::token::{self, DelimToken, Token, TokenKind};
+
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::sync::Lrc;
+use rustc_macros::HashStable_Generic;
+use rustc_span::{Span, DUMMY_SP};
+use smallvec::{smallvec, SmallVec};
+
+use std::{iter, mem};
+
+/// When the main rust parser encounters a syntax-extension invocation, it
+/// parses the arguments to the invocation as a token-tree. This is a very
+/// loose structure, such that all sorts of different AST-fragments can
+/// be passed to syntax extensions using a uniform type.
+///
+/// If the syntax extension is an MBE macro, it will attempt to match its
+/// LHS token tree against the provided token tree, and if it finds a
+/// match, will transcribe the RHS token tree, splicing in any captured
+/// `macro_parser::matched_nonterminals` into the `SubstNt`s it finds.
+///
+/// The RHS of an MBE macro is the only place `SubstNt`s are substituted.
+/// Nothing special happens to misnamed or misplaced `SubstNt`s.
+#[derive(Debug, Clone, PartialEq, Encodable, Decodable, HashStable_Generic)]
+pub enum TokenTree {
+    /// A single token
+    Token(Token),
+    /// A delimited sequence of token trees
+    Delimited(DelimSpan, DelimToken, TokenStream),
+}
+
+// Ensure all fields of `TokenTree` is `Send` and `Sync`.
+#[cfg(parallel_compiler)]
+fn _dummy()
+where
+    Token: Send + Sync,
+    DelimSpan: Send + Sync,
+    DelimToken: Send + Sync,
+    TokenStream: Send + Sync,
+{
+}
+
+impl TokenTree {
+    /// Checks if this TokenTree is equal to the other, regardless of span information.
+    pub fn eq_unspanned(&self, other: &TokenTree) -> bool {
+        match (self, other) {
+            (TokenTree::Token(token), TokenTree::Token(token2)) => token.kind == token2.kind,
+            (TokenTree::Delimited(_, delim, tts), TokenTree::Delimited(_, delim2, tts2)) => {
+                delim == delim2 && tts.eq_unspanned(&tts2)
+            }
+            _ => false,
+        }
+    }
+
+    /// Retrieves the TokenTree's span.
+    pub fn span(&self) -> Span {
+        match self {
+            TokenTree::Token(token) => token.span,
+            TokenTree::Delimited(sp, ..) => sp.entire(),
+        }
+    }
+
+    /// Modify the `TokenTree`'s span in-place.
+    pub fn set_span(&mut self, span: Span) {
+        match self {
+            TokenTree::Token(token) => token.span = span,
+            TokenTree::Delimited(dspan, ..) => *dspan = DelimSpan::from_single(span),
+        }
+    }
+
+    pub fn joint(self) -> TokenStream {
+        TokenStream::new(vec![(self, Joint)])
+    }
+
+    pub fn token(kind: TokenKind, span: Span) -> TokenTree {
+        TokenTree::Token(Token::new(kind, span))
+    }
+
+    /// Returns the opening delimiter as a token tree.
+    pub fn open_tt(span: DelimSpan, delim: DelimToken) -> TokenTree {
+        TokenTree::token(token::OpenDelim(delim), span.open)
+    }
+
+    /// Returns the closing delimiter as a token tree.
+    pub fn close_tt(span: DelimSpan, delim: DelimToken) -> TokenTree {
+        TokenTree::token(token::CloseDelim(delim), span.close)
+    }
+
+    pub fn uninterpolate(self) -> TokenTree {
+        match self {
+            TokenTree::Token(token) => TokenTree::Token(token.uninterpolate().into_owned()),
+            tt => tt,
+        }
+    }
+}
+
+impl<CTX> HashStable<CTX> for TokenStream
+where
+    CTX: crate::HashStableContext,
+{
+    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
+        for sub_tt in self.trees() {
+            sub_tt.hash_stable(hcx, hasher);
+        }
+    }
+}
+
+/// A `TokenStream` is an abstract sequence of tokens, organized into `TokenTree`s.
+///
+/// The goal is for procedural macros to work with `TokenStream`s and `TokenTree`s
+/// instead of a representation of the abstract syntax tree.
+/// Today's `TokenTree`s can still contain AST via `token::Interpolated` for back-compat.
+#[derive(Clone, Debug, Default, Encodable, Decodable)]
+pub struct TokenStream(pub Lrc<Vec<TreeAndJoint>>);
+
+pub type TreeAndJoint = (TokenTree, IsJoint);
+
+// `TokenStream` is used a lot. Make sure it doesn't unintentionally get bigger.
+#[cfg(target_arch = "x86_64")]
+rustc_data_structures::static_assert_size!(TokenStream, 8);
+
+#[derive(Clone, Copy, Debug, PartialEq, Encodable, Decodable)]
+pub enum IsJoint {
+    Joint,
+    NonJoint,
+}
+
+use IsJoint::*;
+
+impl TokenStream {
+    /// Given a `TokenStream` with a `Stream` of only two arguments, return a new `TokenStream`
+    /// separating the two arguments with a comma for diagnostic suggestions.
+    pub fn add_comma(&self) -> Option<(TokenStream, Span)> {
+        // Used to suggest if a user writes `foo!(a b);`
+        let mut suggestion = None;
+        let mut iter = self.0.iter().enumerate().peekable();
+        while let Some((pos, ts)) = iter.next() {
+            if let Some((_, next)) = iter.peek() {
+                let sp = match (&ts, &next) {
+                    (_, (TokenTree::Token(Token { kind: token::Comma, .. }), _)) => continue,
+                    (
+                        (TokenTree::Token(token_left), NonJoint),
+                        (TokenTree::Token(token_right), _),
+                    ) if ((token_left.is_ident() && !token_left.is_reserved_ident())
+                        || token_left.is_lit())
+                        && ((token_right.is_ident() && !token_right.is_reserved_ident())
+                            || token_right.is_lit()) =>
+                    {
+                        token_left.span
+                    }
+                    ((TokenTree::Delimited(sp, ..), NonJoint), _) => sp.entire(),
+                    _ => continue,
+                };
+                let sp = sp.shrink_to_hi();
+                let comma = (TokenTree::token(token::Comma, sp), NonJoint);
+                suggestion = Some((pos, comma, sp));
+            }
+        }
+        if let Some((pos, comma, sp)) = suggestion {
+            let mut new_stream = vec![];
+            let parts = self.0.split_at(pos + 1);
+            new_stream.extend_from_slice(parts.0);
+            new_stream.push(comma);
+            new_stream.extend_from_slice(parts.1);
+            return Some((TokenStream::new(new_stream), sp));
+        }
+        None
+    }
+}
+
+impl From<TokenTree> for TokenStream {
+    fn from(tree: TokenTree) -> TokenStream {
+        TokenStream::new(vec![(tree, NonJoint)])
+    }
+}
+
+impl From<TokenTree> for TreeAndJoint {
+    fn from(tree: TokenTree) -> TreeAndJoint {
+        (tree, NonJoint)
+    }
+}
+
+impl iter::FromIterator<TokenTree> for TokenStream {
+    fn from_iter<I: IntoIterator<Item = TokenTree>>(iter: I) -> Self {
+        TokenStream::new(iter.into_iter().map(Into::into).collect::<Vec<TreeAndJoint>>())
+    }
+}
+
+impl Eq for TokenStream {}
+
+impl PartialEq<TokenStream> for TokenStream {
+    fn eq(&self, other: &TokenStream) -> bool {
+        self.trees().eq(other.trees())
+    }
+}
+
+impl TokenStream {
+    pub fn new(streams: Vec<TreeAndJoint>) -> TokenStream {
+        TokenStream(Lrc::new(streams))
+    }
+
+    pub fn is_empty(&self) -> bool {
+        self.0.is_empty()
+    }
+
+    pub fn len(&self) -> usize {
+        self.0.len()
+    }
+
+    pub fn span(&self) -> Option<Span> {
+        match &**self.0 {
+            [] => None,
+            [(tt, _)] => Some(tt.span()),
+            [(tt_start, _), .., (tt_end, _)] => Some(tt_start.span().to(tt_end.span())),
+        }
+    }
+
+    pub fn from_streams(mut streams: SmallVec<[TokenStream; 2]>) -> TokenStream {
+        match streams.len() {
+            0 => TokenStream::default(),
+            1 => streams.pop().unwrap(),
+            _ => {
+                // We are going to extend the first stream in `streams` with
+                // the elements from the subsequent streams. This requires
+                // using `make_mut()` on the first stream, and in practice this
+                // doesn't cause cloning 99.9% of the time.
+                //
+                // One very common use case is when `streams` has two elements,
+                // where the first stream has any number of elements within
+                // (often 1, but sometimes many more) and the second stream has
+                // a single element within.
+
+                // Determine how much the first stream will be extended.
+                // Needed to avoid quadratic blow up from on-the-fly
+                // reallocations (#57735).
+                let num_appends = streams.iter().skip(1).map(|ts| ts.len()).sum();
+
+                // Get the first stream. If it's `None`, create an empty
+                // stream.
+                let mut iter = streams.drain(..);
+                let mut first_stream_lrc = iter.next().unwrap().0;
+
+                // Append the elements to the first stream, after reserving
+                // space for them.
+                let first_vec_mut = Lrc::make_mut(&mut first_stream_lrc);
+                first_vec_mut.reserve(num_appends);
+                for stream in iter {
+                    first_vec_mut.extend(stream.0.iter().cloned());
+                }
+
+                // Create the final `TokenStream`.
+                TokenStream(first_stream_lrc)
+            }
+        }
+    }
+
+    pub fn trees(&self) -> Cursor {
+        self.clone().into_trees()
+    }
+
+    pub fn into_trees(self) -> Cursor {
+        Cursor::new(self)
+    }
+
+    /// Compares two `TokenStream`s, checking equality without regarding span information.
+    pub fn eq_unspanned(&self, other: &TokenStream) -> bool {
+        let mut t1 = self.trees();
+        let mut t2 = other.trees();
+        for (t1, t2) in t1.by_ref().zip(t2.by_ref()) {
+            if !t1.eq_unspanned(&t2) {
+                return false;
+            }
+        }
+        t1.next().is_none() && t2.next().is_none()
+    }
+
+    pub fn map_enumerated<F: FnMut(usize, TokenTree) -> TokenTree>(self, mut f: F) -> TokenStream {
+        TokenStream(Lrc::new(
+            self.0
+                .iter()
+                .enumerate()
+                .map(|(i, (tree, is_joint))| (f(i, tree.clone()), *is_joint))
+                .collect(),
+        ))
+    }
+
+    pub fn map<F: FnMut(TokenTree) -> TokenTree>(self, mut f: F) -> TokenStream {
+        TokenStream(Lrc::new(
+            self.0.iter().map(|(tree, is_joint)| (f(tree.clone()), *is_joint)).collect(),
+        ))
+    }
+}
+
+// 99.5%+ of the time we have 1 or 2 elements in this vector.
+#[derive(Clone)]
+pub struct TokenStreamBuilder(SmallVec<[TokenStream; 2]>);
+
+impl TokenStreamBuilder {
+    pub fn new() -> TokenStreamBuilder {
+        TokenStreamBuilder(SmallVec::new())
+    }
+
+    pub fn push<T: Into<TokenStream>>(&mut self, stream: T) {
+        let mut stream = stream.into();
+
+        // If `self` is not empty and the last tree within the last stream is a
+        // token tree marked with `Joint`...
+        if let Some(TokenStream(ref mut last_stream_lrc)) = self.0.last_mut() {
+            if let Some((TokenTree::Token(last_token), Joint)) = last_stream_lrc.last() {
+                // ...and `stream` is not empty and the first tree within it is
+                // a token tree...
+                let TokenStream(ref mut stream_lrc) = stream;
+                if let Some((TokenTree::Token(token), is_joint)) = stream_lrc.first() {
+                    // ...and the two tokens can be glued together...
+                    if let Some(glued_tok) = last_token.glue(&token) {
+                        // ...then do so, by overwriting the last token
+                        // tree in `self` and removing the first token tree
+                        // from `stream`. This requires using `make_mut()`
+                        // on the last stream in `self` and on `stream`,
+                        // and in practice this doesn't cause cloning 99.9%
+                        // of the time.
+
+                        // Overwrite the last token tree with the merged
+                        // token.
+                        let last_vec_mut = Lrc::make_mut(last_stream_lrc);
+                        *last_vec_mut.last_mut().unwrap() =
+                            (TokenTree::Token(glued_tok), *is_joint);
+
+                        // Remove the first token tree from `stream`. (This
+                        // is almost always the only tree in `stream`.)
+                        let stream_vec_mut = Lrc::make_mut(stream_lrc);
+                        stream_vec_mut.remove(0);
+
+                        // Don't push `stream` if it's empty -- that could
+                        // block subsequent token gluing, by getting
+                        // between two token trees that should be glued
+                        // together.
+                        if !stream.is_empty() {
+                            self.0.push(stream);
+                        }
+                        return;
+                    }
+                }
+            }
+        }
+        self.0.push(stream);
+    }
+
+    pub fn build(self) -> TokenStream {
+        TokenStream::from_streams(self.0)
+    }
+}
+
+#[derive(Clone)]
+pub struct Cursor {
+    pub stream: TokenStream,
+    index: usize,
+}
+
+impl Iterator for Cursor {
+    type Item = TokenTree;
+
+    fn next(&mut self) -> Option<TokenTree> {
+        self.next_with_joint().map(|(tree, _)| tree)
+    }
+}
+
+impl Cursor {
+    fn new(stream: TokenStream) -> Self {
+        Cursor { stream, index: 0 }
+    }
+
+    pub fn next_with_joint(&mut self) -> Option<TreeAndJoint> {
+        if self.index < self.stream.len() {
+            self.index += 1;
+            Some(self.stream.0[self.index - 1].clone())
+        } else {
+            None
+        }
+    }
+
+    pub fn append(&mut self, new_stream: TokenStream) {
+        if new_stream.is_empty() {
+            return;
+        }
+        let index = self.index;
+        let stream = mem::take(&mut self.stream);
+        *self = TokenStream::from_streams(smallvec![stream, new_stream]).into_trees();
+        self.index = index;
+    }
+
+    pub fn look_ahead(&self, n: usize) -> Option<TokenTree> {
+        self.stream.0[self.index..].get(n).map(|(tree, _)| tree.clone())
+    }
+}
+
+#[derive(Debug, Copy, Clone, PartialEq, Encodable, Decodable, HashStable_Generic)]
+pub struct DelimSpan {
+    pub open: Span,
+    pub close: Span,
+}
+
+impl DelimSpan {
+    pub fn from_single(sp: Span) -> Self {
+        DelimSpan { open: sp, close: sp }
+    }
+
+    pub fn from_pair(open: Span, close: Span) -> Self {
+        DelimSpan { open, close }
+    }
+
+    pub fn dummy() -> Self {
+        Self::from_single(DUMMY_SP)
+    }
+
+    pub fn entire(self) -> Span {
+        self.open.with_hi(self.close.hi())
+    }
+}
diff --git a/compiler/rustc_ast/src/util/classify.rs b/compiler/rustc_ast/src/util/classify.rs
new file mode 100644
index 00000000000..60422a2e573
--- /dev/null
+++ b/compiler/rustc_ast/src/util/classify.rs
@@ -0,0 +1,25 @@
+//! Routines the parser uses to classify AST nodes
+
+// Predicates on exprs and stmts that the pretty-printer and parser use
+
+use crate::ast;
+
+/// Does this expression require a semicolon to be treated
+/// as a statement? The negation of this: 'can this expression
+/// be used as a statement without a semicolon' -- is used
+/// as an early-bail-out in the parser so that, for instance,
+///     if true {...} else {...}
+///      |x| 5
+/// isn't parsed as (if true {...} else {...} | x) | 5
+pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool {
+    match e.kind {
+        ast::ExprKind::If(..)
+        | ast::ExprKind::Match(..)
+        | ast::ExprKind::Block(..)
+        | ast::ExprKind::While(..)
+        | ast::ExprKind::Loop(..)
+        | ast::ExprKind::ForLoop(..)
+        | ast::ExprKind::TryBlock(..) => false,
+        _ => true,
+    }
+}
diff --git a/compiler/rustc_ast/src/util/comments.rs b/compiler/rustc_ast/src/util/comments.rs
new file mode 100644
index 00000000000..e97c8cc4562
--- /dev/null
+++ b/compiler/rustc_ast/src/util/comments.rs
@@ -0,0 +1,222 @@
+use rustc_span::source_map::SourceMap;
+use rustc_span::{BytePos, CharPos, FileName, Pos, Symbol};
+
+#[cfg(test)]
+mod tests;
+
+#[derive(Clone, Copy, PartialEq, Debug)]
+pub enum CommentStyle {
+    /// No code on either side of each line of the comment
+    Isolated,
+    /// Code exists to the left of the comment
+    Trailing,
+    /// Code before /* foo */ and after the comment
+    Mixed,
+    /// Just a manual blank line "\n\n", for layout
+    BlankLine,
+}
+
+#[derive(Clone)]
+pub struct Comment {
+    pub style: CommentStyle,
+    pub lines: Vec<String>,
+    pub pos: BytePos,
+}
+
+/// Makes a doc string more presentable to users.
+/// Used by rustdoc and perhaps other tools, but not by rustc.
+pub fn beautify_doc_string(data: Symbol) -> String {
+    /// remove whitespace-only lines from the start/end of lines
+    fn vertical_trim(lines: Vec<String>) -> Vec<String> {
+        let mut i = 0;
+        let mut j = lines.len();
+        // first line of all-stars should be omitted
+        if !lines.is_empty() && lines[0].chars().all(|c| c == '*') {
+            i += 1;
+        }
+
+        while i < j && lines[i].trim().is_empty() {
+            i += 1;
+        }
+        // like the first, a last line of all stars should be omitted
+        if j > i && lines[j - 1].chars().skip(1).all(|c| c == '*') {
+            j -= 1;
+        }
+
+        while j > i && lines[j - 1].trim().is_empty() {
+            j -= 1;
+        }
+
+        lines[i..j].to_vec()
+    }
+
+    /// remove a "[ \t]*\*" block from each line, if possible
+    fn horizontal_trim(lines: Vec<String>) -> Vec<String> {
+        let mut i = usize::MAX;
+        let mut can_trim = true;
+        let mut first = true;
+
+        for line in &lines {
+            for (j, c) in line.chars().enumerate() {
+                if j > i || !"* \t".contains(c) {
+                    can_trim = false;
+                    break;
+                }
+                if c == '*' {
+                    if first {
+                        i = j;
+                        first = false;
+                    } else if i != j {
+                        can_trim = false;
+                    }
+                    break;
+                }
+            }
+            if i >= line.len() {
+                can_trim = false;
+            }
+            if !can_trim {
+                break;
+            }
+        }
+
+        if can_trim {
+            lines.iter().map(|line| (&line[i + 1..line.len()]).to_string()).collect()
+        } else {
+            lines
+        }
+    }
+
+    let data = data.as_str();
+    if data.contains('\n') {
+        let lines = data.lines().map(|s| s.to_string()).collect::<Vec<String>>();
+        let lines = vertical_trim(lines);
+        let lines = horizontal_trim(lines);
+        lines.join("\n")
+    } else {
+        data.to_string()
+    }
+}
+
+/// Returns `None` if the first `col` chars of `s` contain a non-whitespace char.
+/// Otherwise returns `Some(k)` where `k` is first char offset after that leading
+/// whitespace. Note that `k` may be outside bounds of `s`.
+fn all_whitespace(s: &str, col: CharPos) -> Option<usize> {
+    let mut idx = 0;
+    for (i, ch) in s.char_indices().take(col.to_usize()) {
+        if !ch.is_whitespace() {
+            return None;
+        }
+        idx = i + ch.len_utf8();
+    }
+    Some(idx)
+}
+
+fn trim_whitespace_prefix(s: &str, col: CharPos) -> &str {
+    let len = s.len();
+    match all_whitespace(&s, col) {
+        Some(col) => {
+            if col < len {
+                &s[col..]
+            } else {
+                ""
+            }
+        }
+        None => s,
+    }
+}
+
+fn split_block_comment_into_lines(text: &str, col: CharPos) -> Vec<String> {
+    let mut res: Vec<String> = vec![];
+    let mut lines = text.lines();
+    // just push the first line
+    res.extend(lines.next().map(|it| it.to_string()));
+    // for other lines, strip common whitespace prefix
+    for line in lines {
+        res.push(trim_whitespace_prefix(line, col).to_string())
+    }
+    res
+}
+
+// it appears this function is called only from pprust... that's
+// probably not a good thing.
+pub fn gather_comments(sm: &SourceMap, path: FileName, src: String) -> Vec<Comment> {
+    let sm = SourceMap::new(sm.path_mapping().clone());
+    let source_file = sm.new_source_file(path, src);
+    let text = (*source_file.src.as_ref().unwrap()).clone();
+
+    let text: &str = text.as_str();
+    let start_bpos = source_file.start_pos;
+    let mut pos = 0;
+    let mut comments: Vec<Comment> = Vec::new();
+    let mut code_to_the_left = false;
+
+    if let Some(shebang_len) = rustc_lexer::strip_shebang(text) {
+        comments.push(Comment {
+            style: CommentStyle::Isolated,
+            lines: vec![text[..shebang_len].to_string()],
+            pos: start_bpos,
+        });
+        pos += shebang_len;
+    }
+
+    for token in rustc_lexer::tokenize(&text[pos..]) {
+        let token_text = &text[pos..pos + token.len];
+        match token.kind {
+            rustc_lexer::TokenKind::Whitespace => {
+                if let Some(mut idx) = token_text.find('\n') {
+                    code_to_the_left = false;
+                    while let Some(next_newline) = &token_text[idx + 1..].find('\n') {
+                        idx = idx + 1 + next_newline;
+                        comments.push(Comment {
+                            style: CommentStyle::BlankLine,
+                            lines: vec![],
+                            pos: start_bpos + BytePos((pos + idx) as u32),
+                        });
+                    }
+                }
+            }
+            rustc_lexer::TokenKind::BlockComment { doc_style, .. } => {
+                if doc_style.is_none() {
+                    let code_to_the_right = match text[pos + token.len..].chars().next() {
+                        Some('\r' | '\n') => false,
+                        _ => true,
+                    };
+                    let style = match (code_to_the_left, code_to_the_right) {
+                        (_, true) => CommentStyle::Mixed,
+                        (false, false) => CommentStyle::Isolated,
+                        (true, false) => CommentStyle::Trailing,
+                    };
+
+                    // Count the number of chars since the start of the line by rescanning.
+                    let pos_in_file = start_bpos + BytePos(pos as u32);
+                    let line_begin_in_file = source_file.line_begin_pos(pos_in_file);
+                    let line_begin_pos = (line_begin_in_file - start_bpos).to_usize();
+                    let col = CharPos(text[line_begin_pos..pos].chars().count());
+
+                    let lines = split_block_comment_into_lines(token_text, col);
+                    comments.push(Comment { style, lines, pos: pos_in_file })
+                }
+            }
+            rustc_lexer::TokenKind::LineComment { doc_style } => {
+                if doc_style.is_none() {
+                    comments.push(Comment {
+                        style: if code_to_the_left {
+                            CommentStyle::Trailing
+                        } else {
+                            CommentStyle::Isolated
+                        },
+                        lines: vec![token_text.to_string()],
+                        pos: start_bpos + BytePos(pos as u32),
+                    })
+                }
+            }
+            _ => {
+                code_to_the_left = true;
+            }
+        }
+        pos += token.len;
+    }
+
+    comments
+}
diff --git a/compiler/rustc_ast/src/util/comments/tests.rs b/compiler/rustc_ast/src/util/comments/tests.rs
new file mode 100644
index 00000000000..e19198f863b
--- /dev/null
+++ b/compiler/rustc_ast/src/util/comments/tests.rs
@@ -0,0 +1,43 @@
+use super::*;
+use rustc_span::with_default_session_globals;
+
+#[test]
+fn test_block_doc_comment_1() {
+    with_default_session_globals(|| {
+        let comment = "\n * Test \n **  Test\n *   Test\n";
+        let stripped = beautify_doc_string(Symbol::intern(comment));
+        assert_eq!(stripped, " Test \n*  Test\n   Test");
+    })
+}
+
+#[test]
+fn test_block_doc_comment_2() {
+    with_default_session_globals(|| {
+        let comment = "\n * Test\n *  Test\n";
+        let stripped = beautify_doc_string(Symbol::intern(comment));
+        assert_eq!(stripped, " Test\n  Test");
+    })
+}
+
+#[test]
+fn test_block_doc_comment_3() {
+    with_default_session_globals(|| {
+        let comment = "\n let a: *i32;\n *a = 5;\n";
+        let stripped = beautify_doc_string(Symbol::intern(comment));
+        assert_eq!(stripped, " let a: *i32;\n *a = 5;");
+    })
+}
+
+#[test]
+fn test_line_doc_comment() {
+    with_default_session_globals(|| {
+        let stripped = beautify_doc_string(Symbol::intern(" test"));
+        assert_eq!(stripped, " test");
+        let stripped = beautify_doc_string(Symbol::intern("! test"));
+        assert_eq!(stripped, "! test");
+        let stripped = beautify_doc_string(Symbol::intern("test"));
+        assert_eq!(stripped, "test");
+        let stripped = beautify_doc_string(Symbol::intern("!test"));
+        assert_eq!(stripped, "!test");
+    })
+}
diff --git a/compiler/rustc_ast/src/util/lev_distance.rs b/compiler/rustc_ast/src/util/lev_distance.rs
new file mode 100644
index 00000000000..d4e0e3ba051
--- /dev/null
+++ b/compiler/rustc_ast/src/util/lev_distance.rs
@@ -0,0 +1,108 @@
+// FIXME(Centril): Move to rustc_span?
+
+use rustc_span::symbol::Symbol;
+use std::cmp;
+
+#[cfg(test)]
+mod tests;
+
+/// Finds the Levenshtein distance between two strings
+pub fn lev_distance(a: &str, b: &str) -> usize {
+    // cases which don't require further computation
+    if a.is_empty() {
+        return b.chars().count();
+    } else if b.is_empty() {
+        return a.chars().count();
+    }
+
+    let mut dcol: Vec<_> = (0..=b.len()).collect();
+    let mut t_last = 0;
+
+    for (i, sc) in a.chars().enumerate() {
+        let mut current = i;
+        dcol[0] = current + 1;
+
+        for (j, tc) in b.chars().enumerate() {
+            let next = dcol[j + 1];
+            if sc == tc {
+                dcol[j + 1] = current;
+            } else {
+                dcol[j + 1] = cmp::min(current, next);
+                dcol[j + 1] = cmp::min(dcol[j + 1], dcol[j]) + 1;
+            }
+            current = next;
+            t_last = j;
+        }
+    }
+    dcol[t_last + 1]
+}
+
+/// Finds the best match for a given word in the given iterator
+///
+/// As a loose rule to avoid the obviously incorrect suggestions, it takes
+/// an optional limit for the maximum allowable edit distance, which defaults
+/// to one-third of the given word.
+///
+/// Besides Levenshtein, we use case insensitive comparison to improve accuracy on an edge case with
+/// a lower(upper)case letters mismatch.
+pub fn find_best_match_for_name<'a, T>(
+    iter_names: T,
+    lookup: Symbol,
+    dist: Option<usize>,
+) -> Option<Symbol>
+where
+    T: Iterator<Item = &'a Symbol>,
+{
+    let lookup = &lookup.as_str();
+    let max_dist = dist.map_or_else(|| cmp::max(lookup.len(), 3) / 3, |d| d);
+    let name_vec: Vec<&Symbol> = iter_names.collect();
+
+    let (case_insensitive_match, levenshtein_match) = name_vec
+        .iter()
+        .filter_map(|&name| {
+            let dist = lev_distance(lookup, &name.as_str());
+            if dist <= max_dist { Some((name, dist)) } else { None }
+        })
+        // Here we are collecting the next structure:
+        // (case_insensitive_match, (levenshtein_match, levenshtein_distance))
+        .fold((None, None), |result, (candidate, dist)| {
+            (
+                if candidate.as_str().to_uppercase() == lookup.to_uppercase() {
+                    Some(candidate)
+                } else {
+                    result.0
+                },
+                match result.1 {
+                    None => Some((candidate, dist)),
+                    Some((c, d)) => Some(if dist < d { (candidate, dist) } else { (c, d) }),
+                },
+            )
+        });
+    // Priority of matches:
+    // 1. Exact case insensitive match
+    // 2. Levenshtein distance match
+    // 3. Sorted word match
+    if let Some(candidate) = case_insensitive_match {
+        Some(*candidate)
+    } else if levenshtein_match.is_some() {
+        levenshtein_match.map(|(candidate, _)| *candidate)
+    } else {
+        find_match_by_sorted_words(name_vec, lookup)
+    }
+}
+
+fn find_match_by_sorted_words<'a>(iter_names: Vec<&'a Symbol>, lookup: &str) -> Option<Symbol> {
+    iter_names.iter().fold(None, |result, candidate| {
+        if sort_by_words(&candidate.as_str()) == sort_by_words(lookup) {
+            Some(**candidate)
+        } else {
+            result
+        }
+    })
+}
+
+fn sort_by_words(name: &str) -> String {
+    let mut split_words: Vec<&str> = name.split('_').collect();
+    split_words.sort();
+    split_words.join("_")
+}
diff --git a/compiler/rustc_ast/src/util/lev_distance/tests.rs b/compiler/rustc_ast/src/util/lev_distance/tests.rs
new file mode 100644
index 00000000000..7ebedbcb76a
--- /dev/null
+++ b/compiler/rustc_ast/src/util/lev_distance/tests.rs
@@ -0,0 +1,59 @@
+use super::*;
+
+#[test]
+fn test_lev_distance() {
+    use std::char::{from_u32, MAX};
+    // Test bytelength agnosticity
+    for c in (0..MAX as u32).filter_map(|i| from_u32(i)).map(|i| i.to_string()) {
+        assert_eq!(lev_distance(&c[..], &c[..]), 0);
+    }
+
+    let a = "\nMäry häd ä little lämb\n\nLittle lämb\n";
+    let b = "\nMary häd ä little lämb\n\nLittle lämb\n";
+    let c = "Mary häd ä little lämb\n\nLittle lämb\n";
+    assert_eq!(lev_distance(a, b), 1);
+    assert_eq!(lev_distance(b, a), 1);
+    assert_eq!(lev_distance(a, c), 2);
+    assert_eq!(lev_distance(c, a), 2);
+    assert_eq!(lev_distance(b, c), 1);
+    assert_eq!(lev_distance(c, b), 1);
+}
+
+#[test]
+fn test_find_best_match_for_name() {
+    use rustc_span::with_default_session_globals;
+    with_default_session_globals(|| {
+        let input = vec![Symbol::intern("aaab"), Symbol::intern("aaabc")];
+        assert_eq!(
+            find_best_match_for_name(input.iter(), Symbol::intern("aaaa"), None),
+            Some(Symbol::intern("aaab"))
+        );
+
+        assert_eq!(
+            find_best_match_for_name(input.iter(), Symbol::intern("1111111111"), None),
+            None
+        );
+
+        let input = vec![Symbol::intern("aAAA")];
+        assert_eq!(
+            find_best_match_for_name(input.iter(), Symbol::intern("AAAA"), None),
+            Some(Symbol::intern("aAAA"))
+        );
+
+        let input = vec![Symbol::intern("AAAA")];
+        // Returns None because `lev_distance > max_dist / 3`
+        assert_eq!(find_best_match_for_name(input.iter(), Symbol::intern("aaaa"), None), None);
+
+        let input = vec![Symbol::intern("AAAA")];
+        assert_eq!(
+            find_best_match_for_name(input.iter(), Symbol::intern("aaaa"), Some(4)),
+            Some(Symbol::intern("AAAA"))
+        );
+
+        let input = vec![Symbol::intern("a_longer_variable_name")];
+        assert_eq!(
+            find_best_match_for_name(input.iter(), Symbol::intern("a_variable_longer_name"), None),
+            Some(Symbol::intern("a_longer_variable_name"))
+        );
+    })
+}
diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs
new file mode 100644
index 00000000000..597e5b437fc
--- /dev/null
+++ b/compiler/rustc_ast/src/util/literal.rs
@@ -0,0 +1,320 @@
+//! Code related to parsing literals.
+
+use crate::ast::{self, Lit, LitKind};
+use crate::token::{self, Token};
+use crate::tokenstream::TokenTree;
+
+use rustc_data_structures::sync::Lrc;
+use rustc_lexer::unescape::{unescape_byte, unescape_char};
+use rustc_lexer::unescape::{unescape_byte_literal, unescape_literal, Mode};
+use rustc_span::symbol::{kw, sym, Symbol};
+use rustc_span::Span;
+
+use std::ascii;
+use tracing::debug;
+
+pub enum LitError {
+    NotLiteral,
+    LexerError,
+    InvalidSuffix,
+    InvalidIntSuffix,
+    InvalidFloatSuffix,
+    NonDecimalFloat(u32),
+    IntTooLarge,
+}
+
+impl LitKind {
+    /// Converts literal token into a semantic literal.
+    fn from_lit_token(lit: token::Lit) -> Result<LitKind, LitError> {
+        let token::Lit { kind, symbol, suffix } = lit;
+        if suffix.is_some() && !kind.may_have_suffix() {
+            return Err(LitError::InvalidSuffix);
+        }
+
+        Ok(match kind {
+            token::Bool => {
+                assert!(symbol.is_bool_lit());
+                LitKind::Bool(symbol == kw::True)
+            }
+            token::Byte => {
+                return unescape_byte(&symbol.as_str())
+                    .map(LitKind::Byte)
+                    .map_err(|_| LitError::LexerError);
+            }
+            token::Char => {
+                return unescape_char(&symbol.as_str())
+                    .map(LitKind::Char)
+                    .map_err(|_| LitError::LexerError);
+            }
+
+            // There are some valid suffixes for integer and float literals,
+            // so all the handling is done internally.
+            token::Integer => return integer_lit(symbol, suffix),
+            token::Float => return float_lit(symbol, suffix),
+
+            token::Str => {
+                // If there are no characters requiring special treatment we can
+                // reuse the symbol from the token. Otherwise, we must generate a
+                // new symbol because the string in the LitKind is different to the
+                // string in the token.
+                let s = symbol.as_str();
+                let symbol =
+                    if s.contains(&['\\', '\r'][..]) {
+                        let mut buf = String::with_capacity(s.len());
+                        let mut error = Ok(());
+                        unescape_literal(&s, Mode::Str, &mut |_, unescaped_char| {
+                            match unescaped_char {
+                                Ok(c) => buf.push(c),
+                                Err(_) => error = Err(LitError::LexerError),
+                            }
+                        });
+                        error?;
+                        Symbol::intern(&buf)
+                    } else {
+                        symbol
+                    };
+                LitKind::Str(symbol, ast::StrStyle::Cooked)
+            }
+            token::StrRaw(n) => {
+                // Ditto.
+                let s = symbol.as_str();
+                let symbol =
+                    if s.contains('\r') {
+                        let mut buf = String::with_capacity(s.len());
+                        let mut error = Ok(());
+                        unescape_literal(&s, Mode::RawStr, &mut |_, unescaped_char| {
+                            match unescaped_char {
+                                Ok(c) => buf.push(c),
+                                Err(_) => error = Err(LitError::LexerError),
+                            }
+                        });
+                        error?;
+                        buf.shrink_to_fit();
+                        Symbol::intern(&buf)
+                    } else {
+                        symbol
+                    };
+                LitKind::Str(symbol, ast::StrStyle::Raw(n))
+            }
+            token::ByteStr => {
+                let s = symbol.as_str();
+                let mut buf = Vec::with_capacity(s.len());
+                let mut error = Ok(());
+                unescape_byte_literal(&s, Mode::ByteStr, &mut |_, unescaped_byte| {
+                    match unescaped_byte {
+                        Ok(c) => buf.push(c),
+                        Err(_) => error = Err(LitError::LexerError),
+                    }
+                });
+                error?;
+                buf.shrink_to_fit();
+                LitKind::ByteStr(Lrc::new(buf))
+            }
+            token::ByteStrRaw(_) => {
+                let s = symbol.as_str();
+                let bytes = if s.contains('\r') {
+                    let mut buf = Vec::with_capacity(s.len());
+                    let mut error = Ok(());
+                    unescape_byte_literal(&s, Mode::RawByteStr, &mut |_, unescaped_byte| {
+                        match unescaped_byte {
+                            Ok(c) => buf.push(c),
+                            Err(_) => error = Err(LitError::LexerError),
+                        }
+                    });
+                    error?;
+                    buf.shrink_to_fit();
+                    buf
+                } else {
+                    symbol.to_string().into_bytes()
+                };
+
+                LitKind::ByteStr(Lrc::new(bytes))
+            }
+            token::Err => LitKind::Err(symbol),
+        })
+    }
+
+    /// Attempts to recover a token from semantic literal.
+    /// This function is used when the original token doesn't exist (e.g. the literal is created
+    /// by an AST-based macro) or unavailable (e.g. from HIR pretty-printing).
+    pub fn to_lit_token(&self) -> token::Lit {
+        let (kind, symbol, suffix) = match *self {
+            LitKind::Str(symbol, ast::StrStyle::Cooked) => {
+                // Don't re-intern unless the escaped string is different.
+                let s = symbol.as_str();
+                let escaped = s.escape_default().to_string();
+                let symbol = if s == escaped { symbol } else { Symbol::intern(&escaped) };
+                (token::Str, symbol, None)
+            }
+            LitKind::Str(symbol, ast::StrStyle::Raw(n)) => (token::StrRaw(n), symbol, None),
+            LitKind::ByteStr(ref bytes) => {
+                let string = bytes
+                    .iter()
+                    .cloned()
+                    .flat_map(ascii::escape_default)
+                    .map(Into::<char>::into)
+                    .collect::<String>();
+                (token::ByteStr, Symbol::intern(&string), None)
+            }
+            LitKind::Byte(byte) => {
+                let string: String = ascii::escape_default(byte).map(Into::<char>::into).collect();
+                (token::Byte, Symbol::intern(&string), None)
+            }
+            LitKind::Char(ch) => {
+                let string: String = ch.escape_default().map(Into::<char>::into).collect();
+                (token::Char, Symbol::intern(&string), None)
+            }
+            LitKind::Int(n, ty) => {
+                let suffix = match ty {
+                    ast::LitIntType::Unsigned(ty) => Some(ty.name()),
+                    ast::LitIntType::Signed(ty) => Some(ty.name()),
+                    ast::LitIntType::Unsuffixed => None,
+                };
+                (token::Integer, sym::integer(n), suffix)
+            }
+            LitKind::Float(symbol, ty) => {
+                let suffix = match ty {
+                    ast::LitFloatType::Suffixed(ty) => Some(ty.name()),
+                    ast::LitFloatType::Unsuffixed => None,
+                };
+                (token::Float, symbol, suffix)
+            }
+            LitKind::Bool(value) => {
+                let symbol = if value { kw::True } else { kw::False };
+                (token::Bool, symbol, None)
+            }
+            LitKind::Err(symbol) => (token::Err, symbol, None),
+        };
+
+        token::Lit::new(kind, symbol, suffix)
+    }
+}
+
+impl Lit {
+    /// Converts literal token into an AST literal.
+    pub fn from_lit_token(token: token::Lit, span: Span) -> Result<Lit, LitError> {
+        Ok(Lit { token, kind: LitKind::from_lit_token(token)?, span })
+    }
+
+    /// Converts arbitrary token into an AST literal.
+    ///
+    /// Keep this in sync with `Token::can_begin_literal_or_bool` excluding unary negation.
+    pub fn from_token(token: &Token) -> Result<Lit, LitError> {
+        let lit = match token.uninterpolate().kind {
+            token::Ident(name, false) if name.is_bool_lit() => {
+                token::Lit::new(token::Bool, name, None)
+            }
+            token::Literal(lit) => lit,
+            token::Interpolated(ref nt) => {
+                if let token::NtExpr(expr) | token::NtLiteral(expr) = &**nt {
+                    if let ast::ExprKind::Lit(lit) = &expr.kind {
+                        return Ok(lit.clone());
+                    }
+                }
+                return Err(LitError::NotLiteral);
+            }
+            _ => return Err(LitError::NotLiteral),
+        };
+
+        Lit::from_lit_token(lit, token.span)
+    }
+
+    /// Attempts to recover an AST literal from semantic literal.
+    /// This function is used when the original token doesn't exist (e.g. the literal is created
+    /// by an AST-based macro) or unavailable (e.g. from HIR pretty-printing).
+    pub fn from_lit_kind(kind: LitKind, span: Span) -> Lit {
+        Lit { token: kind.to_lit_token(), kind, span }
+    }
+
+    /// Losslessly convert an AST literal into a token stream.
+    pub fn token_tree(&self) -> TokenTree {
+        let token = match self.token.kind {
+            token::Bool => token::Ident(self.token.symbol, false),
+            _ => token::Literal(self.token),
+        };
+        TokenTree::token(token, self.span)
+    }
+}
+
+fn strip_underscores(symbol: Symbol) -> Symbol {
+    // Do not allocate a new string unless necessary.
+    let s = symbol.as_str();
+    if s.contains('_') {
+        let mut s = s.to_string();
+        s.retain(|c| c != '_');
+        return Symbol::intern(&s);
+    }
+    symbol
+}
+
+fn filtered_float_lit(
+    symbol: Symbol,
+    suffix: Option<Symbol>,
+    base: u32,
+) -> Result<LitKind, LitError> {
+    debug!("filtered_float_lit: {:?}, {:?}, {:?}", symbol, suffix, base);
+    if base != 10 {
+        return Err(LitError::NonDecimalFloat(base));
+    }
+    Ok(match suffix {
+        Some(suf) => LitKind::Float(
+            symbol,
+            ast::LitFloatType::Suffixed(match suf {
+                sym::f32 => ast::FloatTy::F32,
+                sym::f64 => ast::FloatTy::F64,
+                _ => return Err(LitError::InvalidFloatSuffix),
+            }),
+        ),
+        None => LitKind::Float(symbol, ast::LitFloatType::Unsuffixed),
+    })
+}
+
+fn float_lit(symbol: Symbol, suffix: Option<Symbol>) -> Result<LitKind, LitError> {
+    debug!("float_lit: {:?}, {:?}", symbol, suffix);
+    filtered_float_lit(strip_underscores(symbol), suffix, 10)
+}
+
+fn integer_lit(symbol: Symbol, suffix: Option<Symbol>) -> Result<LitKind, LitError> {
+    debug!("integer_lit: {:?}, {:?}", symbol, suffix);
+    let symbol = strip_underscores(symbol);
+    let s = symbol.as_str();
+
+    let base = match s.as_bytes() {
+        [b'0', b'x', ..] => 16,
+        [b'0', b'o', ..] => 8,
+        [b'0', b'b', ..] => 2,
+        _ => 10,
+    };
+
+    let ty = match suffix {
+        Some(suf) => match suf {
+            sym::isize => ast::LitIntType::Signed(ast::IntTy::Isize),
+            sym::i8 => ast::LitIntType::Signed(ast::IntTy::I8),
+            sym::i16 => ast::LitIntType::Signed(ast::IntTy::I16),
+            sym::i32 => ast::LitIntType::Signed(ast::IntTy::I32),
+            sym::i64 => ast::LitIntType::Signed(ast::IntTy::I64),
+            sym::i128 => ast::LitIntType::Signed(ast::IntTy::I128),
+            sym::usize => ast::LitIntType::Unsigned(ast::UintTy::Usize),
+            sym::u8 => ast::LitIntType::Unsigned(ast::UintTy::U8),
+            sym::u16 => ast::LitIntType::Unsigned(ast::UintTy::U16),
+            sym::u32 => ast::LitIntType::Unsigned(ast::UintTy::U32),
+            sym::u64 => ast::LitIntType::Unsigned(ast::UintTy::U64),
+            sym::u128 => ast::LitIntType::Unsigned(ast::UintTy::U128),
+            // `1f64` and `2f32` etc. are valid float literals, and
+            // `fxxx` looks more like an invalid float literal than invalid integer literal.
+            _ if suf.as_str().starts_with('f') => return filtered_float_lit(symbol, suffix, base),
+            _ => return Err(LitError::InvalidIntSuffix),
+        },
+        _ => ast::LitIntType::Unsuffixed,
+    };
+
+    let s = &s[if base != 10 { 2 } else { 0 }..];
+    u128::from_str_radix(s, base).map(|i| LitKind::Int(i, ty)).map_err(|_| {
+        // Small bases are lexed as if they were base 10, e.g, the string
+        // might be `0b10201`. This will cause the conversion above to fail,
+        // but these kinds of errors are already reported by the lexer.
+        let from_lexer =
+            base < 10 && s.chars().any(|c| c.to_digit(10).map_or(false, |d| d >= base));
+        if from_lexer { LitError::LexerError } else { LitError::IntTooLarge }
+    })
+}
diff --git a/compiler/rustc_ast/src/util/parser.rs b/compiler/rustc_ast/src/util/parser.rs
new file mode 100644
index 00000000000..2ee94965756
--- /dev/null
+++ b/compiler/rustc_ast/src/util/parser.rs
@@ -0,0 +1,403 @@
+use crate::ast::{self, BinOpKind};
+use crate::token::{self, BinOpToken, Token};
+use rustc_span::symbol::kw;
+
+/// Associative operator with precedence.
+///
+/// This is the enum which specifies operator precedence and fixity to the parser.
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub enum AssocOp {
+    /// `+`
+    Add,
+    /// `-`
+    Subtract,
+    /// `*`
+    Multiply,
+    /// `/`
+    Divide,
+    /// `%`
+    Modulus,
+    /// `&&`
+    LAnd,
+    /// `||`
+    LOr,
+    /// `^`
+    BitXor,
+    /// `&`
+    BitAnd,
+    /// `|`
+    BitOr,
+    /// `<<`
+    ShiftLeft,
+    /// `>>`
+    ShiftRight,
+    /// `==`
+    Equal,
+    /// `<`
+    Less,
+    /// `<=`
+    LessEqual,
+    /// `!=`
+    NotEqual,
+    /// `>`
+    Greater,
+    /// `>=`
+    GreaterEqual,
+    /// `=`
+    Assign,
+    /// `?=` where ? is one of the BinOpToken
+    AssignOp(BinOpToken),
+    /// `as`
+    As,
+    /// `..` range
+    DotDot,
+    /// `..=` range
+    DotDotEq,
+    /// `:`
+    Colon,
+}
+
+#[derive(PartialEq, Debug)]
+pub enum Fixity {
+    /// The operator is left-associative
+    Left,
+    /// The operator is right-associative
+    Right,
+    /// The operator is not associative
+    None,
+}
+
+impl AssocOp {
+    /// Creates a new AssocOP from a token
+    pub fn from_token(t: &Token) -> Option<AssocOp> {
+        use AssocOp::*;
+        match t.kind {
+            token::BinOpEq(k) => Some(AssignOp(k)),
+            token::Eq => Some(Assign),
+            token::BinOp(BinOpToken::Star) => Some(Multiply),
+            token::BinOp(BinOpToken::Slash) => Some(Divide),
+            token::BinOp(BinOpToken::Percent) => Some(Modulus),
+            token::BinOp(BinOpToken::Plus) => Some(Add),
+            token::BinOp(BinOpToken::Minus) => Some(Subtract),
+            token::BinOp(BinOpToken::Shl) => Some(ShiftLeft),
+            token::BinOp(BinOpToken::Shr) => Some(ShiftRight),
+            token::BinOp(BinOpToken::And) => Some(BitAnd),
+            token::BinOp(BinOpToken::Caret) => Some(BitXor),
+            token::BinOp(BinOpToken::Or) => Some(BitOr),
+            token::Lt => Some(Less),
+            token::Le => Some(LessEqual),
+            token::Ge => Some(GreaterEqual),
+            token::Gt => Some(Greater),
+            token::EqEq => Some(Equal),
+            token::Ne => Some(NotEqual),
+            token::AndAnd => Some(LAnd),
+            token::OrOr => Some(LOr),
+            token::DotDot => Some(DotDot),
+            token::DotDotEq => Some(DotDotEq),
+            // DotDotDot is no longer supported, but we need some way to display the error
+            token::DotDotDot => Some(DotDotEq),
+            token::Colon => Some(Colon),
+            // `<-` should probably be `< -`
+            token::LArrow => Some(Less),
+            _ if t.is_keyword(kw::As) => Some(As),
+            _ => None,
+        }
+    }
+
+    /// Creates a new AssocOp from ast::BinOpKind.
+    pub fn from_ast_binop(op: BinOpKind) -> Self {
+        use AssocOp::*;
+        match op {
+            BinOpKind::Lt => Less,
+            BinOpKind::Gt => Greater,
+            BinOpKind::Le => LessEqual,
+            BinOpKind::Ge => GreaterEqual,
+            BinOpKind::Eq => Equal,
+            BinOpKind::Ne => NotEqual,
+            BinOpKind::Mul => Multiply,
+            BinOpKind::Div => Divide,
+            BinOpKind::Rem => Modulus,
+            BinOpKind::Add => Add,
+            BinOpKind::Sub => Subtract,
+            BinOpKind::Shl => ShiftLeft,
+            BinOpKind::Shr => ShiftRight,
+            BinOpKind::BitAnd => BitAnd,
+            BinOpKind::BitXor => BitXor,
+            BinOpKind::BitOr => BitOr,
+            BinOpKind::And => LAnd,
+            BinOpKind::Or => LOr,
+        }
+    }
+
+    /// Gets the precedence of this operator
+    pub fn precedence(&self) -> usize {
+        use AssocOp::*;
+        match *self {
+            As | Colon => 14,
+            Multiply | Divide | Modulus => 13,
+            Add | Subtract => 12,
+            ShiftLeft | ShiftRight => 11,
+            BitAnd => 10,
+            BitXor => 9,
+            BitOr => 8,
+            Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => 7,
+            LAnd => 6,
+            LOr => 5,
+            DotDot | DotDotEq => 4,
+            Assign | AssignOp(_) => 2,
+        }
+    }
+
+    /// Gets the fixity of this operator
+    pub fn fixity(&self) -> Fixity {
+        use AssocOp::*;
+        // NOTE: it is a bug to have an operators that has same precedence but different fixities!
+        match *self {
+            Assign | AssignOp(_) => Fixity::Right,
+            As | Multiply | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd
+            | BitXor | BitOr | Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual
+            | LAnd | LOr | Colon => Fixity::Left,
+            DotDot | DotDotEq => Fixity::None,
+        }
+    }
+
+    pub fn is_comparison(&self) -> bool {
+        use AssocOp::*;
+        match *self {
+            Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => true,
+            Assign | AssignOp(_) | As | Multiply | Divide | Modulus | Add | Subtract
+            | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd | LOr | DotDot | DotDotEq
+            | Colon => false,
+        }
+    }
+
+    pub fn is_assign_like(&self) -> bool {
+        use AssocOp::*;
+        match *self {
+            Assign | AssignOp(_) => true,
+            Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual | As | Multiply
+            | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd | BitXor
+            | BitOr | LAnd | LOr | DotDot | DotDotEq | Colon => false,
+        }
+    }
+
+    pub fn to_ast_binop(&self) -> Option<BinOpKind> {
+        use AssocOp::*;
+        match *self {
+            Less => Some(BinOpKind::Lt),
+            Greater => Some(BinOpKind::Gt),
+            LessEqual => Some(BinOpKind::Le),
+            GreaterEqual => Some(BinOpKind::Ge),
+            Equal => Some(BinOpKind::Eq),
+            NotEqual => Some(BinOpKind::Ne),
+            Multiply => Some(BinOpKind::Mul),
+            Divide => Some(BinOpKind::Div),
+            Modulus => Some(BinOpKind::Rem),
+            Add => Some(BinOpKind::Add),
+            Subtract => Some(BinOpKind::Sub),
+            ShiftLeft => Some(BinOpKind::Shl),
+            ShiftRight => Some(BinOpKind::Shr),
+            BitAnd => Some(BinOpKind::BitAnd),
+            BitXor => Some(BinOpKind::BitXor),
+            BitOr => Some(BinOpKind::BitOr),
+            LAnd => Some(BinOpKind::And),
+            LOr => Some(BinOpKind::Or),
+            Assign | AssignOp(_) | As | DotDot | DotDotEq | Colon => None,
+        }
+    }
+
+    /// This operator could be used to follow a block unambiguously.
+    ///
+    /// This is used for error recovery at the moment, providing a suggestion to wrap blocks with
+    /// parentheses while having a high degree of confidence on the correctness of the suggestion.
+    pub fn can_continue_expr_unambiguously(&self) -> bool {
+        use AssocOp::*;
+        match self {
+            BitXor | // `{ 42 } ^ 3`
+            Assign | // `{ 42 } = { 42 }`
+            Divide | // `{ 42 } / 42`
+            Modulus | // `{ 42 } % 2`
+            ShiftRight | // `{ 42 } >> 2`
+            LessEqual | // `{ 42 } <= 3`
+            Greater | // `{ 42 } > 3`
+            GreaterEqual | // `{ 42 } >= 3`
+            AssignOp(_) | // `{ 42 } +=`
+            As | // `{ 42 } as usize`
+            // Equal | // `{ 42 } == { 42 }`    Accepting these here would regress incorrect
+            // NotEqual | // `{ 42 } != { 42 }  struct literals parser recovery.
+            Colon => true, // `{ 42 }: usize`
+            _ => false,
+        }
+    }
+}
+
+pub const PREC_RESET: i8 = -100;
+pub const PREC_CLOSURE: i8 = -40;
+pub const PREC_JUMP: i8 = -30;
+pub const PREC_RANGE: i8 = -10;
+// The range 2..=14 is reserved for AssocOp binary operator precedences.
+pub const PREC_PREFIX: i8 = 50;
+pub const PREC_POSTFIX: i8 = 60;
+pub const PREC_PAREN: i8 = 99;
+pub const PREC_FORCE_PAREN: i8 = 100;
+
+#[derive(Debug, Clone, Copy)]
+pub enum ExprPrecedence {
+    Closure,
+    Break,
+    Continue,
+    Ret,
+    Yield,
+
+    Range,
+
+    Binary(BinOpKind),
+
+    Cast,
+    Type,
+
+    Assign,
+    AssignOp,
+
+    Box,
+    AddrOf,
+    Let,
+    Unary,
+
+    Call,
+    MethodCall,
+    Field,
+    Index,
+    Try,
+    InlineAsm,
+    Mac,
+
+    Array,
+    Repeat,
+    Tup,
+    Lit,
+    Path,
+    Paren,
+    If,
+    While,
+    ForLoop,
+    Loop,
+    Match,
+    Block,
+    TryBlock,
+    Struct,
+    Async,
+    Await,
+    Err,
+}
+
+impl ExprPrecedence {
+    pub fn order(self) -> i8 {
+        match self {
+            ExprPrecedence::Closure => PREC_CLOSURE,
+
+            ExprPrecedence::Break |
+            ExprPrecedence::Continue |
+            ExprPrecedence::Ret |
+            ExprPrecedence::Yield => PREC_JUMP,
+
+            // `Range` claims to have higher precedence than `Assign`, but `x .. x = x` fails to
+            // parse, instead of parsing as `(x .. x) = x`.  Giving `Range` a lower precedence
+            // ensures that `pprust` will add parentheses in the right places to get the desired
+            // parse.
+            ExprPrecedence::Range => PREC_RANGE,
+
+            // Binop-like expr kinds, handled by `AssocOp`.
+            ExprPrecedence::Binary(op) => AssocOp::from_ast_binop(op).precedence() as i8,
+            ExprPrecedence::Cast => AssocOp::As.precedence() as i8,
+            ExprPrecedence::Type => AssocOp::Colon.precedence() as i8,
+
+            ExprPrecedence::Assign |
+            ExprPrecedence::AssignOp => AssocOp::Assign.precedence() as i8,
+
+            // Unary, prefix
+            ExprPrecedence::Box |
+            ExprPrecedence::AddrOf |
+            // Here `let pats = expr` has `let pats =` as a "unary" prefix of `expr`.
+            // However, this is not exactly right. When `let _ = a` is the LHS of a binop we
+            // need parens sometimes. E.g. we can print `(let _ = a) && b` as `let _ = a && b`
+            // but we need to print `(let _ = a) < b` as-is with parens.
+            ExprPrecedence::Let |
+            ExprPrecedence::Unary => PREC_PREFIX,
+
+            // Unary, postfix
+            ExprPrecedence::Await |
+            ExprPrecedence::Call |
+            ExprPrecedence::MethodCall |
+            ExprPrecedence::Field |
+            ExprPrecedence::Index |
+            ExprPrecedence::Try |
+            ExprPrecedence::InlineAsm |
+            ExprPrecedence::Mac => PREC_POSTFIX,
+
+            // Never need parens
+            ExprPrecedence::Array |
+            ExprPrecedence::Repeat |
+            ExprPrecedence::Tup |
+            ExprPrecedence::Lit |
+            ExprPrecedence::Path |
+            ExprPrecedence::Paren |
+            ExprPrecedence::If |
+            ExprPrecedence::While |
+            ExprPrecedence::ForLoop |
+            ExprPrecedence::Loop |
+            ExprPrecedence::Match |
+            ExprPrecedence::Block |
+            ExprPrecedence::TryBlock |
+            ExprPrecedence::Async |
+            ExprPrecedence::Struct |
+            ExprPrecedence::Err => PREC_PAREN,
+        }
+    }
+}
+
+/// In `let p = e`, operators with precedence `<=` this one requires parenthesis in `e`.
+pub fn prec_let_scrutinee_needs_par() -> usize {
+    AssocOp::LAnd.precedence()
+}
+
+/// Suppose we have `let _ = e` and the `order` of `e`.
+/// Is the `order` such that `e` in `let _ = e` needs parenthesis when it is on the RHS?
+///
+/// Conversely, suppose that we have `(let _ = a) OP b` and `order` is that of `OP`.
+/// Can we print this as `let _ = a OP b`?
+pub fn needs_par_as_let_scrutinee(order: i8) -> bool {
+    order <= prec_let_scrutinee_needs_par() as i8
+}
+
+/// Expressions that syntactically contain an "exterior" struct literal i.e., not surrounded by any
+/// parens or other delimiters, e.g., `X { y: 1 }`, `X { y: 1 }.method()`, `foo == X { y: 1 }` and
+/// `X { y: 1 } == foo` all do, but `(X { y: 1 }) == foo` does not.
+pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool {
+    match value.kind {
+        ast::ExprKind::Struct(..) => true,
+
+        ast::ExprKind::Assign(ref lhs, ref rhs, _)
+        | ast::ExprKind::AssignOp(_, ref lhs, ref rhs)
+        | ast::ExprKind::Binary(_, ref lhs, ref rhs) => {
+            // X { y: 1 } + X { y: 2 }
+            contains_exterior_struct_lit(&lhs) || contains_exterior_struct_lit(&rhs)
+        }
+        ast::ExprKind::Await(ref x)
+        | ast::ExprKind::Unary(_, ref x)
+        | ast::ExprKind::Cast(ref x, _)
+        | ast::ExprKind::Type(ref x, _)
+        | ast::ExprKind::Field(ref x, _)
+        | ast::ExprKind::Index(ref x, _) => {
+            // &X { y: 1 }, X { y: 1 }.y
+            contains_exterior_struct_lit(&x)
+        }
+
+        ast::ExprKind::MethodCall(.., ref exprs, _) => {
+            // X { y: 1 }.bar(...)
+            contains_exterior_struct_lit(&exprs[0])
+        }
+
+        _ => false,
+    }
+}
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
new file mode 100644
index 00000000000..b65a88cb90e
--- /dev/null
+++ b/compiler/rustc_ast/src/visit.rs
@@ -0,0 +1,913 @@
+//! AST walker. Each overridden visit method has full control over what
+//! happens with its node, it can do its own traversal of the node's children,
+//! call `visit::walk_*` to apply the default traversal algorithm, or prevent
+//! deeper traversal by doing nothing.
+//!
+//! Note: it is an important invariant that the default visitor walks the body
+//! of a function in "execution order" (more concretely, reverse post-order
+//! with respect to the CFG implied by the AST), meaning that if AST node A may
+//! execute before AST node B, then A is visited first. The borrow checker in
+//! particular relies on this property.
+//!
+//! Note: walking an AST before macro expansion is probably a bad idea. For
+//! instance, a walker looking for item names in a module will miss all of
+//! those that are created by the expansion of a macro.
+
+use crate::ast::*;
+use crate::token::Token;
+use crate::tokenstream::{TokenStream, TokenTree};
+
+use rustc_span::symbol::{Ident, Symbol};
+use rustc_span::Span;
+
+#[derive(Copy, Clone, PartialEq)]
+pub enum AssocCtxt {
+    Trait,
+    Impl,
+}
+
+#[derive(Copy, Clone, PartialEq)]
+pub enum FnCtxt {
+    Free,
+    Foreign,
+    Assoc(AssocCtxt),
+}
+
+#[derive(Copy, Clone)]
+pub enum FnKind<'a> {
+    /// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`.
+    Fn(FnCtxt, Ident, &'a FnSig, &'a Visibility, Option<&'a Block>),
+
+    /// E.g., `|x, y| body`.
+    Closure(&'a FnDecl, &'a Expr),
+}
+
+impl<'a> FnKind<'a> {
+    pub fn header(&self) -> Option<&'a FnHeader> {
+        match *self {
+            FnKind::Fn(_, _, sig, _, _) => Some(&sig.header),
+            FnKind::Closure(_, _) => None,
+        }
+    }
+
+    pub fn ident(&self) -> Option<&Ident> {
+        match self {
+            FnKind::Fn(_, ident, ..) => Some(ident),
+            _ => None,
+        }
+    }
+
+    pub fn decl(&self) -> &'a FnDecl {
+        match self {
+            FnKind::Fn(_, _, sig, _, _) => &sig.decl,
+            FnKind::Closure(decl, _) => decl,
+        }
+    }
+
+    pub fn ctxt(&self) -> Option<FnCtxt> {
+        match self {
+            FnKind::Fn(ctxt, ..) => Some(*ctxt),
+            FnKind::Closure(..) => None,
+        }
+    }
+}
+
+/// Each method of the `Visitor` trait is a hook to be potentially
+/// overridden. Each method's default implementation recursively visits
+/// the substructure of the input via the corresponding `walk` method;
+/// e.g., the `visit_mod` method by default calls `visit::walk_mod`.
+///
+/// If you want to ensure that your code handles every variant
+/// explicitly, you need to override each method. (And you also need
+/// to monitor future changes to `Visitor` in case a new method with a
+/// new default implementation gets introduced.)
+pub trait Visitor<'ast>: Sized {
+    fn visit_name(&mut self, _span: Span, _name: Symbol) {
+        // Nothing to do.
+    }
+    fn visit_ident(&mut self, ident: Ident) {
+        walk_ident(self, ident);
+    }
+    fn visit_mod(&mut self, m: &'ast Mod, _s: Span, _attrs: &[Attribute], _n: NodeId) {
+        walk_mod(self, m);
+    }
+    fn visit_foreign_item(&mut self, i: &'ast ForeignItem) {
+        walk_foreign_item(self, i)
+    }
+    fn visit_global_asm(&mut self, ga: &'ast GlobalAsm) {
+        walk_global_asm(self, ga)
+    }
+    fn visit_item(&mut self, i: &'ast Item) {
+        walk_item(self, i)
+    }
+    fn visit_local(&mut self, l: &'ast Local) {
+        walk_local(self, l)
+    }
+    fn visit_block(&mut self, b: &'ast Block) {
+        walk_block(self, b)
+    }
+    fn visit_stmt(&mut self, s: &'ast Stmt) {
+        walk_stmt(self, s)
+    }
+    fn visit_param(&mut self, param: &'ast Param) {
+        walk_param(self, param)
+    }
+    fn visit_arm(&mut self, a: &'ast Arm) {
+        walk_arm(self, a)
+    }
+    fn visit_pat(&mut self, p: &'ast Pat) {
+        walk_pat(self, p)
+    }
+    fn visit_anon_const(&mut self, c: &'ast AnonConst) {
+        walk_anon_const(self, c)
+    }
+    fn visit_expr(&mut self, ex: &'ast Expr) {
+        walk_expr(self, ex)
+    }
+    fn visit_expr_post(&mut self, _ex: &'ast Expr) {}
+    fn visit_ty(&mut self, t: &'ast Ty) {
+        walk_ty(self, t)
+    }
+    fn visit_generic_param(&mut self, param: &'ast GenericParam) {
+        walk_generic_param(self, param)
+    }
+    fn visit_generics(&mut self, g: &'ast Generics) {
+        walk_generics(self, g)
+    }
+    fn visit_where_predicate(&mut self, p: &'ast WherePredicate) {
+        walk_where_predicate(self, p)
+    }
+    fn visit_fn(&mut self, fk: FnKind<'ast>, s: Span, _: NodeId) {
+        walk_fn(self, fk, s)
+    }
+    fn visit_assoc_item(&mut self, i: &'ast AssocItem, ctxt: AssocCtxt) {
+        walk_assoc_item(self, i, ctxt)
+    }
+    fn visit_trait_ref(&mut self, t: &'ast TraitRef) {
+        walk_trait_ref(self, t)
+    }
+    fn visit_param_bound(&mut self, bounds: &'ast GenericBound) {
+        walk_param_bound(self, bounds)
+    }
+    fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef, m: &'ast TraitBoundModifier) {
+        walk_poly_trait_ref(self, t, m)
+    }
+    fn visit_variant_data(&mut self, s: &'ast VariantData) {
+        walk_struct_def(self, s)
+    }
+    fn visit_struct_field(&mut self, s: &'ast StructField) {
+        walk_struct_field(self, s)
+    }
+    fn visit_enum_def(
+        &mut self,
+        enum_definition: &'ast EnumDef,
+        generics: &'ast Generics,
+        item_id: NodeId,
+        _: Span,
+    ) {
+        walk_enum_def(self, enum_definition, generics, item_id)
+    }
+    fn visit_variant(&mut self, v: &'ast Variant) {
+        walk_variant(self, v)
+    }
+    fn visit_label(&mut self, label: &'ast Label) {
+        walk_label(self, label)
+    }
+    fn visit_lifetime(&mut self, lifetime: &'ast Lifetime) {
+        walk_lifetime(self, lifetime)
+    }
+    fn visit_mac(&mut self, _mac: &'ast MacCall) {
+        panic!("visit_mac disabled by default");
+        // N.B., see note about macros above.
+        // if you really want a visitor that
+        // works on macros, use this
+        // definition in your trait impl:
+        // visit::walk_mac(self, _mac)
+    }
+    fn visit_mac_def(&mut self, _mac: &'ast MacroDef, _id: NodeId) {
+        // Nothing to do
+    }
+    fn visit_path(&mut self, path: &'ast Path, _id: NodeId) {
+        walk_path(self, path)
+    }
+    fn visit_use_tree(&mut self, use_tree: &'ast UseTree, id: NodeId, _nested: bool) {
+        walk_use_tree(self, use_tree, id)
+    }
+    fn visit_path_segment(&mut self, path_span: Span, path_segment: &'ast PathSegment) {
+        walk_path_segment(self, path_span, path_segment)
+    }
+    fn visit_generic_args(&mut self, path_span: Span, generic_args: &'ast GenericArgs) {
+        walk_generic_args(self, path_span, generic_args)
+    }
+    fn visit_generic_arg(&mut self, generic_arg: &'ast GenericArg) {
+        match generic_arg {
+            GenericArg::Lifetime(lt) => self.visit_lifetime(lt),
+            GenericArg::Type(ty) => self.visit_ty(ty),
+            GenericArg::Const(ct) => self.visit_anon_const(ct),
+        }
+    }
+    fn visit_assoc_ty_constraint(&mut self, constraint: &'ast AssocTyConstraint) {
+        walk_assoc_ty_constraint(self, constraint)
+    }
+    fn visit_attribute(&mut self, attr: &'ast Attribute) {
+        walk_attribute(self, attr)
+    }
+    fn visit_tt(&mut self, tt: TokenTree) {
+        walk_tt(self, tt)
+    }
+    fn visit_tts(&mut self, tts: TokenStream) {
+        walk_tts(self, tts)
+    }
+    fn visit_token(&mut self, _t: Token) {}
+    // FIXME: add `visit_interpolated` and `walk_interpolated`
+    fn visit_vis(&mut self, vis: &'ast Visibility) {
+        walk_vis(self, vis)
+    }
+    fn visit_fn_ret_ty(&mut self, ret_ty: &'ast FnRetTy) {
+        walk_fn_ret_ty(self, ret_ty)
+    }
+    fn visit_fn_header(&mut self, _header: &'ast FnHeader) {
+        // Nothing to do
+    }
+    fn visit_field(&mut self, f: &'ast Field) {
+        walk_field(self, f)
+    }
+    fn visit_field_pattern(&mut self, fp: &'ast FieldPat) {
+        walk_field_pattern(self, fp)
+    }
+}
+
+#[macro_export]
+macro_rules! walk_list {
+    ($visitor: expr, $method: ident, $list: expr) => {
+        for elem in $list {
+            $visitor.$method(elem)
+        }
+    };
+    ($visitor: expr, $method: ident, $list: expr, $($extra_args: expr),*) => {
+        for elem in $list {
+            $visitor.$method(elem, $($extra_args,)*)
+        }
+    }
+}
+
+pub fn walk_ident<'a, V: Visitor<'a>>(visitor: &mut V, ident: Ident) {
+    visitor.visit_name(ident.span, ident.name);
+}
+
+pub fn walk_crate<'a, V: Visitor<'a>>(visitor: &mut V, krate: &'a Crate) {
+    visitor.visit_mod(&krate.module, krate.span, &krate.attrs, CRATE_NODE_ID);
+    walk_list!(visitor, visit_attribute, &krate.attrs);
+}
+
+pub fn walk_mod<'a, V: Visitor<'a>>(visitor: &mut V, module: &'a Mod) {
+    walk_list!(visitor, visit_item, &module.items);
+}
+
+pub fn walk_local<'a, V: Visitor<'a>>(visitor: &mut V, local: &'a Local) {
+    for attr in local.attrs.iter() {
+        visitor.visit_attribute(attr);
+    }
+    visitor.visit_pat(&local.pat);
+    walk_list!(visitor, visit_ty, &local.ty);
+    walk_list!(visitor, visit_expr, &local.init);
+}
+
+pub fn walk_label<'a, V: Visitor<'a>>(visitor: &mut V, label: &'a Label) {
+    visitor.visit_ident(label.ident);
+}
+
+pub fn walk_lifetime<'a, V: Visitor<'a>>(visitor: &mut V, lifetime: &'a Lifetime) {
+    visitor.visit_ident(lifetime.ident);
+}
+
+pub fn walk_poly_trait_ref<'a, V>(
+    visitor: &mut V,
+    trait_ref: &'a PolyTraitRef,
+    _: &TraitBoundModifier,
+) where
+    V: Visitor<'a>,
+{
+    walk_list!(visitor, visit_generic_param, &trait_ref.bound_generic_params);
+    visitor.visit_trait_ref(&trait_ref.trait_ref);
+}
+
+pub fn walk_trait_ref<'a, V: Visitor<'a>>(visitor: &mut V, trait_ref: &'a TraitRef) {
+    visitor.visit_path(&trait_ref.path, trait_ref.ref_id)
+}
+
+pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
+    visitor.visit_vis(&item.vis);
+    visitor.visit_ident(item.ident);
+    match item.kind {
+        ItemKind::ExternCrate(orig_name) => {
+            if let Some(orig_name) = orig_name {
+                visitor.visit_name(item.span, orig_name);
+            }
+        }
+        ItemKind::Use(ref use_tree) => visitor.visit_use_tree(use_tree, item.id, false),
+        ItemKind::Static(ref typ, _, ref expr) | ItemKind::Const(_, ref typ, ref expr) => {
+            visitor.visit_ty(typ);
+            walk_list!(visitor, visit_expr, expr);
+        }
+        ItemKind::Fn(_, ref sig, ref generics, ref body) => {
+            visitor.visit_generics(generics);
+            let kind = FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, body.as_deref());
+            visitor.visit_fn(kind, item.span, item.id)
+        }
+        ItemKind::Mod(ref module) => visitor.visit_mod(module, item.span, &item.attrs, item.id),
+        ItemKind::ForeignMod(ref foreign_module) => {
+            walk_list!(visitor, visit_foreign_item, &foreign_module.items);
+        }
+        ItemKind::GlobalAsm(ref ga) => visitor.visit_global_asm(ga),
+        ItemKind::TyAlias(_, ref generics, ref bounds, ref ty) => {
+            visitor.visit_generics(generics);
+            walk_list!(visitor, visit_param_bound, bounds);
+            walk_list!(visitor, visit_ty, ty);
+        }
+        ItemKind::Enum(ref enum_definition, ref generics) => {
+            visitor.visit_generics(generics);
+            visitor.visit_enum_def(enum_definition, generics, item.id, item.span)
+        }
+        ItemKind::Impl {
+            unsafety: _,
+            polarity: _,
+            defaultness: _,
+            constness: _,
+            ref generics,
+            ref of_trait,
+            ref self_ty,
+            ref items,
+        } => {
+            visitor.visit_generics(generics);
+            walk_list!(visitor, visit_trait_ref, of_trait);
+            visitor.visit_ty(self_ty);
+            walk_list!(visitor, visit_assoc_item, items, AssocCtxt::Impl);
+        }
+        ItemKind::Struct(ref struct_definition, ref generics)
+        | ItemKind::Union(ref struct_definition, ref generics) => {
+            visitor.visit_generics(generics);
+            visitor.visit_variant_data(struct_definition);
+        }
+        ItemKind::Trait(.., ref generics, ref bounds, ref items) => {
+            visitor.visit_generics(generics);
+            walk_list!(visitor, visit_param_bound, bounds);
+            walk_list!(visitor, visit_assoc_item, items, AssocCtxt::Trait);
+        }
+        ItemKind::TraitAlias(ref generics, ref bounds) => {
+            visitor.visit_generics(generics);
+            walk_list!(visitor, visit_param_bound, bounds);
+        }
+        ItemKind::MacCall(ref mac) => visitor.visit_mac(mac),
+        ItemKind::MacroDef(ref ts) => visitor.visit_mac_def(ts, item.id),
+    }
+    walk_list!(visitor, visit_attribute, &item.attrs);
+}
+
+pub fn walk_enum_def<'a, V: Visitor<'a>>(
+    visitor: &mut V,
+    enum_definition: &'a EnumDef,
+    _: &'a Generics,
+    _: NodeId,
+) {
+    walk_list!(visitor, visit_variant, &enum_definition.variants);
+}
+
+pub fn walk_variant<'a, V: Visitor<'a>>(visitor: &mut V, variant: &'a Variant)
+where
+    V: Visitor<'a>,
+{
+    visitor.visit_ident(variant.ident);
+    visitor.visit_vis(&variant.vis);
+    visitor.visit_variant_data(&variant.data);
+    walk_list!(visitor, visit_anon_const, &variant.disr_expr);
+    walk_list!(visitor, visit_attribute, &variant.attrs);
+}
+
+pub fn walk_field<'a, V: Visitor<'a>>(visitor: &mut V, f: &'a Field) {
+    visitor.visit_expr(&f.expr);
+    visitor.visit_ident(f.ident);
+    walk_list!(visitor, visit_attribute, f.attrs.iter());
+}
+
+pub fn walk_field_pattern<'a, V: Visitor<'a>>(visitor: &mut V, fp: &'a FieldPat) {
+    visitor.visit_ident(fp.ident);
+    visitor.visit_pat(&fp.pat);
+    walk_list!(visitor, visit_attribute, fp.attrs.iter());
+}
+
+pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) {
+    match typ.kind {
+        TyKind::Slice(ref ty) | TyKind::Paren(ref ty) => visitor.visit_ty(ty),
+        TyKind::Ptr(ref mutable_type) => visitor.visit_ty(&mutable_type.ty),
+        TyKind::Rptr(ref opt_lifetime, ref mutable_type) => {
+            walk_list!(visitor, visit_lifetime, opt_lifetime);
+            visitor.visit_ty(&mutable_type.ty)
+        }
+        TyKind::Tup(ref tuple_element_types) => {
+            walk_list!(visitor, visit_ty, tuple_element_types);
+        }
+        TyKind::BareFn(ref function_declaration) => {
+            walk_list!(visitor, visit_generic_param, &function_declaration.generic_params);
+            walk_fn_decl(visitor, &function_declaration.decl);
+        }
+        TyKind::Path(ref maybe_qself, ref path) => {
+            if let Some(ref qself) = *maybe_qself {
+                visitor.visit_ty(&qself.ty);
+            }
+            visitor.visit_path(path, typ.id);
+        }
+        TyKind::Array(ref ty, ref length) => {
+            visitor.visit_ty(ty);
+            visitor.visit_anon_const(length)
+        }
+        TyKind::TraitObject(ref bounds, ..) | TyKind::ImplTrait(_, ref bounds) => {
+            walk_list!(visitor, visit_param_bound, bounds);
+        }
+        TyKind::Typeof(ref expression) => visitor.visit_anon_const(expression),
+        TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err => {}
+        TyKind::MacCall(ref mac) => visitor.visit_mac(mac),
+        TyKind::Never | TyKind::CVarArgs => {}
+    }
+}
+
+pub fn walk_path<'a, V: Visitor<'a>>(visitor: &mut V, path: &'a Path) {
+    for segment in &path.segments {
+        visitor.visit_path_segment(path.span, segment);
+    }
+}
+
+pub fn walk_use_tree<'a, V: Visitor<'a>>(visitor: &mut V, use_tree: &'a UseTree, id: NodeId) {
+    visitor.visit_path(&use_tree.prefix, id);
+    match use_tree.kind {
+        UseTreeKind::Simple(rename, ..) => {
+            // The extra IDs are handled during HIR lowering.
+            if let Some(rename) = rename {
+                visitor.visit_ident(rename);
+            }
+        }
+        UseTreeKind::Glob => {}
+        UseTreeKind::Nested(ref use_trees) => {
+            for &(ref nested_tree, nested_id) in use_trees {
+                visitor.visit_use_tree(nested_tree, nested_id, true);
+            }
+        }
+    }
+}
+
+pub fn walk_path_segment<'a, V: Visitor<'a>>(
+    visitor: &mut V,
+    path_span: Span,
+    segment: &'a PathSegment,
+) {
+    visitor.visit_ident(segment.ident);
+    if let Some(ref args) = segment.args {
+        visitor.visit_generic_args(path_span, args);
+    }
+}
+
+pub fn walk_generic_args<'a, V>(visitor: &mut V, _path_span: Span, generic_args: &'a GenericArgs)
+where
+    V: Visitor<'a>,
+{
+    match *generic_args {
+        GenericArgs::AngleBracketed(ref data) => {
+            for arg in &data.args {
+                match arg {
+                    AngleBracketedArg::Arg(a) => visitor.visit_generic_arg(a),
+                    AngleBracketedArg::Constraint(c) => visitor.visit_assoc_ty_constraint(c),
+                }
+            }
+        }
+        GenericArgs::Parenthesized(ref data) => {
+            walk_list!(visitor, visit_ty, &data.inputs);
+            walk_fn_ret_ty(visitor, &data.output);
+        }
+    }
+}
+
+pub fn walk_assoc_ty_constraint<'a, V: Visitor<'a>>(
+    visitor: &mut V,
+    constraint: &'a AssocTyConstraint,
+) {
+    visitor.visit_ident(constraint.ident);
+    match constraint.kind {
+        AssocTyConstraintKind::Equality { ref ty } => {
+            visitor.visit_ty(ty);
+        }
+        AssocTyConstraintKind::Bound { ref bounds } => {
+            walk_list!(visitor, visit_param_bound, bounds);
+        }
+    }
+}
+
+pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) {
+    match pattern.kind {
+        PatKind::TupleStruct(ref path, ref elems) => {
+            visitor.visit_path(path, pattern.id);
+            walk_list!(visitor, visit_pat, elems);
+        }
+        PatKind::Path(ref opt_qself, ref path) => {
+            if let Some(ref qself) = *opt_qself {
+                visitor.visit_ty(&qself.ty);
+            }
+            visitor.visit_path(path, pattern.id)
+        }
+        PatKind::Struct(ref path, ref fields, _) => {
+            visitor.visit_path(path, pattern.id);
+            walk_list!(visitor, visit_field_pattern, fields);
+        }
+        PatKind::Box(ref subpattern)
+        | PatKind::Ref(ref subpattern, _)
+        | PatKind::Paren(ref subpattern) => visitor.visit_pat(subpattern),
+        PatKind::Ident(_, ident, ref optional_subpattern) => {
+            visitor.visit_ident(ident);
+            walk_list!(visitor, visit_pat, optional_subpattern);
+        }
+        PatKind::Lit(ref expression) => visitor.visit_expr(expression),
+        PatKind::Range(ref lower_bound, ref upper_bound, _) => {
+            walk_list!(visitor, visit_expr, lower_bound);
+            walk_list!(visitor, visit_expr, upper_bound);
+        }
+        PatKind::Wild | PatKind::Rest => {}
+        PatKind::Tuple(ref elems) | PatKind::Slice(ref elems) | PatKind::Or(ref elems) => {
+            walk_list!(visitor, visit_pat, elems);
+        }
+        PatKind::MacCall(ref mac) => visitor.visit_mac(mac),
+    }
+}
+
+pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a ForeignItem) {
+    let Item { id, span, ident, ref vis, ref attrs, ref kind, tokens: _ } = *item;
+    visitor.visit_vis(vis);
+    visitor.visit_ident(ident);
+    walk_list!(visitor, visit_attribute, attrs);
+    match kind {
+        ForeignItemKind::Static(ty, _, expr) => {
+            visitor.visit_ty(ty);
+            walk_list!(visitor, visit_expr, expr);
+        }
+        ForeignItemKind::Fn(_, sig, generics, body) => {
+            visitor.visit_generics(generics);
+            let kind = FnKind::Fn(FnCtxt::Foreign, ident, sig, vis, body.as_deref());
+            visitor.visit_fn(kind, span, id);
+        }
+        ForeignItemKind::TyAlias(_, generics, bounds, ty) => {
+            visitor.visit_generics(generics);
+            walk_list!(visitor, visit_param_bound, bounds);
+            walk_list!(visitor, visit_ty, ty);
+        }
+        ForeignItemKind::MacCall(mac) => {
+            visitor.visit_mac(mac);
+        }
+    }
+}
+
+pub fn walk_global_asm<'a, V: Visitor<'a>>(_: &mut V, _: &'a GlobalAsm) {
+    // Empty!
+}
+
+pub fn walk_param_bound<'a, V: Visitor<'a>>(visitor: &mut V, bound: &'a GenericBound) {
+    match *bound {
+        GenericBound::Trait(ref typ, ref modifier) => visitor.visit_poly_trait_ref(typ, modifier),
+        GenericBound::Outlives(ref lifetime) => visitor.visit_lifetime(lifetime),
+    }
+}
+
+pub fn walk_generic_param<'a, V: Visitor<'a>>(visitor: &mut V, param: &'a GenericParam) {
+    visitor.visit_ident(param.ident);
+    walk_list!(visitor, visit_attribute, param.attrs.iter());
+    walk_list!(visitor, visit_param_bound, &param.bounds);
+    match param.kind {
+        GenericParamKind::Lifetime => (),
+        GenericParamKind::Type { ref default } => walk_list!(visitor, visit_ty, default),
+        GenericParamKind::Const { ref ty, .. } => visitor.visit_ty(ty),
+    }
+}
+
+pub fn walk_generics<'a, V: Visitor<'a>>(visitor: &mut V, generics: &'a Generics) {
+    walk_list!(visitor, visit_generic_param, &generics.params);
+    walk_list!(visitor, visit_where_predicate, &generics.where_clause.predicates);
+}
+
+pub fn walk_where_predicate<'a, V: Visitor<'a>>(visitor: &mut V, predicate: &'a WherePredicate) {
+    match *predicate {
+        WherePredicate::BoundPredicate(WhereBoundPredicate {
+            ref bounded_ty,
+            ref bounds,
+            ref bound_generic_params,
+            ..
+        }) => {
+            visitor.visit_ty(bounded_ty);
+            walk_list!(visitor, visit_param_bound, bounds);
+            walk_list!(visitor, visit_generic_param, bound_generic_params);
+        }
+        WherePredicate::RegionPredicate(WhereRegionPredicate {
+            ref lifetime, ref bounds, ..
+        }) => {
+            visitor.visit_lifetime(lifetime);
+            walk_list!(visitor, visit_param_bound, bounds);
+        }
+        WherePredicate::EqPredicate(WhereEqPredicate { ref lhs_ty, ref rhs_ty, .. }) => {
+            visitor.visit_ty(lhs_ty);
+            visitor.visit_ty(rhs_ty);
+        }
+    }
+}
+
+pub fn walk_fn_ret_ty<'a, V: Visitor<'a>>(visitor: &mut V, ret_ty: &'a FnRetTy) {
+    if let FnRetTy::Ty(ref output_ty) = *ret_ty {
+        visitor.visit_ty(output_ty)
+    }
+}
+
+pub fn walk_fn_decl<'a, V: Visitor<'a>>(visitor: &mut V, function_declaration: &'a FnDecl) {
+    for param in &function_declaration.inputs {
+        visitor.visit_param(param);
+    }
+    visitor.visit_fn_ret_ty(&function_declaration.output);
+}
+
+pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>, _span: Span) {
+    match kind {
+        FnKind::Fn(_, _, sig, _, body) => {
+            visitor.visit_fn_header(&sig.header);
+            walk_fn_decl(visitor, &sig.decl);
+            walk_list!(visitor, visit_block, body);
+        }
+        FnKind::Closure(decl, body) => {
+            walk_fn_decl(visitor, decl);
+            visitor.visit_expr(body);
+        }
+    }
+}
+
+pub fn walk_assoc_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem, ctxt: AssocCtxt) {
+    let Item { id, span, ident, ref vis, ref attrs, ref kind, tokens: _ } = *item;
+    visitor.visit_vis(vis);
+    visitor.visit_ident(ident);
+    walk_list!(visitor, visit_attribute, attrs);
+    match kind {
+        AssocItemKind::Const(_, ty, expr) => {
+            visitor.visit_ty(ty);
+            walk_list!(visitor, visit_expr, expr);
+        }
+        AssocItemKind::Fn(_, sig, generics, body) => {
+            visitor.visit_generics(generics);
+            let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, vis, body.as_deref());
+            visitor.visit_fn(kind, span, id);
+        }
+        AssocItemKind::TyAlias(_, generics, bounds, ty) => {
+            visitor.visit_generics(generics);
+            walk_list!(visitor, visit_param_bound, bounds);
+            walk_list!(visitor, visit_ty, ty);
+        }
+        AssocItemKind::MacCall(mac) => {
+            visitor.visit_mac(mac);
+        }
+    }
+}
+
+pub fn walk_struct_def<'a, V: Visitor<'a>>(visitor: &mut V, struct_definition: &'a VariantData) {
+    walk_list!(visitor, visit_struct_field, struct_definition.fields());
+}
+
+pub fn walk_struct_field<'a, V: Visitor<'a>>(visitor: &mut V, struct_field: &'a StructField) {
+    visitor.visit_vis(&struct_field.vis);
+    if let Some(ident) = struct_field.ident {
+        visitor.visit_ident(ident);
+    }
+    visitor.visit_ty(&struct_field.ty);
+    walk_list!(visitor, visit_attribute, &struct_field.attrs);
+}
+
+pub fn walk_block<'a, V: Visitor<'a>>(visitor: &mut V, block: &'a Block) {
+    walk_list!(visitor, visit_stmt, &block.stmts);
+}
+
+pub fn walk_stmt<'a, V: Visitor<'a>>(visitor: &mut V, statement: &'a Stmt) {
+    match statement.kind {
+        StmtKind::Local(ref local) => visitor.visit_local(local),
+        StmtKind::Item(ref item) => visitor.visit_item(item),
+        StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => visitor.visit_expr(expr),
+        StmtKind::Empty => {}
+        StmtKind::MacCall(ref mac) => {
+            let (ref mac, _, ref attrs) = **mac;
+            visitor.visit_mac(mac);
+            for attr in attrs.iter() {
+                visitor.visit_attribute(attr);
+            }
+        }
+    }
+}
+
+pub fn walk_mac<'a, V: Visitor<'a>>(visitor: &mut V, mac: &'a MacCall) {
+    visitor.visit_path(&mac.path, DUMMY_NODE_ID);
+}
+
+pub fn walk_anon_const<'a, V: Visitor<'a>>(visitor: &mut V, constant: &'a AnonConst) {
+    visitor.visit_expr(&constant.value);
+}
+
+pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
+    walk_list!(visitor, visit_attribute, expression.attrs.iter());
+
+    match expression.kind {
+        ExprKind::Box(ref subexpression) => visitor.visit_expr(subexpression),
+        ExprKind::Array(ref subexpressions) => {
+            walk_list!(visitor, visit_expr, subexpressions);
+        }
+        ExprKind::Repeat(ref element, ref count) => {
+            visitor.visit_expr(element);
+            visitor.visit_anon_const(count)
+        }
+        ExprKind::Struct(ref path, ref fields, ref optional_base) => {
+            visitor.visit_path(path, expression.id);
+            walk_list!(visitor, visit_field, fields);
+            walk_list!(visitor, visit_expr, optional_base);
+        }
+        ExprKind::Tup(ref subexpressions) => {
+            walk_list!(visitor, visit_expr, subexpressions);
+        }
+        ExprKind::Call(ref callee_expression, ref arguments) => {
+            visitor.visit_expr(callee_expression);
+            walk_list!(visitor, visit_expr, arguments);
+        }
+        ExprKind::MethodCall(ref segment, ref arguments, _span) => {
+            visitor.visit_path_segment(expression.span, segment);
+            walk_list!(visitor, visit_expr, arguments);
+        }
+        ExprKind::Binary(_, ref left_expression, ref right_expression) => {
+            visitor.visit_expr(left_expression);
+            visitor.visit_expr(right_expression)
+        }
+        ExprKind::AddrOf(_, _, ref subexpression) | ExprKind::Unary(_, ref subexpression) => {
+            visitor.visit_expr(subexpression)
+        }
+        ExprKind::Cast(ref subexpression, ref typ) | ExprKind::Type(ref subexpression, ref typ) => {
+            visitor.visit_expr(subexpression);
+            visitor.visit_ty(typ)
+        }
+        ExprKind::Let(ref pat, ref scrutinee) => {
+            visitor.visit_pat(pat);
+            visitor.visit_expr(scrutinee);
+        }
+        ExprKind::If(ref head_expression, ref if_block, ref optional_else) => {
+            visitor.visit_expr(head_expression);
+            visitor.visit_block(if_block);
+            walk_list!(visitor, visit_expr, optional_else);
+        }
+        ExprKind::While(ref subexpression, ref block, ref opt_label) => {
+            walk_list!(visitor, visit_label, opt_label);
+            visitor.visit_expr(subexpression);
+            visitor.visit_block(block);
+        }
+        ExprKind::ForLoop(ref pattern, ref subexpression, ref block, ref opt_label) => {
+            walk_list!(visitor, visit_label, opt_label);
+            visitor.visit_pat(pattern);
+            visitor.visit_expr(subexpression);
+            visitor.visit_block(block);
+        }
+        ExprKind::Loop(ref block, ref opt_label) => {
+            walk_list!(visitor, visit_label, opt_label);
+            visitor.visit_block(block);
+        }
+        ExprKind::Match(ref subexpression, ref arms) => {
+            visitor.visit_expr(subexpression);
+            walk_list!(visitor, visit_arm, arms);
+        }
+        ExprKind::Closure(_, _, _, ref decl, ref body, _decl_span) => {
+            visitor.visit_fn(FnKind::Closure(decl, body), expression.span, expression.id)
+        }
+        ExprKind::Block(ref block, ref opt_label) => {
+            walk_list!(visitor, visit_label, opt_label);
+            visitor.visit_block(block);
+        }
+        ExprKind::Async(_, _, ref body) => {
+            visitor.visit_block(body);
+        }
+        ExprKind::Await(ref expr) => visitor.visit_expr(expr),
+        ExprKind::Assign(ref lhs, ref rhs, _) => {
+            visitor.visit_expr(lhs);
+            visitor.visit_expr(rhs);
+        }
+        ExprKind::AssignOp(_, ref left_expression, ref right_expression) => {
+            visitor.visit_expr(left_expression);
+            visitor.visit_expr(right_expression);
+        }
+        ExprKind::Field(ref subexpression, ident) => {
+            visitor.visit_expr(subexpression);
+            visitor.visit_ident(ident);
+        }
+        ExprKind::Index(ref main_expression, ref index_expression) => {
+            visitor.visit_expr(main_expression);
+            visitor.visit_expr(index_expression)
+        }
+        ExprKind::Range(ref start, ref end, _) => {
+            walk_list!(visitor, visit_expr, start);
+            walk_list!(visitor, visit_expr, end);
+        }
+        ExprKind::Path(ref maybe_qself, ref path) => {
+            if let Some(ref qself) = *maybe_qself {
+                visitor.visit_ty(&qself.ty);
+            }
+            visitor.visit_path(path, expression.id)
+        }
+        ExprKind::Break(ref opt_label, ref opt_expr) => {
+            walk_list!(visitor, visit_label, opt_label);
+            walk_list!(visitor, visit_expr, opt_expr);
+        }
+        ExprKind::Continue(ref opt_label) => {
+            walk_list!(visitor, visit_label, opt_label);
+        }
+        ExprKind::Ret(ref optional_expression) => {
+            walk_list!(visitor, visit_expr, optional_expression);
+        }
+        ExprKind::MacCall(ref mac) => visitor.visit_mac(mac),
+        ExprKind::Paren(ref subexpression) => visitor.visit_expr(subexpression),
+        ExprKind::InlineAsm(ref ia) => {
+            for (op, _) in &ia.operands {
+                match op {
+                    InlineAsmOperand::In { expr, .. }
+                    | InlineAsmOperand::InOut { expr, .. }
+                    | InlineAsmOperand::Const { expr, .. }
+                    | InlineAsmOperand::Sym { expr, .. } => visitor.visit_expr(expr),
+                    InlineAsmOperand::Out { expr, .. } => {
+                        if let Some(expr) = expr {
+                            visitor.visit_expr(expr);
+                        }
+                    }
+                    InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => {
+                        visitor.visit_expr(in_expr);
+                        if let Some(out_expr) = out_expr {
+                            visitor.visit_expr(out_expr);
+                        }
+                    }
+                }
+            }
+        }
+        ExprKind::LlvmInlineAsm(ref ia) => {
+            for &(_, ref input) in &ia.inputs {
+                visitor.visit_expr(input)
+            }
+            for output in &ia.outputs {
+                visitor.visit_expr(&output.expr)
+            }
+        }
+        ExprKind::Yield(ref optional_expression) => {
+            walk_list!(visitor, visit_expr, optional_expression);
+        }
+        ExprKind::Try(ref subexpression) => visitor.visit_expr(subexpression),
+        ExprKind::TryBlock(ref body) => visitor.visit_block(body),
+        ExprKind::Lit(_) | ExprKind::Err => {}
+    }
+
+    visitor.visit_expr_post(expression)
+}
+
+pub fn walk_param<'a, V: Visitor<'a>>(visitor: &mut V, param: &'a Param) {
+    walk_list!(visitor, visit_attribute, param.attrs.iter());
+    visitor.visit_pat(&param.pat);
+    visitor.visit_ty(&param.ty);
+}
+
+pub fn walk_arm<'a, V: Visitor<'a>>(visitor: &mut V, arm: &'a Arm) {
+    visitor.visit_pat(&arm.pat);
+    walk_list!(visitor, visit_expr, &arm.guard);
+    visitor.visit_expr(&arm.body);
+    walk_list!(visitor, visit_attribute, &arm.attrs);
+}
+
+pub fn walk_vis<'a, V: Visitor<'a>>(visitor: &mut V, vis: &'a Visibility) {
+    if let VisibilityKind::Restricted { ref path, id } = vis.node {
+        visitor.visit_path(path, id);
+    }
+}
+
+pub fn walk_attribute<'a, V: Visitor<'a>>(visitor: &mut V, attr: &'a Attribute) {
+    match attr.kind {
+        AttrKind::Normal(ref item) => walk_mac_args(visitor, &item.args),
+        AttrKind::DocComment(..) => {}
+    }
+}
+
+pub fn walk_mac_args<'a, V: Visitor<'a>>(visitor: &mut V, args: &'a MacArgs) {
+    match args {
+        MacArgs::Empty => {}
+        MacArgs::Delimited(_dspan, _delim, tokens) => visitor.visit_tts(tokens.clone()),
+        MacArgs::Eq(_eq_span, tokens) => visitor.visit_tts(tokens.clone()),
+    }
+}
+
+pub fn walk_tt<'a, V: Visitor<'a>>(visitor: &mut V, tt: TokenTree) {
+    match tt {
+        TokenTree::Token(token) => visitor.visit_token(token),
+        TokenTree::Delimited(_, _, tts) => visitor.visit_tts(tts),
+    }
+}
+
+pub fn walk_tts<'a, V: Visitor<'a>>(visitor: &mut V, tts: TokenStream) {
+    for tt in tts.trees() {
+        visitor.visit_tt(tt);
+    }
+}