about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-04-05 19:25:37 +0000
committerbors <bors@rust-lang.org>2018-04-05 19:25:37 +0000
commit48fa6f9631868b07309b02f479e2ec523bb58c2b (patch)
treef42e4285226c191c4448946f440ba79642ba1080 /src
parent7222241e7c2d7caf9ad6ee6e34748e4addfb8dd3 (diff)
parentcd615e9863fa4593ff87243920875ad5bb73906a (diff)
downloadrust-48fa6f9631868b07309b02f479e2ec523bb58c2b.tar.gz
rust-48fa6f9631868b07309b02f479e2ec523bb58c2b.zip
Auto merge of #49696 - alexcrichton:rollup, r=alexcrichton
Rollup of 8 pull requests

Successful merges:

 - #49045 (Make queries thread safe)
 - #49350 (Expand macros in `extern {}` blocks)
 - #49497 (Chalkify - Tweak `Clause` definition and HRTBs)
 - #49597 (proc_macro: Reorganize public API)
 - #49686 (typos)
- #49621
- #49697
- #49705

Failed merges:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/ci/docker/run.sh1
-rwxr-xr-xsrc/ci/run.sh4
-rw-r--r--src/liballoc/boxed.rs3
-rw-r--r--src/libcore/mem.rs3
-rw-r--r--src/libproc_macro/lib.rs753
-rw-r--r--src/libproc_macro/quote.rs138
-rw-r--r--src/librustc/hir/lowering.rs1
-rw-r--r--src/librustc/hir/map/def_collector.rs4
-rw-r--r--src/librustc/ich/impls_ty.rs12
-rw-r--r--src/librustc/traits/mod.rs35
-rw-r--r--src/librustc/traits/structural_impls.rs42
-rw-r--r--src/librustc_passes/ast_validation.rs18
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs6
-rw-r--r--src/librustc_resolve/lib.rs1
-rw-r--r--src/librustc_save_analysis/dump_visitor.rs1
-rw-r--r--src/librustc_save_analysis/lib.rs1
-rw-r--r--src/librustc_save_analysis/sig.rs1
-rw-r--r--src/librustc_traits/lowering.rs52
-rw-r--r--src/libstd/lib.rs2
-rw-r--r--src/libstd/panic.rs2
-rw-r--r--src/libstd/sys/windows/pipe.rs2
-rw-r--r--src/libsyntax/ast.rs3
-rw-r--r--src/libsyntax/ext/base.rs28
-rw-r--r--src/libsyntax/ext/expand.rs58
-rw-r--r--src/libsyntax/ext/placeholders.rs11
-rw-r--r--src/libsyntax/feature_gate.rs11
-rw-r--r--src/libsyntax/fold.rs20
-rw-r--r--src/libsyntax/parse/parser.rs124
-rw-r--r--src/libsyntax/parse/token.rs2
-rw-r--r--src/libsyntax/print/pprust.rs9
-rw-r--r--src/libsyntax/visit.rs1
-rw-r--r--src/libsyntax_ext/deriving/custom.rs1
-rw-r--r--src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs6
-rw-r--r--src/test/compile-fail-fulldeps/proc-macro/auxiliary/attributes-included.rs87
-rw-r--r--src/test/compile-fail-fulldeps/proc-macro/auxiliary/test-macros.rs36
-rw-r--r--src/test/compile-fail-fulldeps/proc-macro/macros-in-extern.rs38
-rw-r--r--src/test/compile-fail/macros-in-extern.rs42
-rw-r--r--src/test/parse-fail/duplicate-visibility.rs2
-rw-r--r--src/test/parse-fail/extern-no-fn.rs4
-rw-r--r--src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs12
-rw-r--r--src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs8
-rw-r--r--src/test/run-pass-fulldeps/auxiliary/proc_macro_def.rs2
-rw-r--r--src/test/run-pass-fulldeps/proc-macro/auxiliary/count_compound_ops.rs15
-rw-r--r--src/test/run-pass-fulldeps/proc-macro/auxiliary/negative-token.rs10
-rw-r--r--src/test/run-pass-fulldeps/proc-macro/auxiliary/span-api-tests.rs4
-rw-r--r--src/test/run-pass-fulldeps/proc-macro/auxiliary/test-macros.rs36
-rw-r--r--src/test/run-pass-fulldeps/proc-macro/macros-in-extern.rs35
-rw-r--r--src/test/run-pass/macros-in-extern.rs39
-rw-r--r--src/test/ui-fulldeps/proc-macro/auxiliary/parent-source-spans.rs8
-rw-r--r--src/test/ui-fulldeps/proc-macro/auxiliary/three-equals.rs17
-rw-r--r--src/test/ui/feature-gate-macros_in_extern.rs35
-rw-r--r--src/test/ui/feature-gate-macros_in_extern.stderr27
-rw-r--r--src/tools/build-manifest/src/main.rs22
53 files changed, 1400 insertions, 435 deletions
diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh
index ea2387b67db..c470ae7eb30 100755
--- a/src/ci/docker/run.sh
+++ b/src/ci/docker/run.sh
@@ -130,6 +130,7 @@ exec docker \
   --env TRAVIS \
   --env TRAVIS_BRANCH \
   --env TOOLSTATE_REPO_ACCESS_TOKEN \
+  --env CI_JOB_NAME="${CI_JOB_NAME-$IMAGE}" \
   --volume "$HOME/.cargo:/cargo" \
   --volume "$HOME/rustsrc:$HOME/rustsrc" \
   --init \
diff --git a/src/ci/run.sh b/src/ci/run.sh
index 44eae0d1800..119b239d6b2 100755
--- a/src/ci/run.sh
+++ b/src/ci/run.sh
@@ -11,6 +11,10 @@
 
 set -e
 
+if [ -n "$CI_JOB_NAME" ]; then
+  echo "[CI_JOB_NAME=$CI_JOB_NAME]"
+fi
+
 if [ "$NO_CHANGE_USER" = "" ]; then
   if [ "$LOCAL_USER_ID" != "" ]; then
     useradd --shell /bin/bash -u $LOCAL_USER_ID -o -c "" -m user
diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs
index 4f9dc61ce19..71b53cc88e5 100644
--- a/src/liballoc/boxed.rs
+++ b/src/liballoc/boxed.rs
@@ -845,3 +845,6 @@ impl<T: ?Sized> fmt::Pointer for PinBox<T> {
 
 #[unstable(feature = "pin", issue = "49150")]
 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<PinBox<U>> for PinBox<T> {}
+
+#[unstable(feature = "pin", issue = "49150")]
+unsafe impl<T: ?Sized> Unpin for PinBox<T> {}
diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs
index b2467c948b4..e3f08926610 100644
--- a/src/libcore/mem.rs
+++ b/src/libcore/mem.rs
@@ -1213,3 +1213,6 @@ impl<'a, T: ?Sized> fmt::Pointer for Pin<'a, T> {
 
 #[unstable(feature = "pin", issue = "49150")]
 impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Pin<'a, U>> for Pin<'a, T> {}
+
+#[unstable(feature = "pin", issue = "49150")]
+unsafe impl<'a, T: ?Sized> Unpin for Pin<'a, T> {}
diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs
index 007093981d3..ebd5c834fd0 100644
--- a/src/libproc_macro/lib.rs
+++ b/src/libproc_macro/lib.rs
@@ -59,7 +59,7 @@ use syntax::errors::DiagnosticBuilder;
 use syntax::parse::{self, token};
 use syntax::symbol::Symbol;
 use syntax::tokenstream;
-use syntax_pos::DUMMY_SP;
+use syntax::parse::lexer::comments;
 use syntax_pos::{FileMap, Pos, SyntaxContext, FileName};
 use syntax_pos::hygiene::Mark;
 
@@ -73,7 +73,7 @@ use syntax_pos::hygiene::Mark;
 /// The API of this type is intentionally bare-bones, but it'll be expanded over
 /// time!
 #[stable(feature = "proc_macro_lib", since = "1.15.0")]
-#[derive(Clone, Debug)]
+#[derive(Clone)]
 pub struct TokenStream(tokenstream::TokenStream);
 
 /// Error returned from `TokenStream::from_str`.
@@ -83,6 +83,20 @@ pub struct LexError {
     _inner: (),
 }
 
+impl TokenStream {
+    /// Returns an empty `TokenStream`.
+    #[unstable(feature = "proc_macro", issue = "38356")]
+    pub fn empty() -> TokenStream {
+        TokenStream(tokenstream::TokenStream::empty())
+    }
+
+    /// Checks if this `TokenStream` is empty.
+    #[unstable(feature = "proc_macro", issue = "38356")]
+    pub fn is_empty(&self) -> bool {
+        self.0.is_empty()
+    }
+}
+
 #[stable(feature = "proc_macro_lib", since = "1.15.0")]
 impl FromStr for TokenStream {
     type Err = LexError;
@@ -110,19 +124,12 @@ impl fmt::Display for TokenStream {
     }
 }
 
-/// `quote!(..)` accepts arbitrary tokens and expands into a `TokenStream` describing the input.
-/// For example, `quote!(a + b)` will produce a expression, that, when evaluated, constructs
-/// the `TokenStream` `[Word("a"), Op('+', Alone), Word("b")]`.
-///
-/// Unquoting is done with `$`, and works by taking the single next ident as the unquoted term.
-/// To quote `$` itself, use `$$`.
-#[unstable(feature = "proc_macro", issue = "38356")]
-#[macro_export]
-macro_rules! quote { () => {} }
-
-#[unstable(feature = "proc_macro_internals", issue = "27812")]
-#[doc(hidden)]
-mod quote;
+#[stable(feature = "proc_macro_lib", since = "1.15.0")]
+impl fmt::Debug for TokenStream {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        self.0.fmt(f)
+    }
+}
 
 #[unstable(feature = "proc_macro", issue = "38356")]
 impl From<TokenTree> for TokenStream {
@@ -132,62 +139,79 @@ impl From<TokenTree> for TokenStream {
 }
 
 #[unstable(feature = "proc_macro", issue = "38356")]
-impl From<TokenNode> for TokenStream {
-    fn from(kind: TokenNode) -> TokenStream {
-        TokenTree::from(kind).into()
-    }
-}
-
-#[unstable(feature = "proc_macro", issue = "38356")]
-impl<T: Into<TokenStream>> iter::FromIterator<T> for TokenStream {
-    fn from_iter<I: IntoIterator<Item = T>>(streams: I) -> Self {
+impl iter::FromIterator<TokenTree> for TokenStream {
+    fn from_iter<I: IntoIterator<Item = TokenTree>>(trees: I) -> Self {
         let mut builder = tokenstream::TokenStreamBuilder::new();
-        for stream in streams {
-            builder.push(stream.into().0);
+        for tree in trees {
+            builder.push(tree.to_internal());
         }
         TokenStream(builder.build())
     }
 }
 
+/// Implementation details for the `TokenTree` type, such as iterators.
 #[unstable(feature = "proc_macro", issue = "38356")]
-impl IntoIterator for TokenStream {
-    type Item = TokenTree;
-    type IntoIter = TokenTreeIter;
+pub mod token_stream {
+    use syntax::tokenstream;
+    use syntax_pos::DUMMY_SP;
+
+    use {TokenTree, TokenStream, Delimiter};
 
-    fn into_iter(self) -> TokenTreeIter {
-        TokenTreeIter { cursor: self.0.trees(), stack: Vec::new() }
+    /// An iterator over `TokenTree`s.
+    #[derive(Clone)]
+    #[unstable(feature = "proc_macro", issue = "38356")]
+    pub struct IntoIter {
+        cursor: tokenstream::Cursor,
+        stack: Vec<TokenTree>,
     }
-}
 
-impl TokenStream {
-    /// Returns an empty `TokenStream`.
     #[unstable(feature = "proc_macro", issue = "38356")]
-    pub fn empty() -> TokenStream {
-        TokenStream(tokenstream::TokenStream::empty())
+    impl Iterator for IntoIter {
+        type Item = TokenTree;
+
+        fn next(&mut self) -> Option<TokenTree> {
+            loop {
+                let tree = self.stack.pop().or_else(|| {
+                    let next = self.cursor.next_as_stream()?;
+                    Some(TokenTree::from_internal(next, &mut self.stack))
+                })?;
+                if tree.span().0 == DUMMY_SP {
+                    if let TokenTree::Group(ref group) = tree {
+                        if group.delimiter() == Delimiter::None {
+                            self.cursor.insert(group.stream.clone().0);
+                            continue
+                        }
+                    }
+                }
+                return Some(tree);
+            }
+        }
     }
 
-    /// Checks if this `TokenStream` is empty.
     #[unstable(feature = "proc_macro", issue = "38356")]
-    pub fn is_empty(&self) -> bool {
-        self.0.is_empty()
+    impl IntoIterator for TokenStream {
+        type Item = TokenTree;
+        type IntoIter = IntoIter;
+
+        fn into_iter(self) -> IntoIter {
+            IntoIter { cursor: self.0.trees(), stack: Vec::new() }
+        }
     }
 }
 
-/// A region of source code, along with macro expansion information.
+/// `quote!(..)` accepts arbitrary tokens and expands into a `TokenStream` describing the input.
+/// For example, `quote!(a + b)` will produce a expression, that, when evaluated, constructs
+/// the `TokenStream` `[Word("a"), Op('+', Alone), Word("b")]`.
+///
+/// Unquoting is done with `$`, and works by taking the single next ident as the unquoted term.
+/// To quote `$` itself, use `$$`.
 #[unstable(feature = "proc_macro", issue = "38356")]
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub struct Span(syntax_pos::Span);
+#[macro_export]
+macro_rules! quote { () => {} }
 
-impl Span {
-    /// A span that resolves at the macro definition site.
-    #[unstable(feature = "proc_macro", issue = "38356")]
-    pub fn def_site() -> Span {
-        ::__internal::with_sess(|(_, mark)| {
-            let call_site = mark.expn_info().unwrap().call_site;
-            Span(call_site.with_ctxt(SyntaxContext::empty().apply_mark(mark)))
-        })
-    }
-}
+#[unstable(feature = "proc_macro_internals", issue = "27812")]
+#[doc(hidden)]
+mod quote;
 
 /// Quote a `Span` into a `TokenStream`.
 /// This is needed to implement a custom quoter.
@@ -196,6 +220,11 @@ pub fn quote_span(span: Span) -> TokenStream {
     quote::Quote::quote(span)
 }
 
+/// A region of source code, along with macro expansion information.
+#[unstable(feature = "proc_macro", issue = "38356")]
+#[derive(Copy, Clone, Debug)]
+pub struct Span(syntax_pos::Span);
+
 macro_rules! diagnostic_method {
     ($name:ident, $level:expr) => (
         /// Create a new `Diagnostic` with the given `message` at the span
@@ -208,6 +237,15 @@ macro_rules! diagnostic_method {
 }
 
 impl Span {
+    /// A span that resolves at the macro definition site.
+    #[unstable(feature = "proc_macro", issue = "38356")]
+    pub fn def_site() -> Span {
+        ::__internal::with_sess(|(_, mark)| {
+            let call_site = mark.expn_info().unwrap().call_site;
+            Span(call_site.with_ctxt(SyntaxContext::empty().apply_mark(mark)))
+        })
+    }
+
     /// The span of the invocation of the current procedural macro.
     #[unstable(feature = "proc_macro", issue = "38356")]
     pub fn call_site() -> Span {
@@ -284,6 +322,12 @@ impl Span {
         other.resolved_at(*self)
     }
 
+    /// Compares to spans to see if they're equal.
+    #[unstable(feature = "proc_macro", issue = "38356")]
+    pub fn eq(&self, other: &Span) -> bool {
+        self.0 == other.0
+    }
+
     diagnostic_method!(error, Level::Error);
     diagnostic_method!(warning, Level::Warning);
     diagnostic_method!(note, Level::Note);
@@ -379,39 +423,97 @@ impl PartialEq<FileName> for SourceFile {
 /// A single token or a delimited sequence of token trees (e.g. `[1, (), ..]`).
 #[unstable(feature = "proc_macro", issue = "38356")]
 #[derive(Clone, Debug)]
-pub struct TokenTree {
-    /// The `TokenTree`'s span
-    pub span: Span,
-    /// Description of the `TokenTree`
-    pub kind: TokenNode,
+pub enum TokenTree {
+    /// A delimited tokenstream
+    Group(Group),
+    /// A unicode identifier
+    Term(Term),
+    /// A punctuation character (`+`, `,`, `$`, etc.).
+    Op(Op),
+    /// A literal character (`'a'`), string (`"hello"`), number (`2.3`), etc.
+    Literal(Literal),
+}
+
+impl TokenTree {
+    /// Returns the span of this token, accessing the `span` method of each of
+    /// the internal tokens.
+    #[unstable(feature = "proc_macro", issue = "38356")]
+    pub fn span(&self) -> Span {
+        match *self {
+            TokenTree::Group(ref t) => t.span(),
+            TokenTree::Term(ref t) => t.span(),
+            TokenTree::Op(ref t) => t.span(),
+            TokenTree::Literal(ref t) => t.span(),
+        }
+    }
+
+    /// Configures the span for *only this token*.
+    ///
+    /// Note that if this token is a `Group` then this method will not configure
+    /// the span of each of the internal tokens, this will simply delegate to
+    /// the `set_span` method of each variant.
+    #[unstable(feature = "proc_macro", issue = "38356")]
+    pub fn set_span(&mut self, span: Span) {
+        match *self {
+            TokenTree::Group(ref mut t) => t.set_span(span),
+            TokenTree::Term(ref mut t) => t.set_span(span),
+            TokenTree::Op(ref mut t) => t.set_span(span),
+            TokenTree::Literal(ref mut t) => t.set_span(span),
+        }
+    }
+}
+
+#[unstable(feature = "proc_macro", issue = "38356")]
+impl From<Group> for TokenTree {
+    fn from(g: Group) -> TokenTree {
+        TokenTree::Group(g)
+    }
+}
+
+#[unstable(feature = "proc_macro", issue = "38356")]
+impl From<Term> for TokenTree {
+    fn from(g: Term) -> TokenTree {
+        TokenTree::Term(g)
+    }
+}
+
+#[unstable(feature = "proc_macro", issue = "38356")]
+impl From<Op> for TokenTree {
+    fn from(g: Op) -> TokenTree {
+        TokenTree::Op(g)
+    }
 }
 
 #[unstable(feature = "proc_macro", issue = "38356")]
-impl From<TokenNode> for TokenTree {
-    fn from(kind: TokenNode) -> TokenTree {
-        TokenTree { span: Span::def_site(), kind: kind }
+impl From<Literal> for TokenTree {
+    fn from(g: Literal) -> TokenTree {
+        TokenTree::Literal(g)
     }
 }
 
 #[unstable(feature = "proc_macro", issue = "38356")]
 impl fmt::Display for TokenTree {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        TokenStream::from(self.clone()).fmt(f)
+        match *self {
+            TokenTree::Group(ref t) => t.fmt(f),
+            TokenTree::Term(ref t) => t.fmt(f),
+            TokenTree::Op(ref t) => t.fmt(f),
+            TokenTree::Literal(ref t) => t.fmt(f),
+        }
     }
 }
 
-/// Description of a `TokenTree`
+/// A delimited token stream
+///
+/// A `Group` internally contains a `TokenStream` which is delimited by a
+/// `Delimiter`. Groups represent multiple tokens internally and have a `Span`
+/// for the entire stream.
 #[derive(Clone, Debug)]
 #[unstable(feature = "proc_macro", issue = "38356")]
-pub enum TokenNode {
-    /// A delimited tokenstream.
-    Group(Delimiter, TokenStream),
-    /// A unicode identifier.
-    Term(Term),
-    /// A punctuation character (`+`, `,`, `$`, etc.).
-    Op(char, Spacing),
-    /// A literal character (`'a'`), string (`"hello"`), or number (`2.3`).
-    Literal(Literal),
+pub struct Group {
+    delimiter: Delimiter,
+    stream: TokenStream,
+    span: Span,
 }
 
 /// Describes how a sequence of token trees is delimited.
@@ -428,25 +530,74 @@ pub enum Delimiter {
     None,
 }
 
-/// An interned string.
-#[derive(Copy, Clone, Debug)]
-#[unstable(feature = "proc_macro", issue = "38356")]
-pub struct Term(Symbol);
+impl Group {
+    /// Creates a new `group` with the given delimiter and token stream.
+    ///
+    /// This constructor will set the span for this group to
+    /// `Span::call_site()`. To change the span you can use the `set_span`
+    /// method below.
+    #[unstable(feature = "proc_macro", issue = "38356")]
+    pub fn new(delimiter: Delimiter, stream: TokenStream) -> Group {
+        Group {
+            delimiter: delimiter,
+            stream: stream,
+            span: Span::call_site(),
+        }
+    }
 
-impl Term {
-    /// Intern a string into a `Term`.
+    /// Returns the delimiter of this `Group`
     #[unstable(feature = "proc_macro", issue = "38356")]
-    pub fn intern(string: &str) -> Term {
-        Term(Symbol::intern(string))
+    pub fn delimiter(&self) -> Delimiter {
+        self.delimiter
     }
 
-    /// Get a reference to the interned string.
+    /// Returns the `TokenStream` of tokens that are delimited in this `Group`.
+    ///
+    /// Note that the returned token stream does not include the delimiter
+    /// returned above.
     #[unstable(feature = "proc_macro", issue = "38356")]
-    pub fn as_str(&self) -> &str {
-        unsafe { &*(&*self.0.as_str() as *const str) }
+    pub fn stream(&self) -> TokenStream {
+        self.stream.clone()
+    }
+
+    /// Returns the span for the delimiters of this token stream, spanning the
+    /// entire `Group`.
+    #[unstable(feature = "proc_macro", issue = "38356")]
+    pub fn span(&self) -> Span {
+        self.span
+    }
+
+    /// Configures the span for this `Group`'s delimiters, but not its internal
+    /// tokens.
+    ///
+    /// This method will **not** set the span of all the internal tokens spanned
+    /// by this group, but rather it will only set the span of the delimiter
+    /// tokens at the level of the `Group`.
+    #[unstable(feature = "proc_macro", issue = "38356")]
+    pub fn set_span(&mut self, span: Span) {
+        self.span = span;
     }
 }
 
+#[unstable(feature = "proc_macro", issue = "38356")]
+impl fmt::Display for Group {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        TokenStream::from(TokenTree::from(self.clone())).fmt(f)
+    }
+}
+
+/// An `Op` is an operator like `+` or `-`, and only represents one character.
+///
+/// Operators like `+=` are represented as two instance of `Op` with different
+/// forms of `Spacing` returned.
+#[unstable(feature = "proc_macro", issue = "38356")]
+#[derive(Copy, Clone, Debug)]
+pub struct Op {
+    op: char,
+    spacing: Spacing,
+    span: Span,
+}
+
 /// Whether an `Op` is either followed immediately by another `Op` or followed by whitespace.
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
 #[unstable(feature = "proc_macro", issue = "38356")]
@@ -457,68 +608,285 @@ pub enum Spacing {
     Joint,
 }
 
-/// A literal character (`'a'`), string (`"hello"`), or number (`2.3`).
-#[derive(Clone, Debug)]
+impl Op {
+    /// Creates a new `Op` from the given character and spacing.
+    ///
+    /// The returned `Op` will have the default span of `Span::call_site()`
+    /// which can be further configured with the `set_span` method below.
+    #[unstable(feature = "proc_macro", issue = "38356")]
+    pub fn new(op: char, spacing: Spacing) -> Op {
+        Op {
+            op: op,
+            spacing: spacing,
+            span: Span::call_site(),
+        }
+    }
+
+    /// Returns the character this operation represents, for example `'+'`
+    #[unstable(feature = "proc_macro", issue = "38356")]
+    pub fn op(&self) -> char {
+        self.op
+    }
+
+    /// Returns the spacing of this operator, indicating whether it's a joint
+    /// operator with more operators coming next in the token stream or an
+    /// `Alone` meaning that the operator has ended.
+    #[unstable(feature = "proc_macro", issue = "38356")]
+    pub fn spacing(&self) -> Spacing {
+        self.spacing
+    }
+
+    /// Returns the span for this operator character
+    #[unstable(feature = "proc_macro", issue = "38356")]
+    pub fn span(&self) -> Span {
+        self.span
+    }
+
+    /// Configure the span for this operator's character
+    #[unstable(feature = "proc_macro", issue = "38356")]
+    pub fn set_span(&mut self, span: Span) {
+        self.span = span;
+    }
+}
+
 #[unstable(feature = "proc_macro", issue = "38356")]
-pub struct Literal(token::Token);
+impl fmt::Display for Op {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        TokenStream::from(TokenTree::from(self.clone())).fmt(f)
+    }
+}
 
+/// An interned string.
+#[derive(Copy, Clone, Debug)]
 #[unstable(feature = "proc_macro", issue = "38356")]
-impl fmt::Display for Literal {
+pub struct Term {
+    sym: Symbol,
+    span: Span,
+}
+
+impl Term {
+    /// Creates a new `Term` with the given `string` as well as the specified
+    /// `span`.
+    ///
+    /// Note that `span`, currently in rustc, configures the hygiene information
+    /// for this identifier. As of this time `Span::call_site()` explicitly
+    /// opts-in to **non-hygienic** information (aka copy/pasted code) while
+    /// spans like `Span::def_site()` will opt-in to hygienic information,
+    /// meaning that code at the call site of the macro can't access this
+    /// identifier.
+    ///
+    /// Due to the current importance of hygiene this constructor, unlike other
+    /// tokens, requires a `Span` to be specified at construction.
+    #[unstable(feature = "proc_macro", issue = "38356")]
+    pub fn new(string: &str, span: Span) -> Term {
+        Term {
+            sym: Symbol::intern(string),
+            span,
+        }
+    }
+
+    /// Get a reference to the interned string.
+    #[unstable(feature = "proc_macro", issue = "38356")]
+    pub fn as_str(&self) -> &str {
+        unsafe { &*(&*self.sym.as_str() as *const str) }
+    }
+
+    /// Returns the span of this `Term`, encompassing the entire string returned
+    /// by `as_str`.
+    #[unstable(feature = "proc_macro", issue = "38356")]
+    pub fn span(&self) -> Span {
+        self.span
+    }
+
+    /// Configures the span of this `Term`, possibly changing hygiene
+    /// information.
+    #[unstable(feature = "proc_macro", issue = "38356")]
+    pub fn set_span(&mut self, span: Span) {
+        self.span = span;
+    }
+}
+
+#[unstable(feature = "proc_macro", issue = "38356")]
+impl fmt::Display for Term {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        TokenTree { kind: TokenNode::Literal(self.clone()), span: Span(DUMMY_SP) }.fmt(f)
+        self.as_str().fmt(f)
     }
 }
 
-macro_rules! int_literals {
-    ($($int_kind:ident),*) => {$(
-        /// Integer literal.
+/// A literal character (`'a'`), string (`"hello"`), a number (`2.3`), etc.
+#[derive(Clone, Debug)]
+#[unstable(feature = "proc_macro", issue = "38356")]
+pub struct Literal {
+    token: token::Token,
+    span: Span,
+}
+
+macro_rules! suffixed_int_literals {
+    ($($name:ident => $kind:ident,)*) => ($(
+        /// Creates a new suffixed integer literal with the specified value.
+        ///
+        /// This function will create an integer like `1u32` where the integer
+        /// value specified is the first part of the token and the integral is
+        /// also suffixed at the end.
+        ///
+        /// Literals created through this method have the `Span::call_site()`
+        /// span by default, which can be configured with the `set_span` method
+        /// below.
         #[unstable(feature = "proc_macro", issue = "38356")]
-        pub fn $int_kind(n: $int_kind) -> Literal {
-            Literal::typed_integer(n as i128, stringify!($int_kind))
+        pub fn $name(n: $kind) -> Literal {
+            let lit = token::Lit::Integer(Symbol::intern(&n.to_string()));
+            let ty = Some(Symbol::intern(stringify!($kind)));
+            Literal {
+                token: token::Literal(lit, ty),
+                span: Span::call_site(),
+            }
         }
-    )*}
+    )*)
+}
+
+macro_rules! unsuffixed_int_literals {
+    ($($name:ident => $kind:ident,)*) => ($(
+        /// Creates a new unsuffixed integer literal with the specified value.
+        ///
+        /// This function will create an integer like `1` where the integer
+        /// value specified is the first part of the token. No suffix is
+        /// specified on this token, meaning that invocations like
+        /// `Literal::i8_unsuffixed(1)` are equivalent to
+        /// `Literal::u32_unsuffixed(1)`.
+        ///
+        /// Literals created through this method have the `Span::call_site()`
+        /// span by default, which can be configured with the `set_span` method
+        /// below.
+        #[unstable(feature = "proc_macro", issue = "38356")]
+        pub fn $name(n: $kind) -> Literal {
+            let lit = token::Lit::Integer(Symbol::intern(&n.to_string()));
+            Literal {
+                token: token::Literal(lit, None),
+                span: Span::call_site(),
+            }
+        }
+    )*)
 }
 
 impl Literal {
-    /// Integer literal
-    #[unstable(feature = "proc_macro", issue = "38356")]
-    pub fn integer(n: i128) -> Literal {
-        Literal(token::Literal(token::Lit::Integer(Symbol::intern(&n.to_string())), None))
+    suffixed_int_literals! {
+        u8_suffixed => u8,
+        u16_suffixed => u16,
+        u32_suffixed => u32,
+        u64_suffixed => u64,
+        u128_suffixed => u128,
+        usize_suffixed => usize,
+        i8_suffixed => i8,
+        i16_suffixed => i16,
+        i32_suffixed => i32,
+        i64_suffixed => i64,
+        i128_suffixed => i128,
+        isize_suffixed => isize,
     }
 
-    int_literals!(u8, i8, u16, i16, u32, i32, u64, i64, usize, isize);
-    fn typed_integer(n: i128, kind: &'static str) -> Literal {
-        Literal(token::Literal(token::Lit::Integer(Symbol::intern(&n.to_string())),
-                               Some(Symbol::intern(kind))))
+    unsuffixed_int_literals! {
+        u8_unsuffixed => u8,
+        u16_unsuffixed => u16,
+        u32_unsuffixed => u32,
+        u64_unsuffixed => u64,
+        u128_unsuffixed => u128,
+        usize_unsuffixed => usize,
+        i8_unsuffixed => i8,
+        i16_unsuffixed => i16,
+        i32_unsuffixed => i32,
+        i64_unsuffixed => i64,
+        i128_unsuffixed => i128,
+        isize_unsuffixed => isize,
     }
 
-    /// Floating point literal.
+    /// Creates a new unsuffixed floating-point literal.
+    ///
+    /// This constructor is similar to those like `Literal::i8_unsuffixed` where
+    /// the float's value is emitted directly into the token but no suffix is
+    /// used, so it may be inferred to be a `f64` later in the compiler.
+    ///
+    /// # Panics
+    ///
+    /// This function requires that the specified float is finite, for
+    /// example if it is infinity or NaN this function will panic.
     #[unstable(feature = "proc_macro", issue = "38356")]
-    pub fn float(n: f64) -> Literal {
+    pub fn f32_unsuffixed(n: f32) -> Literal {
         if !n.is_finite() {
             panic!("Invalid float literal {}", n);
         }
-        Literal(token::Literal(token::Lit::Float(Symbol::intern(&n.to_string())), None))
+        let lit = token::Lit::Float(Symbol::intern(&n.to_string()));
+        Literal {
+            token: token::Literal(lit, None),
+            span: Span::call_site(),
+        }
     }
 
-    /// Floating point literal.
+    /// Creates a new suffixed floating-point literal.
+    ///
+    /// This consturctor will create a literal like `1.0f32` where the value
+    /// specified is the preceding part of the token and `f32` is the suffix of
+    /// the token. This token will always be inferred to be an `f32` in the
+    /// compiler.
+    ///
+    /// # Panics
+    ///
+    /// This function requires that the specified float is finite, for
+    /// example if it is infinity or NaN this function will panic.
     #[unstable(feature = "proc_macro", issue = "38356")]
-    pub fn f32(n: f32) -> Literal {
+    pub fn f32_suffixed(n: f32) -> Literal {
         if !n.is_finite() {
-            panic!("Invalid f32 literal {}", n);
+            panic!("Invalid float literal {}", n);
+        }
+        let lit = token::Lit::Float(Symbol::intern(&n.to_string()));
+        Literal {
+            token: token::Literal(lit, Some(Symbol::intern("f32"))),
+            span: Span::call_site(),
         }
-        Literal(token::Literal(token::Lit::Float(Symbol::intern(&n.to_string())),
-                               Some(Symbol::intern("f32"))))
     }
 
-    /// Floating point literal.
+    /// Creates a new unsuffixed floating-point literal.
+    ///
+    /// This constructor is similar to those like `Literal::i8_unsuffixed` where
+    /// the float's value is emitted directly into the token but no suffix is
+    /// used, so it may be inferred to be a `f64` later in the compiler.
+    ///
+    /// # Panics
+    ///
+    /// This function requires that the specified float is finite, for
+    /// example if it is infinity or NaN this function will panic.
     #[unstable(feature = "proc_macro", issue = "38356")]
-    pub fn f64(n: f64) -> Literal {
+    pub fn f64_unsuffixed(n: f64) -> Literal {
         if !n.is_finite() {
-            panic!("Invalid f64 literal {}", n);
+            panic!("Invalid float literal {}", n);
+        }
+        let lit = token::Lit::Float(Symbol::intern(&n.to_string()));
+        Literal {
+            token: token::Literal(lit, None),
+            span: Span::call_site(),
+        }
+    }
+
+    /// Creates a new suffixed floating-point literal.
+    ///
+    /// This consturctor will create a literal like `1.0f64` where the value
+    /// specified is the preceding part of the token and `f64` is the suffix of
+    /// the token. This token will always be inferred to be an `f64` in the
+    /// compiler.
+    ///
+    /// # Panics
+    ///
+    /// This function requires that the specified float is finite, for
+    /// example if it is infinity or NaN this function will panic.
+    #[unstable(feature = "proc_macro", issue = "38356")]
+    pub fn f64_suffixed(n: f64) -> Literal {
+        if !n.is_finite() {
+            panic!("Invalid float literal {}", n);
+        }
+        let lit = token::Lit::Float(Symbol::intern(&n.to_string()));
+        Literal {
+            token: token::Literal(lit, Some(Symbol::intern("f64"))),
+            span: Span::call_site(),
         }
-        Literal(token::Literal(token::Lit::Float(Symbol::intern(&n.to_string())),
-                               Some(Symbol::intern("f64"))))
     }
 
     /// String literal.
@@ -528,7 +896,10 @@ impl Literal {
         for ch in string.chars() {
             escaped.extend(ch.escape_debug());
         }
-        Literal(token::Literal(token::Lit::Str_(Symbol::intern(&escaped)), None))
+        Literal {
+            token: token::Literal(token::Lit::Str_(Symbol::intern(&escaped)), None),
+            span: Span::call_site(),
+        }
     }
 
     /// Character literal.
@@ -536,7 +907,10 @@ impl Literal {
     pub fn character(ch: char) -> Literal {
         let mut escaped = String::new();
         escaped.extend(ch.escape_unicode());
-        Literal(token::Literal(token::Lit::Char(Symbol::intern(&escaped)), None))
+        Literal {
+            token: token::Literal(token::Lit::Char(Symbol::intern(&escaped)), None),
+            span: Span::call_site(),
+        }
     }
 
     /// Byte string literal.
@@ -544,36 +918,29 @@ impl Literal {
     pub fn byte_string(bytes: &[u8]) -> Literal {
         let string = bytes.iter().cloned().flat_map(ascii::escape_default)
             .map(Into::<char>::into).collect::<String>();
-        Literal(token::Literal(token::Lit::ByteStr(Symbol::intern(&string)), None))
+        Literal {
+            token: token::Literal(token::Lit::ByteStr(Symbol::intern(&string)), None),
+            span: Span::call_site(),
+        }
     }
-}
 
-/// An iterator over `TokenTree`s.
-#[derive(Clone)]
-#[unstable(feature = "proc_macro", issue = "38356")]
-pub struct TokenTreeIter {
-    cursor: tokenstream::Cursor,
-    stack: Vec<TokenTree>,
+    /// Returns the span encompassing this literal.
+    #[unstable(feature = "proc_macro", issue = "38356")]
+    pub fn span(&self) -> Span {
+        self.span
+    }
+
+    /// Configures the span associated for this literal.
+    #[unstable(feature = "proc_macro", issue = "38356")]
+    pub fn set_span(&mut self, span: Span) {
+        self.span = span;
+    }
 }
 
 #[unstable(feature = "proc_macro", issue = "38356")]
-impl Iterator for TokenTreeIter {
-    type Item = TokenTree;
-
-    fn next(&mut self) -> Option<TokenTree> {
-        loop {
-            let tree = self.stack.pop().or_else(|| {
-                let next = self.cursor.next_as_stream()?;
-                Some(TokenTree::from_internal(next, &mut self.stack))
-            })?;
-            if tree.span.0 == DUMMY_SP {
-                if let TokenNode::Group(Delimiter::None, stream) = tree.kind {
-                    self.cursor.insert(stream.0);
-                    continue
-                }
-            }
-            return Some(tree);
-        }
+impl fmt::Display for Literal {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        TokenStream::from(TokenTree::from(self.clone())).fmt(f)
     }
 }
 
@@ -607,31 +974,34 @@ impl TokenTree {
             tokenstream::TokenTree::Token(span, token) => (span, token),
             tokenstream::TokenTree::Delimited(span, delimed) => {
                 let delimiter = Delimiter::from_internal(delimed.delim);
-                return TokenTree {
-                    span: Span(span),
-                    kind: TokenNode::Group(delimiter, TokenStream(delimed.tts.into())),
-                };
+                let mut g = Group::new(delimiter, TokenStream(delimed.tts.into()));
+                g.set_span(Span(span));
+                return g.into()
             }
         };
 
         let op_kind = if is_joint { Spacing::Joint } else { Spacing::Alone };
         macro_rules! tt {
-            ($e:expr) => (TokenTree { span: Span(span), kind: $e })
+            ($e:expr) => ({
+                let mut x = TokenTree::from($e);
+                x.set_span(Span(span));
+                x
+            })
         }
         macro_rules! op {
-            ($a:expr) => (TokenNode::Op($a, op_kind));
+            ($a:expr) => (tt!(Op::new($a, op_kind)));
             ($a:expr, $b:expr) => ({
-                stack.push(tt!(TokenNode::Op($b, op_kind).into()));
-                TokenNode::Op($a, Spacing::Joint)
+                stack.push(tt!(Op::new($b, op_kind)));
+                tt!(Op::new($a, Spacing::Joint))
             });
             ($a:expr, $b:expr, $c:expr) => ({
-                stack.push(tt!(TokenNode::Op($c, op_kind)));
-                stack.push(tt!(TokenNode::Op($b, Spacing::Joint)));
-                TokenNode::Op($a, Spacing::Joint)
+                stack.push(tt!(Op::new($c, op_kind)));
+                stack.push(tt!(Op::new($b, Spacing::Joint)));
+                tt!(Op::new($a, Spacing::Joint))
             })
         }
 
-        let kind = match token {
+        match token {
             Eq => op!('='),
             Lt => op!('<'),
             Le => op!('<', '='),
@@ -679,80 +1049,93 @@ impl TokenTree {
             Dollar => op!('$'),
             Question => op!('?'),
 
-            Ident(ident, false) | Lifetime(ident) => TokenNode::Term(Term(ident.name)),
-            Ident(ident, true) => TokenNode::Term(Term(Symbol::intern(&format!("r#{}", ident)))),
-            Literal(..) => TokenNode::Literal(self::Literal(token)),
+            Ident(ident, false) | Lifetime(ident) => {
+                tt!(Term::new(&ident.name.as_str(), Span(span)))
+            }
+            Ident(ident, true) => {
+                tt!(Term::new(&format!("r#{}", ident), Span(span)))
+            }
+            Literal(..) => tt!(self::Literal { token, span: Span(span) }),
             DocComment(c) => {
+                let style = comments::doc_comment_style(&c.as_str());
+                let stripped = comments::strip_doc_comment_decoration(&c.as_str());
                 let stream = vec![
-                    tt!(TokenNode::Term(Term::intern("doc"))),
-                    tt!(op!('=')),
-                    tt!(TokenNode::Literal(self::Literal(Literal(Lit::Str_(c), None)))),
+                    tt!(Term::new("doc", Span(span))),
+                    tt!(Op::new('=', Spacing::Alone)),
+                    tt!(self::Literal::string(&stripped)),
                 ].into_iter().collect();
-                stack.push(tt!(TokenNode::Group(Delimiter::Bracket, stream)));
-                op!('#')
+                stack.push(tt!(Group::new(Delimiter::Bracket, stream)));
+                if style == ast::AttrStyle::Inner {
+                    stack.push(tt!(Op::new('!', Spacing::Alone)));
+                }
+                tt!(Op::new('#', Spacing::Alone))
             }
 
             Interpolated(_) => {
                 __internal::with_sess(|(sess, _)| {
                     let tts = token.interpolated_to_tokenstream(sess, span);
-                    TokenNode::Group(Delimiter::None, TokenStream(tts))
+                    tt!(Group::new(Delimiter::None, TokenStream(tts)))
                 })
             }
 
             DotEq => op!('.', '='),
             OpenDelim(..) | CloseDelim(..) => unreachable!(),
             Whitespace | Comment | Shebang(..) | Eof => unreachable!(),
-        };
-
-        TokenTree { span: Span(span), kind: kind }
+        }
     }
 
     fn to_internal(self) -> tokenstream::TokenStream {
         use syntax::parse::token::*;
         use syntax::tokenstream::{TokenTree, Delimited};
 
-        let (op, kind) = match self.kind {
-            TokenNode::Op(op, kind) => (op, kind),
-            TokenNode::Group(delimiter, tokens) => {
-                return TokenTree::Delimited(self.span.0, Delimited {
-                    delim: delimiter.to_internal(),
-                    tts: tokens.0.into(),
+        let (op, kind, span) = match self {
+            self::TokenTree::Op(tt) => (tt.op(), tt.spacing(), tt.span()),
+            self::TokenTree::Group(tt) => {
+                return TokenTree::Delimited(tt.span.0, Delimited {
+                    delim: tt.delimiter.to_internal(),
+                    tts: tt.stream.0.into(),
                 }).into();
             },
-            TokenNode::Term(symbol) => {
-                let ident = ast::Ident { name: symbol.0, ctxt: self.span.0.ctxt() };
-                let sym_str = symbol.0.as_str();
+            self::TokenTree::Term(tt) => {
+                let ident = ast::Ident { name: tt.sym, ctxt: tt.span.0.ctxt() };
+                let sym_str = tt.sym.as_str();
                 let token =
                     if sym_str.starts_with("'") { Lifetime(ident) }
                     else if sym_str.starts_with("r#") {
                         let name = Symbol::intern(&sym_str[2..]);
-                        let ident = ast::Ident { name, ctxt: self.span.0.ctxt() };
+                        let ident = ast::Ident { name, ctxt: tt.span.0.ctxt() };
                         Ident(ident, true)
                     } else { Ident(ident, false) };
-                return TokenTree::Token(self.span.0, token).into();
+                return TokenTree::Token(tt.span.0, token).into();
             }
-            TokenNode::Literal(self::Literal(Literal(Lit::Integer(ref a), b)))
+            self::TokenTree::Literal(self::Literal {
+                token: Literal(Lit::Integer(ref a), b),
+                span,
+            })
                 if a.as_str().starts_with("-") =>
             {
                 let minus = BinOp(BinOpToken::Minus);
                 let integer = Symbol::intern(&a.as_str()[1..]);
                 let integer = Literal(Lit::Integer(integer), b);
-                let a = TokenTree::Token(self.span.0, minus);
-                let b = TokenTree::Token(self.span.0, integer);
+                let a = TokenTree::Token(span.0, minus);
+                let b = TokenTree::Token(span.0, integer);
                 return vec![a, b].into_iter().collect()
             }
-            TokenNode::Literal(self::Literal(Literal(Lit::Float(ref a), b)))
+            self::TokenTree::Literal(self::Literal {
+                token: Literal(Lit::Float(ref a), b),
+                span,
+            })
                 if a.as_str().starts_with("-") =>
             {
                 let minus = BinOp(BinOpToken::Minus);
                 let float = Symbol::intern(&a.as_str()[1..]);
                 let float = Literal(Lit::Float(float), b);
-                let a = TokenTree::Token(self.span.0, minus);
-                let b = TokenTree::Token(self.span.0, float);
+                let a = TokenTree::Token(span.0, minus);
+                let b = TokenTree::Token(span.0, float);
                 return vec![a, b].into_iter().collect()
             }
-            TokenNode::Literal(token) => {
-                return TokenTree::Token(self.span.0, token.0).into()
+            self::TokenTree::Literal(tt) => {
+                return TokenTree::Token(tt.span.0, tt.token).into()
             }
         };
 
@@ -781,7 +1164,7 @@ impl TokenTree {
             _ => panic!("unsupported character {}", op),
         };
 
-        let tree = TokenTree::Token(self.span.0, token);
+        let tree = TokenTree::Token(span.0, token);
         match kind {
             Spacing::Alone => tree.into(),
             Spacing::Joint => tree.joint(),
diff --git a/src/libproc_macro/quote.rs b/src/libproc_macro/quote.rs
index 8b5add1a0f0..cc8575b88be 100644
--- a/src/libproc_macro/quote.rs
+++ b/src/libproc_macro/quote.rs
@@ -14,7 +14,7 @@
 //! This quasiquoter uses macros 2.0 hygiene to reliably access
 //! items from `proc_macro`, to build a `proc_macro::TokenStream`.
 
-use {Delimiter, Literal, Spacing, Span, Term, TokenNode, TokenStream, TokenTree};
+use {Delimiter, Literal, Spacing, Span, Term, Op, Group, TokenStream, TokenTree};
 
 use syntax::ext::base::{ExtCtxt, ProcMacro};
 use syntax::parse::token;
@@ -23,47 +23,59 @@ use syntax::tokenstream;
 pub struct Quoter;
 
 pub fn unquote<T: Into<TokenStream> + Clone>(tokens: &T) -> TokenStream {
-    T::into(tokens.clone())
+    tokens.clone().into()
 }
 
 pub trait Quote {
     fn quote(self) -> TokenStream;
 }
 
+macro_rules! tt2ts {
+    ($e:expr) => (TokenStream::from(TokenTree::from($e)))
+}
+
 macro_rules! quote_tok {
-    (,) => { TokenNode::Op(',', Spacing::Alone) };
-    (.) => { TokenNode::Op('.', Spacing::Alone) };
-    (:) => { TokenNode::Op(':', Spacing::Alone) };
+    (,) => { tt2ts!(Op::new(',', Spacing::Alone)) };
+    (.) => { tt2ts!(Op::new('.', Spacing::Alone)) };
+    (:) => { tt2ts!(Op::new(':', Spacing::Alone)) };
+    (|) => { tt2ts!(Op::new('|', Spacing::Alone)) };
     (::) => {
         [
-            TokenNode::Op(':', Spacing::Joint),
-            TokenNode::Op(':', Spacing::Alone)
-        ].iter().cloned().collect::<TokenStream>()
+            TokenTree::from(Op::new(':', Spacing::Joint)),
+            TokenTree::from(Op::new(':', Spacing::Alone)),
+        ].iter()
+            .cloned()
+            .map(|mut x| {
+                x.set_span(Span::def_site());
+                x
+            })
+            .collect::<TokenStream>()
     };
-    (!) => { TokenNode::Op('!', Spacing::Alone) };
-    (<) => { TokenNode::Op('<', Spacing::Alone) };
-    (>) => { TokenNode::Op('>', Spacing::Alone) };
-    (_) => { TokenNode::Op('_', Spacing::Alone) };
-    (0) => { TokenNode::Literal(::Literal::integer(0)) };
-    (&) => { TokenNode::Op('&', Spacing::Alone) };
-    ($i:ident) => { TokenNode::Term(Term::intern(stringify!($i))) };
+    (!) => { tt2ts!(Op::new('!', Spacing::Alone)) };
+    (<) => { tt2ts!(Op::new('<', Spacing::Alone)) };
+    (>) => { tt2ts!(Op::new('>', Spacing::Alone)) };
+    (_) => { tt2ts!(Op::new('_', Spacing::Alone)) };
+    (0) => { tt2ts!(Literal::i8_unsuffixed(0)) };
+    (&) => { tt2ts!(Op::new('&', Spacing::Alone)) };
+    ($i:ident) => { tt2ts!(Term::new(stringify!($i), Span::def_site())) };
 }
 
 macro_rules! quote_tree {
     ((unquote $($t:tt)*)) => { $($t)* };
     ((quote $($t:tt)*)) => { ($($t)*).quote() };
-    (($($t:tt)*)) => { TokenNode::Group(Delimiter::Parenthesis, quote!($($t)*)) };
-    ([$($t:tt)*]) => { TokenNode::Group(Delimiter::Bracket, quote!($($t)*)) };
-    ({$($t:tt)*}) => { TokenNode::Group(Delimiter::Brace, quote!($($t)*)) };
+    (($($t:tt)*)) => { tt2ts!(Group::new(Delimiter::Parenthesis, quote!($($t)*))) };
+    ([$($t:tt)*]) => { tt2ts!(Group::new(Delimiter::Bracket, quote!($($t)*))) };
+    ({$($t:tt)*}) => { tt2ts!(Group::new(Delimiter::Brace, quote!($($t)*))) };
     ($t:tt) => { quote_tok!($t) };
 }
 
 macro_rules! quote {
     () => { TokenStream::empty() };
     ($($t:tt)*) => {
-        [
-            $(TokenStream::from(quote_tree!($t)),)*
-        ].iter().cloned().collect::<TokenStream>()
+        [$(quote_tree!($t),)*].iter()
+            .cloned()
+            .flat_map(|x| x.into_iter())
+            .collect::<TokenStream>()
     };
 }
 
@@ -97,72 +109,81 @@ impl Quote for TokenStream {
         let tokens = self.into_iter().filter_map(|tree| {
             if after_dollar {
                 after_dollar = false;
-                match tree.kind {
-                    TokenNode::Term(_) => {
+                match tree {
+                    TokenTree::Term(_) => {
+                        let tree = TokenStream::from(tree);
                         return Some(quote!(::__internal::unquote(&(unquote tree)),));
                     }
-                    TokenNode::Op('$', _) => {}
+                    TokenTree::Op(ref tt) if tt.op() == '$' => {}
                     _ => panic!("`$` must be followed by an ident or `$` in `quote!`"),
                 }
-            } else if let TokenNode::Op('$', _) = tree.kind {
-                after_dollar = true;
-                return None;
+            } else if let TokenTree::Op(tt) = tree {
+                if tt.op() == '$' {
+                    after_dollar = true;
+                    return None;
+                }
             }
 
             Some(quote!(::TokenStream::from((quote tree)),))
-        }).collect::<TokenStream>();
+        }).flat_map(|t| t.into_iter()).collect::<TokenStream>();
 
         if after_dollar {
             panic!("unexpected trailing `$` in `quote!`");
         }
 
-        quote!([(unquote tokens)].iter().cloned().collect::<::TokenStream>())
+        quote!(
+            [(unquote tokens)].iter()
+                .cloned()
+                .flat_map(|x| x.into_iter())
+                .collect::<::TokenStream>()
+        )
     }
 }
 
 impl Quote for TokenTree {
     fn quote(self) -> TokenStream {
-        quote!(::TokenTree { span: (quote self.span), kind: (quote self.kind) })
+        match self {
+            TokenTree::Op(tt) => quote!(::TokenTree::Op( (quote tt) )),
+            TokenTree::Group(tt) => quote!(::TokenTree::Group( (quote tt) )),
+            TokenTree::Term(tt) => quote!(::TokenTree::Term( (quote tt) )),
+            TokenTree::Literal(tt) => quote!(::TokenTree::Literal( (quote tt) )),
+        }
     }
 }
 
-impl Quote for TokenNode {
+impl Quote for char {
     fn quote(self) -> TokenStream {
-        macro_rules! gen_match {
-            ($($i:ident($($arg:ident),+)),*) => {
-                match self {
-                    $(TokenNode::$i($($arg),+) => quote! {
-                        ::TokenNode::$i($((quote $arg)),+)
-                    },)*
-                }
-            }
-        }
+        TokenTree::from(Literal::character(self)).into()
+    }
+}
 
-        gen_match! { Op(op, kind), Group(delim, tokens), Term(term), Literal(lit) }
+impl<'a> Quote for &'a str {
+    fn quote(self) -> TokenStream {
+        TokenTree::from(Literal::string(self)).into()
     }
 }
 
-impl Quote for char {
+impl Quote for usize {
     fn quote(self) -> TokenStream {
-        TokenNode::Literal(Literal::character(self)).into()
+        TokenTree::from(Literal::usize_unsuffixed(self)).into()
     }
 }
 
-impl<'a> Quote for &'a str {
+impl Quote for Group {
     fn quote(self) -> TokenStream {
-        TokenNode::Literal(Literal::string(self)).into()
+        quote!(::Group::new((quote self.delimiter()), (quote self.stream())))
     }
 }
 
-impl Quote for usize {
+impl Quote for Op {
     fn quote(self) -> TokenStream {
-        TokenNode::Literal(Literal::integer(self as i128)).into()
+        quote!(::Op::new((quote self.op()), (quote self.spacing())))
     }
 }
 
 impl Quote for Term {
     fn quote(self) -> TokenStream {
-        quote!(::Term::intern((quote self.as_str())))
+        quote!(::Term::new((quote self.as_str()), (quote self.span())))
     }
 }
 
@@ -182,14 +203,20 @@ macro_rules! literals {
         impl LiteralKind {
             pub fn with_contents_and_suffix(self, contents: Term, suffix: Option<Term>)
                                             -> Literal {
-                let contents = contents.0;
-                let suffix = suffix.map(|t| t.0);
+                let sym = contents.sym;
+                let suffix = suffix.map(|t| t.sym);
                 match self {
                     $(LiteralKind::$i => {
-                        Literal(token::Literal(token::Lit::$i(contents), suffix))
+                        Literal {
+                            token: token::Literal(token::Lit::$i(sym), suffix),
+                            span: contents.span,
+                        }
                     })*
                     $(LiteralKind::$raw(n) => {
-                        Literal(token::Literal(token::Lit::$raw(contents, n), suffix))
+                        Literal {
+                            token: token::Literal(token::Lit::$raw(sym, n), suffix),
+                            span: contents.span,
+                        }
                     })*
                 }
             }
@@ -197,16 +224,17 @@ macro_rules! literals {
 
         impl Literal {
             fn kind_contents_and_suffix(self) -> (LiteralKind, Term, Option<Term>) {
-                let (lit, suffix) = match self.0 {
+                let (lit, suffix) = match self.token {
                     token::Literal(lit, suffix) => (lit, suffix),
-                    _ => panic!("unsupported literal {:?}", self.0),
+                    _ => panic!("unsupported literal {:?}", self.token),
                 };
 
                 let (kind, contents) = match lit {
                     $(token::Lit::$i(contents) => (LiteralKind::$i, contents),)*
                     $(token::Lit::$raw(contents, n) => (LiteralKind::$raw(n), contents),)*
                 };
-                (kind, Term(contents), suffix.map(Term))
+                let suffix = suffix.map(|sym| Term::new(&sym.as_str(), self.span()));
+                (kind, Term::new(&contents.as_str(), self.span()), suffix)
             }
         }
 
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 5f9f37094f5..b767ede5faa 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -2724,6 +2724,7 @@ impl<'a> LoweringContext<'a> {
                         hir::ForeignItemStatic(this.lower_ty(t, ImplTraitContext::Disallowed), m)
                     }
                     ForeignItemKind::Ty => hir::ForeignItemType,
+                    ForeignItemKind::Macro(_) => panic!("shouldn't exist here"),
                 },
                 vis: this.lower_visibility(&i.vis, None),
                 span: i.span,
diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs
index 3619a7fb0c6..20f46cb348d 100644
--- a/src/librustc/hir/map/def_collector.rs
+++ b/src/librustc/hir/map/def_collector.rs
@@ -181,6 +181,10 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
     }
 
     fn visit_foreign_item(&mut self, foreign_item: &'a ForeignItem) {
+        if let ForeignItemKind::Macro(_) = foreign_item.node {
+            return self.visit_macro_invoc(foreign_item.id, false);
+        }
+
         let def = self.create_def(foreign_item.id,
                                   DefPathData::ValueNs(foreign_item.ident.name.as_str()),
                                   REGULAR_SPACE,
diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs
index 340dd32a237..da1a2592f14 100644
--- a/src/librustc/ich/impls_ty.rs
+++ b/src/librustc/ich/impls_ty.rs
@@ -1392,6 +1392,12 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for traits::Goal<'tcx> {
     }
 }
 
+impl_stable_hash_for!(
+    impl<'tcx> for struct traits::ProgramClause<'tcx> {
+        goal, hypotheses
+    }
+);
+
 impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for traits::Clause<'tcx> {
     fn hash_stable<W: StableHasherResult>(&self,
                                           hcx: &mut StableHashingContext<'a>,
@@ -1400,11 +1406,7 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for traits::Clause<'tcx> {
 
         mem::discriminant(self).hash_stable(hcx, hasher);
         match self {
-            Implies(hypotheses, goal) => {
-                hypotheses.hash_stable(hcx, hasher);
-                goal.hash_stable(hcx, hasher);
-            }
-            DomainGoal(domain_goal) => domain_goal.hash_stable(hcx, hasher),
+            Implies(clause) => clause.hash_stable(hcx, hasher),
             ForAll(clause) => clause.hash_stable(hcx, hasher),
         }
     }
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index 2ce1b75e315..b30fb2ce016 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -272,6 +272,8 @@ pub enum DomainGoal<'tcx> {
     TypeOutlives(ty::TypeOutlivesPredicate<'tcx>),
 }
 
+pub type PolyDomainGoal<'tcx> = ty::Binder<DomainGoal<'tcx>>;
+
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
 pub enum QuantifierKind {
     Universal,
@@ -294,9 +296,15 @@ impl<'tcx> From<DomainGoal<'tcx>> for Goal<'tcx> {
     }
 }
 
-impl<'tcx> From<DomainGoal<'tcx>> for Clause<'tcx> {
-    fn from(domain_goal: DomainGoal<'tcx>) -> Self {
-        Clause::DomainGoal(domain_goal)
+impl<'tcx> From<PolyDomainGoal<'tcx>> for Goal<'tcx> {
+    fn from(domain_goal: PolyDomainGoal<'tcx>) -> Self {
+        match domain_goal.no_late_bound_regions() {
+            Some(p) => p.into(),
+            None => Goal::Quantified(
+                QuantifierKind::Universal,
+                Box::new(domain_goal.map_bound(|p| p.into()))
+            ),
+        }
     }
 }
 
@@ -304,10 +312,23 @@ impl<'tcx> From<DomainGoal<'tcx>> for Clause<'tcx> {
 /// Harrop Formulas".
 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
 pub enum Clause<'tcx> {
-    // FIXME: again, use interned refs instead of `Box`
-    Implies(Vec<Goal<'tcx>>, DomainGoal<'tcx>),
-    DomainGoal(DomainGoal<'tcx>),
-    ForAll(Box<ty::Binder<Clause<'tcx>>>),
+    Implies(ProgramClause<'tcx>),
+    ForAll(ty::Binder<ProgramClause<'tcx>>),
+}
+
+/// A "program clause" has the form `D :- G1, ..., Gn`. It is saying
+/// that the domain goal `D` is true if `G1...Gn` are provable. This
+/// is equivalent to the implication `G1..Gn => D`; we usually write
+/// it with the reverse implication operator `:-` to emphasize the way
+/// that programs are actually solved (via backchaining, which starts
+/// with the goal to solve and proceeds from there).
+#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+pub struct ProgramClause<'tcx> {
+    /// This goal will be considered true...
+    pub goal: DomainGoal<'tcx>,
+
+    /// ...if we can prove these hypotheses (there may be no hypotheses at all):
+    pub hypotheses: Vec<Goal<'tcx>>,
 }
 
 pub type Selection<'tcx> = Vtable<'tcx, PredicateObligation<'tcx>>;
diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs
index d6e6f0e98ad..865a9a34aaa 100644
--- a/src/librustc/traits/structural_impls.rs
+++ b/src/librustc/traits/structural_impls.rs
@@ -493,25 +493,29 @@ impl<'tcx> fmt::Display for traits::Goal<'tcx> {
     }
 }
 
+impl<'tcx> fmt::Display for traits::ProgramClause<'tcx> {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        let traits::ProgramClause { goal, hypotheses } = self;
+        write!(fmt, "{}", goal)?;
+        if !hypotheses.is_empty() {
+            write!(fmt, " :- ")?;
+            for (index, condition) in hypotheses.iter().enumerate() {
+                if index > 0 {
+                    write!(fmt, ", ")?;
+                }
+                write!(fmt, "{}", condition)?;
+            }
+        }
+        write!(fmt, ".")
+    }
+}
+
 impl<'tcx> fmt::Display for traits::Clause<'tcx> {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         use traits::Clause::*;
 
         match self {
-            Implies(hypotheses, goal) => {
-                write!(fmt, "{}", goal)?;
-                if !hypotheses.is_empty() {
-                    write!(fmt, " :- ")?;
-                    for (index, condition) in hypotheses.iter().enumerate() {
-                        if index > 0 {
-                            write!(fmt, ", ")?;
-                        }
-                        write!(fmt, "{}", condition)?;
-                    }
-                }
-                write!(fmt, ".")
-            }
-            DomainGoal(domain_goal) => write!(fmt, "{}.", domain_goal),
+            Implies(clause) => write!(fmt, "{}", clause),
             ForAll(clause) => {
                 // FIXME: appropriate binder names
                 write!(fmt, "forall<> {{ {} }}", clause.skip_binder())
@@ -553,10 +557,16 @@ EnumTypeFoldableImpl! {
     }
 }
 
+BraceStructTypeFoldableImpl! {
+    impl<'tcx> TypeFoldable<'tcx> for traits::ProgramClause<'tcx> {
+        goal,
+        hypotheses
+    }
+}
+
 EnumTypeFoldableImpl! {
     impl<'tcx> TypeFoldable<'tcx> for traits::Clause<'tcx> {
-        (traits::Clause::Implies)(hypotheses, goal),
-        (traits::Clause::DomainGoal)(domain_goal),
+        (traits::Clause::Implies)(clause),
         (traits::Clause::ForAll)(clause),
     }
 }
diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs
index 37274d1fc44..b34decc1c69 100644
--- a/src/librustc_passes/ast_validation.rs
+++ b/src/librustc_passes/ast_validation.rs
@@ -381,7 +381,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                         .span_label(span, "pattern not allowed in foreign function").emit();
                 });
             }
-            ForeignItemKind::Static(..) | ForeignItemKind::Ty => {}
+            ForeignItemKind::Static(..) | ForeignItemKind::Ty | ForeignItemKind::Macro(..) => {}
         }
 
         visit::walk_foreign_item(self, fi)
@@ -460,6 +460,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
         self.check_late_bound_lifetime_defs(&t.bound_generic_params);
         visit::walk_poly_trait_ref(self, t, m);
     }
+
+    fn visit_mac(&mut self, mac: &Spanned<Mac_>) {
+        // when a new macro kind is added but the author forgets to set it up for expansion
+        // because that's the only part that won't cause a compiler error
+        self.session.diagnostic()
+            .span_bug(mac.span, "macro invocation missed in expansion; did you forget to override \
+                                 the relevant `fold_*()` method in `PlaceholderExpander`?");
+    }
 }
 
 // Bans nested `impl Trait`, e.g. `impl Into<impl Debug>`.
@@ -522,6 +530,10 @@ impl<'a> Visitor<'a> for NestedImplTraitVisitor<'a> {
             }
         }
     }
+
+    fn visit_mac(&mut self, _mac: &Spanned<Mac_>) {
+        // covered in AstValidator
+    }
 }
 
 // Bans `impl Trait` in path projections like `<impl Iterator>::Item` or `Foo::Bar<impl Trait>`.
@@ -583,6 +595,10 @@ impl<'a> Visitor<'a> for ImplTraitProjectionVisitor<'a> {
             _ => visit::walk_ty(self, t),
         }
     }
+
+    fn visit_mac(&mut self, _mac: &Spanned<Mac_>) {
+        // covered in AstValidator
+    }
 }
 
 pub fn check_crate(session: &Session, krate: &Crate) {
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index c192f349c20..397590012fd 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -456,6 +456,7 @@ impl<'a> Resolver<'a> {
             ForeignItemKind::Ty => {
                 (Def::TyForeign(self.definitions.local_def_id(item.id)), TypeNS)
             }
+            ForeignItemKind::Macro(_) => unreachable!(),
         };
         let parent = self.current_module;
         let vis = self.resolve_visibility(&item.vis);
@@ -816,6 +817,11 @@ impl<'a, 'b> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b> {
     }
 
     fn visit_foreign_item(&mut self, foreign_item: &'a ForeignItem) {
+        if let ForeignItemKind::Macro(_) = foreign_item.node {
+            self.visit_invoc(foreign_item.id);
+            return;
+        }
+
         self.resolver.build_reduced_graph_for_foreign_item(foreign_item, self.expansion);
         visit::walk_foreign_item(self, foreign_item);
     }
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 3a97d276744..64d57ea34c2 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -863,6 +863,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
             }
             ForeignItemKind::Static(..) => NoTypeParameters,
             ForeignItemKind::Ty => NoTypeParameters,
+            ForeignItemKind::Macro(..) => NoTypeParameters,
         };
         self.with_type_parameter_rib(type_parameters, |this| {
             visit::walk_foreign_item(this, foreign_item);
diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs
index 3d4d8571c6e..5e51797d720 100644
--- a/src/librustc_save_analysis/dump_visitor.rs
+++ b/src/librustc_save_analysis/dump_visitor.rs
@@ -1812,6 +1812,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc
                     self.dumper.dump_def(&access, var_data);
                 }
             }
+            ast::ForeignItemKind::Macro(..) => {}
         }
     }
 }
diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs
index 95374775651..fb4cb2afe5a 100644
--- a/src/librustc_save_analysis/lib.rs
+++ b/src/librustc_save_analysis/lib.rs
@@ -182,6 +182,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
             }
             // FIXME(plietar): needs a new DefKind in rls-data
             ast::ForeignItemKind::Ty => None,
+            ast::ForeignItemKind::Macro(..) => None,
         }
     }
 
diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs
index 0c890ce19d0..fd4d3e76386 100644
--- a/src/librustc_save_analysis/sig.rs
+++ b/src/librustc_save_analysis/sig.rs
@@ -822,6 +822,7 @@ impl Sig for ast::ForeignItem {
                     refs: vec![],
                 })
             }
+            ast::ForeignItemKind::Macro(..) => Err("macro"),
         }
     }
 }
diff --git a/src/librustc_traits/lowering.rs b/src/librustc_traits/lowering.rs
index 1092e826a35..153b2e73033 100644
--- a/src/librustc_traits/lowering.rs
+++ b/src/librustc_traits/lowering.rs
@@ -13,7 +13,7 @@ use rustc::hir::def_id::DefId;
 use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc::ty::{self, TyCtxt};
 use rustc::ty::subst::Substs;
-use rustc::traits::{QuantifierKind, Goal, DomainGoal, Clause, WhereClauseAtom};
+use rustc::traits::{WhereClauseAtom, PolyDomainGoal, DomainGoal, ProgramClause, Clause};
 use syntax::ast;
 use rustc_data_structures::sync::Lrc;
 
@@ -61,28 +61,19 @@ impl<'tcx> Lower<DomainGoal<'tcx>> for ty::TypeOutlivesPredicate<'tcx> {
 /// `ty::Binder` is used for wrapping a rustc construction possibly containing generic
 /// lifetimes, e.g. `for<'a> T: Fn(&'a i32)`. Instead of representing higher-ranked things
 /// in that leaf-form (i.e. `Holds(Implemented(Binder<TraitPredicate>))` in the previous
-/// example), we model them with quantified goals, e.g. as for the previous example:
+/// example), we model them with quantified domain goals, e.g. as for the previous example:
 /// `forall<'a> { T: Fn(&'a i32) }` which corresponds to something like
 /// `Binder<Holds(Implemented(TraitPredicate))>`.
-///
-/// Also, if `self` does not contain generic lifetimes, we can safely drop the binder and we
-/// can directly lower to a leaf goal instead of a quantified goal.
-impl<'tcx, T> Lower<Goal<'tcx>> for ty::Binder<T>
-    where T: Lower<DomainGoal<'tcx>> + ty::fold::TypeFoldable<'tcx> + Copy
+impl<'tcx, T> Lower<PolyDomainGoal<'tcx>> for ty::Binder<T>
+    where T: Lower<DomainGoal<'tcx>> + ty::fold::TypeFoldable<'tcx>
 {
-    fn lower(&self) -> Goal<'tcx> {
-        match self.no_late_bound_regions() {
-            Some(p) => p.lower().into(),
-            None => Goal::Quantified(
-                QuantifierKind::Universal,
-                Box::new(self.map_bound(|p| p.lower().into()))
-            ),
-        }
+    fn lower(&self) -> PolyDomainGoal<'tcx> {
+        self.map_bound_ref(|p| p.lower())
     }
 }
 
-impl<'tcx> Lower<Goal<'tcx>> for ty::Predicate<'tcx> {
-    fn lower(&self) -> Goal<'tcx> {
+impl<'tcx> Lower<PolyDomainGoal<'tcx>> for ty::Predicate<'tcx> {
+    fn lower(&self) -> PolyDomainGoal<'tcx> {
         use rustc::ty::Predicate::*;
 
         match self {
@@ -90,7 +81,7 @@ impl<'tcx> Lower<Goal<'tcx>> for ty::Predicate<'tcx> {
             RegionOutlives(predicate) => predicate.lower(),
             TypeOutlives(predicate) => predicate.lower(),
             Projection(predicate) => predicate.lower(),
-            WellFormed(ty) => DomainGoal::WellFormedTy(*ty).into(),
+            WellFormed(ty) => ty::Binder::dummy(DomainGoal::WellFormedTy(*ty)),
             ObjectSafe(..) |
             ClosureKind(..) |
             Subtype(..) |
@@ -134,13 +125,16 @@ fn program_clauses_for_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefI
         }
     };
     // `FromEnv(Self: Trait<P1..Pn>)`
-    let from_env = Goal::DomainGoal(DomainGoal::FromEnv(trait_pred.lower()));
+    let from_env = DomainGoal::FromEnv(trait_pred.lower()).into();
     // `Implemented(Self: Trait<P1..Pn>)`
     let impl_trait = DomainGoal::Holds(WhereClauseAtom::Implemented(trait_pred));
 
     // `Implemented(Self: Trait<P1..Pn>) :- FromEnv(Self: Trait<P1..Pn>)`
-    let clause = Clause::Implies(vec![from_env], impl_trait);
-    Lrc::new(vec![clause])
+    let clause = ProgramClause {
+        goal: impl_trait,
+        hypotheses: vec![from_env],
+    };
+    Lrc::new(vec![Clause::ForAll(ty::Binder::dummy(clause))])
 }
 
 fn program_clauses_for_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
@@ -167,8 +161,11 @@ fn program_clauses_for_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId
     let where_clauses = tcx.predicates_of(def_id).predicates.lower();
 
      // `Implemented(A0: Trait<A1..An>) :- WC`
-    let clause = Clause::Implies(where_clauses, trait_pred);
-    Lrc::new(vec![clause])
+    let clause = ProgramClause {
+        goal: trait_pred,
+        hypotheses: where_clauses.into_iter().map(|wc| wc.into()).collect()
+    };
+    Lrc::new(vec![Clause::ForAll(ty::Binder::dummy(clause))])
 }
 
 pub fn dump_program_clauses<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
@@ -184,14 +181,19 @@ struct ClauseDumper<'a, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
 }
 
-impl <'a, 'tcx> ClauseDumper<'a, 'tcx > {
+impl<'a, 'tcx> ClauseDumper<'a, 'tcx > {
     fn process_attrs(&mut self, node_id: ast::NodeId, attrs: &[ast::Attribute]) {
         let def_id = self.tcx.hir.local_def_id(node_id);
         for attr in attrs {
             if attr.check_name("rustc_dump_program_clauses") {
                 let clauses = self.tcx.program_clauses_for(def_id);
                 for clause in &*clauses {
-                    self.tcx.sess.struct_span_err(attr.span, &format!("{}", clause)).emit();
+                    // Skip the top-level binder for a less verbose output
+                    let program_clause = match clause {
+                        Clause::Implies(program_clause) => program_clause,
+                        Clause::ForAll(program_clause) => program_clause.skip_binder(),
+                    };
+                    self.tcx.sess.struct_span_err(attr.span, &format!("{}", program_clause)).emit();
                 }
             }
         }
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index 3f1fec4c317..6f6abfdd31e 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -378,7 +378,7 @@ extern crate compiler_builtins;
 // During testing, this crate is not actually the "real" std library, but rather
 // it links to the real std library, which was compiled from this same source
 // code. So any lang items std defines are conditionally excluded (or else they
-// wolud generate duplicate lang item errors), and any globals it defines are
+// would generate duplicate lang item errors), and any globals it defines are
 // _not_ the globals used by "real" std. So this import, defined only during
 // testing gives test-std access to real-std lang items and globals. See #2912
 #[cfg(test)] extern crate std as realstd;
diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs
index 79857104b9b..28c178307a5 100644
--- a/src/libstd/panic.rs
+++ b/src/libstd/panic.rs
@@ -188,7 +188,7 @@ pub struct AssertUnwindSafe<T>(
 // * By default everything is unwind safe
 // * pointers T contains mutability of some form are not unwind safe
 // * Unique, an owning pointer, lifts an implementation
-// * Types like Mutex/RwLock which are explicilty poisoned are unwind safe
+// * Types like Mutex/RwLock which are explicitly poisoned are unwind safe
 // * Our custom AssertUnwindSafe wrapper is indeed unwind safe
 
 #[stable(feature = "catch_unwind", since = "1.9.0")]
diff --git a/src/libstd/sys/windows/pipe.rs b/src/libstd/sys/windows/pipe.rs
index f3b1185c6ea..df1dd7401af 100644
--- a/src/libstd/sys/windows/pipe.rs
+++ b/src/libstd/sys/windows/pipe.rs
@@ -236,7 +236,7 @@ enum State {
 impl<'a> AsyncPipe<'a> {
     fn new(pipe: Handle, dst: &'a mut Vec<u8>) -> io::Result<AsyncPipe<'a>> {
         // Create an event which we'll use to coordinate our overlapped
-        // opreations, this event will be used in WaitForMultipleObjects
+        // operations, this event will be used in WaitForMultipleObjects
         // and passed as part of the OVERLAPPED handle.
         //
         // Note that we do a somewhat clever thing here by flagging the
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 31bb1c88b87..9d0c85a34f9 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -2192,6 +2192,8 @@ pub enum ForeignItemKind {
     Static(P<Ty>, bool),
     /// A foreign type
     Ty,
+    /// A macro invocation
+    Macro(Mac),
 }
 
 impl ForeignItemKind {
@@ -2200,6 +2202,7 @@ impl ForeignItemKind {
             ForeignItemKind::Fn(..) => "foreign function",
             ForeignItemKind::Static(..) => "foreign static item",
             ForeignItemKind::Ty => "foreign type",
+            ForeignItemKind::Macro(..) => "macro in foreign module",
         }
     }
 }
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index d3157af984e..5a735be55c0 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -38,6 +38,7 @@ pub enum Annotatable {
     Item(P<ast::Item>),
     TraitItem(P<ast::TraitItem>),
     ImplItem(P<ast::ImplItem>),
+    ForeignItem(P<ast::ForeignItem>),
     Stmt(P<ast::Stmt>),
     Expr(P<ast::Expr>),
 }
@@ -48,6 +49,7 @@ impl HasAttrs for Annotatable {
             Annotatable::Item(ref item) => &item.attrs,
             Annotatable::TraitItem(ref trait_item) => &trait_item.attrs,
             Annotatable::ImplItem(ref impl_item) => &impl_item.attrs,
+            Annotatable::ForeignItem(ref foreign_item) => &foreign_item.attrs,
             Annotatable::Stmt(ref stmt) => stmt.attrs(),
             Annotatable::Expr(ref expr) => &expr.attrs,
         }
@@ -58,6 +60,8 @@ impl HasAttrs for Annotatable {
             Annotatable::Item(item) => Annotatable::Item(item.map_attrs(f)),
             Annotatable::TraitItem(trait_item) => Annotatable::TraitItem(trait_item.map_attrs(f)),
             Annotatable::ImplItem(impl_item) => Annotatable::ImplItem(impl_item.map_attrs(f)),
+            Annotatable::ForeignItem(foreign_item) =>
+                Annotatable::ForeignItem(foreign_item.map_attrs(f)),
             Annotatable::Stmt(stmt) => Annotatable::Stmt(stmt.map_attrs(f)),
             Annotatable::Expr(expr) => Annotatable::Expr(expr.map_attrs(f)),
         }
@@ -70,6 +74,7 @@ impl Annotatable {
             Annotatable::Item(ref item) => item.span,
             Annotatable::TraitItem(ref trait_item) => trait_item.span,
             Annotatable::ImplItem(ref impl_item) => impl_item.span,
+            Annotatable::ForeignItem(ref foreign_item) => foreign_item.span,
             Annotatable::Stmt(ref stmt) => stmt.span,
             Annotatable::Expr(ref expr) => expr.span,
         }
@@ -106,6 +111,13 @@ impl Annotatable {
         }
     }
 
+    pub fn expect_foreign_item(self) -> ast::ForeignItem {
+        match self {
+            Annotatable::ForeignItem(i) => i.into_inner(),
+            _ => panic!("expected foreign item")
+        }
+    }
+
     pub fn derive_allowed(&self) -> bool {
         match *self {
             Annotatable::Item(ref item) => match item.node {
@@ -317,6 +329,9 @@ pub trait MacResult {
         None
     }
 
+    /// Create zero or more items in an `extern {}` block
+    fn make_foreign_items(self: Box<Self>) -> Option<SmallVector<ast::ForeignItem>> { None }
+
     /// Create a pattern.
     fn make_pat(self: Box<Self>) -> Option<P<ast::Pat>> {
         None
@@ -365,6 +380,7 @@ make_MacEager! {
     items: SmallVector<P<ast::Item>>,
     impl_items: SmallVector<ast::ImplItem>,
     trait_items: SmallVector<ast::TraitItem>,
+    foreign_items: SmallVector<ast::ForeignItem>,
     stmts: SmallVector<ast::Stmt>,
     ty: P<ast::Ty>,
 }
@@ -386,6 +402,10 @@ impl MacResult for MacEager {
         self.trait_items
     }
 
+    fn make_foreign_items(self: Box<Self>) -> Option<SmallVector<ast::ForeignItem>> {
+        self.foreign_items
+    }
+
     fn make_stmts(self: Box<Self>) -> Option<SmallVector<ast::Stmt>> {
         match self.stmts.as_ref().map_or(0, |s| s.len()) {
             0 => make_stmts_default!(self),
@@ -502,6 +522,14 @@ impl MacResult for DummyResult {
         }
     }
 
+    fn make_foreign_items(self: Box<Self>) -> Option<SmallVector<ast::ForeignItem>> {
+        if self.expr_only {
+            None
+        } else {
+            Some(SmallVector::new())
+        }
+    }
+
     fn make_stmts(self: Box<DummyResult>) -> Option<SmallVector<ast::Stmt>> {
         Some(SmallVector::one(ast::Stmt {
             id: ast::DUMMY_NODE_ID,
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 864969c4075..105de13b976 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -133,6 +133,8 @@ expansions! {
         "trait item", .make_trait_items, lift .fold_trait_item, lift .visit_trait_item;
     ImplItems: SmallVector<ast::ImplItem> [SmallVector, ast::ImplItem],
         "impl item",  .make_impl_items,  lift .fold_impl_item,  lift .visit_impl_item;
+    ForeignItems: SmallVector<ast::ForeignItem> [SmallVector, ast::ForeignItem],
+        "foreign item", .make_foreign_items, lift .fold_foreign_item, lift .visit_foreign_item;
 }
 
 impl ExpansionKind {
@@ -149,6 +151,8 @@ impl ExpansionKind {
                 Expansion::ImplItems(items.map(Annotatable::expect_impl_item).collect()),
             ExpansionKind::TraitItems =>
                 Expansion::TraitItems(items.map(Annotatable::expect_trait_item).collect()),
+            ExpansionKind::ForeignItems =>
+                Expansion::ForeignItems(items.map(Annotatable::expect_foreign_item).collect()),
             _ => unreachable!(),
         }
     }
@@ -435,6 +439,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             Annotatable::ImplItem(item) => {
                 Annotatable::ImplItem(item.map(|item| cfg.fold_impl_item(item).pop().unwrap()))
             }
+            Annotatable::ForeignItem(item) => {
+                Annotatable::ForeignItem(
+                    item.map(|item| cfg.fold_foreign_item(item).pop().unwrap())
+                )
+            }
             Annotatable::Stmt(stmt) => {
                 Annotatable::Stmt(stmt.map(|stmt| cfg.fold_stmt(stmt).pop().unwrap()))
             }
@@ -509,6 +518,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                     Annotatable::Item(item) => token::NtItem(item),
                     Annotatable::TraitItem(item) => token::NtTraitItem(item.into_inner()),
                     Annotatable::ImplItem(item) => token::NtImplItem(item.into_inner()),
+                    Annotatable::ForeignItem(item) => token::NtForeignItem(item.into_inner()),
                     Annotatable::Stmt(stmt) => token::NtStmt(stmt.into_inner()),
                     Annotatable::Expr(expr) => token::NtExpr(expr),
                 })).into();
@@ -793,6 +803,15 @@ impl<'a> Parser<'a> {
                 }
                 Expansion::ImplItems(items)
             }
+            ExpansionKind::ForeignItems => {
+                let mut items = SmallVector::new();
+                while self.token != token::Eof {
+                    if let Some(item) = self.parse_foreign_item()? {
+                        items.push(item);
+                    }
+                }
+                Expansion::ForeignItems(items)
+            }
             ExpansionKind::Stmts => {
                 let mut stmts = SmallVector::new();
                 while self.token != token::Eof &&
@@ -1166,6 +1185,44 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
         noop_fold_foreign_mod(self.cfg.configure_foreign_mod(foreign_mod), self)
     }
 
+    fn fold_foreign_item(&mut self,
+                         foreign_item: ast::ForeignItem) -> SmallVector<ast::ForeignItem> {
+        let (attr, traits, foreign_item) = self.classify_item(foreign_item);
+
+        let explain = if self.cx.ecfg.proc_macro_enabled() {
+            feature_gate::EXPLAIN_PROC_MACROS_IN_EXTERN
+        } else {
+            feature_gate::EXPLAIN_MACROS_IN_EXTERN
+        };
+
+        if attr.is_some() || !traits.is_empty()  {
+            if !self.cx.ecfg.macros_in_extern_enabled() {
+                if let Some(ref attr) = attr {
+                    emit_feature_err(&self.cx.parse_sess, "macros_in_extern", attr.span,
+                                     GateIssue::Language, explain);
+                }
+            }
+
+            let item = Annotatable::ForeignItem(P(foreign_item));
+            return self.collect_attr(attr, traits, item, ExpansionKind::ForeignItems)
+                .make_foreign_items();
+        }
+
+        if let ast::ForeignItemKind::Macro(mac) = foreign_item.node {
+            self.check_attributes(&foreign_item.attrs);
+
+            if !self.cx.ecfg.macros_in_extern_enabled() {
+                emit_feature_err(&self.cx.parse_sess, "macros_in_extern", foreign_item.span,
+                                 GateIssue::Language, explain);
+            }
+
+            return self.collect_bang(mac, foreign_item.span, ExpansionKind::ForeignItems)
+                .make_foreign_items();
+        }
+
+        noop_fold_foreign_item(foreign_item, self)
+    }
+
     fn fold_item_kind(&mut self, item: ast::ItemKind) -> ast::ItemKind {
         match item {
             ast::ItemKind::MacroDef(..) => item,
@@ -1311,6 +1368,7 @@ impl<'feat> ExpansionConfig<'feat> {
         fn enable_allow_internal_unstable = allow_internal_unstable,
         fn enable_custom_derive = custom_derive,
         fn proc_macro_enabled = proc_macro,
+        fn macros_in_extern_enabled = macros_in_extern,
     }
 }
 
diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs
index 9c2c22476e9..9f60882ca29 100644
--- a/src/libsyntax/ext/placeholders.rs
+++ b/src/libsyntax/ext/placeholders.rs
@@ -60,6 +60,10 @@ pub fn placeholder(kind: ExpansionKind, id: ast::NodeId) -> Expansion {
             defaultness: ast::Defaultness::Final,
             tokens: None,
         })),
+        ExpansionKind::ForeignItems => Expansion::ForeignItems(SmallVector::one(ast::ForeignItem {
+            id, span, ident, vis, attrs,
+            node: ast::ForeignItemKind::Macro(mac_placeholder()),
+        })),
         ExpansionKind::Pat => Expansion::Pat(P(ast::Pat {
             id, span, node: ast::PatKind::Mac(mac_placeholder()),
         })),
@@ -132,6 +136,13 @@ impl<'a, 'b> Folder for PlaceholderExpander<'a, 'b> {
         }
     }
 
+    fn fold_foreign_item(&mut self, item: ast::ForeignItem) -> SmallVector<ast::ForeignItem> {
+        match item.node {
+            ast::ForeignItemKind::Macro(_) => self.remove(item.id).make_foreign_items(),
+            _ => noop_fold_foreign_item(item, self),
+        }
+    }
+
     fn fold_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> {
         match expr.node {
             ast::ExprKind::Mac(_) => self.remove(expr.id).make_expr(),
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 0f039895dee..9d1f4ccf8a3 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -443,6 +443,9 @@ declare_features! (
 
     // Allows keywords to be escaped for use as identifiers
     (active, raw_identifiers, "1.26.0", Some(48589), None),
+
+    // Allows macro invocations in `extern {}` blocks
+    (active, macros_in_extern, "1.27.0", Some(49476), None),
 );
 
 declare_features! (
@@ -1291,6 +1294,13 @@ pub const EXPLAIN_UNSIZED_TUPLE_COERCION: &'static str =
 pub const EXPLAIN_MACRO_AT_MOST_ONCE_REP: &'static str =
     "Using the `?` macro Kleene operator for \"at most one\" repetition is unstable";
 
+pub const EXPLAIN_MACROS_IN_EXTERN: &'static str =
+    "Macro invocations in `extern {}` blocks are experimental.";
+
+// mention proc-macros when enabled
+pub const EXPLAIN_PROC_MACROS_IN_EXTERN: &'static str =
+    "Macro and proc-macro invocations in `extern {}` blocks are experimental.";
+
 struct PostExpansionVisitor<'a> {
     context: &'a Context<'a>,
 }
@@ -1595,6 +1605,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
                     gate_feature_post!(&self, extern_types, i.span,
                                        "extern types are experimental");
             }
+            ast::ForeignItemKind::Macro(..) => {}
         }
 
         visit::walk_foreign_item(self, i)
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index e702bf56e7f..1bee67bf360 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -60,10 +60,14 @@ pub trait Folder : Sized {
         noop_fold_use_tree(use_tree, self)
     }
 
-    fn fold_foreign_item(&mut self, ni: ForeignItem) -> ForeignItem {
+    fn fold_foreign_item(&mut self, ni: ForeignItem) -> SmallVector<ForeignItem> {
         noop_fold_foreign_item(ni, self)
     }
 
+    fn fold_foreign_item_simple(&mut self, ni: ForeignItem) -> ForeignItem {
+        noop_fold_foreign_item_simple(ni, self)
+    }
+
     fn fold_item(&mut self, i: P<Item>) -> SmallVector<P<Item>> {
         noop_fold_item(i, self)
     }
@@ -414,7 +418,7 @@ pub fn noop_fold_foreign_mod<T: Folder>(ForeignMod {abi, items}: ForeignMod,
                                         fld: &mut T) -> ForeignMod {
     ForeignMod {
         abi,
-        items: items.move_map(|x| fld.fold_foreign_item(x)),
+        items: items.move_flat_map(|x| fld.fold_foreign_item(x)),
     }
 }
 
@@ -648,6 +652,10 @@ pub fn noop_fold_interpolated<T: Folder>(nt: token::Nonterminal, fld: &mut T)
         token::NtArg(arg) => token::NtArg(fld.fold_arg(arg)),
         token::NtVis(vis) => token::NtVis(fld.fold_vis(vis)),
         token::NtLifetime(lifetime) => token::NtLifetime(fld.fold_lifetime(lifetime)),
+        token::NtForeignItem(ni) =>
+            token::NtForeignItem(fld.fold_foreign_item(ni)
+                                 // see reasoning above
+                                 .expect_one("expected fold to produce exactly one item")),
     }
 }
 
@@ -1072,7 +1080,12 @@ pub fn noop_fold_item_simple<T: Folder>(Item {id, ident, attrs, node, vis, span,
     }
 }
 
-pub fn noop_fold_foreign_item<T: Folder>(ni: ForeignItem, folder: &mut T) -> ForeignItem {
+pub fn noop_fold_foreign_item<T: Folder>(ni: ForeignItem, folder: &mut T)
+-> SmallVector<ForeignItem> {
+    SmallVector::one(folder.fold_foreign_item_simple(ni))
+}
+
+pub fn noop_fold_foreign_item_simple<T: Folder>(ni: ForeignItem, folder: &mut T) -> ForeignItem {
     ForeignItem {
         id: folder.new_id(ni.id),
         vis: folder.fold_vis(ni.vis),
@@ -1086,6 +1099,7 @@ pub fn noop_fold_foreign_item<T: Folder>(ni: ForeignItem, folder: &mut T) -> For
                 ForeignItemKind::Static(folder.fold_ty(t), m)
             }
             ForeignItemKind::Ty => ForeignItemKind::Ty,
+            ForeignItemKind::Macro(mac) => ForeignItemKind::Macro(folder.fold_mac(mac)),
         },
         span: folder.new_span(ni.span)
     }
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index f5ab023b30e..9936eea9356 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -26,7 +26,7 @@ use ast::{Ident, ImplItem, IsAuto, Item, ItemKind};
 use ast::{Label, Lifetime, LifetimeDef, Lit, LitKind, UintTy};
 use ast::Local;
 use ast::MacStmtStyle;
-use ast::Mac_;
+use ast::{Mac, Mac_};
 use ast::{MutTy, Mutability};
 use ast::{Pat, PatKind, PathSegment};
 use ast::{PolyTraitRef, QSelf};
@@ -1417,28 +1417,8 @@ impl<'a> Parser<'a> {
                 None
             };
             (ident, TraitItemKind::Const(ty, default), ast::Generics::default())
-        } else if self.token.is_path_start() && !self.is_extern_non_path() {
+        } else if let Some(mac) = self.parse_assoc_macro_invoc("trait", None, &mut false)? {
             // trait item macro.
-            // code copied from parse_macro_use_or_failure... abstraction!
-            let prev_span = self.prev_span;
-            let lo = self.span;
-            let pth = self.parse_path(PathStyle::Mod)?;
-
-            if pth.segments.len() == 1 {
-                if !self.eat(&token::Not) {
-                    return Err(self.missing_assoc_item_kind_err("trait", prev_span));
-                }
-            } else {
-                self.expect(&token::Not)?;
-            }
-
-            // eat a matched-delimiter token tree:
-            let (delim, tts) = self.expect_delimited_token_tree()?;
-            if delim != token::Brace {
-                self.expect(&token::Semi)?
-            }
-
-            let mac = respan(lo.to(self.prev_span), Mac_ { path: pth, tts: tts });
             (keywords::Invalid.ident(), ast::TraitItemKind::Macro(mac), ast::Generics::default())
         } else {
             let (constness, unsafety, abi) = self.parse_fn_front_matter()?;
@@ -5393,6 +5373,12 @@ impl<'a> Parser<'a> {
     fn missing_assoc_item_kind_err(&mut self, item_type: &str, prev_span: Span)
                                    -> DiagnosticBuilder<'a>
     {
+        let expected_kinds = if item_type == "extern" {
+            "missing `fn`, `type`, or `static`"
+        } else {
+            "missing `fn`, `type`, or `const`"
+        };
+
         // Given this code `path(`, it seems like this is not
         // setting the visibility of a macro invocation, but rather
         // a mistyped method declaration.
@@ -5405,9 +5391,9 @@ impl<'a> Parser<'a> {
         let sp = prev_span.between(self.prev_span);
         let mut err = self.diagnostic().struct_span_err(
             sp,
-            &format!("missing `fn`, `type`, or `const` for {}-item declaration",
-                     item_type));
-        err.span_label(sp, "missing `fn`, `type`, or `const`");
+            &format!("{} for {}-item declaration",
+                     expected_kinds, item_type));
+        err.span_label(sp, expected_kinds);
         err
     }
 
@@ -5416,31 +5402,8 @@ impl<'a> Parser<'a> {
                          -> PResult<'a, (Ident, Vec<Attribute>, ast::Generics,
                              ast::ImplItemKind)> {
         // code copied from parse_macro_use_or_failure... abstraction!
-        if self.token.is_path_start() && !self.is_extern_non_path() {
+        if let Some(mac) = self.parse_assoc_macro_invoc("impl", Some(vis), at_end)? {
             // Method macro.
-
-            let prev_span = self.prev_span;
-
-            let lo = self.span;
-            let pth = self.parse_path(PathStyle::Mod)?;
-            if pth.segments.len() == 1 {
-                if !self.eat(&token::Not) {
-                    return Err(self.missing_assoc_item_kind_err("impl", prev_span));
-                }
-            } else {
-                self.expect(&token::Not)?;
-            }
-
-            self.complain_if_pub_macro(&vis.node, prev_span);
-
-            // eat a matched-delimiter token tree:
-            *at_end = true;
-            let (delim, tts) = self.expect_delimited_token_tree()?;
-            if delim != token::Brace {
-                self.expect(&token::Semi)?
-            }
-
-            let mac = respan(lo.to(self.prev_span), Mac_ { path: pth, tts: tts });
             Ok((keywords::Invalid.ident(), vec![], ast::Generics::default(),
                 ast::ImplItemKind::Macro(mac)))
         } else {
@@ -6786,7 +6749,9 @@ impl<'a> Parser<'a> {
     }
 
     /// Parse a foreign item.
-    fn parse_foreign_item(&mut self) -> PResult<'a, Option<ForeignItem>> {
+    pub fn parse_foreign_item(&mut self) -> PResult<'a, Option<ForeignItem>> {
+        maybe_whole!(self, NtForeignItem, |ni| Some(ni));
+
         let attrs = self.parse_outer_attributes()?;
         let lo = self.span;
         let visibility = self.parse_visibility(false)?;
@@ -6812,12 +6777,26 @@ impl<'a> Parser<'a> {
             return Ok(Some(self.parse_item_foreign_type(visibility, lo, attrs)?));
         }
 
-        // FIXME #5668: this will occur for a macro invocation:
-        match self.parse_macro_use_or_failure(attrs, true, false, lo, visibility)? {
-            Some(item) => {
-                return Err(self.span_fatal(item.span, "macros cannot expand to foreign items"));
+        match self.parse_assoc_macro_invoc("extern", Some(&visibility), &mut false)? {
+            Some(mac) => {
+                Ok(Some(
+                    ForeignItem {
+                        ident: keywords::Invalid.ident(),
+                        span: lo.to(self.prev_span),
+                        id: ast::DUMMY_NODE_ID,
+                        attrs,
+                        vis: visibility,
+                        node: ForeignItemKind::Macro(mac),
+                    }
+                ))
+            }
+            None => {
+                if !attrs.is_empty() {
+                    self.expected_item_err(&attrs);
+                }
+
+                Ok(None)
             }
-            None => Ok(None)
         }
     }
 
@@ -6881,6 +6860,41 @@ impl<'a> Parser<'a> {
         Ok(None)
     }
 
+    /// Parse a macro invocation inside a `trait`, `impl` or `extern` block
+    fn parse_assoc_macro_invoc(&mut self, item_kind: &str, vis: Option<&Visibility>,
+                               at_end: &mut bool) -> PResult<'a, Option<Mac>>
+    {
+        if self.token.is_path_start() && !self.is_extern_non_path() {
+            let prev_span = self.prev_span;
+            let lo = self.span;
+            let pth = self.parse_path(PathStyle::Mod)?;
+
+            if pth.segments.len() == 1 {
+                if !self.eat(&token::Not) {
+                    return Err(self.missing_assoc_item_kind_err(item_kind, prev_span));
+                }
+            } else {
+                self.expect(&token::Not)?;
+            }
+
+            if let Some(vis) = vis {
+                self.complain_if_pub_macro(&vis.node, prev_span);
+            }
+
+            *at_end = true;
+
+            // eat a matched-delimiter token tree:
+            let (delim, tts) = self.expect_delimited_token_tree()?;
+            if delim != token::Brace {
+                self.expect(&token::Semi)?
+            }
+
+            Ok(Some(respan(lo.to(self.prev_span), Mac_ { path: pth, tts: tts })))
+        } else {
+            Ok(None)
+        }
+    }
+
     fn collect_tokens<F, R>(&mut self, f: F) -> PResult<'a, (R, TokenStream)>
         where F: FnOnce(&mut Self) -> PResult<'a, R>
     {
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index e2dfca5d10a..5fe2b081566 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -581,6 +581,7 @@ pub enum Nonterminal {
     NtArm(ast::Arm),
     NtImplItem(ast::ImplItem),
     NtTraitItem(ast::TraitItem),
+    NtForeignItem(ast::ForeignItem),
     NtGenerics(ast::Generics),
     NtWhereClause(ast::WhereClause),
     NtArg(ast::Arg),
@@ -603,6 +604,7 @@ impl fmt::Debug for Nonterminal {
             NtArm(..) => f.pad("NtArm(..)"),
             NtImplItem(..) => f.pad("NtImplItem(..)"),
             NtTraitItem(..) => f.pad("NtTraitItem(..)"),
+            NtForeignItem(..) => f.pad("NtForeignItem(..)"),
             NtGenerics(..) => f.pad("NtGenerics(..)"),
             NtWhereClause(..) => f.pad("NtWhereClause(..)"),
             NtArg(..) => f.pad("NtArg(..)"),
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index c3785c10f69..1bed6109dd2 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -281,6 +281,7 @@ pub fn token_to_string(tok: &Token) -> String {
             token::NtArg(ref e)          => arg_to_string(e),
             token::NtVis(ref e)          => vis_to_string(e),
             token::NtLifetime(ref e)     => lifetime_to_string(e),
+            token::NtForeignItem(ref ni) => foreign_item_to_string(ni),
         }
     }
 }
@@ -422,6 +423,10 @@ pub fn mac_to_string(arg: &ast::Mac) -> String {
     to_string(|s| s.print_mac(arg, ::parse::token::Paren))
 }
 
+pub fn foreign_item_to_string(arg: &ast::ForeignItem) -> String {
+    to_string(|s| s.print_foreign_item(arg))
+}
+
 pub fn visibility_qualified(vis: &ast::Visibility, s: &str) -> String {
     format!("{}{}", to_string(|s| s.print_visibility(vis)), s)
 }
@@ -1127,6 +1132,10 @@ impl<'a> State<'a> {
                 self.end()?; // end the head-ibox
                 self.end() // end the outer cbox
             }
+            ast::ForeignItemKind::Macro(ref m) => {
+                self.print_mac(m, token::Paren)?;
+                self.s.word(";")
+            }
         }
     }
 
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index d8de78054ab..3a2069efd89 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -460,6 +460,7 @@ pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, foreign_item: &'a
         }
         ForeignItemKind::Static(ref typ, _) => visitor.visit_ty(typ),
         ForeignItemKind::Ty => (),
+        ForeignItemKind::Macro(ref mac) => visitor.visit_mac(mac),
     }
 
     walk_list!(visitor, visit_attribute, &foreign_item.attrs);
diff --git a/src/libsyntax_ext/deriving/custom.rs b/src/libsyntax_ext/deriving/custom.rs
index 80557078d54..5fd5e299488 100644
--- a/src/libsyntax_ext/deriving/custom.rs
+++ b/src/libsyntax_ext/deriving/custom.rs
@@ -55,6 +55,7 @@ impl MultiItemModifier for ProcMacroDerive {
             Annotatable::Item(item) => item,
             Annotatable::ImplItem(_) |
             Annotatable::TraitItem(_) |
+            Annotatable::ForeignItem(_) |
             Annotatable::Stmt(_) |
             Annotatable::Expr(_) => {
                 ecx.span_err(span, "proc-macro derives may only be \
diff --git a/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs b/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs
index 77ea3019419..bc51b4061ed 100644
--- a/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs
+++ b/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs
@@ -93,7 +93,9 @@ fn expand_into_foo_multi(cx: &mut ExtCtxt,
                 }
             })
         }
-        // these are covered in proc_macro/attr-stmt-expr.rs
+        // covered in proc_macro/macros-in-extern.rs
+        Annotatable::ForeignItem(_) => unimplemented!(),
+        // covered in proc_macro/attr-stmt-expr.rs
         Annotatable::Stmt(_) | Annotatable::Expr(_) => panic!("expected item")
     }
 }
@@ -147,6 +149,8 @@ fn expand_duplicate(cx: &mut ExtCtxt,
             new_it.ident = copy_name;
             push(Annotatable::TraitItem(P(new_it)));
         }
+        // covered in proc_macro/macros-in-extern.rs
+        Annotatable::ForeignItem(_) => unimplemented!(),
         // covered in proc_macro/attr-stmt-expr.rs
         Annotatable::Stmt(_) | Annotatable::Expr(_) => panic!("expected item")
     }
diff --git a/src/test/compile-fail-fulldeps/proc-macro/auxiliary/attributes-included.rs b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/attributes-included.rs
index d725adfec75..bbfec5815ba 100644
--- a/src/test/compile-fail-fulldeps/proc-macro/auxiliary/attributes-included.rs
+++ b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/attributes-included.rs
@@ -16,7 +16,7 @@
 
 extern crate proc_macro;
 
-use proc_macro::{TokenStream, TokenTree, TokenNode, Delimiter, Literal, Spacing};
+use proc_macro::{TokenStream, TokenTree, Delimiter, Literal, Spacing, Group};
 
 #[proc_macro_attribute]
 pub fn foo(attr: TokenStream, input: TokenStream) -> TokenStream {
@@ -52,24 +52,30 @@ pub fn bar(attr: TokenStream, input: TokenStream) -> TokenStream {
 }
 
 fn assert_inline(slice: &mut &[TokenTree]) {
-    match slice[0].kind {
-        TokenNode::Op('#', _) => {}
+    match &slice[0] {
+        TokenTree::Op(tt) => assert_eq!(tt.op(), '#'),
         _ => panic!("expected '#' char"),
     }
-    match slice[1].kind {
-        TokenNode::Group(Delimiter::Bracket, _) => {}
+    match &slice[1] {
+        TokenTree::Group(tt) => assert_eq!(tt.delimiter(), Delimiter::Bracket),
         _ => panic!("expected brackets"),
     }
     *slice = &slice[2..];
 }
 
 fn assert_doc(slice: &mut &[TokenTree]) {
-    match slice[0].kind {
-        TokenNode::Op('#', Spacing::Alone) => {}
+    match &slice[0] {
+        TokenTree::Op(tt) => {
+            assert_eq!(tt.op(), '#');
+            assert_eq!(tt.spacing(), Spacing::Alone);
+        }
         _ => panic!("expected #"),
     }
-    let inner = match slice[1].kind {
-        TokenNode::Group(Delimiter::Bracket, ref s) => s.clone(),
+    let inner = match &slice[1] {
+        TokenTree::Group(tt) => {
+            assert_eq!(tt.delimiter(), Delimiter::Bracket);
+            tt.stream()
+        }
         _ => panic!("expected brackets"),
     };
     let tokens = inner.into_iter().collect::<Vec<_>>();
@@ -79,16 +85,19 @@ fn assert_doc(slice: &mut &[TokenTree]) {
         panic!("expected three tokens in doc")
     }
 
-    match tokens[0].kind {
-        TokenNode::Term(ref t) => assert_eq!("doc", t.as_str()),
+    match &tokens[0] {
+        TokenTree::Term(tt) => assert_eq!("doc", tt.as_str()),
         _ => panic!("expected `doc`"),
     }
-    match tokens[1].kind {
-        TokenNode::Op('=', Spacing::Alone) => {}
+    match &tokens[1] {
+        TokenTree::Op(tt) => {
+            assert_eq!(tt.op(), '=');
+            assert_eq!(tt.spacing(), Spacing::Alone);
+        }
         _ => panic!("expected equals"),
     }
-    match tokens[2].kind {
-        TokenNode::Literal(_) => {}
+    match tokens[2] {
+        TokenTree::Literal(_) => {}
         _ => panic!("expected literal"),
     }
 
@@ -96,32 +105,35 @@ fn assert_doc(slice: &mut &[TokenTree]) {
 }
 
 fn assert_invoc(slice: &mut &[TokenTree]) {
-    match slice[0].kind {
-        TokenNode::Op('#', _) => {}
+    match &slice[0] {
+        TokenTree::Op(tt) => assert_eq!(tt.op(), '#'),
         _ => panic!("expected '#' char"),
     }
-    match slice[1].kind {
-        TokenNode::Group(Delimiter::Bracket, _) => {}
+    match &slice[1] {
+        TokenTree::Group(tt) => assert_eq!(tt.delimiter(), Delimiter::Bracket),
         _ => panic!("expected brackets"),
     }
     *slice = &slice[2..];
 }
 
 fn assert_foo(slice: &mut &[TokenTree]) {
-    match slice[0].kind {
-        TokenNode::Term(ref name) => assert_eq!(name.as_str(), "fn"),
+    match &slice[0] {
+        TokenTree::Term(tt) => assert_eq!(tt.as_str(), "fn"),
         _ => panic!("expected fn"),
     }
-    match slice[1].kind {
-        TokenNode::Term(ref name) => assert_eq!(name.as_str(), "foo"),
+    match &slice[1] {
+        TokenTree::Term(tt) => assert_eq!(tt.as_str(), "foo"),
         _ => panic!("expected foo"),
     }
-    match slice[2].kind {
-        TokenNode::Group(Delimiter::Parenthesis, ref s) => assert!(s.is_empty()),
+    match &slice[2] {
+        TokenTree::Group(tt) => {
+            assert_eq!(tt.delimiter(), Delimiter::Parenthesis);
+            assert!(tt.stream().is_empty());
+        }
         _ => panic!("expected parens"),
     }
-    match slice[3].kind {
-        TokenNode::Group(Delimiter::Brace, _) => {}
+    match &slice[3] {
+        TokenTree::Group(tt) => assert_eq!(tt.delimiter(), Delimiter::Brace),
         _ => panic!("expected braces"),
     }
     *slice = &slice[4..];
@@ -132,22 +144,17 @@ fn fold_stream(input: TokenStream) -> TokenStream {
 }
 
 fn fold_tree(input: TokenTree) -> TokenTree {
-    TokenTree {
-        span: input.span,
-        kind: fold_node(input.kind),
-    }
-}
-
-fn fold_node(input: TokenNode) -> TokenNode {
     match input {
-        TokenNode::Group(a, b) => TokenNode::Group(a, fold_stream(b)),
-        TokenNode::Op(a, b) => TokenNode::Op(a, b),
-        TokenNode::Term(a) => TokenNode::Term(a),
-        TokenNode::Literal(a) => {
+        TokenTree::Group(b) => {
+            TokenTree::Group(Group::new(b.delimiter(), fold_stream(b.stream())))
+        }
+        TokenTree::Op(b) => TokenTree::Op(b),
+        TokenTree::Term(a) => TokenTree::Term(a),
+        TokenTree::Literal(a) => {
             if a.to_string() != "\"foo\"" {
-                TokenNode::Literal(a)
+                TokenTree::Literal(a)
             } else {
-                TokenNode::Literal(Literal::integer(3))
+                TokenTree::Literal(Literal::i32_unsuffixed(3))
             }
         }
     }
diff --git a/src/test/compile-fail-fulldeps/proc-macro/auxiliary/test-macros.rs b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/test-macros.rs
new file mode 100644
index 00000000000..d1c5b9050aa
--- /dev/null
+++ b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/test-macros.rs
@@ -0,0 +1,36 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+#![feature(proc_macro)]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro_attribute]
+pub fn nop_attr(_attr: TokenStream, input: TokenStream) -> TokenStream {
+    assert!(_attr.to_string().is_empty());
+    input
+}
+
+#[proc_macro_attribute]
+pub fn no_output(_attr: TokenStream, _input: TokenStream) -> TokenStream {
+    assert!(_attr.to_string().is_empty());
+    assert!(!_input.to_string().is_empty());
+    "".parse().unwrap()
+}
+
+#[proc_macro]
+pub fn emit_input(input: TokenStream) -> TokenStream {
+    input
+}
diff --git a/src/test/compile-fail-fulldeps/proc-macro/macros-in-extern.rs b/src/test/compile-fail-fulldeps/proc-macro/macros-in-extern.rs
new file mode 100644
index 00000000000..4c88df33246
--- /dev/null
+++ b/src/test/compile-fail-fulldeps/proc-macro/macros-in-extern.rs
@@ -0,0 +1,38 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:test-macros.rs
+// ignore-stage1
+// ignore-wasm32
+
+#![feature(proc_macro)]
+
+extern crate test_macros;
+
+use test_macros::{nop_attr, no_output, emit_input};
+
+fn main() {
+    assert_eq!(unsafe { rust_get_test_int() }, 0isize);
+    assert_eq!(unsafe { rust_dbg_extern_identity_u32(0xDEADBEEF) }, 0xDEADBEEF);
+}
+
+#[link(name = "rust_test_helpers", kind = "static")]
+extern {
+    #[no_output]
+    //~^ ERROR Macro and proc-macro invocations in `extern {}` blocks are experimental.
+    fn some_definitely_unknown_symbol_which_should_be_removed();
+
+    #[nop_attr]
+    //~^ ERROR Macro and proc-macro invocations in `extern {}` blocks are experimental.
+    fn rust_get_test_int() -> isize;
+
+    emit_input!(fn rust_dbg_extern_identity_u32(arg: u32) -> u32;);
+    //~^ ERROR Macro and proc-macro invocations in `extern {}` blocks are experimental.
+}
diff --git a/src/test/compile-fail/macros-in-extern.rs b/src/test/compile-fail/macros-in-extern.rs
new file mode 100644
index 00000000000..7d7f95cbbf5
--- /dev/null
+++ b/src/test/compile-fail/macros-in-extern.rs
@@ -0,0 +1,42 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-wasm32
+
+#![feature(decl_macro)]
+
+macro_rules! returns_isize(
+    ($ident:ident) => (
+        fn $ident() -> isize;
+    )
+);
+
+macro takes_u32_returns_u32($ident:ident) {
+    fn $ident (arg: u32) -> u32;
+}
+
+macro_rules! emits_nothing(
+    () => ()
+);
+
+fn main() {
+    assert_eq!(unsafe { rust_get_test_int() }, 0isize);
+    assert_eq!(unsafe { rust_dbg_extern_identity_u32(0xDEADBEEF) }, 0xDEADBEEFu32);
+}
+
+#[link(name = "rust_test_helpers", kind = "static")]
+extern {
+    returns_isize!(rust_get_test_int);
+    //~^ ERROR Macro invocations in `extern {}` blocks are experimental.
+    takes_u32_returns_u32!(rust_dbg_extern_identity_u32);
+    //~^ ERROR Macro invocations in `extern {}` blocks are experimental.
+    emits_nothing!();
+    //~^ ERROR Macro invocations in `extern {}` blocks are experimental.
+}
diff --git a/src/test/parse-fail/duplicate-visibility.rs b/src/test/parse-fail/duplicate-visibility.rs
index 5ee84cd5543..6899caa7153 100644
--- a/src/test/parse-fail/duplicate-visibility.rs
+++ b/src/test/parse-fail/duplicate-visibility.rs
@@ -10,7 +10,7 @@
 
 // compile-flags: -Z parse-only
 
-// error-pattern:unmatched visibility `pub`
+// error-pattern:expected one of `(`, `fn`, `static`, `type`, or `}` here
 extern {
     pub pub fn foo();
 }
diff --git a/src/test/parse-fail/extern-no-fn.rs b/src/test/parse-fail/extern-no-fn.rs
index ff3fefde40e..aa0dbd4d4fc 100644
--- a/src/test/parse-fail/extern-no-fn.rs
+++ b/src/test/parse-fail/extern-no-fn.rs
@@ -10,8 +10,8 @@
 
 // compile-flags: -Z parse-only
 
-extern {
-    f(); //~ ERROR expected one of `!` or `::`, found `(`
+extern { //~ ERROR missing `fn`, `type`, or `static` for extern-item declaration
+    f();
 }
 
 fn main() {
diff --git a/src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs b/src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs
index e2c68a626f9..281ee70815e 100644
--- a/src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs
+++ b/src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs
@@ -15,15 +15,15 @@
 
 extern crate proc_macro;
 
-use proc_macro::{TokenStream, TokenNode, quote};
+use proc_macro::*;
 
 #[proc_macro]
 pub fn cond(input: TokenStream) -> TokenStream {
     let mut conds = Vec::new();
     let mut input = input.into_iter().peekable();
     while let Some(tree) = input.next() {
-        let cond = match tree.kind {
-            TokenNode::Group(_, cond) => cond,
+        let cond = match tree {
+            TokenTree::Group(tt) => tt.stream(),
             _ => panic!("Invalid input"),
         };
         let mut cond_trees = cond.clone().into_iter();
@@ -32,8 +32,8 @@ pub fn cond(input: TokenStream) -> TokenStream {
         if rhs.is_empty() {
             panic!("Invalid macro usage in cond: {}", cond);
         }
-        let is_else = match test.kind {
-            TokenNode::Term(word) => word.as_str() == "else",
+        let is_else = match test {
+            TokenTree::Term(word) => word.as_str() == "else",
             _ => false,
         };
         conds.push(if is_else || input.peek().is_none() {
@@ -43,5 +43,5 @@ pub fn cond(input: TokenStream) -> TokenStream {
         });
     }
 
-    conds.into_iter().collect()
+    conds.into_iter().flat_map(|x| x.into_iter()).collect()
 }
diff --git a/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs b/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs
index 5ebd3292132..6612fe45b81 100644
--- a/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs
+++ b/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs
@@ -96,7 +96,9 @@ fn expand_into_foo_multi(cx: &mut ExtCtxt,
                 }
             })
         ],
-        // these are covered in proc_macro/attr-stmt-expr.rs
+        // covered in proc_macro/macros-in-extern.rs
+        Annotatable::ForeignItem(..) => unimplemented!(),
+        // covered in proc_macro/attr-stmt-expr.rs
         Annotatable::Stmt(_) | Annotatable::Expr(_) => panic!("expected item"),
     }
 }
@@ -142,7 +144,9 @@ fn expand_duplicate(cx: &mut ExtCtxt,
             new_it.ident = copy_name;
             push(Annotatable::TraitItem(P(new_it)));
         }
-        // these are covered in proc_macro/attr-stmt-expr.rs
+        // covered in proc_macro/macros-in-extern.rs
+        Annotatable::ForeignItem(..) => unimplemented!(),
+        // covered in proc_macro/attr-stmt-expr.rs
         Annotatable::Stmt(_) | Annotatable::Expr(_) => panic!("expected item")
     }
 }
diff --git a/src/test/run-pass-fulldeps/auxiliary/proc_macro_def.rs b/src/test/run-pass-fulldeps/auxiliary/proc_macro_def.rs
index 1b470438848..d3670ae66fe 100644
--- a/src/test/run-pass-fulldeps/auxiliary/proc_macro_def.rs
+++ b/src/test/run-pass-fulldeps/auxiliary/proc_macro_def.rs
@@ -15,7 +15,7 @@
 
 extern crate proc_macro;
 
-use proc_macro::{TokenStream, quote};
+use proc_macro::*;
 
 #[proc_macro_attribute]
 pub fn attr_tru(_attr: TokenStream, item: TokenStream) -> TokenStream {
diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/count_compound_ops.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/count_compound_ops.rs
index ec2ff0d1e2b..063d8dc4053 100644
--- a/src/test/run-pass-fulldeps/proc-macro/auxiliary/count_compound_ops.rs
+++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/count_compound_ops.rs
@@ -15,20 +15,25 @@
 
 extern crate proc_macro;
 
-use proc_macro::{TokenStream, TokenNode, Spacing, Literal, quote};
+use proc_macro::{TokenStream, TokenTree, Spacing, Literal, quote};
 
 #[proc_macro]
 pub fn count_compound_ops(input: TokenStream) -> TokenStream {
     assert_eq!(count_compound_ops_helper(quote!(++ (&&) 4@a)), 3);
-    TokenNode::Literal(Literal::u32(count_compound_ops_helper(input))).into()
+    let l = Literal::u32_suffixed(count_compound_ops_helper(input));
+    TokenTree::from(l).into()
 }
 
 fn count_compound_ops_helper(input: TokenStream) -> u32 {
     let mut count = 0;
     for token in input {
-        match token.kind {
-            TokenNode::Op(c, Spacing::Alone) => count += 1,
-            TokenNode::Group(_, tokens) => count += count_compound_ops_helper(tokens),
+        match &token {
+            TokenTree::Op(tt) if tt.spacing() == Spacing::Alone => {
+                count += 1;
+            }
+            TokenTree::Group(tt) => {
+                count += count_compound_ops_helper(tt.stream());
+            }
             _ => {}
         }
     }
diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/negative-token.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/negative-token.rs
index e5ebb7c2e41..e76e4d585f4 100644
--- a/src/test/run-pass-fulldeps/proc-macro/auxiliary/negative-token.rs
+++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/negative-token.rs
@@ -19,16 +19,10 @@ use proc_macro::*;
 
 #[proc_macro]
 pub fn neg_one(_input: TokenStream) -> TokenStream {
-    TokenTree {
-        span: Span::call_site(),
-        kind: TokenNode::Literal(Literal::i32(-1)),
-    }.into()
+    TokenTree::Literal(Literal::i32_suffixed(-1)).into()
 }
 
 #[proc_macro]
 pub fn neg_one_float(_input: TokenStream) -> TokenStream {
-    TokenTree {
-        span: Span::call_site(),
-        kind: TokenNode::Literal(Literal::f32(-1.0)),
-    }.into()
+    TokenTree::Literal(Literal::f32_suffixed(-1.0)).into()
 }
diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/span-api-tests.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/span-api-tests.rs
index ce6ffcc3cb0..6ab9d6d0b8a 100644
--- a/src/test/run-pass-fulldeps/proc-macro/auxiliary/span-api-tests.rs
+++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/span-api-tests.rs
@@ -27,7 +27,7 @@ pub fn reemit(input: TokenStream) -> TokenStream {
 #[proc_macro]
 pub fn assert_fake_source_file(input: TokenStream) -> TokenStream {
     for tk in input {
-        let source_file = tk.span.source_file();
+        let source_file = tk.span().source_file();
         assert!(!source_file.is_real(), "Source file is real: {:?}", source_file);
     }
 
@@ -37,7 +37,7 @@ pub fn assert_fake_source_file(input: TokenStream) -> TokenStream {
 #[proc_macro]
 pub fn assert_source_file(input: TokenStream) -> TokenStream {
     for tk in input {
-        let source_file = tk.span.source_file();
+        let source_file = tk.span().source_file();
         assert!(source_file.is_real(), "Source file is not real: {:?}", source_file);
     }
 
diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/test-macros.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/test-macros.rs
new file mode 100644
index 00000000000..d1c5b9050aa
--- /dev/null
+++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/test-macros.rs
@@ -0,0 +1,36 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+#![feature(proc_macro)]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro_attribute]
+pub fn nop_attr(_attr: TokenStream, input: TokenStream) -> TokenStream {
+    assert!(_attr.to_string().is_empty());
+    input
+}
+
+#[proc_macro_attribute]
+pub fn no_output(_attr: TokenStream, _input: TokenStream) -> TokenStream {
+    assert!(_attr.to_string().is_empty());
+    assert!(!_input.to_string().is_empty());
+    "".parse().unwrap()
+}
+
+#[proc_macro]
+pub fn emit_input(input: TokenStream) -> TokenStream {
+    input
+}
diff --git a/src/test/run-pass-fulldeps/proc-macro/macros-in-extern.rs b/src/test/run-pass-fulldeps/proc-macro/macros-in-extern.rs
new file mode 100644
index 00000000000..59b9b0baa8a
--- /dev/null
+++ b/src/test/run-pass-fulldeps/proc-macro/macros-in-extern.rs
@@ -0,0 +1,35 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:test-macros.rs
+// ignore-stage1
+// ignore-wasm32
+
+#![feature(proc_macro, macros_in_extern)]
+
+extern crate test_macros;
+
+use test_macros::{nop_attr, no_output, emit_input};
+
+fn main() {
+    assert_eq!(unsafe { rust_get_test_int() }, 1isize);
+    assert_eq!(unsafe { rust_dbg_extern_identity_u32(0xDEADBEEF) }, 0xDEADBEEF);
+}
+
+#[link(name = "rust_test_helpers", kind = "static")]
+extern {
+    #[no_output]
+    fn some_definitely_unknown_symbol_which_should_be_removed();
+
+    #[nop_attr]
+    fn rust_get_test_int() -> isize;
+
+    emit_input!(fn rust_dbg_extern_identity_u32(arg: u32) -> u32;);
+}
diff --git a/src/test/run-pass/macros-in-extern.rs b/src/test/run-pass/macros-in-extern.rs
new file mode 100644
index 00000000000..d9094934356
--- /dev/null
+++ b/src/test/run-pass/macros-in-extern.rs
@@ -0,0 +1,39 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-wasm32
+
+#![feature(decl_macro, macros_in_extern)]
+
+macro_rules! returns_isize(
+    ($ident:ident) => (
+        fn $ident() -> isize;
+    )
+);
+
+macro takes_u32_returns_u32($ident:ident) {
+    fn $ident (arg: u32) -> u32;
+}
+
+macro_rules! emits_nothing(
+    () => ()
+);
+
+fn main() {
+    assert_eq!(unsafe { rust_get_test_int() }, 1isize);
+    assert_eq!(unsafe { rust_dbg_extern_identity_u32(0xDEADBEEF) }, 0xDEADBEEFu32);
+}
+
+#[link(name = "rust_test_helpers", kind = "static")]
+extern {
+    returns_isize!(rust_get_test_int);
+    takes_u32_returns_u32!(rust_dbg_extern_identity_u32);
+    emits_nothing!();
+}
diff --git a/src/test/ui-fulldeps/proc-macro/auxiliary/parent-source-spans.rs b/src/test/ui-fulldeps/proc-macro/auxiliary/parent-source-spans.rs
index 3eb96c2ab96..ed11b2db2f5 100644
--- a/src/test/ui-fulldeps/proc-macro/auxiliary/parent-source-spans.rs
+++ b/src/test/ui-fulldeps/proc-macro/auxiliary/parent-source-spans.rs
@@ -14,12 +14,12 @@
 
 extern crate proc_macro;
 
-use proc_macro::{TokenStream, TokenTree, TokenNode, Span};
+use proc_macro::{TokenStream, TokenTree, Span};
 
 fn lit_span(tt: TokenTree) -> (Span, String) {
-    use TokenNode::*;
-    match tt.kind {
-        Literal(..) | Group(..) => (tt.span, tt.to_string().trim().into()),
+    match tt {
+        TokenTree::Literal(..) |
+        TokenTree::Group(..) => (tt.span(), tt.to_string().trim().into()),
         _ => panic!("expected a literal in token tree, got: {:?}", tt)
     }
 }
diff --git a/src/test/ui-fulldeps/proc-macro/auxiliary/three-equals.rs b/src/test/ui-fulldeps/proc-macro/auxiliary/three-equals.rs
index 2381c61b87b..fda0e28891f 100644
--- a/src/test/ui-fulldeps/proc-macro/auxiliary/three-equals.rs
+++ b/src/test/ui-fulldeps/proc-macro/auxiliary/three-equals.rs
@@ -14,26 +14,27 @@
 
 extern crate proc_macro;
 
-use proc_macro::{TokenStream, TokenNode, Span, Diagnostic};
+use proc_macro::{TokenStream, TokenTree, Span, Diagnostic};
 
 fn parse(input: TokenStream) -> Result<(), Diagnostic> {
     let mut count = 0;
     let mut last_span = Span::def_site();
     for tree in input {
-        let span = tree.span;
+        let span = tree.span();
         if count >= 3 {
             return Err(span.error(format!("expected EOF, found `{}`.", tree))
                            .span_note(last_span, "last good input was here")
                            .help("input must be: `===`"))
         }
 
-        if let TokenNode::Op('=', _) = tree.kind {
-            count += 1;
-        } else {
-            return Err(span.error(format!("expected `=`, found `{}`.", tree)));
+        if let TokenTree::Op(tt) = tree {
+            if tt.op() == '=' {
+                count += 1;
+                last_span = span;
+                continue
+            }
         }
-
-        last_span = span;
+        return Err(span.error(format!("expected `=`, found `{}`.", tree)));
     }
 
     if count < 3 {
diff --git a/src/test/ui/feature-gate-macros_in_extern.rs b/src/test/ui/feature-gate-macros_in_extern.rs
new file mode 100644
index 00000000000..9c758241ea1
--- /dev/null
+++ b/src/test/ui/feature-gate-macros_in_extern.rs
@@ -0,0 +1,35 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(decl_macro)]
+
+macro_rules! returns_isize(
+    ($ident:ident) => (
+        fn $ident() -> isize;
+    )
+);
+
+macro takes_u32_returns_u32($ident:ident) {
+    fn $ident (arg: u32) -> u32;
+}
+
+macro_rules! emits_nothing(
+    () => ()
+);
+
+#[link(name = "rust_test_helpers", kind = "static")]
+extern {
+    returns_isize!(rust_get_test_int);
+    //~^ ERROR Macro invocations in `extern {}` blocks are experimental.
+    takes_u32_returns_u32!(rust_dbg_extern_identity_u32);
+    //~^ ERROR Macro invocations in `extern {}` blocks are experimental.
+    emits_nothing!();
+    //~^ ERROR Macro invocations in `extern {}` blocks are experimental.
+}
diff --git a/src/test/ui/feature-gate-macros_in_extern.stderr b/src/test/ui/feature-gate-macros_in_extern.stderr
new file mode 100644
index 00000000000..49aca0db2d4
--- /dev/null
+++ b/src/test/ui/feature-gate-macros_in_extern.stderr
@@ -0,0 +1,27 @@
+error[E0658]: Macro invocations in `extern {}` blocks are experimental. (see issue #49476)
+  --> $DIR/feature-gate-macros_in_extern.rs:29:5
+   |
+LL |     returns_isize!(rust_get_test_int);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: add #![feature(macros_in_extern)] to the crate attributes to enable
+
+error[E0658]: Macro invocations in `extern {}` blocks are experimental. (see issue #49476)
+  --> $DIR/feature-gate-macros_in_extern.rs:31:5
+   |
+LL |     takes_u32_returns_u32!(rust_dbg_extern_identity_u32);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: add #![feature(macros_in_extern)] to the crate attributes to enable
+
+error[E0658]: Macro invocations in `extern {}` blocks are experimental. (see issue #49476)
+  --> $DIR/feature-gate-macros_in_extern.rs:33:5
+   |
+LL |     emits_nothing!();
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = help: add #![feature(macros_in_extern)] to the crate attributes to enable
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs
index 49b054f8b9e..0f482c95e05 100644
--- a/src/tools/build-manifest/src/main.rs
+++ b/src/tools/build-manifest/src/main.rs
@@ -356,6 +356,28 @@ impl Builder {
                 target: "*".to_string(),
             });
 
+            // If the components/extensions don't actually exist for this
+            // particular host/target combination then nix it entirely from our
+            // lists.
+            {
+                let has_component = |c: &Component| {
+                    if c.target == "*" {
+                        return true
+                    }
+                    let pkg = match manifest.pkg.get(&c.pkg) {
+                        Some(p) => p,
+                        None => return false,
+                    };
+                    let target = match pkg.target.get(&c.target) {
+                        Some(t) => t,
+                        None => return false,
+                    };
+                    target.available
+                };
+                extensions.retain(&has_component);
+                components.retain(&has_component);
+            }
+
             pkg.target.insert(host.to_string(), Target {
                 available: true,
                 url: Some(self.url(&filename)),