about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-07-28 01:03:16 +0000
committerbors <bors@rust-lang.org>2019-07-28 01:03:16 +0000
commit9a239ef4ded03d155c72b68b5a2dd7aff013e141 (patch)
treeddecacf7cf04b32211999b7d65dae0bbf2012102 /src
parentc798dffac9dc8c82374db48f5b474690cc6e9686 (diff)
parent34c0f4698bda7e06d66ee9040a2923250b0c12d0 (diff)
downloadrust-9a239ef4ded03d155c72b68b5a2dd7aff013e141.tar.gz
rust-9a239ef4ded03d155c72b68b5a2dd7aff013e141.zip
Auto merge of #63057 - Centril:rollup-z3a3c6v, r=Centril
Rollup of 8 pull requests

Successful merges:

 - #61207 (Allow lifetime elision in `Pin<&(mut) Self>`)
 - #62074 (squash of all commits for nth_back on ChunksMut)
 - #62771 (Break dependencies between `syntax_ext` and other crates)
 - #62883 (Refactoring use common code between option, result and accum)
 - #62949 (Re-enable assertions in PPC dist builder)
 - #62996 (tidy: Add a check for inline unit tests)
 - #63038 (Make more informative error on outer attribute after inner)
 - #63050 (ci: download awscli from our mirror)

Failed merges:

r? @ghost
Diffstat (limited to 'src')
-rw-r--r--src/ci/awscli-requirements.txt13
-rw-r--r--src/ci/docker/dist-powerpc-linux/Dockerfile4
-rwxr-xr-xsrc/ci/install-awscli.sh35
-rw-r--r--src/libcore/iter/adapters/mod.rs135
-rw-r--r--src/libcore/iter/mod.rs2
-rw-r--r--src/libcore/iter/traits/accum.rs136
-rw-r--r--src/libcore/option.rs42
-rw-r--r--src/libcore/result.rs36
-rw-r--r--src/libcore/slice/mod.rs19
-rw-r--r--src/libcore/tests/slice.rs22
-rw-r--r--src/librustc/hir/lowering.rs3
-rw-r--r--src/librustc/middle/resolve_lifetime.rs95
-rw-r--r--src/librustc_driver/Cargo.toml11
-rw-r--r--src/librustc_interface/passes.rs11
-rw-r--r--src/librustc_metadata/Cargo.toml1
-rw-r--r--src/librustc_metadata/creader.rs3
-rw-r--r--src/librustc_metadata/cstore_impl.rs2
-rw-r--r--src/librustc_passes/Cargo.toml2
-rw-r--r--src/librustc_passes/ast_validation.rs2
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs7
-rw-r--r--src/libsyntax/ext/base.rs4
-rw-r--r--src/libsyntax/ext/derive.rs72
-rw-r--r--src/libsyntax/ext/expand.rs2
-rw-r--r--src/libsyntax/ext/proc_macro.rs249
-rw-r--r--src/libsyntax/ext/proc_macro_server.rs (renamed from src/libsyntax_ext/proc_macro_server.rs)30
-rw-r--r--src/libsyntax/lib.rs15
-rw-r--r--src/libsyntax/parse/attr.rs61
-rw-r--r--src/libsyntax/parse/lexer/mod.rs3
-rw-r--r--src/libsyntax/parse/mod.rs5
-rw-r--r--src/libsyntax/print/pprust.rs3
-rw-r--r--src/libsyntax_ext/Cargo.toml8
-rw-r--r--src/libsyntax_ext/deriving/custom.rs119
-rw-r--r--src/libsyntax_ext/deriving/generic/mod.rs44
-rw-r--r--src/libsyntax_ext/deriving/generic/ty.rs8
-rw-r--r--src/libsyntax_ext/deriving/mod.rs1
-rw-r--r--src/libsyntax_ext/lib.rs23
-rw-r--r--src/libsyntax_ext/proc_macro_harness.rs (renamed from src/libsyntax_ext/proc_macro_decls.rs)14
-rw-r--r--src/libsyntax_ext/proc_macro_impl.rs68
-rw-r--r--src/libsyntax_ext/source_util.rs (renamed from src/libsyntax/ext/source_util.rs)18
-rw-r--r--src/libsyntax_ext/standard_library_imports.rs (renamed from src/libsyntax/std_inject.rs)43
-rw-r--r--src/libsyntax_ext/test.rs33
-rw-r--r--src/libsyntax_ext/test_case.rs44
-rw-r--r--src/libsyntax_ext/test_harness.rs (renamed from src/libsyntax/test.rs)78
-rw-r--r--src/test/ui/issues/issue-45296.stderr4
-rw-r--r--src/test/ui/parser/attr.stderr4
-rw-r--r--src/test/ui/parser/inner-attr-after-doc-comment.stderr11
-rw-r--r--src/test/ui/parser/inner-attr.stderr7
-rw-r--r--src/test/ui/self/arbitrary_self_types_pin_lifetime.rs60
-rw-r--r--src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.nll.stderr14
-rw-r--r--src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.rs13
-rw-r--r--src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr20
-rw-r--r--src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.nll.stderr28
-rw-r--r--src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.rs18
-rw-r--r--src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.stderr26
-rw-r--r--src/test/ui/self/elision/README.md44
-rw-r--r--src/test/ui/self/elision/alias.rs36
-rw-r--r--src/test/ui/self/elision/assoc.rs40
-rw-r--r--src/test/ui/self/elision/lt-alias.rs38
-rw-r--r--src/test/ui/self/elision/lt-assoc.rs44
-rw-r--r--src/test/ui/self/elision/lt-ref-self.nll.stderr62
-rw-r--r--src/test/ui/self/elision/lt-ref-self.rs38
-rw-r--r--src/test/ui/self/elision/lt-ref-self.stderr62
-rw-r--r--src/test/ui/self/elision/lt-self.rs49
-rw-r--r--src/test/ui/self/elision/lt-struct.rs36
-rw-r--r--src/test/ui/self/elision/multiple-ref-self.rs43
-rw-r--r--src/test/ui/self/elision/ref-alias.rs39
-rw-r--r--src/test/ui/self/elision/ref-assoc.rs40
-rw-r--r--src/test/ui/self/elision/ref-mut-alias.rs36
-rw-r--r--src/test/ui/self/elision/ref-mut-self.nll.stderr62
-rw-r--r--src/test/ui/self/elision/ref-mut-self.rs38
-rw-r--r--src/test/ui/self/elision/ref-mut-self.stderr62
-rw-r--r--src/test/ui/self/elision/ref-mut-struct.nll.stderr52
-rw-r--r--src/test/ui/self/elision/ref-mut-struct.rs32
-rw-r--r--src/test/ui/self/elision/ref-mut-struct.stderr52
-rw-r--r--src/test/ui/self/elision/ref-self.nll.stderr72
-rw-r--r--src/test/ui/self/elision/ref-self.rs51
-rw-r--r--src/test/ui/self/elision/ref-self.stderr72
-rw-r--r--src/test/ui/self/elision/ref-struct.nll.stderr52
-rw-r--r--src/test/ui/self/elision/ref-struct.rs32
-rw-r--r--src/test/ui/self/elision/ref-struct.stderr52
-rw-r--r--src/test/ui/self/elision/self.rs36
-rw-r--r--src/test/ui/self/elision/struct.rs32
-rw-r--r--src/test/ui/self/self_lifetime.rs15
-rw-r--r--src/tools/tidy/src/lib.rs2
-rw-r--r--src/tools/tidy/src/libcoretest.rs28
-rw-r--r--src/tools/tidy/src/main.rs2
-rw-r--r--src/tools/tidy/src/unit_tests.rs95
87 files changed, 2330 insertions, 847 deletions
diff --git a/src/ci/awscli-requirements.txt b/src/ci/awscli-requirements.txt
deleted file mode 100644
index c1ffa525a1b..00000000000
--- a/src/ci/awscli-requirements.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-awscli==1.16.201
-botocore==1.12.191
-colorama==0.3.9
-docutils==0.14
-jmespath==0.9.4
-pyasn1==0.4.5
-python-dateutil==2.8.0
-PyYAML==5.1
-rsa==3.4.2
-s3transfer==0.2.1
-six==1.12.0
-urllib3==1.25.3
-futures==3.3.0; python_version < '3.0'
diff --git a/src/ci/docker/dist-powerpc-linux/Dockerfile b/src/ci/docker/dist-powerpc-linux/Dockerfile
index f03aff060c1..8c052db1b0d 100644
--- a/src/ci/docker/dist-powerpc-linux/Dockerfile
+++ b/src/ci/docker/dist-powerpc-linux/Dockerfile
@@ -36,7 +36,3 @@ ENV HOSTS=powerpc-unknown-linux-gnu
 
 ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs
 ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
-
-# FIXME(#36150) this will fail the bootstrap. Probably means something bad is
-#               happening!
-ENV NO_LLVM_ASSERTIONS 1
diff --git a/src/ci/install-awscli.sh b/src/ci/install-awscli.sh
new file mode 100755
index 00000000000..d491b9fbcdc
--- /dev/null
+++ b/src/ci/install-awscli.sh
@@ -0,0 +1,35 @@
+#!/bin/bash
+# This script downloads and installs awscli from the packages mirrored in our
+# own S3 bucket. This follows the recommendations at:
+#
+#    https://packaging.python.org/guides/index-mirrors-and-caches/#caching-with-pip
+#
+# To create a new mirrored copy you can run the command:
+#
+#    pip wheel awscli
+#
+# Before compressing please make sure all the wheels end with `-none-any.whl`.
+# If that's not the case you'll need to remove the non-cross-platform ones and
+# replace them with the .tar.gz downloaded from https://pypi.org. Also make
+# sure it's possible to call this script with both Python 2 and Python 3.
+
+set -euo pipefail
+IFS=$'\n\t'
+
+MIRROR="https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/2019-07-27-awscli.tar"
+DEPS_DIR="/tmp/awscli-deps"
+
+pip="pip"
+pipflags=""
+if [[ "${AGENT_OS}" == "Linux" ]]; then
+    pip="pip3"
+    pipflags="--user"
+
+    sudo apt-get install -y python3-setuptools
+    echo "##vso[task.prependpath]$HOME/.local/bin"
+fi
+
+mkdir -p "${DEPS_DIR}"
+curl "${MIRROR}" | tar xf - -C "${DEPS_DIR}"
+"${pip}" install ${pipflags} --no-index "--find-links=${DEPS_DIR}" awscli
+rm -rf "${DEPS_DIR}"
diff --git a/src/libcore/iter/adapters/mod.rs b/src/libcore/iter/adapters/mod.rs
index c2edcd22f95..8eae52ffd32 100644
--- a/src/libcore/iter/adapters/mod.rs
+++ b/src/libcore/iter/adapters/mod.rs
@@ -2062,3 +2062,138 @@ impl<I: ExactSizeIterator, F> ExactSizeIterator for Inspect<I, F>
 #[stable(feature = "fused", since = "1.26.0")]
 impl<I: FusedIterator, F> FusedIterator for Inspect<I, F>
     where F: FnMut(&I::Item) {}
+
+/// An iterator adapter that produces output as long as the underlying
+/// iterator produces `Option::Some` values.
+pub(crate) struct OptionShunt<I> {
+    iter: I,
+    exited_early: bool,
+}
+
+impl<I, T> OptionShunt<I>
+where
+    I: Iterator<Item = Option<T>>,
+{
+    /// Process the given iterator as if it yielded a `T` instead of a
+    /// `Option<T>`. Any `None` value will stop the inner iterator and
+    /// the overall result will be a `None`.
+    pub fn process<F, U>(iter: I, mut f: F) -> Option<U>
+    where
+        F: FnMut(&mut Self) -> U,
+    {
+        let mut shunt = OptionShunt::new(iter);
+        let value = f(shunt.by_ref());
+        shunt.reconstruct(value)
+    }
+
+    fn new(iter: I) -> Self {
+        OptionShunt {
+            iter,
+            exited_early: false,
+        }
+    }
+
+    /// Consume the adapter and rebuild a `Option` value.
+    fn reconstruct<U>(self, val: U) -> Option<U> {
+        if self.exited_early {
+            None
+        } else {
+            Some(val)
+        }
+    }
+}
+
+impl<I, T> Iterator for OptionShunt<I>
+where
+    I: Iterator<Item = Option<T>>,
+{
+    type Item = T;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        match self.iter.next() {
+            Some(Some(v)) => Some(v),
+            Some(None) => {
+                self.exited_early = true;
+                None
+            }
+            None => None,
+        }
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        if self.exited_early {
+            (0, Some(0))
+        } else {
+            let (_, upper) = self.iter.size_hint();
+            (0, upper)
+        }
+    }
+}
+
+/// An iterator adapter that produces output as long as the underlying
+/// iterator produces `Result::Ok` values.
+///
+/// If an error is encountered, the iterator stops and the error is
+/// stored. The error may be recovered later via `reconstruct`.
+pub(crate) struct ResultShunt<I, E> {
+    iter: I,
+    error: Option<E>,
+}
+
+impl<I, T, E> ResultShunt<I, E>
+    where I: Iterator<Item = Result<T, E>>
+{
+    /// Process the given iterator as if it yielded a `T` instead of a
+    /// `Result<T, _>`. Any errors will stop the inner iterator and
+    /// the overall result will be an error.
+    pub fn process<F, U>(iter: I, mut f: F) -> Result<U, E>
+        where F: FnMut(&mut Self) -> U
+    {
+        let mut shunt = ResultShunt::new(iter);
+        let value = f(shunt.by_ref());
+        shunt.reconstruct(value)
+    }
+
+    fn new(iter: I) -> Self {
+        ResultShunt {
+            iter,
+            error: None,
+        }
+    }
+
+    /// Consume the adapter and rebuild a `Result` value. This should
+    /// *always* be called, otherwise any potential error would be
+    /// lost.
+    fn reconstruct<U>(self, val: U) -> Result<U, E> {
+        match self.error {
+            None => Ok(val),
+            Some(e) => Err(e),
+        }
+    }
+}
+
+impl<I, T, E> Iterator for ResultShunt<I, E>
+    where I: Iterator<Item = Result<T, E>>
+{
+    type Item = T;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        match self.iter.next() {
+            Some(Ok(v)) => Some(v),
+            Some(Err(e)) => {
+                self.error = Some(e);
+                None
+            }
+            None => None,
+        }
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        if self.error.is_some() {
+            (0, Some(0))
+        } else {
+            let (_, upper) = self.iter.size_hint();
+            (0, upper)
+        }
+    }
+}
diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs
index 6eccb9d1ea8..4a7d7f96b9b 100644
--- a/src/libcore/iter/mod.rs
+++ b/src/libcore/iter/mod.rs
@@ -360,7 +360,7 @@ pub use self::adapters::Flatten;
 #[stable(feature = "iter_copied", since = "1.36.0")]
 pub use self::adapters::Copied;
 
-pub(crate) use self::adapters::TrustedRandomAccess;
+pub(crate) use self::adapters::{TrustedRandomAccess, OptionShunt, ResultShunt};
 
 mod range;
 mod sources;
diff --git a/src/libcore/iter/traits/accum.rs b/src/libcore/iter/traits/accum.rs
index adfb639bae3..01b64fb08ac 100644
--- a/src/libcore/iter/traits/accum.rs
+++ b/src/libcore/iter/traits/accum.rs
@@ -1,5 +1,6 @@
 use crate::ops::{Mul, Add};
 use crate::num::Wrapping;
+use crate::iter::adapters::{OptionShunt, ResultShunt};
 
 /// Trait to represent types that can be created by summing up an iterator.
 ///
@@ -114,74 +115,6 @@ macro_rules! float_sum_product {
 integer_sum_product! { i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize }
 float_sum_product! { f32 f64 }
 
-/// An iterator adapter that produces output as long as the underlying
-/// iterator produces `Result::Ok` values.
-///
-/// If an error is encountered, the iterator stops and the error is
-/// stored. The error may be recovered later via `reconstruct`.
-struct ResultShunt<I, E> {
-    iter: I,
-    error: Option<E>,
-}
-
-impl<I, T, E> ResultShunt<I, E>
-    where I: Iterator<Item = Result<T, E>>
-{
-    /// Process the given iterator as if it yielded a `T` instead of a
-    /// `Result<T, _>`. Any errors will stop the inner iterator and
-    /// the overall result will be an error.
-    pub fn process<F, U>(iter: I, mut f: F) -> Result<U, E>
-        where F: FnMut(&mut Self) -> U
-    {
-        let mut shunt = ResultShunt::new(iter);
-        let value = f(shunt.by_ref());
-        shunt.reconstruct(value)
-    }
-
-    fn new(iter: I) -> Self {
-        ResultShunt {
-            iter,
-            error: None,
-        }
-    }
-
-    /// Consume the adapter and rebuild a `Result` value. This should
-    /// *always* be called, otherwise any potential error would be
-    /// lost.
-    fn reconstruct<U>(self, val: U) -> Result<U, E> {
-        match self.error {
-            None => Ok(val),
-            Some(e) => Err(e),
-        }
-    }
-}
-
-impl<I, T, E> Iterator for ResultShunt<I, E>
-    where I: Iterator<Item = Result<T, E>>
-{
-    type Item = T;
-
-    fn next(&mut self) -> Option<Self::Item> {
-        match self.iter.next() {
-            Some(Ok(v)) => Some(v),
-            Some(Err(e)) => {
-                self.error = Some(e);
-                None
-            }
-            None => None,
-        }
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        if self.error.is_some() {
-            (0, Some(0))
-        } else {
-            let (_, upper) = self.iter.size_hint();
-            (0, upper)
-        }
-    }
-}
-
 #[stable(feature = "iter_arith_traits_result", since="1.16.0")]
 impl<T, U, E> Sum<Result<U, E>> for Result<T, E>
     where T: Sum<U>,
@@ -224,73 +157,6 @@ impl<T, U, E> Product<Result<U, E>> for Result<T, E>
     }
 }
 
-/// An iterator adapter that produces output as long as the underlying
-/// iterator produces `Option::Some` values.
-struct OptionShunt<I> {
-    iter: I,
-    exited_early: bool,
-}
-
-impl<I, T> OptionShunt<I>
-where
-    I: Iterator<Item = Option<T>>,
-{
-    /// Process the given iterator as if it yielded a `T` instead of a
-    /// `Option<T>`. Any `None` value will stop the inner iterator and
-    /// the overall result will be a `None`.
-    pub fn process<F, U>(iter: I, mut f: F) -> Option<U>
-    where
-        F: FnMut(&mut Self) -> U,
-    {
-        let mut shunt = OptionShunt::new(iter);
-        let value = f(shunt.by_ref());
-        shunt.reconstruct(value)
-    }
-
-    fn new(iter: I) -> Self {
-        OptionShunt {
-            iter,
-            exited_early: false,
-        }
-    }
-
-    /// Consume the adapter and rebuild a `Option` value.
-    fn reconstruct<U>(self, val: U) -> Option<U> {
-        if self.exited_early {
-            None
-        } else {
-            Some(val)
-        }
-    }
-}
-
-impl<I, T> Iterator for OptionShunt<I>
-where
-    I: Iterator<Item = Option<T>>,
-{
-    type Item = T;
-
-    fn next(&mut self) -> Option<Self::Item> {
-        match self.iter.next() {
-            Some(Some(v)) => Some(v),
-            Some(None) => {
-                self.exited_early = true;
-                None
-            }
-            None => None,
-        }
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        if self.exited_early {
-            (0, Some(0))
-        } else {
-            let (_, upper) = self.iter.size_hint();
-            (0, upper)
-        }
-    }
-}
-
 #[stable(feature = "iter_arith_traits_option", since = "1.37.0")]
 impl<T, U> Sum<Option<U>> for Option<T>
 where
diff --git a/src/libcore/option.rs b/src/libcore/option.rs
index abc8883d398..70a87cfe5a7 100644
--- a/src/libcore/option.rs
+++ b/src/libcore/option.rs
@@ -135,7 +135,7 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
-use crate::iter::{FromIterator, FusedIterator, TrustedLen};
+use crate::iter::{FromIterator, FusedIterator, TrustedLen, OptionShunt};
 use crate::{convert, fmt, hint, mem, ops::{self, Deref, DerefMut}};
 use crate::pin::Pin;
 
@@ -1499,45 +1499,7 @@ impl<A, V: FromIterator<A>> FromIterator<Option<A>> for Option<V> {
         // FIXME(#11084): This could be replaced with Iterator::scan when this
         // performance bug is closed.
 
-        struct Adapter<Iter> {
-            iter: Iter,
-            found_none: bool,
-        }
-
-        impl<T, Iter: Iterator<Item=Option<T>>> Iterator for Adapter<Iter> {
-            type Item = T;
-
-            #[inline]
-            fn next(&mut self) -> Option<T> {
-                match self.iter.next() {
-                    Some(Some(value)) => Some(value),
-                    Some(None) => {
-                        self.found_none = true;
-                        None
-                    }
-                    None => None,
-                }
-            }
-
-            #[inline]
-            fn size_hint(&self) -> (usize, Option<usize>) {
-                if self.found_none {
-                    (0, Some(0))
-                } else {
-                    let (_, upper) = self.iter.size_hint();
-                    (0, upper)
-                }
-            }
-        }
-
-        let mut adapter = Adapter { iter: iter.into_iter(), found_none: false };
-        let v: V = FromIterator::from_iter(adapter.by_ref());
-
-        if adapter.found_none {
-            None
-        } else {
-            Some(v)
-        }
+        OptionShunt::process(iter.into_iter(), |i| i.collect())
     }
 }
 
diff --git a/src/libcore/result.rs b/src/libcore/result.rs
index cb6bc058730..559877ddd5a 100644
--- a/src/libcore/result.rs
+++ b/src/libcore/result.rs
@@ -231,7 +231,7 @@
 #![stable(feature = "rust1", since = "1.0.0")]
 
 use crate::fmt;
-use crate::iter::{FromIterator, FusedIterator, TrustedLen};
+use crate::iter::{FromIterator, FusedIterator, TrustedLen, ResultShunt};
 use crate::ops::{self, Deref, DerefMut};
 
 /// `Result` is a type that represents either success ([`Ok`]) or failure ([`Err`]).
@@ -1343,39 +1343,7 @@ impl<A, E, V: FromIterator<A>> FromIterator<Result<A, E>> for Result<V, E> {
         // FIXME(#11084): This could be replaced with Iterator::scan when this
         // performance bug is closed.
 
-        struct Adapter<Iter, E> {
-            iter: Iter,
-            err: Option<E>,
-        }
-
-        impl<T, E, Iter: Iterator<Item=Result<T, E>>> Iterator for Adapter<Iter, E> {
-            type Item = T;
-
-            #[inline]
-            fn next(&mut self) -> Option<T> {
-                match self.iter.next() {
-                    Some(Ok(value)) => Some(value),
-                    Some(Err(err)) => {
-                        self.err = Some(err);
-                        None
-                    }
-                    None => None,
-                }
-            }
-
-            fn size_hint(&self) -> (usize, Option<usize>) {
-                let (_min, max) = self.iter.size_hint();
-                (0, max)
-            }
-        }
-
-        let mut adapter = Adapter { iter: iter.into_iter(), err: None };
-        let v: V = FromIterator::from_iter(adapter.by_ref());
-
-        match adapter.err {
-            Some(err) => Err(err),
-            None => Ok(v),
-        }
+        ResultShunt::process(iter.into_iter(), |i| i.collect())
     }
 }
 
diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs
index e7b820e79e5..b06511cad97 100644
--- a/src/libcore/slice/mod.rs
+++ b/src/libcore/slice/mod.rs
@@ -4339,6 +4339,25 @@ impl<'a, T> DoubleEndedIterator for ChunksMut<'a, T> {
             Some(tail)
         }
     }
+
+    #[inline]
+    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
+        let len = self.len();
+        if n >= len {
+            self.v = &mut [];
+            None
+        } else {
+            let start = (len - 1 - n) * self.chunk_size;
+            let end = match start.checked_add(self.chunk_size) {
+                Some(res) => cmp::min(res, self.v.len()),
+                None => self.v.len(),
+            };
+            let (temp, _tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end);
+            let (head, nth_back) = temp.split_at_mut(start);
+            self.v = head;
+            Some(nth_back)
+        }
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/src/libcore/tests/slice.rs b/src/libcore/tests/slice.rs
index 42ec9d451f7..b046c3ce5ce 100644
--- a/src/libcore/tests/slice.rs
+++ b/src/libcore/tests/slice.rs
@@ -223,6 +223,28 @@ fn test_chunks_mut_nth() {
 }
 
 #[test]
+fn test_chunks_mut_nth_back() {
+    let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
+    let mut c = v.chunks_mut(2);
+    assert_eq!(c.nth_back(1).unwrap(), &[2, 3]);
+    assert_eq!(c.next().unwrap(), &[0, 1]);
+
+    let v1: &mut [i32] = &mut [0, 1, 2, 3, 4];
+    let mut c1 = v1.chunks_mut(3);
+    assert_eq!(c1.nth_back(1).unwrap(), &[0, 1, 2]);
+    assert_eq!(c1.next(), None);
+
+    let v3: &mut [i32] = &mut [0, 1, 2, 3, 4];
+    let mut c3 = v3.chunks_mut(10);
+    assert_eq!(c3.nth_back(0).unwrap(), &[0, 1, 2, 3, 4]);
+    assert_eq!(c3.next(), None);
+
+    let v4: &mut [i32] = &mut [0, 1, 2];
+    let mut c4 = v4.chunks_mut(10);
+    assert_eq!(c4.nth_back(1_000_000_000usize), None);
+}
+
+#[test]
 fn test_chunks_mut_last() {
     let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
     let c = v.chunks_mut(2);
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 639994ed14d..eb0ea9e08a4 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -63,7 +63,6 @@ use syntax::errors;
 use syntax::ext::hygiene::ExpnId;
 use syntax::print::pprust;
 use syntax::source_map::{respan, ExpnInfo, ExpnKind, DesugaringKind, Spanned};
-use syntax::std_inject;
 use syntax::symbol::{kw, sym, Symbol};
 use syntax::tokenstream::{TokenStream, TokenTree};
 use syntax::parse::token::{self, Token};
@@ -241,7 +240,7 @@ pub fn lower_crate(
     dep_graph.assert_ignored();
 
     LoweringContext {
-        crate_root: std_inject::injected_crate_name().map(Symbol::intern),
+        crate_root: sess.parse_sess.injected_crate_name.try_get().copied(),
         sess,
         cstore,
         resolver,
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index abb896a7c9b..e2b1b54cef3 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -2146,48 +2146,77 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
         // First (determined here), if `self` is by-reference, then the
         // implied output region is the region of the self parameter.
         if has_self {
-            // Look for `self: &'a Self` - also desugared from `&'a self`,
-            // and if that matches, use it for elision and return early.
-            let is_self_ty = |res: Res| {
-                if let Res::SelfTy(..) = res {
-                    return true;
-                }
-
-                // Can't always rely on literal (or implied) `Self` due
-                // to the way elision rules were originally specified.
-                let impl_self = impl_self.map(|ty| &ty.node);
-                if let Some(&hir::TyKind::Path(hir::QPath::Resolved(None, ref path))) = impl_self {
-                    match path.res {
-                        // Whitelist the types that unambiguously always
-                        // result in the same type constructor being used
-                        // (it can't differ between `Self` and `self`).
-                        Res::Def(DefKind::Struct, _)
-                        | Res::Def(DefKind::Union, _)
-                        | Res::Def(DefKind::Enum, _)
-                        | Res::PrimTy(_) => {
-                            return res == path.res
+            struct SelfVisitor<'a> {
+                map: &'a NamedRegionMap,
+                impl_self: Option<&'a hir::TyKind>,
+                lifetime: Set1<Region>,
+            }
+
+            impl SelfVisitor<'_> {
+                // Look for `self: &'a Self` - also desugared from `&'a self`,
+                // and if that matches, use it for elision and return early.
+                fn is_self_ty(&self, res: Res) -> bool {
+                    if let Res::SelfTy(..) = res {
+                        return true;
+                    }
+
+                    // Can't always rely on literal (or implied) `Self` due
+                    // to the way elision rules were originally specified.
+                    if let Some(&hir::TyKind::Path(hir::QPath::Resolved(None, ref path))) =
+                        self.impl_self
+                    {
+                        match path.res {
+                            // Whitelist the types that unambiguously always
+                            // result in the same type constructor being used
+                            // (it can't differ between `Self` and `self`).
+                            Res::Def(DefKind::Struct, _)
+                            | Res::Def(DefKind::Union, _)
+                            | Res::Def(DefKind::Enum, _)
+                            | Res::PrimTy(_) => {
+                                return res == path.res
+                            }
+                            _ => {}
                         }
-                        _ => {}
                     }
+
+                    false
                 }
+            }
 
-                false
-            };
+            impl<'a> Visitor<'a> for SelfVisitor<'a> {
+                fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'a> {
+                    NestedVisitorMap::None
+                }
 
-            if let hir::TyKind::Rptr(lifetime_ref, ref mt) = inputs[0].node {
-                if let hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) = mt.ty.node {
-                    if is_self_ty(path.res) {
-                        if let Some(&lifetime) = self.map.defs.get(&lifetime_ref.hir_id) {
-                            let scope = Scope::Elision {
-                                elide: Elide::Exact(lifetime),
-                                s: self.scope,
-                            };
-                            self.with(scope, |_, this| this.visit_ty(output));
-                            return;
+                fn visit_ty(&mut self, ty: &'a hir::Ty) {
+                    if let hir::TyKind::Rptr(lifetime_ref, ref mt) = ty.node {
+                        if let hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) = mt.ty.node
+                        {
+                            if self.is_self_ty(path.res) {
+                                if let Some(lifetime) = self.map.defs.get(&lifetime_ref.hir_id) {
+                                    self.lifetime.insert(*lifetime);
+                                }
+                            }
                         }
                     }
+                    intravisit::walk_ty(self, ty)
                 }
             }
+
+            let mut visitor = SelfVisitor {
+                map: self.map,
+                impl_self: impl_self.map(|ty| &ty.node),
+                lifetime: Set1::Empty,
+            };
+            visitor.visit_ty(&inputs[0]);
+            if let Set1::One(lifetime) = visitor.lifetime {
+                let scope = Scope::Elision {
+                    elide: Elide::Exact(lifetime),
+                    s: self.scope,
+                };
+                self.with(scope, |_, this| this.visit_ty(output));
+                return;
+            }
         }
 
         // Second, if there was exactly one lifetime (either a substitution or a
diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml
index e8c9828a202..42aa8203cba 100644
--- a/src/librustc_driver/Cargo.toml
+++ b/src/librustc_driver/Cargo.toml
@@ -10,30 +10,19 @@ path = "lib.rs"
 crate-type = ["dylib"]
 
 [dependencies]
-arena = { path = "../libarena" }
 graphviz = { path = "../libgraphviz" }
 log = "0.4"
 env_logger = { version = "0.5", default-features = false }
-rayon = { version = "0.2.0", package = "rustc-rayon" }
 rustc = { path = "../librustc" }
 rustc_target = { path = "../librustc_target" }
 rustc_ast_borrowck = { path = "../librustc_ast_borrowck" }
 rustc_data_structures = { path = "../librustc_data_structures" }
 errors = { path = "../librustc_errors", package = "rustc_errors" }
-rustc_incremental = { path = "../librustc_incremental" }
-rustc_lint = { path = "../librustc_lint" }
 rustc_metadata = { path = "../librustc_metadata" }
 rustc_mir = { path = "../librustc_mir" }
-rustc_passes = { path = "../librustc_passes" }
-rustc_plugin = { path = "../librustc_plugin" }
-rustc_privacy = { path = "../librustc_privacy" }
-rustc_resolve = { path = "../librustc_resolve" }
 rustc_save_analysis = { path = "../librustc_save_analysis" }
-rustc_traits = { path = "../librustc_traits" }
 rustc_codegen_utils = { path = "../librustc_codegen_utils" }
-rustc_typeck = { path = "../librustc_typeck" }
 rustc_interface = { path = "../librustc_interface" }
 rustc_serialize = { path = "../libserialize", package = "serialize" }
 syntax = { path = "../libsyntax" }
-smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }
 syntax_pos = { path = "../libsyntax_pos" }
diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs
index 2754c55ea06..3c7d854b36b 100644
--- a/src/librustc_interface/passes.rs
+++ b/src/librustc_interface/passes.rs
@@ -278,7 +278,12 @@ pub fn register_plugins<'a>(
 
     krate = time(sess, "crate injection", || {
         let alt_std_name = sess.opts.alt_std_name.as_ref().map(|s| &**s);
-        syntax::std_inject::maybe_inject_crates_ref(krate, alt_std_name, sess.edition())
+        let (krate, name) =
+            syntax_ext::standard_library_imports::inject(krate, alt_std_name, sess.edition());
+        if let Some(name) = name {
+            sess.parse_sess.injected_crate_name.set(name);
+        }
+        krate
     });
 
     let registrars = time(sess, "plugin loading", || {
@@ -456,7 +461,7 @@ fn configure_and_expand_inner<'a>(
     sess.profiler(|p| p.end_activity("macro expansion"));
 
     time(sess, "maybe building test harness", || {
-        syntax::test::modify_for_testing(
+        syntax_ext::test_harness::inject(
             &sess.parse_sess,
             &mut resolver,
             sess.opts.test,
@@ -485,7 +490,7 @@ fn configure_and_expand_inner<'a>(
             let num_crate_types = crate_types.len();
             let is_proc_macro_crate = crate_types.contains(&config::CrateType::ProcMacro);
             let is_test_crate = sess.opts.test;
-            syntax_ext::proc_macro_decls::modify(
+            syntax_ext::proc_macro_harness::inject(
                 &sess.parse_sess,
                 &mut resolver,
                 krate,
diff --git a/src/librustc_metadata/Cargo.toml b/src/librustc_metadata/Cargo.toml
index a9f054d5e8b..5ff60a9267b 100644
--- a/src/librustc_metadata/Cargo.toml
+++ b/src/librustc_metadata/Cargo.toml
@@ -21,5 +21,4 @@ rustc_target = { path = "../librustc_target" }
 rustc_serialize = { path = "../libserialize", package = "serialize" }
 stable_deref_trait = "1.0.0"
 syntax = { path = "../libsyntax" }
-syntax_ext = { path = "../libsyntax_ext" }
 syntax_pos = { path = "../libsyntax_pos" }
diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs
index 3404ec5e173..d5f1e715186 100644
--- a/src/librustc_metadata/creader.rs
+++ b/src/librustc_metadata/creader.rs
@@ -586,8 +586,7 @@ impl<'a> CrateLoader<'a> {
         use std::{env, mem};
         use crate::dynamic_lib::DynamicLibrary;
         use proc_macro::bridge::client::ProcMacro;
-        use syntax_ext::deriving::custom::ProcMacroDerive;
-        use syntax_ext::proc_macro_impl::{AttrProcMacro, BangProcMacro};
+        use syntax::ext::proc_macro::{BangProcMacro, AttrProcMacro, ProcMacroDerive};
 
         let path = match dylib {
             Some(dylib) => dylib,
diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs
index 914084d7e9e..ee1175e798d 100644
--- a/src/librustc_metadata/cstore_impl.rs
+++ b/src/librustc_metadata/cstore_impl.rs
@@ -31,10 +31,10 @@ use syntax::attr;
 use syntax::source_map;
 use syntax::edition::Edition;
 use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind};
+use syntax::ext::proc_macro::BangProcMacro;
 use syntax::parse::source_file_to_stream;
 use syntax::parse::parser::emit_unclosed_delims;
 use syntax::symbol::{Symbol, sym};
-use syntax_ext::proc_macro_impl::BangProcMacro;
 use syntax_pos::{Span, NO_EXPANSION, FileName};
 use rustc_data_structures::bit_set::BitSet;
 
diff --git a/src/librustc_passes/Cargo.toml b/src/librustc_passes/Cargo.toml
index de2476775b0..596ec6c19bc 100644
--- a/src/librustc_passes/Cargo.toml
+++ b/src/librustc_passes/Cargo.toml
@@ -11,9 +11,7 @@ path = "lib.rs"
 [dependencies]
 log = "0.4"
 rustc = { path = "../librustc" }
-rustc_mir = { path = "../librustc_mir"}
 rustc_data_structures = { path = "../librustc_data_structures" }
 syntax = { path = "../libsyntax" }
-syntax_ext = { path = "../libsyntax_ext" }
 syntax_pos = { path = "../libsyntax_pos" }
 errors = { path = "../librustc_errors", package = "rustc_errors" }
diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs
index b550029d978..562865ef55f 100644
--- a/src/librustc_passes/ast_validation.rs
+++ b/src/librustc_passes/ast_validation.rs
@@ -14,12 +14,12 @@ use rustc::session::Session;
 use rustc_data_structures::fx::FxHashMap;
 use syntax::ast::*;
 use syntax::attr;
+use syntax::ext::proc_macro::is_proc_macro_attr;
 use syntax::feature_gate::is_builtin_attr;
 use syntax::source_map::Spanned;
 use syntax::symbol::{kw, sym};
 use syntax::visit::{self, Visitor};
 use syntax::{span_err, struct_span_err, walk_list};
-use syntax_ext::proc_macro_decls::is_proc_macro_attr;
 use syntax_pos::{Span, MultiSpan};
 use errors::{Applicability, FatalError};
 
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index f52f7d9cfb3..41349cf72a1 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -34,7 +34,6 @@ use syntax::ext::hygiene::ExpnId;
 use syntax::feature_gate::is_builtin_attr;
 use syntax::parse::token::{self, Token};
 use syntax::span_err;
-use syntax::std_inject::injected_crate_name;
 use syntax::symbol::{kw, sym};
 use syntax::visit::{self, Visitor};
 
@@ -367,8 +366,10 @@ impl<'a> Resolver<'a> {
                 };
 
                 self.populate_module_if_necessary(module);
-                if injected_crate_name().map_or(false, |name| ident.name.as_str() == name) {
-                    self.injected_crate = Some(module);
+                if let Some(name) = self.session.parse_sess.injected_crate_name.try_get() {
+                    if name.as_str() == ident.name.as_str() {
+                        self.injected_crate = Some(module);
+                    }
                 }
 
                 let used = self.process_legacy_macro_imports(item, module, &parent_scope);
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index 0ab14bee160..bb7834a133f 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -1,6 +1,6 @@
 use crate::ast::{self, Attribute, Name, PatKind};
 use crate::attr::{HasAttrs, Stability, Deprecation};
-use crate::source_map::{SourceMap, Spanned, FileName, respan};
+use crate::source_map::{SourceMap, Spanned, respan};
 use crate::edition::Edition;
 use crate::ext::expand::{self, AstFragment, Invocation};
 use crate::ext::hygiene::{ExpnId, SyntaxContext, Transparency};
@@ -14,7 +14,7 @@ use crate::tokenstream::{self, TokenStream, TokenTree};
 
 use errors::{DiagnosticBuilder, DiagnosticId};
 use smallvec::{smallvec, SmallVec};
-use syntax_pos::{Span, MultiSpan, DUMMY_SP};
+use syntax_pos::{FileName, Span, MultiSpan, DUMMY_SP};
 use syntax_pos::hygiene::{ExpnInfo, ExpnKind};
 
 use rustc_data_structures::fx::FxHashMap;
diff --git a/src/libsyntax/ext/derive.rs b/src/libsyntax/ext/derive.rs
deleted file mode 100644
index ff9ad46deec..00000000000
--- a/src/libsyntax/ext/derive.rs
+++ /dev/null
@@ -1,72 +0,0 @@
-use crate::attr::HasAttrs;
-use crate::ast;
-use crate::source_map::{ExpnInfo, ExpnKind};
-use crate::ext::base::{ExtCtxt, MacroKind};
-use crate::ext::build::AstBuilder;
-use crate::parse::parser::PathStyle;
-use crate::symbol::{Symbol, sym};
-use crate::errors::Applicability;
-
-use syntax_pos::Span;
-use rustc_data_structures::fx::FxHashSet;
-
-pub fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec<ast::Attribute>) -> Vec<ast::Path> {
-    let mut result = Vec::new();
-    attrs.retain(|attr| {
-        if attr.path != sym::derive {
-            return true;
-        }
-        if !attr.is_meta_item_list() {
-            cx.struct_span_err(attr.span, "malformed `derive` attribute input")
-                .span_suggestion(
-                    attr.span,
-                    "missing traits to be derived",
-                    "#[derive(Trait1, Trait2, ...)]".to_owned(),
-                    Applicability::HasPlaceholders,
-                ).emit();
-            return false;
-        }
-
-        match attr.parse_list(cx.parse_sess,
-                              |parser| parser.parse_path_allowing_meta(PathStyle::Mod)) {
-            Ok(traits) => {
-                result.extend(traits);
-                true
-            }
-            Err(mut e) => {
-                e.emit();
-                false
-            }
-        }
-    });
-    result
-}
-
-pub fn add_derived_markers<T>(cx: &mut ExtCtxt<'_>, span: Span, traits: &[ast::Path], item: &mut T)
-    where T: HasAttrs,
-{
-    let (mut names, mut pretty_name) = (FxHashSet::default(), String::new());
-    for (i, path) in traits.iter().enumerate() {
-        if i > 0 {
-            pretty_name.push_str(", ");
-        }
-        pretty_name.push_str(&path.to_string());
-        names.insert(unwrap_or!(path.segments.get(0), continue).ident.name);
-    }
-
-    let span = span.fresh_expansion(cx.current_expansion.id, ExpnInfo::allow_unstable(
-        ExpnKind::Macro(MacroKind::Derive, Symbol::intern(&pretty_name)), span,
-        cx.parse_sess.edition, cx.allow_derive_markers.clone(),
-    ));
-
-    item.visit_attrs(|attrs| {
-        if names.contains(&sym::Eq) && names.contains(&sym::PartialEq) {
-            let meta = cx.meta_word(span, sym::structural_match);
-            attrs.push(cx.attribute(span, meta));
-        }
-        if names.contains(&sym::Copy) {
-            let meta = cx.meta_word(span, sym::rustc_copy_clone_marker);
-            attrs.push(cx.attribute(span, meta));
-        }
-    });
-}
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 640daaccc3a..cd602d08c5b 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -4,7 +4,7 @@ use crate::attr::{self, HasAttrs};
 use crate::source_map::{dummy_spanned, respan};
 use crate::config::StripUnconfigured;
 use crate::ext::base::*;
-use crate::ext::derive::{add_derived_markers, collect_derives};
+use crate::ext::proc_macro::{add_derived_markers, collect_derives};
 use crate::ext::hygiene::{ExpnId, SyntaxContext, ExpnInfo, ExpnKind};
 use crate::ext::placeholders::{placeholder, PlaceholderExpander};
 use crate::feature_gate::{self, Features, GateIssue, is_builtin_attr, emit_feature_err};
diff --git a/src/libsyntax/ext/proc_macro.rs b/src/libsyntax/ext/proc_macro.rs
new file mode 100644
index 00000000000..425b9813f59
--- /dev/null
+++ b/src/libsyntax/ext/proc_macro.rs
@@ -0,0 +1,249 @@
+use crate::ast::{self, ItemKind, Attribute, Mac};
+use crate::attr::{mark_used, mark_known, HasAttrs};
+use crate::errors::{Applicability, FatalError};
+use crate::ext::base::{self, *};
+use crate::ext::build::AstBuilder;
+use crate::ext::proc_macro_server;
+use crate::parse::{self, token};
+use crate::parse::parser::PathStyle;
+use crate::symbol::{sym, Symbol};
+use crate::tokenstream::{self, TokenStream};
+use crate::visit::Visitor;
+
+use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::sync::Lrc;
+use syntax_pos::hygiene::{ExpnInfo, ExpnKind};
+use syntax_pos::{Span, DUMMY_SP};
+
+const EXEC_STRATEGY: proc_macro::bridge::server::SameThread =
+    proc_macro::bridge::server::SameThread;
+
+pub struct BangProcMacro {
+    pub client: proc_macro::bridge::client::Client<
+        fn(proc_macro::TokenStream) -> proc_macro::TokenStream,
+    >,
+}
+
+impl base::ProcMacro for BangProcMacro {
+    fn expand<'cx>(&self,
+                   ecx: &'cx mut ExtCtxt<'_>,
+                   span: Span,
+                   input: TokenStream)
+                   -> TokenStream {
+        let server = proc_macro_server::Rustc::new(ecx);
+        match self.client.run(&EXEC_STRATEGY, server, input) {
+            Ok(stream) => stream,
+            Err(e) => {
+                let msg = "proc macro panicked";
+                let mut err = ecx.struct_span_fatal(span, msg);
+                if let Some(s) = e.as_str() {
+                    err.help(&format!("message: {}", s));
+                }
+
+                err.emit();
+                FatalError.raise();
+            }
+        }
+    }
+}
+
+pub struct AttrProcMacro {
+    pub client: proc_macro::bridge::client::Client<
+        fn(proc_macro::TokenStream, proc_macro::TokenStream) -> proc_macro::TokenStream,
+    >,
+}
+
+impl base::AttrProcMacro for AttrProcMacro {
+    fn expand<'cx>(&self,
+                   ecx: &'cx mut ExtCtxt<'_>,
+                   span: Span,
+                   annotation: TokenStream,
+                   annotated: TokenStream)
+                   -> TokenStream {
+        let server = proc_macro_server::Rustc::new(ecx);
+        match self.client.run(&EXEC_STRATEGY, server, annotation, annotated) {
+            Ok(stream) => stream,
+            Err(e) => {
+                let msg = "custom attribute panicked";
+                let mut err = ecx.struct_span_fatal(span, msg);
+                if let Some(s) = e.as_str() {
+                    err.help(&format!("message: {}", s));
+                }
+
+                err.emit();
+                FatalError.raise();
+            }
+        }
+    }
+}
+
+pub struct ProcMacroDerive {
+    pub client: proc_macro::bridge::client::Client<
+        fn(proc_macro::TokenStream) -> proc_macro::TokenStream,
+    >,
+    pub attrs: Vec<ast::Name>,
+}
+
+impl MultiItemModifier for ProcMacroDerive {
+    fn expand(&self,
+              ecx: &mut ExtCtxt<'_>,
+              span: Span,
+              _meta_item: &ast::MetaItem,
+              item: Annotatable)
+              -> Vec<Annotatable> {
+        let item = match item {
+            Annotatable::Item(item) => item,
+            Annotatable::ImplItem(_) |
+            Annotatable::TraitItem(_) |
+            Annotatable::ForeignItem(_) |
+            Annotatable::Stmt(_) |
+            Annotatable::Expr(_) => {
+                ecx.span_err(span, "proc-macro derives may only be \
+                                    applied to a struct, enum, or union");
+                return Vec::new()
+            }
+        };
+        match item.node {
+            ItemKind::Struct(..) |
+            ItemKind::Enum(..) |
+            ItemKind::Union(..) => {},
+            _ => {
+                ecx.span_err(span, "proc-macro derives may only be \
+                                    applied to a struct, enum, or union");
+                return Vec::new()
+            }
+        }
+
+        // Mark attributes as known, and used.
+        MarkAttrs(&self.attrs).visit_item(&item);
+
+        let token = token::Interpolated(Lrc::new(token::NtItem(item)));
+        let input = tokenstream::TokenTree::token(token, DUMMY_SP).into();
+
+        let server = proc_macro_server::Rustc::new(ecx);
+        let stream = match self.client.run(&EXEC_STRATEGY, server, input) {
+            Ok(stream) => stream,
+            Err(e) => {
+                let msg = "proc-macro derive panicked";
+                let mut err = ecx.struct_span_fatal(span, msg);
+                if let Some(s) = e.as_str() {
+                    err.help(&format!("message: {}", s));
+                }
+
+                err.emit();
+                FatalError.raise();
+            }
+        };
+
+        let error_count_before = ecx.parse_sess.span_diagnostic.err_count();
+        let msg = "proc-macro derive produced unparseable tokens";
+
+        let mut parser = parse::stream_to_parser(ecx.parse_sess, stream, Some("proc-macro derive"));
+        let mut items = vec![];
+
+        loop {
+            match parser.parse_item() {
+                Ok(None) => break,
+                Ok(Some(item)) => {
+                    items.push(Annotatable::Item(item))
+                }
+                Err(mut err) => {
+                    // FIXME: handle this better
+                    err.cancel();
+                    ecx.struct_span_fatal(span, msg).emit();
+                    FatalError.raise();
+                }
+            }
+        }
+
+
+        // fail if there have been errors emitted
+        if ecx.parse_sess.span_diagnostic.err_count() > error_count_before {
+            ecx.struct_span_fatal(span, msg).emit();
+            FatalError.raise();
+        }
+
+        items
+    }
+}
+
+struct MarkAttrs<'a>(&'a [ast::Name]);
+
+impl<'a> Visitor<'a> for MarkAttrs<'a> {
+    fn visit_attribute(&mut self, attr: &Attribute) {
+        if let Some(ident) = attr.ident() {
+            if self.0.contains(&ident.name) {
+                mark_used(attr);
+                mark_known(attr);
+            }
+        }
+    }
+
+    fn visit_mac(&mut self, _mac: &Mac) {}
+}
+
+pub fn is_proc_macro_attr(attr: &Attribute) -> bool {
+    [sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive]
+        .iter().any(|kind| attr.check_name(*kind))
+}
+
+crate fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec<ast::Attribute>) -> Vec<ast::Path> {
+    let mut result = Vec::new();
+    attrs.retain(|attr| {
+        if attr.path != sym::derive {
+            return true;
+        }
+        if !attr.is_meta_item_list() {
+            cx.struct_span_err(attr.span, "malformed `derive` attribute input")
+                .span_suggestion(
+                    attr.span,
+                    "missing traits to be derived",
+                    "#[derive(Trait1, Trait2, ...)]".to_owned(),
+                    Applicability::HasPlaceholders,
+                ).emit();
+            return false;
+        }
+
+        match attr.parse_list(cx.parse_sess,
+                              |parser| parser.parse_path_allowing_meta(PathStyle::Mod)) {
+            Ok(traits) => {
+                result.extend(traits);
+                true
+            }
+            Err(mut e) => {
+                e.emit();
+                false
+            }
+        }
+    });
+    result
+}
+
+crate fn add_derived_markers<T: HasAttrs>(
+    cx: &mut ExtCtxt<'_>, span: Span, traits: &[ast::Path], item: &mut T
+) {
+    let (mut names, mut pretty_name) = (FxHashSet::default(), String::new());
+    for (i, path) in traits.iter().enumerate() {
+        if i > 0 {
+            pretty_name.push_str(", ");
+        }
+        pretty_name.push_str(&path.to_string());
+        names.insert(unwrap_or!(path.segments.get(0), continue).ident.name);
+    }
+
+    let span = span.fresh_expansion(cx.current_expansion.id, ExpnInfo::allow_unstable(
+        ExpnKind::Macro(MacroKind::Derive, Symbol::intern(&pretty_name)), span,
+        cx.parse_sess.edition, cx.allow_derive_markers.clone(),
+    ));
+
+    item.visit_attrs(|attrs| {
+        if names.contains(&sym::Eq) && names.contains(&sym::PartialEq) {
+            let meta = cx.meta_word(span, sym::structural_match);
+            attrs.push(cx.attribute(span, meta));
+        }
+        if names.contains(&sym::Copy) {
+            let meta = cx.meta_word(span, sym::rustc_copy_clone_marker);
+            attrs.push(cx.attribute(span, meta));
+        }
+    });
+}
diff --git a/src/libsyntax_ext/proc_macro_server.rs b/src/libsyntax/ext/proc_macro_server.rs
index e94d79a140d..8d0023c9ab1 100644
--- a/src/libsyntax_ext/proc_macro_server.rs
+++ b/src/libsyntax/ext/proc_macro_server.rs
@@ -1,21 +1,19 @@
-use errors::{Diagnostic, DiagnosticBuilder};
-
-use std::panic;
-
-use proc_macro::bridge::{server, TokenTree};
-use proc_macro::{Delimiter, Level, LineColumn, Spacing};
+use crate::ast;
+use crate::ext::base::ExtCtxt;
+use crate::parse::{self, token, ParseSess};
+use crate::parse::lexer::comments;
+use crate::tokenstream::{self, DelimSpan, IsJoint::*, TokenStream, TreeAndJoint};
 
+use errors::{Diagnostic, DiagnosticBuilder};
 use rustc_data_structures::sync::Lrc;
-use std::ascii;
-use std::ops::Bound;
-use syntax::ast;
-use syntax::ext::base::ExtCtxt;
-use syntax::parse::lexer::comments;
-use syntax::parse::{self, token, ParseSess};
-use syntax::tokenstream::{self, DelimSpan, IsJoint::*, TokenStream, TreeAndJoint};
+use syntax_pos::{BytePos, FileName, MultiSpan, Pos, SourceFile, Span};
 use syntax_pos::hygiene::{SyntaxContext, Transparency};
 use syntax_pos::symbol::{kw, sym, Symbol};
-use syntax_pos::{BytePos, FileName, MultiSpan, Pos, SourceFile, Span};
+
+use proc_macro::{Delimiter, Level, LineColumn, Spacing};
+use proc_macro::bridge::{server, TokenTree};
+use std::{ascii, panic};
+use std::ops::Bound;
 
 trait FromInternal<T> {
     fn from_internal(x: T) -> Self;
@@ -52,7 +50,7 @@ impl FromInternal<(TreeAndJoint, &'_ ParseSess, &'_ mut Vec<Self>)>
 {
     fn from_internal(((tree, is_joint), sess, stack): (TreeAndJoint, &ParseSess, &mut Vec<Self>))
                     -> Self {
-        use syntax::parse::token::*;
+        use crate::parse::token::*;
 
         let joint = is_joint == Joint;
         let Token { kind, span } = match tree {
@@ -193,7 +191,7 @@ impl FromInternal<(TreeAndJoint, &'_ ParseSess, &'_ mut Vec<Self>)>
 
 impl ToInternal<TokenStream> for TokenTree<Group, Punct, Ident, Literal> {
     fn to_internal(self) -> TokenStream {
-        use syntax::parse::token::*;
+        use crate::parse::token::*;
 
         let (ch, joint, span) = match self {
             TokenTree::Punct(Punct { ch, joint, span }) => (ch, joint, span),
diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs
index 75b4e89ec01..bb6a8dfb141 100644
--- a/src/libsyntax/lib.rs
+++ b/src/libsyntax/lib.rs
@@ -18,12 +18,17 @@
 #![feature(label_break_value)]
 #![feature(mem_take)]
 #![feature(nll)]
+#![feature(proc_macro_diagnostic)]
+#![feature(proc_macro_internals)]
+#![feature(proc_macro_span)]
 #![feature(rustc_diagnostic_macros)]
 #![feature(try_trait)]
 #![feature(unicode_internals)]
 
 #![recursion_limit="256"]
 
+extern crate proc_macro;
+
 pub use errors;
 use rustc_data_structures::sync::Lock;
 use rustc_data_structures::bit_set::GrowableBitSet;
@@ -37,6 +42,7 @@ const MACRO_ARGUMENTS: Option<&'static str> = Some("macro arguments");
 // way towards a non-panic!-prone parser. It should be used for fatal parsing
 // errors; eventually we plan to convert all code using panictry to just use
 // normal try.
+#[macro_export]
 macro_rules! panictry {
     ($e:expr) => ({
         use std::result::Result::{Ok, Err};
@@ -147,10 +153,8 @@ pub mod mut_visit;
 pub mod parse;
 pub mod ptr;
 pub mod show_span;
-pub mod std_inject;
 pub use syntax_pos::edition;
 pub use syntax_pos::symbol;
-pub mod test;
 pub mod tokenstream;
 pub mod visit;
 
@@ -161,14 +165,15 @@ pub mod print {
 }
 
 pub mod ext {
+    mod placeholders;
+    mod proc_macro_server;
+
     pub use syntax_pos::hygiene;
     pub mod allocator;
     pub mod base;
     pub mod build;
-    pub mod derive;
     pub mod expand;
-    pub mod placeholders;
-    pub mod source_util;
+    pub mod proc_macro;
 
     pub mod tt {
         pub mod transcribe;
diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs
index 1758d0b0bb9..af484c886ab 100644
--- a/src/libsyntax/parse/attr.rs
+++ b/src/libsyntax/parse/attr.rs
@@ -4,6 +4,7 @@ use crate::parse::{SeqSep, PResult};
 use crate::parse::token::{self, Nonterminal, DelimToken};
 use crate::parse::parser::{Parser, TokenType, PathStyle};
 use crate::tokenstream::{TokenStream, TokenTree};
+use crate::source_map::Span;
 
 use log::debug;
 use smallvec::smallvec;
@@ -11,7 +12,7 @@ use smallvec::smallvec;
 #[derive(Debug)]
 enum InnerAttributeParsePolicy<'a> {
     Permitted,
-    NotPermitted { reason: &'a str },
+    NotPermitted { reason: &'a str, saw_doc_comment: bool, prev_attr_sp: Option<Span> },
 }
 
 const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG: &str = "an inner attribute is not \
@@ -42,7 +43,11 @@ impl<'a> Parser<'a> {
                         DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG
                     };
                     let inner_parse_policy =
-                        InnerAttributeParsePolicy::NotPermitted { reason: inner_error_reason };
+                        InnerAttributeParsePolicy::NotPermitted {
+                            reason: inner_error_reason,
+                            saw_doc_comment: just_parsed_doc_comment,
+                            prev_attr_sp: attrs.last().and_then(|a| Some(a.span))
+                        };
                     let attr = self.parse_attribute_with_inner_parse_policy(inner_parse_policy)?;
                     attrs.push(attr);
                     just_parsed_doc_comment = false;
@@ -76,8 +81,11 @@ impl<'a> Parser<'a> {
         let inner_parse_policy = if permit_inner {
             InnerAttributeParsePolicy::Permitted
         } else {
-            InnerAttributeParsePolicy::NotPermitted
-                { reason: DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG }
+            InnerAttributeParsePolicy::NotPermitted {
+                reason: DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG,
+                saw_doc_comment: false,
+                prev_attr_sp: None
+            }
         };
         self.parse_attribute_with_inner_parse_policy(inner_parse_policy)
     }
@@ -98,19 +106,9 @@ impl<'a> Parser<'a> {
                 if let InnerAttributeParsePolicy::Permitted = inner_parse_policy {
                     self.expected_tokens.push(TokenType::Token(token::Not));
                 }
+
                 let style = if self.token == token::Not {
                     self.bump();
-                    if let InnerAttributeParsePolicy::NotPermitted { reason } = inner_parse_policy
-                    {
-                        let span = self.token.span;
-                        self.diagnostic()
-                            .struct_span_err(span, reason)
-                            .note("inner attributes, like `#![no_std]`, annotate the item \
-                                   enclosing them, and are usually found at the beginning of \
-                                   source files. Outer attributes, like `#[test]`, annotate the \
-                                   item following them.")
-                            .emit()
-                    }
                     ast::AttrStyle::Inner
                 } else {
                     ast::AttrStyle::Outer
@@ -121,7 +119,38 @@ impl<'a> Parser<'a> {
                 self.expect(&token::CloseDelim(token::Bracket))?;
                 let hi = self.prev_span;
 
-                (lo.to(hi), path, tokens, style)
+                let attr_sp = lo.to(hi);
+
+                // Emit error if inner attribute is encountered and not permitted
+                if style == ast::AttrStyle::Inner {
+                    if let InnerAttributeParsePolicy::NotPermitted { reason,
+                        saw_doc_comment, prev_attr_sp } = inner_parse_policy {
+                        let prev_attr_note = if saw_doc_comment {
+                            "previous doc comment"
+                        } else {
+                            "previous outer attribute"
+                        };
+
+                        let mut diagnostic = self
+                            .diagnostic()
+                            .struct_span_err(attr_sp, reason);
+
+                        if let Some(prev_attr_sp) = prev_attr_sp {
+                            diagnostic
+                                .span_label(attr_sp, "not permitted following an outer attibute")
+                                .span_label(prev_attr_sp, prev_attr_note);
+                        }
+
+                        diagnostic
+                            .note("inner attributes, like `#![no_std]`, annotate the item \
+                                   enclosing them, and are usually found at the beginning of \
+                                   source files. Outer attributes, like `#[test]`, annotate the \
+                                   item following them.")
+                            .emit()
+                    }
+                }
+
+                (attr_sp, path, tokens, style)
             }
             _ => {
                 let token_str = self.this_token_to_string();
diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs
index 52f65e1b474..3cd5464f357 100644
--- a/src/libsyntax/parse/lexer/mod.rs
+++ b/src/libsyntax/parse/lexer/mod.rs
@@ -794,7 +794,7 @@ mod tests {
     use std::path::PathBuf;
     use syntax_pos::{BytePos, Span, NO_EXPANSION, edition::Edition};
     use rustc_data_structures::fx::{FxHashSet, FxHashMap};
-    use rustc_data_structures::sync::Lock;
+    use rustc_data_structures::sync::{Lock, Once};
 
     fn mk_sess(sm: Lrc<SourceMap>) -> ParseSess {
         let emitter = errors::emitter::EmitterWriter::new(Box::new(io::sink()),
@@ -817,6 +817,7 @@ mod tests {
             param_attr_spans: Lock::new(Vec::new()),
             let_chains_spans: Lock::new(Vec::new()),
             async_closure_spans: Lock::new(Vec::new()),
+            injected_crate_name: Once::new(),
         }
     }
 
diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs
index 225065c1cf1..1aac8bbb7aa 100644
--- a/src/libsyntax/parse/mod.rs
+++ b/src/libsyntax/parse/mod.rs
@@ -10,9 +10,10 @@ use crate::parse::token::TokenKind;
 use crate::tokenstream::{TokenStream, TokenTree};
 use crate::diagnostics::plugin::ErrorMap;
 use crate::print::pprust;
+use crate::symbol::Symbol;
 
 use errors::{Applicability, FatalError, Level, Handler, ColorConfig, Diagnostic, DiagnosticBuilder};
-use rustc_data_structures::sync::{Lrc, Lock};
+use rustc_data_structures::sync::{Lrc, Lock, Once};
 use syntax_pos::{Span, SourceFile, FileName, MultiSpan};
 use syntax_pos::edition::Edition;
 
@@ -58,6 +59,7 @@ pub struct ParseSess {
     pub let_chains_spans: Lock<Vec<Span>>,
     // Places where `async || ..` exprs were used and should be feature gated.
     pub async_closure_spans: Lock<Vec<Span>>,
+    pub injected_crate_name: Once<Symbol>,
 }
 
 impl ParseSess {
@@ -86,6 +88,7 @@ impl ParseSess {
             param_attr_spans: Lock::new(Vec::new()),
             let_chains_spans: Lock::new(Vec::new()),
             async_closure_spans: Lock::new(Vec::new()),
+            injected_crate_name: Once::new(),
         }
     }
 
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 16e0bace925..c4623576395 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -10,7 +10,6 @@ use crate::parse::{self, ParseSess};
 use crate::print::pp::{self, Breaks};
 use crate::print::pp::Breaks::{Consistent, Inconsistent};
 use crate::ptr::P;
-use crate::std_inject;
 use crate::symbol::{kw, sym};
 use crate::tokenstream::{self, TokenStream, TokenTree};
 
@@ -114,7 +113,7 @@ pub fn print_crate<'a>(cm: &'a SourceMap,
         is_expanded,
     };
 
-    if is_expanded && std_inject::injected_crate_name().is_some() {
+    if is_expanded && sess.injected_crate_name.try_get().is_some() {
         // We need to print `#![no_std]` (and its feature gate) so that
         // compiling pretty-printed source won't inject libstd again.
         // However we don't want these attributes in the AST because
diff --git a/src/libsyntax_ext/Cargo.toml b/src/libsyntax_ext/Cargo.toml
index eafbe6371a3..73310df305b 100644
--- a/src/libsyntax_ext/Cargo.toml
+++ b/src/libsyntax_ext/Cargo.toml
@@ -10,11 +10,11 @@ path = "lib.rs"
 doctest = false
 
 [dependencies]
-fmt_macros = { path = "../libfmt_macros" }
 errors = { path = "../librustc_errors", package = "rustc_errors" }
-syntax = { path = "../libsyntax" }
-syntax_pos = { path = "../libsyntax_pos" }
+fmt_macros = { path = "../libfmt_macros" }
+log = "0.4"
 rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_target = { path = "../librustc_target" }
 smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }
-log = "0.4"
+syntax = { path = "../libsyntax" }
+syntax_pos = { path = "../libsyntax_pos" }
diff --git a/src/libsyntax_ext/deriving/custom.rs b/src/libsyntax_ext/deriving/custom.rs
deleted file mode 100644
index 98465d75e46..00000000000
--- a/src/libsyntax_ext/deriving/custom.rs
+++ /dev/null
@@ -1,119 +0,0 @@
-use crate::proc_macro_impl::EXEC_STRATEGY;
-use crate::proc_macro_server;
-
-use errors::FatalError;
-use rustc_data_structures::sync::Lrc;
-use syntax::ast::{self, ItemKind, Attribute, Mac};
-use syntax::attr::{mark_used, mark_known};
-use syntax::source_map::Span;
-use syntax::ext::base::*;
-use syntax::parse;
-use syntax::parse::token;
-use syntax::tokenstream;
-use syntax::visit::Visitor;
-use syntax_pos::DUMMY_SP;
-
-struct MarkAttrs<'a>(&'a [ast::Name]);
-
-impl<'a> Visitor<'a> for MarkAttrs<'a> {
-    fn visit_attribute(&mut self, attr: &Attribute) {
-        if let Some(ident) = attr.ident() {
-            if self.0.contains(&ident.name) {
-                mark_used(attr);
-                mark_known(attr);
-            }
-        }
-    }
-
-    fn visit_mac(&mut self, _mac: &Mac) {}
-}
-
-pub struct ProcMacroDerive {
-    pub client: proc_macro::bridge::client::Client<
-        fn(proc_macro::TokenStream) -> proc_macro::TokenStream,
-    >,
-    pub attrs: Vec<ast::Name>,
-}
-
-impl MultiItemModifier for ProcMacroDerive {
-    fn expand(&self,
-              ecx: &mut ExtCtxt<'_>,
-              span: Span,
-              _meta_item: &ast::MetaItem,
-              item: Annotatable)
-              -> Vec<Annotatable> {
-        let item = match item {
-            Annotatable::Item(item) => item,
-            Annotatable::ImplItem(_) |
-            Annotatable::TraitItem(_) |
-            Annotatable::ForeignItem(_) |
-            Annotatable::Stmt(_) |
-            Annotatable::Expr(_) => {
-                ecx.span_err(span, "proc-macro derives may only be \
-                                    applied to a struct, enum, or union");
-                return Vec::new()
-            }
-        };
-        match item.node {
-            ItemKind::Struct(..) |
-            ItemKind::Enum(..) |
-            ItemKind::Union(..) => {},
-            _ => {
-                ecx.span_err(span, "proc-macro derives may only be \
-                                    applied to a struct, enum, or union");
-                return Vec::new()
-            }
-        }
-
-        // Mark attributes as known, and used.
-        MarkAttrs(&self.attrs).visit_item(&item);
-
-        let token = token::Interpolated(Lrc::new(token::NtItem(item)));
-        let input = tokenstream::TokenTree::token(token, DUMMY_SP).into();
-
-        let server = proc_macro_server::Rustc::new(ecx);
-        let stream = match self.client.run(&EXEC_STRATEGY, server, input) {
-            Ok(stream) => stream,
-            Err(e) => {
-                let msg = "proc-macro derive panicked";
-                let mut err = ecx.struct_span_fatal(span, msg);
-                if let Some(s) = e.as_str() {
-                    err.help(&format!("message: {}", s));
-                }
-
-                err.emit();
-                FatalError.raise();
-            }
-        };
-
-        let error_count_before = ecx.parse_sess.span_diagnostic.err_count();
-        let msg = "proc-macro derive produced unparseable tokens";
-
-        let mut parser = parse::stream_to_parser(ecx.parse_sess, stream, Some("proc-macro derive"));
-        let mut items = vec![];
-
-        loop {
-            match parser.parse_item() {
-                Ok(None) => break,
-                Ok(Some(item)) => {
-                    items.push(Annotatable::Item(item))
-                }
-                Err(mut err) => {
-                    // FIXME: handle this better
-                    err.cancel();
-                    ecx.struct_span_fatal(span, msg).emit();
-                    FatalError.raise();
-                }
-            }
-        }
-
-
-        // fail if there have been errors emitted
-        if ecx.parse_sess.span_diagnostic.err_count() > error_count_before {
-            ecx.struct_span_fatal(span, msg).emit();
-            FatalError.raise();
-        }
-
-        items
-    }
-}
diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs
index 12482f7248e..7f27769f236 100644
--- a/src/libsyntax_ext/deriving/generic/mod.rs
+++ b/src/libsyntax_ext/deriving/generic/mod.rs
@@ -1770,50 +1770,6 @@ pub fn cs_fold1<F, B>(use_foldl: bool,
     }
 }
 
-/// Call the method that is being derived on all the fields, and then
-/// process the collected results. i.e.
-///
-/// ```ignore (only-for-syntax-highlight)
-/// f(cx, span, vec![self_1.method(__arg_1_1, __arg_2_1),
-///                  self_2.method(__arg_1_2, __arg_2_2)])
-/// ```
-#[inline]
-pub fn cs_same_method<F>(f: F,
-                         mut enum_nonmatch_f: EnumNonMatchCollapsedFunc<'_>,
-                         cx: &mut ExtCtxt<'_>,
-                         trait_span: Span,
-                         substructure: &Substructure<'_>)
-                         -> P<Expr>
-    where F: FnOnce(&mut ExtCtxt<'_>, Span, Vec<P<Expr>>) -> P<Expr>
-{
-    match *substructure.fields {
-        EnumMatching(.., ref all_fields) |
-        Struct(_, ref all_fields) => {
-            // call self_n.method(other_1_n, other_2_n, ...)
-            let called = all_fields.iter()
-                .map(|field| {
-                    cx.expr_method_call(field.span,
-                                        field.self_.clone(),
-                                        substructure.method_ident,
-                                        field.other
-                                            .iter()
-                                            .map(|e| cx.expr_addr_of(field.span, e.clone()))
-                                            .collect())
-                })
-                .collect();
-
-            f(cx, trait_span, called)
-        }
-        EnumNonMatchingCollapsed(ref all_self_args, _, tuple) => {
-            enum_nonmatch_f(cx,
-                            trait_span,
-                            (&all_self_args[..], tuple),
-                            substructure.nonself_args)
-        }
-        StaticEnum(..) | StaticStruct(..) => cx.span_bug(trait_span, "static function in `derive`"),
-    }
-}
-
 /// Returns `true` if the type has no value fields
 /// (for an enum, no variant has any fields)
 pub fn is_type_without_fields(item: &Annotatable) -> bool {
diff --git a/src/libsyntax_ext/deriving/generic/ty.rs b/src/libsyntax_ext/deriving/generic/ty.rs
index fef1b4eebcf..394beb14171 100644
--- a/src/libsyntax_ext/deriving/generic/ty.rs
+++ b/src/libsyntax_ext/deriving/generic/ty.rs
@@ -18,6 +18,7 @@ pub enum PtrTy<'a> {
     /// &'lifetime mut
     Borrowed(Option<&'a str>, ast::Mutability),
     /// *mut
+    #[allow(dead_code)]
     Raw(ast::Mutability),
 }
 
@@ -107,13 +108,6 @@ pub enum Ty<'a> {
     Tuple(Vec<Ty<'a>>),
 }
 
-/// A const expression. Supports literals and blocks.
-#[derive(Clone, Eq, PartialEq)]
-pub enum Const {
-    Literal,
-    Block,
-}
-
 pub fn borrowed_ptrty<'r>() -> PtrTy<'r> {
     Borrowed(None, ast::Mutability::Immutable)
 }
diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs
index 1a865099288..cad79917af2 100644
--- a/src/libsyntax_ext/deriving/mod.rs
+++ b/src/libsyntax_ext/deriving/mod.rs
@@ -26,7 +26,6 @@ pub mod decodable;
 pub mod hash;
 pub mod debug;
 pub mod default;
-pub mod custom;
 
 #[path="cmp/partial_eq.rs"]
 pub mod partial_eq;
diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs
index 7940abed245..fae884860ed 100644
--- a/src/libsyntax_ext/lib.rs
+++ b/src/libsyntax_ext/lib.rs
@@ -1,4 +1,5 @@
-//! Syntax extensions in the Rust compiler.
+//! This crate contains implementations of built-in macros and other code generating facilities
+//! injecting code into the crate before it is lowered to HIR.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
 
@@ -7,21 +8,15 @@
 
 #![feature(crate_visibility_modifier)]
 #![feature(decl_macro)]
+#![feature(mem_take)]
 #![feature(nll)]
-#![feature(proc_macro_diagnostic)]
-#![feature(proc_macro_internals)]
-#![feature(proc_macro_span)]
 #![feature(rustc_diagnostic_macros)]
-#![feature(unicode_internals)]
-
-extern crate proc_macro;
 
 use crate::deriving::*;
 
 use syntax::ast::Ident;
 use syntax::edition::Edition;
 use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind, MacroExpanderFn};
-use syntax::ext::source_util;
 use syntax::symbol::sym;
 
 mod error_codes;
@@ -32,21 +27,21 @@ mod cfg;
 mod compile_error;
 mod concat;
 mod concat_idents;
+mod deriving;
 mod env;
 mod format;
 mod format_foreign;
 mod global_allocator;
 mod global_asm;
 mod log_syntax;
-mod proc_macro_server;
+mod source_util;
 mod test;
-mod test_case;
 mod trace_macros;
 
-pub mod deriving;
 pub mod plugin_macro_defs;
-pub mod proc_macro_decls;
-pub mod proc_macro_impl;
+pub mod proc_macro_harness;
+pub mod standard_library_imports;
+pub mod test_harness;
 
 pub fn register_builtin_macros(resolver: &mut dyn syntax::ext::base::Resolver, edition: Edition) {
     let mut register = |name, kind| resolver.register_builtin_macro(
@@ -93,7 +88,7 @@ pub fn register_builtin_macros(resolver: &mut dyn syntax::ext::base::Resolver, e
         bench: test::expand_bench,
         global_allocator: global_allocator::expand,
         test: test::expand_test,
-        test_case: test_case::expand,
+        test_case: test::expand_test_case,
     }
 
     register_derive! {
diff --git a/src/libsyntax_ext/proc_macro_decls.rs b/src/libsyntax_ext/proc_macro_harness.rs
index 303d5f00deb..fc6cd5dc94c 100644
--- a/src/libsyntax_ext/proc_macro_decls.rs
+++ b/src/libsyntax_ext/proc_macro_harness.rs
@@ -7,21 +7,15 @@ use syntax::ext::base::{ExtCtxt, MacroKind};
 use syntax::ext::build::AstBuilder;
 use syntax::ext::expand::ExpansionConfig;
 use syntax::ext::hygiene::ExpnId;
+use syntax::ext::proc_macro::is_proc_macro_attr;
 use syntax::mut_visit::MutVisitor;
 use syntax::parse::ParseSess;
 use syntax::ptr::P;
-use syntax::symbol::Symbol;
 use syntax::symbol::{kw, sym};
 use syntax::visit::{self, Visitor};
 
 use syntax_pos::{Span, DUMMY_SP};
 
-const PROC_MACRO_KINDS: [Symbol; 3] = [
-    sym::proc_macro_derive,
-    sym::proc_macro_attribute,
-    sym::proc_macro
-];
-
 struct ProcMacroDerive {
     trait_name: ast::Name,
     function_name: Ident,
@@ -44,7 +38,7 @@ struct CollectProcMacros<'a> {
     is_test_crate: bool,
 }
 
-pub fn modify(sess: &ParseSess,
+pub fn inject(sess: &ParseSess,
               resolver: &mut dyn (::syntax::ext::base::Resolver),
               mut krate: ast::Crate,
               is_proc_macro_crate: bool,
@@ -88,10 +82,6 @@ pub fn modify(sess: &ParseSess,
     krate
 }
 
-pub fn is_proc_macro_attr(attr: &ast::Attribute) -> bool {
-    PROC_MACRO_KINDS.iter().any(|kind| attr.check_name(*kind))
-}
-
 impl<'a> CollectProcMacros<'a> {
     fn check_not_pub_in_root(&self, vis: &ast::Visibility, sp: Span) {
         if self.is_proc_macro_crate && self.in_root && vis.node.is_pub() {
diff --git a/src/libsyntax_ext/proc_macro_impl.rs b/src/libsyntax_ext/proc_macro_impl.rs
deleted file mode 100644
index f0fc6392cd7..00000000000
--- a/src/libsyntax_ext/proc_macro_impl.rs
+++ /dev/null
@@ -1,68 +0,0 @@
-use crate::proc_macro_server;
-
-use errors::FatalError;
-use syntax::source_map::Span;
-use syntax::ext::base::{self, *};
-use syntax::tokenstream::TokenStream;
-
-pub const EXEC_STRATEGY: proc_macro::bridge::server::SameThread =
-    proc_macro::bridge::server::SameThread;
-
-pub struct AttrProcMacro {
-    pub client: proc_macro::bridge::client::Client<
-        fn(proc_macro::TokenStream, proc_macro::TokenStream) -> proc_macro::TokenStream,
-    >,
-}
-
-impl base::AttrProcMacro for AttrProcMacro {
-    fn expand<'cx>(&self,
-                   ecx: &'cx mut ExtCtxt<'_>,
-                   span: Span,
-                   annotation: TokenStream,
-                   annotated: TokenStream)
-                   -> TokenStream {
-        let server = proc_macro_server::Rustc::new(ecx);
-        match self.client.run(&EXEC_STRATEGY, server, annotation, annotated) {
-            Ok(stream) => stream,
-            Err(e) => {
-                let msg = "custom attribute panicked";
-                let mut err = ecx.struct_span_fatal(span, msg);
-                if let Some(s) = e.as_str() {
-                    err.help(&format!("message: {}", s));
-                }
-
-                err.emit();
-                FatalError.raise();
-            }
-        }
-    }
-}
-
-pub struct BangProcMacro {
-    pub client: proc_macro::bridge::client::Client<
-        fn(proc_macro::TokenStream) -> proc_macro::TokenStream,
-    >,
-}
-
-impl base::ProcMacro for BangProcMacro {
-    fn expand<'cx>(&self,
-                   ecx: &'cx mut ExtCtxt<'_>,
-                   span: Span,
-                   input: TokenStream)
-                   -> TokenStream {
-        let server = proc_macro_server::Rustc::new(ecx);
-        match self.client.run(&EXEC_STRATEGY, server, input) {
-            Ok(stream) => stream,
-            Err(e) => {
-                let msg = "proc macro panicked";
-                let mut err = ecx.struct_span_fatal(span, msg);
-                if let Some(s) = e.as_str() {
-                    err.help(&format!("message: {}", s));
-                }
-
-                err.emit();
-                FatalError.raise();
-            }
-        }
-    }
-}
diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax_ext/source_util.rs
index ae080c05eec..8ecfd4ddda7 100644
--- a/src/libsyntax/ext/source_util.rs
+++ b/src/libsyntax_ext/source_util.rs
@@ -1,11 +1,11 @@
-use crate::ast;
-use crate::ext::base::{self, *};
-use crate::ext::build::AstBuilder;
-use crate::parse::{self, token, DirectoryOwnership};
-use crate::print::pprust;
-use crate::ptr::P;
-use crate::symbol::Symbol;
-use crate::tokenstream;
+use syntax::{ast, panictry};
+use syntax::ext::base::{self, *};
+use syntax::ext::build::AstBuilder;
+use syntax::parse::{self, token, DirectoryOwnership};
+use syntax::print::pprust;
+use syntax::ptr::P;
+use syntax::symbol::Symbol;
+use syntax::tokenstream;
 
 use smallvec::SmallVec;
 use syntax_pos::{self, Pos, Span};
@@ -94,7 +94,7 @@ pub fn expand_include<'cx>(cx: &'cx mut ExtCtxt<'_>, sp: Span, tts: &[tokenstrea
             while self.p.token != token::Eof {
                 match panictry!(self.p.parse_item()) {
                     Some(item) => ret.push(item),
-                    None => self.p.diagnostic().span_fatal(self.p.token.span,
+                    None => self.p.sess.span_diagnostic.span_fatal(self.p.token.span,
                                                            &format!("expected item, found `{}`",
                                                                     self.p.this_token_to_string()))
                                                .raise()
diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax_ext/standard_library_imports.rs
index 3fba81c0b69..81bb32d79a2 100644
--- a/src/libsyntax/std_inject.rs
+++ b/src/libsyntax_ext/standard_library_imports.rs
@@ -1,37 +1,22 @@
-use crate::ast;
-use crate::attr;
-use crate::edition::Edition;
-use crate::ext::hygiene::{ExpnId, MacroKind};
-use crate::symbol::{Ident, Symbol, kw, sym};
-use crate::source_map::{ExpnInfo, ExpnKind, dummy_spanned, respan};
-use crate::ptr::P;
-use crate::tokenstream::TokenStream;
-
-use std::cell::Cell;
-use std::iter;
+use syntax::{ast, attr};
+use syntax::edition::Edition;
+use syntax::ext::hygiene::{ExpnId, MacroKind};
+use syntax::ptr::P;
+use syntax::source_map::{ExpnInfo, ExpnKind, dummy_spanned, respan};
+use syntax::symbol::{Ident, Symbol, kw, sym};
+use syntax::tokenstream::TokenStream;
 use syntax_pos::DUMMY_SP;
 
-pub fn injected_crate_name() -> Option<&'static str> {
-    INJECTED_CRATE_NAME.with(|name| name.get())
-}
-
-thread_local! {
-    // A `Symbol` might make more sense here, but it doesn't work, probably for
-    // reasons relating to the use of thread-local storage for the Symbol
-    // interner.
-    static INJECTED_CRATE_NAME: Cell<Option<&'static str>> = Cell::new(None);
-}
+use std::iter;
 
-pub fn maybe_inject_crates_ref(
-    mut krate: ast::Crate,
-    alt_std_name: Option<&str>,
-    edition: Edition,
-) -> ast::Crate {
+pub fn inject(
+    mut krate: ast::Crate, alt_std_name: Option<&str>, edition: Edition
+) -> (ast::Crate, Option<Symbol>) {
     let rust_2018 = edition >= Edition::Edition2018;
 
     // the first name in this list is the crate name of the crate with the prelude
     let names: &[&str] = if attr::contains_name(&krate.attrs, sym::no_core) {
-        return krate;
+        return (krate, None);
     } else if attr::contains_name(&krate.attrs, sym::no_std) {
         if attr::contains_name(&krate.attrs, sym::compiler_builtins) {
             &["core"]
@@ -73,8 +58,6 @@ pub fn maybe_inject_crates_ref(
     // the prelude.
     let name = names[0];
 
-    INJECTED_CRATE_NAME.with(|opt_name| opt_name.set(Some(name)));
-
     let span = DUMMY_SP.fresh_expansion(ExpnId::root(), ExpnInfo::allow_unstable(
         ExpnKind::Macro(MacroKind::Attr, sym::std_inject), DUMMY_SP, edition,
         [sym::prelude_import][..].into(),
@@ -108,5 +91,5 @@ pub fn maybe_inject_crates_ref(
         tokens: None,
     }));
 
-    krate
+    (krate, Some(Symbol::intern(name)))
 }
diff --git a/src/libsyntax_ext/test.rs b/src/libsyntax_ext/test.rs
index d381c42f9ce..a2d93d01cec 100644
--- a/src/libsyntax_ext/test.rs
+++ b/src/libsyntax_ext/test.rs
@@ -7,11 +7,44 @@ use syntax::ext::base::*;
 use syntax::ext::build::AstBuilder;
 use syntax::ext::hygiene::SyntaxContext;
 use syntax::print::pprust;
+use syntax::source_map::respan;
 use syntax::symbol::{Symbol, sym};
 use syntax_pos::Span;
 
 use std::iter;
 
+// #[test_case] is used by custom test authors to mark tests
+// When building for test, it needs to make the item public and gensym the name
+// Otherwise, we'll omit the item. This behavior means that any item annotated
+// with #[test_case] is never addressable.
+//
+// We mark item with an inert attribute "rustc_test_marker" which the test generation
+// logic will pick up on.
+pub fn expand_test_case(
+    ecx: &mut ExtCtxt<'_>,
+    attr_sp: Span,
+    meta_item: &ast::MetaItem,
+    anno_item: Annotatable
+) -> Vec<Annotatable> {
+    check_builtin_macro_attribute(ecx, meta_item, sym::test_case);
+
+    if !ecx.ecfg.should_test { return vec![]; }
+
+    let sp = attr_sp.with_ctxt(SyntaxContext::empty().apply_mark(ecx.current_expansion.id));
+    let mut item = anno_item.expect_item();
+    item = item.map(|mut item| {
+        item.vis = respan(item.vis.span, ast::VisibilityKind::Public);
+        item.ident = item.ident.gensym();
+        item.attrs.push(
+            ecx.attribute(sp,
+                ecx.meta_word(sp, sym::rustc_test_marker))
+        );
+        item
+    });
+
+    return vec![Annotatable::Item(item)]
+}
+
 pub fn expand_test(
     cx: &mut ExtCtxt<'_>,
     attr_sp: Span,
diff --git a/src/libsyntax_ext/test_case.rs b/src/libsyntax_ext/test_case.rs
deleted file mode 100644
index ea4a8d541ab..00000000000
--- a/src/libsyntax_ext/test_case.rs
+++ /dev/null
@@ -1,44 +0,0 @@
-// http://rust-lang.org/COPYRIGHT.
-//
-
-// #[test_case] is used by custom test authors to mark tests
-// When building for test, it needs to make the item public and gensym the name
-// Otherwise, we'll omit the item. This behavior means that any item annotated
-// with #[test_case] is never addressable.
-//
-// We mark item with an inert attribute "rustc_test_marker" which the test generation
-// logic will pick up on.
-
-use syntax::ast;
-use syntax::attr::check_builtin_macro_attribute;
-use syntax::ext::base::*;
-use syntax::ext::build::AstBuilder;
-use syntax::ext::hygiene::SyntaxContext;
-use syntax::source_map::respan;
-use syntax::symbol::sym;
-use syntax_pos::Span;
-
-pub fn expand(
-    ecx: &mut ExtCtxt<'_>,
-    attr_sp: Span,
-    meta_item: &ast::MetaItem,
-    anno_item: Annotatable
-) -> Vec<Annotatable> {
-    check_builtin_macro_attribute(ecx, meta_item, sym::test_case);
-
-    if !ecx.ecfg.should_test { return vec![]; }
-
-    let sp = attr_sp.with_ctxt(SyntaxContext::empty().apply_mark(ecx.current_expansion.id));
-    let mut item = anno_item.expect_item();
-    item = item.map(|mut item| {
-        item.vis = respan(item.vis.span, ast::VisibilityKind::Public);
-        item.ident = item.ident.gensym();
-        item.attrs.push(
-            ecx.attribute(sp,
-                ecx.meta_word(sp, sym::rustc_test_marker))
-        );
-        item
-    });
-
-    return vec![Annotatable::Item(item)]
-}
diff --git a/src/libsyntax/test.rs b/src/libsyntax_ext/test_harness.rs
index 2ada7104843..848c797856e 100644
--- a/src/libsyntax/test.rs
+++ b/src/libsyntax_ext/test_harness.rs
@@ -1,35 +1,23 @@
 // Code that generates a test runner to run all the tests in a crate
 
-#![allow(dead_code)]
-#![allow(unused_imports)]
-
-use HasTestSignature::*;
-
-use std::iter;
-use std::slice;
-use std::mem;
-use std::vec;
-
 use log::debug;
 use smallvec::{smallvec, SmallVec};
-use syntax_pos::{DUMMY_SP, NO_EXPANSION, Span, SourceFile, BytePos};
-
-use crate::attr::{self, HasAttrs};
-use crate::source_map::{self, SourceMap, ExpnInfo, ExpnKind, dummy_spanned, respan};
-use crate::config;
-use crate::entry::{self, EntryPointType};
-use crate::ext::base::{ExtCtxt, Resolver};
-use crate::ext::build::AstBuilder;
-use crate::ext::expand::ExpansionConfig;
-use crate::ext::hygiene::{self, ExpnId, SyntaxContext, MacroKind};
-use crate::mut_visit::{*, ExpectOne};
-use crate::feature_gate::Features;
-use crate::util::map_in_place::MapInPlace;
-use crate::parse::{token, ParseSess};
-use crate::ast::{self, Ident};
-use crate::ptr::P;
-use crate::symbol::{self, Symbol, kw, sym};
-use crate::ThinVec;
+use syntax::ast::{self, Ident};
+use syntax::attr;
+use syntax::entry::{self, EntryPointType};
+use syntax::ext::base::{ExtCtxt, Resolver};
+use syntax::ext::build::AstBuilder;
+use syntax::ext::expand::ExpansionConfig;
+use syntax::ext::hygiene::{ExpnId, MacroKind};
+use syntax::feature_gate::Features;
+use syntax::mut_visit::{*, ExpectOne};
+use syntax::parse::ParseSess;
+use syntax::ptr::P;
+use syntax::source_map::{ExpnInfo, ExpnKind, dummy_spanned};
+use syntax::symbol::{kw, sym, Symbol};
+use syntax_pos::{Span, DUMMY_SP};
+
+use std::{iter, mem};
 
 struct Test {
     span: Span,
@@ -42,22 +30,21 @@ struct TestCtxt<'a> {
     ext_cx: ExtCtxt<'a>,
     test_cases: Vec<Test>,
     reexport_test_harness_main: Option<Symbol>,
-    is_libtest: bool,
-    features: &'a Features,
     test_runner: Option<ast::Path>,
-
     // top-level re-export submodule, filled out after folding is finished
     toplevel_reexport: Option<Ident>,
 }
 
 // Traverse the crate, collecting all the test functions, eliding any
 // existing main functions, and synthesizing a main test harness
-pub fn modify_for_testing(sess: &ParseSess,
-                          resolver: &mut dyn Resolver,
-                          should_test: bool,
-                          krate: &mut ast::Crate,
-                          span_diagnostic: &errors::Handler,
-                          features: &Features) {
+pub fn inject(
+    sess: &ParseSess,
+    resolver: &mut dyn Resolver,
+    should_test: bool,
+    krate: &mut ast::Crate,
+    span_diagnostic: &errors::Handler,
+    features: &Features,
+) {
     // Check for #[reexport_test_harness_main = "some_name"] which
     // creates a `use __test::main as some_name;`. This needs to be
     // unconditional, so that the attribute is still marked as used in
@@ -267,11 +254,7 @@ fn generate_test_harness(sess: &ParseSess,
         path: Vec::new(),
         test_cases: Vec::new(),
         reexport_test_harness_main,
-        // N.B., doesn't consider the value of `--crate-name` passed on the command line.
-        is_libtest: attr::find_crate_name(&krate.attrs)
-            .map(|s| s == sym::test).unwrap_or(false),
         toplevel_reexport: None,
-        features,
         test_runner
     };
 
@@ -282,19 +265,6 @@ fn generate_test_harness(sess: &ParseSess,
     }.visit_crate(krate);
 }
 
-enum HasTestSignature {
-    Yes,
-    No(BadTestSignature),
-}
-
-#[derive(PartialEq)]
-enum BadTestSignature {
-    NotEvenAFunction,
-    WrongTypeSignature,
-    NoArgumentsAllowed,
-    ShouldPanicOnlyWithNoArgs,
-}
-
 /// Creates a function item for use as the main function of a test build.
 /// This function will call the `test_runner` as specified by the crate attribute
 fn mk_main(cx: &mut TestCtxt<'_>) -> P<ast::Item> {
diff --git a/src/test/ui/issues/issue-45296.stderr b/src/test/ui/issues/issue-45296.stderr
index bc14d20b623..c0d4ce1243e 100644
--- a/src/test/ui/issues/issue-45296.stderr
+++ b/src/test/ui/issues/issue-45296.stderr
@@ -1,8 +1,8 @@
 error: an inner attribute is not permitted in this context
-  --> $DIR/issue-45296.rs:4:7
+  --> $DIR/issue-45296.rs:4:5
    |
 LL |     #![allow(unused_variables)]
-   |       ^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
 
diff --git a/src/test/ui/parser/attr.stderr b/src/test/ui/parser/attr.stderr
index 5111b40603c..400a0276b3b 100644
--- a/src/test/ui/parser/attr.stderr
+++ b/src/test/ui/parser/attr.stderr
@@ -1,8 +1,8 @@
 error: an inner attribute is not permitted in this context
-  --> $DIR/attr.rs:5:3
+  --> $DIR/attr.rs:5:1
    |
 LL | #![lang = "foo"]
-   |   ^
+   | ^^^^^^^^^^^^^^^^
    |
    = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
 
diff --git a/src/test/ui/parser/inner-attr-after-doc-comment.stderr b/src/test/ui/parser/inner-attr-after-doc-comment.stderr
index 0dde49a2913..b012abc25e7 100644
--- a/src/test/ui/parser/inner-attr-after-doc-comment.stderr
+++ b/src/test/ui/parser/inner-attr-after-doc-comment.stderr
@@ -1,8 +1,13 @@
 error: an inner attribute is not permitted following an outer doc comment
-  --> $DIR/inner-attr-after-doc-comment.rs:6:3
+  --> $DIR/inner-attr-after-doc-comment.rs:6:1
    |
-LL | #![recursion_limit="100"]
-   |   ^
+LL | / /**
+LL | |  * My module
+LL | |  */
+   | |___- previous doc comment
+LL | 
+LL |   #![recursion_limit="100"]
+   |   ^^^^^^^^^^^^^^^^^^^^^^^^^ not permitted following an outer attibute
    |
    = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
 
diff --git a/src/test/ui/parser/inner-attr.stderr b/src/test/ui/parser/inner-attr.stderr
index 11a37bc139b..070d9f47d96 100644
--- a/src/test/ui/parser/inner-attr.stderr
+++ b/src/test/ui/parser/inner-attr.stderr
@@ -1,8 +1,11 @@
 error: an inner attribute is not permitted following an outer attribute
-  --> $DIR/inner-attr.rs:3:3
+  --> $DIR/inner-attr.rs:3:1
    |
+LL | #[feature(lang_items)]
+   | ---------------------- previous outer attribute
+LL | 
 LL | #![recursion_limit="100"]
-   |   ^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^ not permitted following an outer attibute
    |
    = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
 
diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime.rs b/src/test/ui/self/arbitrary_self_types_pin_lifetime.rs
new file mode 100644
index 00000000000..30020138812
--- /dev/null
+++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime.rs
@@ -0,0 +1,60 @@
+// check-pass
+
+use std::pin::Pin;
+use std::task::{Context, Poll};
+
+struct Foo;
+
+impl Foo {
+    fn pin_ref(self: Pin<&Self>) -> Pin<&Self> { self }
+
+    fn pin_mut(self: Pin<&mut Self>) -> Pin<&mut Self> { self }
+
+    fn pin_pin_pin_ref(self: Pin<Pin<Pin<&Self>>>) -> Pin<Pin<Pin<&Self>>> { self }
+
+    fn pin_ref_impl_trait(self: Pin<&Self>) -> impl Clone + '_ { self }
+
+    fn b(self: Pin<&Foo>, f: &Foo) -> Pin<&Foo> { self }
+}
+
+type Alias<T> = Pin<T>;
+impl Foo {
+    fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> Alias<&Self> { self }
+}
+
+struct Bar<T: Unpin, U: Unpin> {
+    field1: T,
+    field2: U,
+}
+
+impl<T: Unpin, U: Unpin> Bar<T, U> {
+    fn fields(self: Pin<&mut Self>) -> (Pin<&mut T>, Pin<&mut U>) {
+        let this = self.get_mut();
+        (Pin::new(&mut this.field1), Pin::new(&mut this.field2))
+    }
+}
+
+trait AsyncBufRead {
+    fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>)
+        -> Poll<std::io::Result<&[u8]>>;
+}
+
+struct Baz(Vec<u8>);
+
+impl AsyncBufRead for Baz {
+    fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>)
+        -> Poll<std::io::Result<&[u8]>>
+    {
+        Poll::Ready(Ok(&self.get_mut().0))
+    }
+}
+
+fn main() {
+    let mut foo = Foo;
+    { Pin::new(&foo).pin_ref() };
+    { Pin::new(&mut foo).pin_mut() };
+    { Pin::new(Pin::new(Pin::new(&foo))).pin_pin_pin_ref() };
+    { Pin::new(&foo).pin_ref_impl_trait() };
+    let mut bar = Bar { field1: 0u8, field2: 1u8 };
+    { Pin::new(&mut bar).fields() };
+}
diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.nll.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.nll.stderr
new file mode 100644
index 00000000000..dcfc9ba511d
--- /dev/null
+++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.nll.stderr
@@ -0,0 +1,14 @@
+error: lifetime may not live long enough
+  --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait.rs:8:31
+   |
+LL |     fn f(self: Pin<&Self>) -> impl Clone { self }
+   |                    -          ^^^^^^^^^^ opaque type requires that `'1` must outlive `'static`
+   |                    |
+   |                    let's call the lifetime of this reference `'1`
+help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as a constraint
+   |
+LL |     fn f(self: Pin<&Self>) -> impl Clone + '_ { self }
+   |                               ^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.rs b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.rs
new file mode 100644
index 00000000000..ad8959727cb
--- /dev/null
+++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.rs
@@ -0,0 +1,13 @@
+// compile-fail
+
+use std::pin::Pin;
+
+struct Foo;
+
+impl Foo {
+    fn f(self: Pin<&Self>) -> impl Clone { self } //~ ERROR cannot infer an appropriate lifetime
+}
+
+fn main() {
+    { Pin::new(&Foo).f() };
+}
diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr
new file mode 100644
index 00000000000..5118280e7ec
--- /dev/null
+++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr
@@ -0,0 +1,20 @@
+error: cannot infer an appropriate lifetime
+  --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait.rs:8:44
+   |
+LL |     fn f(self: Pin<&Self>) -> impl Clone { self }
+   |                               ----------   ^^^^ ...but this borrow...
+   |                               |
+   |                               this return type evaluates to the `'static` lifetime...
+   |
+note: ...can't outlive the anonymous lifetime #1 defined on the method body at 8:5
+  --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait.rs:8:5
+   |
+LL |     fn f(self: Pin<&Self>) -> impl Clone { self }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: you can add a constraint to the return type to make it last less than `'static` and match the anonymous lifetime #1 defined on the method body at 8:5
+   |
+LL |     fn f(self: Pin<&Self>) -> impl Clone + '_ { self }
+   |                               ^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.nll.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.nll.stderr
new file mode 100644
index 00000000000..8a0f1a804ad
--- /dev/null
+++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.nll.stderr
@@ -0,0 +1,28 @@
+error: lifetime may not live long enough
+  --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:8:46
+   |
+LL |     fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
+   |                    -         -               ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |                    |         |
+   |                    |         let's call the lifetime of this reference `'1`
+   |                    let's call the lifetime of this reference `'2`
+
+error: lifetime may not live long enough
+  --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:10:69
+   |
+LL |     fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
+   |                    -          -                                     ^^^^^^^^^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |                    |          |
+   |                    |          let's call the lifetime of this reference `'1`
+   |                    let's call the lifetime of this reference `'2`
+
+error: lifetime may not live long enough
+  --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:15:58
+   |
+LL |     fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg }
+   |            --  ---- has type `std::pin::Pin<&'1 Foo>`    ^^^ function was supposed to return data with lifetime `'1` but it is returning data with lifetime `'a`
+   |            |
+   |            lifetime `'a` defined here
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.rs b/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.rs
new file mode 100644
index 00000000000..fc5f94201b8
--- /dev/null
+++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.rs
@@ -0,0 +1,18 @@
+// compile-fail
+
+use std::pin::Pin;
+
+struct Foo;
+
+impl Foo {
+    fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f } //~ ERROR E0623
+
+    fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) } //~ ERROR E0623
+}
+
+type Alias<T> = Pin<T>;
+impl Foo {
+    fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg } //~ ERROR E0623
+}
+
+fn main() {}
diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.stderr
new file mode 100644
index 00000000000..3296e14f806
--- /dev/null
+++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.stderr
@@ -0,0 +1,26 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:8:46
+   |
+LL |     fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
+   |                              ----     ----   ^ ...but data from `f` is returned here
+   |                              |
+   |                              this parameter and the return type are declared with different lifetimes...
+
+error[E0623]: lifetime mismatch
+  --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:10:76
+   |
+LL |     fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
+   |                               ----              -----------------          ^ ...but data from `f` is returned here
+   |                               |
+   |                               this parameter and the return type are declared with different lifetimes...
+
+error[E0623]: lifetime mismatch
+  --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:15:58
+   |
+LL |     fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg }
+   |                                         ------     ---   ^^^ ...but data from `arg` is returned here
+   |                                         |
+   |                                         this parameter and the return type are declared with different lifetimes...
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/self/elision/README.md b/src/test/ui/self/elision/README.md
new file mode 100644
index 00000000000..7ace2e0c890
--- /dev/null
+++ b/src/test/ui/self/elision/README.md
@@ -0,0 +1,44 @@
+Test cases intended to document behavior and try to exhaustively
+explore the combinations.
+
+## Confidence
+
+These tests are not yet considered 100% normative, in that some
+aspects of the current behavior are not desirable. This is expressed
+in the "confidence" field in the following table. Values:
+
+| Confidence | Interpretation |
+| --- | --- |
+| 100% | this will remain recommended behavior |
+| 75% | unclear whether we will continue to accept this |
+| 50% | this will likely be deprecated but remain valid |
+| 25% | this could change in the future |
+| 0% | this is definitely bogus and will likely change in the future in *some* way |
+
+## Tests
+
+| Test file | `Self` type | Pattern | Current elision behavior | Confidence |
+| --- | --- | --- | --- | --- |
+| `self.rs` | `Struct` | `Self` | ignore `self` parameter | 100% |
+| `struct.rs` | `Struct` | `Struct` | ignore `self` parameter | 100% |
+| `alias.rs` | `Struct` | `Alias` | ignore `self` parameter | 100% |
+| `ref-self.rs` | `Struct` | `&Self` | take lifetime from `&Self` | 100% |
+| `ref-mut-self.rs` | `Struct` | `&mut Self` | take lifetime from `&mut Self` | 100% |
+| `ref-struct.rs` | `Struct` | `&Struct` | take lifetime from `&Self` | 50% |
+| `ref-mut-struct.rs` | `Struct` | `&mut Struct` | take lifetime from `&mut Self` | 50% |
+| `ref-alias.rs` | `Struct` | `&Alias` | ignore `Alias` | 0% |
+| `ref-mut-alias.rs` | `Struct` | `&mut Alias` | ignore `Alias` | 0% |
+| `lt-self.rs` | `Struct<'a>` | `Self` | ignore `Self` (and hence `'a`) | 25% |
+| `lt-struct.rs` | `Struct<'a>` | `Self` | ignore `Self` (and hence `'a`) | 0% |
+| `lt-alias.rs`   | `Alias<'a>` | `Self` | ignore `Self` (and hence `'a`) | 0% |
+| `lt-ref-self.rs` | `Struct<'a>` | `&Self` | take lifetime from `&Self` | 75% |
+
+In each case, we test the following patterns:
+
+- `self: XXX`
+- `self: Box<XXX>`
+- `self: Pin<XXX>`
+- `self: Box<Box<XXX>>`
+- `self: Box<Pin<XXX>>`
+
+In the non-reference cases, `Pin` causes errors so we substitute `Rc`.
diff --git a/src/test/ui/self/elision/alias.rs b/src/test/ui/self/elision/alias.rs
new file mode 100644
index 00000000000..b5aacfaeec4
--- /dev/null
+++ b/src/test/ui/self/elision/alias.rs
@@ -0,0 +1,36 @@
+// check-pass
+
+#![feature(arbitrary_self_types)]
+#![allow(non_snake_case)]
+
+use std::rc::Rc;
+
+struct Struct { }
+
+type Alias = Struct;
+
+impl Struct {
+    // Test using an alias for `Struct`:
+
+    fn alias(self: Alias, f: &u32) -> &u32 {
+        f
+    }
+
+    fn box_Alias(self: Box<Alias>, f: &u32) -> &u32 {
+        f
+    }
+
+    fn rc_Alias(self: Rc<Alias>, f: &u32) -> &u32 {
+        f
+    }
+
+    fn box_box_Alias(self: Box<Box<Alias>>, f: &u32) -> &u32 {
+        f
+    }
+
+    fn box_rc_Alias(self: Box<Rc<Alias>>, f: &u32) -> &u32 {
+        f
+    }
+}
+
+fn main() { }
diff --git a/src/test/ui/self/elision/assoc.rs b/src/test/ui/self/elision/assoc.rs
new file mode 100644
index 00000000000..163eb49383a
--- /dev/null
+++ b/src/test/ui/self/elision/assoc.rs
@@ -0,0 +1,40 @@
+// check-pass
+
+#![feature(arbitrary_self_types)]
+#![allow(non_snake_case)]
+
+use std::rc::Rc;
+
+trait Trait {
+    type AssocType;
+}
+
+struct Struct { }
+
+impl Trait for Struct {
+    type AssocType = Self;
+}
+
+impl Struct {
+    fn assoc(self: <Struct as Trait>::AssocType, f: &u32) -> &u32 {
+        f
+    }
+
+    fn box_AssocType(self: Box<<Struct as Trait>::AssocType>, f: &u32) -> &u32 {
+        f
+    }
+
+    fn rc_AssocType(self: Rc<<Struct as Trait>::AssocType>, f: &u32) -> &u32 {
+        f
+    }
+
+    fn box_box_AssocType(self: Box<Box<<Struct as Trait>::AssocType>>, f: &u32) -> &u32 {
+        f
+    }
+
+    fn box_rc_AssocType(self: Box<Rc<<Struct as Trait>::AssocType>>, f: &u32) -> &u32 {
+        f
+    }
+}
+
+fn main() { }
diff --git a/src/test/ui/self/elision/lt-alias.rs b/src/test/ui/self/elision/lt-alias.rs
new file mode 100644
index 00000000000..df2300deda2
--- /dev/null
+++ b/src/test/ui/self/elision/lt-alias.rs
@@ -0,0 +1,38 @@
+// check-pass
+
+#![feature(arbitrary_self_types)]
+#![allow(non_snake_case)]
+
+use std::rc::Rc;
+
+struct Struct<'a> { x: &'a u32 }
+
+type Alias<'a> = Struct<'a>;
+
+impl<'a> Alias<'a> {
+    fn take_self(self, f: &u32) -> &u32 {
+        f
+    }
+
+    fn take_Alias(self: Alias<'a>, f: &u32) -> &u32 {
+        f
+    }
+
+    fn take_Box_Alias(self: Box<Alias<'a>>, f: &u32) -> &u32 {
+        f
+    }
+
+    fn take_Box_Box_Alias(self: Box<Box<Alias<'a>>>, f: &u32) -> &u32 {
+        f
+    }
+
+    fn take_Rc_Alias(self: Rc<Alias<'a>>, f: &u32) -> &u32 {
+        f
+    }
+
+    fn take_Box_Rc_Alias(self: Box<Rc<Alias<'a>>>, f: &u32) -> &u32 {
+        f
+    }
+}
+
+fn main() { }
diff --git a/src/test/ui/self/elision/lt-assoc.rs b/src/test/ui/self/elision/lt-assoc.rs
new file mode 100644
index 00000000000..70573598fcb
--- /dev/null
+++ b/src/test/ui/self/elision/lt-assoc.rs
@@ -0,0 +1,44 @@
+// check-pass
+
+#![feature(arbitrary_self_types)]
+#![allow(non_snake_case)]
+
+use std::rc::Rc;
+
+trait Trait {
+    type AssocType;
+}
+
+struct Struct<'a> { x: &'a u32 }
+
+impl<'a> Trait for Struct<'a> {
+    type AssocType = Self;
+}
+
+impl<'a> Struct<'a> {
+    fn take_self(self, f: &u32) -> &u32 {
+        f
+    }
+
+    fn take_AssocType(self: <Struct<'a> as Trait>::AssocType, f: &u32) -> &u32 {
+        f
+    }
+
+    fn take_Box_AssocType(self: Box<<Struct<'a> as Trait>::AssocType>, f: &u32) -> &u32 {
+        f
+    }
+
+    fn take_Box_Box_AssocType(self: Box<Box<<Struct<'a> as Trait>::AssocType>>, f: &u32) -> &u32 {
+        f
+    }
+
+    fn take_Rc_AssocType(self: Rc<<Struct<'a> as Trait>::AssocType>, f: &u32) -> &u32 {
+        f
+    }
+
+    fn take_Box_Rc_AssocType(self: Box<Rc<<Struct<'a> as Trait>::AssocType>>, f: &u32) -> &u32 {
+        f
+    }
+}
+
+fn main() { }
diff --git a/src/test/ui/self/elision/lt-ref-self.nll.stderr b/src/test/ui/self/elision/lt-ref-self.nll.stderr
new file mode 100644
index 00000000000..e97a01e746d
--- /dev/null
+++ b/src/test/ui/self/elision/lt-ref-self.nll.stderr
@@ -0,0 +1,62 @@
+error: lifetime may not live long enough
+  --> $DIR/lt-ref-self.rs:12:9
+   |
+LL |     fn ref_self(&self, f: &u32) -> &u32 {
+   |                 -         - let's call the lifetime of this reference `'1`
+   |                 |
+   |                 let's call the lifetime of this reference `'2`
+LL |         f
+   |         ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+  --> $DIR/lt-ref-self.rs:18:9
+   |
+LL |     fn ref_Self(self: &Self, f: &u32) -> &u32 {
+   |                       -         - let's call the lifetime of this reference `'1`
+   |                       |
+   |                       let's call the lifetime of this reference `'2`
+LL |         f
+   |         ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+  --> $DIR/lt-ref-self.rs:22:9
+   |
+LL |     fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
+   |                               -          - let's call the lifetime of this reference `'1`
+   |                               |
+   |                               let's call the lifetime of this reference `'2`
+LL |         f
+   |         ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+  --> $DIR/lt-ref-self.rs:26:9
+   |
+LL |     fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
+   |                               -          - let's call the lifetime of this reference `'1`
+   |                               |
+   |                               let's call the lifetime of this reference `'2`
+LL |         f
+   |         ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+  --> $DIR/lt-ref-self.rs:30:9
+   |
+LL |     fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
+   |                                       -           - let's call the lifetime of this reference `'1`
+   |                                       |
+   |                                       let's call the lifetime of this reference `'2`
+LL |         f
+   |         ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+  --> $DIR/lt-ref-self.rs:34:9
+   |
+LL |     fn box_pin_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
+   |                                   -           - let's call the lifetime of this reference `'1`
+   |                                   |
+   |                                   let's call the lifetime of this reference `'2`
+LL |         f
+   |         ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: aborting due to 6 previous errors
+
diff --git a/src/test/ui/self/elision/lt-ref-self.rs b/src/test/ui/self/elision/lt-ref-self.rs
new file mode 100644
index 00000000000..8abf2876a5c
--- /dev/null
+++ b/src/test/ui/self/elision/lt-ref-self.rs
@@ -0,0 +1,38 @@
+#![feature(arbitrary_self_types)]
+#![allow(non_snake_case)]
+
+use std::pin::Pin;
+
+struct Struct<'a> { data: &'a u32 }
+
+impl<'a> Struct<'a> {
+    // Test using `&self` sugar:
+
+    fn ref_self(&self, f: &u32) -> &u32 {
+        f //~ ERROR lifetime mismatch
+    }
+
+    // Test using `&Self` explicitly:
+
+    fn ref_Self(self: &Self, f: &u32) -> &u32 {
+        f //~ ERROR lifetime mismatch
+    }
+
+    fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
+        f //~ ERROR lifetime mismatch
+    }
+
+    fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
+        f //~ ERROR lifetime mismatch
+    }
+
+    fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
+        f //~ ERROR lifetime mismatch
+    }
+
+    fn box_pin_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
+        f //~ ERROR lifetime mismatch
+    }
+}
+
+fn main() { }
diff --git a/src/test/ui/self/elision/lt-ref-self.stderr b/src/test/ui/self/elision/lt-ref-self.stderr
new file mode 100644
index 00000000000..f73b3eddd38
--- /dev/null
+++ b/src/test/ui/self/elision/lt-ref-self.stderr
@@ -0,0 +1,62 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/lt-ref-self.rs:12:9
+   |
+LL |     fn ref_self(&self, f: &u32) -> &u32 {
+   |                           ----     ----
+   |                           |
+   |                           this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/lt-ref-self.rs:18:9
+   |
+LL |     fn ref_Self(self: &Self, f: &u32) -> &u32 {
+   |                                 ----     ----
+   |                                 |
+   |                                 this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/lt-ref-self.rs:22:9
+   |
+LL |     fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
+   |                                          ----     ----
+   |                                          |
+   |                                          this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/lt-ref-self.rs:26:9
+   |
+LL |     fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
+   |                                          ----     ----
+   |                                          |
+   |                                          this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/lt-ref-self.rs:30:9
+   |
+LL |     fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
+   |                                                   ----     ----
+   |                                                   |
+   |                                                   this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/lt-ref-self.rs:34:9
+   |
+LL |     fn box_pin_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
+   |                                               ----     ----
+   |                                               |
+   |                                               this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error: aborting due to 6 previous errors
+
diff --git a/src/test/ui/self/elision/lt-self.rs b/src/test/ui/self/elision/lt-self.rs
new file mode 100644
index 00000000000..9b0ee5e42a5
--- /dev/null
+++ b/src/test/ui/self/elision/lt-self.rs
@@ -0,0 +1,49 @@
+// check-pass
+
+#![feature(arbitrary_self_types)]
+#![allow(non_snake_case)]
+
+use std::pin::Pin;
+use std::rc::Rc;
+
+struct Struct<'a> {
+    x: &'a u32
+}
+
+impl<'a> Struct<'a> {
+    fn take_self(self, f: &u32) -> &u32 {
+        f
+    }
+
+    fn take_Self(self: Self, f: &u32) -> &u32 {
+        f
+    }
+
+    fn take_Box_Self(self: Box<Self>, f: &u32) -> &u32 {
+        f
+    }
+
+    fn take_Box_Box_Self(self: Box<Box<Self>>, f: &u32) -> &u32 {
+        f
+    }
+
+    fn take_Rc_Self(self: Rc<Self>, f: &u32) -> &u32 {
+        f
+    }
+
+    fn take_Box_Rc_Self(self: Box<Rc<Self>>, f: &u32) -> &u32 {
+        f
+    }
+
+    // N/A
+    //fn take_Pin_Self(self: Pin<Self>, f: &u32) -> &u32 {
+    //    f
+    //}
+
+    // N/A
+    //fn take_Box_Pin_Self(self: Box<Pin<Self>>, f: &u32) -> &u32 {
+    //    f
+    //}
+}
+
+fn main() { }
diff --git a/src/test/ui/self/elision/lt-struct.rs b/src/test/ui/self/elision/lt-struct.rs
new file mode 100644
index 00000000000..e41dfbbe0bf
--- /dev/null
+++ b/src/test/ui/self/elision/lt-struct.rs
@@ -0,0 +1,36 @@
+// check-pass
+
+#![feature(arbitrary_self_types)]
+#![allow(non_snake_case)]
+
+use std::rc::Rc;
+
+struct Struct<'a> { x: &'a u32 }
+
+impl<'a> Struct<'a> {
+    fn take_self(self, f: &u32) -> &u32 {
+        f
+    }
+
+    fn take_Struct(self: Struct<'a>, f: &u32) -> &u32 {
+        f
+    }
+
+    fn take_Box_Struct(self: Box<Struct<'a>>, f: &u32) -> &u32 {
+        f
+    }
+
+    fn take_Box_Box_Struct(self: Box<Box<Struct<'a>>>, f: &u32) -> &u32 {
+        f
+    }
+
+    fn take_Rc_Struct(self: Rc<Struct<'a>>, f: &u32) -> &u32 {
+        f
+    }
+
+    fn take_Box_Rc_Struct(self: Box<Rc<Struct<'a>>>, f: &u32) -> &u32 {
+        f
+    }
+}
+
+fn main() { }
diff --git a/src/test/ui/self/elision/multiple-ref-self.rs b/src/test/ui/self/elision/multiple-ref-self.rs
new file mode 100644
index 00000000000..f39613d0c90
--- /dev/null
+++ b/src/test/ui/self/elision/multiple-ref-self.rs
@@ -0,0 +1,43 @@
+// check-pass
+
+#![feature(arbitrary_self_types)]
+#![allow(non_snake_case)]
+
+use std::marker::PhantomData;
+use std::ops::Deref;
+use std::pin::Pin;
+
+struct Struct { }
+
+struct Wrap<T, P>(T, PhantomData<P>);
+
+impl<T, P> Deref for Wrap<T, P> {
+    type Target = T;
+    fn deref(&self) -> &T { &self.0 }
+}
+
+impl Struct {
+    // Test using multiple `&Self`:
+
+    fn wrap_ref_Self_ref_Self(self: Wrap<&Self, &Self>, f: &u8) -> &u8 {
+        f
+    }
+
+    fn box_wrap_ref_Self_ref_Self(self: Box<Wrap<&Self, &Self>>, f: &u32) -> &u32 {
+        f
+    }
+
+    fn pin_wrap_ref_Self_ref_Self(self: Pin<Wrap<&Self, &Self>>, f: &u32) -> &u32 {
+        f
+    }
+
+    fn box_box_wrap_ref_Self_ref_Self(self: Box<Box<Wrap<&Self, &Self>>>, f: &u32) -> &u32 {
+        f
+    }
+
+    fn box_pin_wrap_ref_Self_ref_Self(self: Box<Pin<Wrap<&Self, &Self>>>, f: &u32) -> &u32 {
+        f
+    }
+}
+
+fn main() { }
diff --git a/src/test/ui/self/elision/ref-alias.rs b/src/test/ui/self/elision/ref-alias.rs
new file mode 100644
index 00000000000..d83ac612235
--- /dev/null
+++ b/src/test/ui/self/elision/ref-alias.rs
@@ -0,0 +1,39 @@
+// check-pass
+
+#![feature(arbitrary_self_types)]
+#![allow(non_snake_case)]
+
+use std::pin::Pin;
+
+struct Struct { }
+
+type Alias = Struct;
+
+impl Struct {
+    // Test using an alias for `Struct`:
+    //
+    // FIXME. We currently fail to recognize this as the self type, which
+    // feels like a bug.
+
+    fn ref_Alias(self: &Alias, f: &u32) -> &u32 {
+        f
+    }
+
+    fn box_ref_Alias(self: Box<&Alias>, f: &u32) -> &u32 {
+        f
+    }
+
+    fn pin_ref_Alias(self: Pin<&Alias>, f: &u32) -> &u32 {
+        f
+    }
+
+    fn box_box_ref_Alias(self: Box<Box<&Alias>>, f: &u32) -> &u32 {
+        f
+    }
+
+    fn box_pin_ref_Alias(self: Box<Pin<&Alias>>, f: &u32) -> &u32 {
+        f
+    }
+}
+
+fn main() { }
diff --git a/src/test/ui/self/elision/ref-assoc.rs b/src/test/ui/self/elision/ref-assoc.rs
new file mode 100644
index 00000000000..f9354bc8847
--- /dev/null
+++ b/src/test/ui/self/elision/ref-assoc.rs
@@ -0,0 +1,40 @@
+// check-pass
+
+#![feature(arbitrary_self_types)]
+#![allow(non_snake_case)]
+
+use std::pin::Pin;
+
+trait Trait {
+    type AssocType;
+}
+
+struct Struct { }
+
+impl Trait for Struct {
+    type AssocType = Self;
+}
+
+impl Struct {
+    fn ref_AssocType(self: &<Struct as Trait>::AssocType, f: &u32) -> &u32 {
+        f
+    }
+
+    fn box_ref_AssocType(self: Box<&<Struct as Trait>::AssocType>, f: &u32) -> &u32 {
+        f
+    }
+
+    fn pin_ref_AssocType(self: Pin<&<Struct as Trait>::AssocType>, f: &u32) -> &u32 {
+        f
+    }
+
+    fn box_box_ref_AssocType(self: Box<Box<&<Struct as Trait>::AssocType>>, f: &u32) -> &u32 {
+        f
+    }
+
+    fn box_pin_ref_AssocType(self: Box<Pin<&<Struct as Trait>::AssocType>>, f: &u32) -> &u32 {
+        f
+    }
+}
+
+fn main() { }
diff --git a/src/test/ui/self/elision/ref-mut-alias.rs b/src/test/ui/self/elision/ref-mut-alias.rs
new file mode 100644
index 00000000000..395816f8f5d
--- /dev/null
+++ b/src/test/ui/self/elision/ref-mut-alias.rs
@@ -0,0 +1,36 @@
+// check-pass
+
+#![feature(arbitrary_self_types)]
+#![allow(non_snake_case)]
+
+use std::pin::Pin;
+
+struct Struct { }
+
+type Alias = Struct;
+
+impl Struct {
+    // Test using an alias for `Struct`:
+
+    fn ref_Alias(self: &mut Alias, f: &u32) -> &u32 {
+        f
+    }
+
+    fn box_ref_Alias(self: Box<&mut Alias>, f: &u32) -> &u32 {
+        f
+    }
+
+    fn pin_ref_Alias(self: Pin<&mut Alias>, f: &u32) -> &u32 {
+        f
+    }
+
+    fn box_box_ref_Alias(self: Box<Box<&mut Alias>>, f: &u32) -> &u32 {
+        f
+    }
+
+    fn box_pin_ref_Alias(self: Box<Pin<&mut Alias>>, f: &u32) -> &u32 {
+        f
+    }
+}
+
+fn main() { }
diff --git a/src/test/ui/self/elision/ref-mut-self.nll.stderr b/src/test/ui/self/elision/ref-mut-self.nll.stderr
new file mode 100644
index 00000000000..3a8ae3fdcba
--- /dev/null
+++ b/src/test/ui/self/elision/ref-mut-self.nll.stderr
@@ -0,0 +1,62 @@
+error: lifetime may not live long enough
+  --> $DIR/ref-mut-self.rs:12:9
+   |
+LL |     fn ref_self(&mut self, f: &u32) -> &u32 {
+   |                 -             - let's call the lifetime of this reference `'1`
+   |                 |
+   |                 let's call the lifetime of this reference `'2`
+LL |         f
+   |         ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+  --> $DIR/ref-mut-self.rs:18:9
+   |
+LL |     fn ref_Self(self: &mut Self, f: &u32) -> &u32 {
+   |                       -             - let's call the lifetime of this reference `'1`
+   |                       |
+   |                       let's call the lifetime of this reference `'2`
+LL |         f
+   |         ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+  --> $DIR/ref-mut-self.rs:22:9
+   |
+LL |     fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 {
+   |                               -              - let's call the lifetime of this reference `'1`
+   |                               |
+   |                               let's call the lifetime of this reference `'2`
+LL |         f
+   |         ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+  --> $DIR/ref-mut-self.rs:26:9
+   |
+LL |     fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 {
+   |                               -              - let's call the lifetime of this reference `'1`
+   |                               |
+   |                               let's call the lifetime of this reference `'2`
+LL |         f
+   |         ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+  --> $DIR/ref-mut-self.rs:30:9
+   |
+LL |     fn box_box_ref_Self(self: Box<Box<&mut Self>>, f: &u32) -> &u32 {
+   |                                       -               - let's call the lifetime of this reference `'1`
+   |                                       |
+   |                                       let's call the lifetime of this reference `'2`
+LL |         f
+   |         ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+  --> $DIR/ref-mut-self.rs:34:9
+   |
+LL |     fn box_pin_ref_Self(self: Box<Pin<&mut Self>>, f: &u32) -> &u32 {
+   |                                       -               - let's call the lifetime of this reference `'1`
+   |                                       |
+   |                                       let's call the lifetime of this reference `'2`
+LL |         f
+   |         ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: aborting due to 6 previous errors
+
diff --git a/src/test/ui/self/elision/ref-mut-self.rs b/src/test/ui/self/elision/ref-mut-self.rs
new file mode 100644
index 00000000000..a7ea47bb7f6
--- /dev/null
+++ b/src/test/ui/self/elision/ref-mut-self.rs
@@ -0,0 +1,38 @@
+#![feature(arbitrary_self_types)]
+#![allow(non_snake_case)]
+
+use std::pin::Pin;
+
+struct Struct { }
+
+impl Struct {
+    // Test using `&mut self` sugar:
+
+    fn ref_self(&mut self, f: &u32) -> &u32 {
+        f //~ ERROR lifetime mismatch
+    }
+
+    // Test using `&mut Self` explicitly:
+
+    fn ref_Self(self: &mut Self, f: &u32) -> &u32 {
+        f //~ ERROR lifetime mismatch
+    }
+
+    fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 {
+        f //~ ERROR lifetime mismatch
+    }
+
+    fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 {
+        f //~ ERROR lifetime mismatch
+    }
+
+    fn box_box_ref_Self(self: Box<Box<&mut Self>>, f: &u32) -> &u32 {
+        f //~ ERROR lifetime mismatch
+    }
+
+    fn box_pin_ref_Self(self: Box<Pin<&mut Self>>, f: &u32) -> &u32 {
+        f //~ ERROR lifetime mismatch
+    }
+}
+
+fn main() { }
diff --git a/src/test/ui/self/elision/ref-mut-self.stderr b/src/test/ui/self/elision/ref-mut-self.stderr
new file mode 100644
index 00000000000..37984cd72fb
--- /dev/null
+++ b/src/test/ui/self/elision/ref-mut-self.stderr
@@ -0,0 +1,62 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-mut-self.rs:12:9
+   |
+LL |     fn ref_self(&mut self, f: &u32) -> &u32 {
+   |                               ----     ----
+   |                               |
+   |                               this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-mut-self.rs:18:9
+   |
+LL |     fn ref_Self(self: &mut Self, f: &u32) -> &u32 {
+   |                                     ----     ----
+   |                                     |
+   |                                     this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-mut-self.rs:22:9
+   |
+LL |     fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 {
+   |                                              ----     ----
+   |                                              |
+   |                                              this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-mut-self.rs:26:9
+   |
+LL |     fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 {
+   |                                              ----     ----
+   |                                              |
+   |                                              this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-mut-self.rs:30:9
+   |
+LL |     fn box_box_ref_Self(self: Box<Box<&mut Self>>, f: &u32) -> &u32 {
+   |                                                       ----     ----
+   |                                                       |
+   |                                                       this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-mut-self.rs:34:9
+   |
+LL |     fn box_pin_ref_Self(self: Box<Pin<&mut Self>>, f: &u32) -> &u32 {
+   |                                                       ----     ----
+   |                                                       |
+   |                                                       this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error: aborting due to 6 previous errors
+
diff --git a/src/test/ui/self/elision/ref-mut-struct.nll.stderr b/src/test/ui/self/elision/ref-mut-struct.nll.stderr
new file mode 100644
index 00000000000..66152ba40a5
--- /dev/null
+++ b/src/test/ui/self/elision/ref-mut-struct.nll.stderr
@@ -0,0 +1,52 @@
+error: lifetime may not live long enough
+  --> $DIR/ref-mut-struct.rs:12:9
+   |
+LL |     fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 {
+   |                         -               - let's call the lifetime of this reference `'1`
+   |                         |
+   |                         let's call the lifetime of this reference `'2`
+LL |         f
+   |         ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+  --> $DIR/ref-mut-struct.rs:16:9
+   |
+LL |     fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 {
+   |                                 -                - let's call the lifetime of this reference `'1`
+   |                                 |
+   |                                 let's call the lifetime of this reference `'2`
+LL |         f
+   |         ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+  --> $DIR/ref-mut-struct.rs:20:9
+   |
+LL |     fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 {
+   |                                 -                - let's call the lifetime of this reference `'1`
+   |                                 |
+   |                                 let's call the lifetime of this reference `'2`
+LL |         f
+   |         ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+  --> $DIR/ref-mut-struct.rs:24:9
+   |
+LL |     fn box_box_ref_Struct(self: Box<Box<&mut Struct>>, f: &u32) -> &u32 {
+   |                                         -                 - let's call the lifetime of this reference `'1`
+   |                                         |
+   |                                         let's call the lifetime of this reference `'2`
+LL |         f
+   |         ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+  --> $DIR/ref-mut-struct.rs:28:9
+   |
+LL |     fn box_pin_ref_Struct(self: Box<Pin<&mut Struct>>, f: &u32) -> &u32 {
+   |                                         -                 - let's call the lifetime of this reference `'1`
+   |                                         |
+   |                                         let's call the lifetime of this reference `'2`
+LL |         f
+   |         ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: aborting due to 5 previous errors
+
diff --git a/src/test/ui/self/elision/ref-mut-struct.rs b/src/test/ui/self/elision/ref-mut-struct.rs
new file mode 100644
index 00000000000..795ddf8ac13
--- /dev/null
+++ b/src/test/ui/self/elision/ref-mut-struct.rs
@@ -0,0 +1,32 @@
+#![feature(arbitrary_self_types)]
+#![allow(non_snake_case)]
+
+use std::pin::Pin;
+
+struct Struct { }
+
+impl Struct {
+    // Test using `&mut Struct` explicitly:
+
+    fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 {
+        f //~ ERROR lifetime mismatch
+    }
+
+    fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 {
+        f //~ ERROR lifetime mismatch
+    }
+
+    fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 {
+        f //~ ERROR lifetime mismatch
+    }
+
+    fn box_box_ref_Struct(self: Box<Box<&mut Struct>>, f: &u32) -> &u32 {
+        f //~ ERROR lifetime mismatch
+    }
+
+    fn box_pin_ref_Struct(self: Box<Pin<&mut Struct>>, f: &u32) -> &u32 {
+        f //~ ERROR lifetime mismatch
+    }
+}
+
+fn main() { }
diff --git a/src/test/ui/self/elision/ref-mut-struct.stderr b/src/test/ui/self/elision/ref-mut-struct.stderr
new file mode 100644
index 00000000000..2a4826905b9
--- /dev/null
+++ b/src/test/ui/self/elision/ref-mut-struct.stderr
@@ -0,0 +1,52 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-mut-struct.rs:12:9
+   |
+LL |     fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 {
+   |                                         ----     ----
+   |                                         |
+   |                                         this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-mut-struct.rs:16:9
+   |
+LL |     fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 {
+   |                                                  ----     ----
+   |                                                  |
+   |                                                  this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-mut-struct.rs:20:9
+   |
+LL |     fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 {
+   |                                                  ----     ----
+   |                                                  |
+   |                                                  this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-mut-struct.rs:24:9
+   |
+LL |     fn box_box_ref_Struct(self: Box<Box<&mut Struct>>, f: &u32) -> &u32 {
+   |                                                           ----     ----
+   |                                                           |
+   |                                                           this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-mut-struct.rs:28:9
+   |
+LL |     fn box_pin_ref_Struct(self: Box<Pin<&mut Struct>>, f: &u32) -> &u32 {
+   |                                                           ----     ----
+   |                                                           |
+   |                                                           this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error: aborting due to 5 previous errors
+
diff --git a/src/test/ui/self/elision/ref-self.nll.stderr b/src/test/ui/self/elision/ref-self.nll.stderr
new file mode 100644
index 00000000000..20045be0527
--- /dev/null
+++ b/src/test/ui/self/elision/ref-self.nll.stderr
@@ -0,0 +1,72 @@
+error: lifetime may not live long enough
+  --> $DIR/ref-self.rs:21:9
+   |
+LL |     fn ref_self(&self, f: &u32) -> &u32 {
+   |                 -         - let's call the lifetime of this reference `'1`
+   |                 |
+   |                 let's call the lifetime of this reference `'2`
+LL |         f
+   |         ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+  --> $DIR/ref-self.rs:27:9
+   |
+LL |     fn ref_Self(self: &Self, f: &u32) -> &u32 {
+   |                       -         - let's call the lifetime of this reference `'1`
+   |                       |
+   |                       let's call the lifetime of this reference `'2`
+LL |         f
+   |         ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+  --> $DIR/ref-self.rs:31:9
+   |
+LL |     fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
+   |                               -          - let's call the lifetime of this reference `'1`
+   |                               |
+   |                               let's call the lifetime of this reference `'2`
+LL |         f
+   |         ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+  --> $DIR/ref-self.rs:35:9
+   |
+LL |     fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
+   |                               -          - let's call the lifetime of this reference `'1`
+   |                               |
+   |                               let's call the lifetime of this reference `'2`
+LL |         f
+   |         ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+  --> $DIR/ref-self.rs:39:9
+   |
+LL |     fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
+   |                                       -           - let's call the lifetime of this reference `'1`
+   |                                       |
+   |                                       let's call the lifetime of this reference `'2`
+LL |         f
+   |         ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+  --> $DIR/ref-self.rs:43:9
+   |
+LL |     fn box_pin_ref_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
+   |                                       -           - let's call the lifetime of this reference `'1`
+   |                                       |
+   |                                       let's call the lifetime of this reference `'2`
+LL |         f
+   |         ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+  --> $DIR/ref-self.rs:47:9
+   |
+LL |     fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 {
+   |                                      -                - let's call the lifetime of this reference `'1`
+   |                                      |
+   |                                      let's call the lifetime of this reference `'2`
+LL |         f
+   |         ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: aborting due to 7 previous errors
+
diff --git a/src/test/ui/self/elision/ref-self.rs b/src/test/ui/self/elision/ref-self.rs
new file mode 100644
index 00000000000..e389d8518ad
--- /dev/null
+++ b/src/test/ui/self/elision/ref-self.rs
@@ -0,0 +1,51 @@
+#![feature(arbitrary_self_types)]
+#![allow(non_snake_case)]
+
+use std::marker::PhantomData;
+use std::ops::Deref;
+use std::pin::Pin;
+
+struct Struct { }
+
+struct Wrap<T, P>(T, PhantomData<P>);
+
+impl<T, P> Deref for Wrap<T, P> {
+    type Target = T;
+    fn deref(&self) -> &T { &self.0 }
+}
+
+impl Struct {
+    // Test using `&self` sugar:
+
+    fn ref_self(&self, f: &u32) -> &u32 {
+        f //~ ERROR lifetime mismatch
+    }
+
+    // Test using `&Self` explicitly:
+
+    fn ref_Self(self: &Self, f: &u32) -> &u32 {
+        f //~ ERROR lifetime mismatch
+    }
+
+    fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
+        f //~ ERROR lifetime mismatch
+    }
+
+    fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
+        f //~ ERROR lifetime mismatch
+    }
+
+    fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
+        f //~ ERROR lifetime mismatch
+    }
+
+    fn box_pin_ref_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
+        f //~ ERROR lifetime mismatch
+    }
+
+    fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 {
+        f //~ ERROR lifetime mismatch
+    }
+}
+
+fn main() { }
diff --git a/src/test/ui/self/elision/ref-self.stderr b/src/test/ui/self/elision/ref-self.stderr
new file mode 100644
index 00000000000..611498f18da
--- /dev/null
+++ b/src/test/ui/self/elision/ref-self.stderr
@@ -0,0 +1,72 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-self.rs:21:9
+   |
+LL |     fn ref_self(&self, f: &u32) -> &u32 {
+   |                           ----     ----
+   |                           |
+   |                           this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-self.rs:27:9
+   |
+LL |     fn ref_Self(self: &Self, f: &u32) -> &u32 {
+   |                                 ----     ----
+   |                                 |
+   |                                 this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-self.rs:31:9
+   |
+LL |     fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
+   |                                          ----     ----
+   |                                          |
+   |                                          this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-self.rs:35:9
+   |
+LL |     fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
+   |                                          ----     ----
+   |                                          |
+   |                                          this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-self.rs:39:9
+   |
+LL |     fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
+   |                                                   ----     ----
+   |                                                   |
+   |                                                   this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-self.rs:43:9
+   |
+LL |     fn box_pin_ref_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
+   |                                                   ----     ----
+   |                                                   |
+   |                                                   this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-self.rs:47:9
+   |
+LL |     fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 {
+   |                                                       ---     ---
+   |                                                       |
+   |                                                       this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error: aborting due to 7 previous errors
+
diff --git a/src/test/ui/self/elision/ref-struct.nll.stderr b/src/test/ui/self/elision/ref-struct.nll.stderr
new file mode 100644
index 00000000000..a258bc9f743
--- /dev/null
+++ b/src/test/ui/self/elision/ref-struct.nll.stderr
@@ -0,0 +1,52 @@
+error: lifetime may not live long enough
+  --> $DIR/ref-struct.rs:12:9
+   |
+LL |     fn ref_Struct(self: &Struct, f: &u32) -> &u32 {
+   |                         -           - let's call the lifetime of this reference `'1`
+   |                         |
+   |                         let's call the lifetime of this reference `'2`
+LL |         f
+   |         ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+  --> $DIR/ref-struct.rs:16:9
+   |
+LL |     fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 {
+   |                                 -            - let's call the lifetime of this reference `'1`
+   |                                 |
+   |                                 let's call the lifetime of this reference `'2`
+LL |         f
+   |         ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+  --> $DIR/ref-struct.rs:20:9
+   |
+LL |     fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 {
+   |                                 -            - let's call the lifetime of this reference `'1`
+   |                                 |
+   |                                 let's call the lifetime of this reference `'2`
+LL |         f
+   |         ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+  --> $DIR/ref-struct.rs:24:9
+   |
+LL |     fn box_box_ref_Struct(self: Box<Box<&Struct>>, f: &u32) -> &u32 {
+   |                                         -             - let's call the lifetime of this reference `'1`
+   |                                         |
+   |                                         let's call the lifetime of this reference `'2`
+LL |         f
+   |         ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+  --> $DIR/ref-struct.rs:28:9
+   |
+LL |     fn box_pin_Struct(self: Box<Pin<&Struct>>, f: &u32) -> &u32 {
+   |                                     -             - let's call the lifetime of this reference `'1`
+   |                                     |
+   |                                     let's call the lifetime of this reference `'2`
+LL |         f
+   |         ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: aborting due to 5 previous errors
+
diff --git a/src/test/ui/self/elision/ref-struct.rs b/src/test/ui/self/elision/ref-struct.rs
new file mode 100644
index 00000000000..342d6d2b363
--- /dev/null
+++ b/src/test/ui/self/elision/ref-struct.rs
@@ -0,0 +1,32 @@
+#![feature(arbitrary_self_types)]
+#![allow(non_snake_case)]
+
+use std::pin::Pin;
+
+struct Struct { }
+
+impl Struct {
+    // Test using `&Struct` explicitly:
+
+    fn ref_Struct(self: &Struct, f: &u32) -> &u32 {
+        f //~ ERROR lifetime mismatch
+    }
+
+    fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 {
+        f //~ ERROR lifetime mismatch
+    }
+
+    fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 {
+        f //~ ERROR lifetime mismatch
+    }
+
+    fn box_box_ref_Struct(self: Box<Box<&Struct>>, f: &u32) -> &u32 {
+        f //~ ERROR lifetime mismatch
+    }
+
+    fn box_pin_Struct(self: Box<Pin<&Struct>>, f: &u32) -> &u32 {
+        f //~ ERROR lifetime mismatch
+    }
+}
+
+fn main() { }
diff --git a/src/test/ui/self/elision/ref-struct.stderr b/src/test/ui/self/elision/ref-struct.stderr
new file mode 100644
index 00000000000..186e651c143
--- /dev/null
+++ b/src/test/ui/self/elision/ref-struct.stderr
@@ -0,0 +1,52 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-struct.rs:12:9
+   |
+LL |     fn ref_Struct(self: &Struct, f: &u32) -> &u32 {
+   |                                     ----     ----
+   |                                     |
+   |                                     this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-struct.rs:16:9
+   |
+LL |     fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 {
+   |                                              ----     ----
+   |                                              |
+   |                                              this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-struct.rs:20:9
+   |
+LL |     fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 {
+   |                                              ----     ----
+   |                                              |
+   |                                              this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-struct.rs:24:9
+   |
+LL |     fn box_box_ref_Struct(self: Box<Box<&Struct>>, f: &u32) -> &u32 {
+   |                                                       ----     ----
+   |                                                       |
+   |                                                       this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-struct.rs:28:9
+   |
+LL |     fn box_pin_Struct(self: Box<Pin<&Struct>>, f: &u32) -> &u32 {
+   |                                                   ----     ----
+   |                                                   |
+   |                                                   this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error: aborting due to 5 previous errors
+
diff --git a/src/test/ui/self/elision/self.rs b/src/test/ui/self/elision/self.rs
new file mode 100644
index 00000000000..dbcef71ba14
--- /dev/null
+++ b/src/test/ui/self/elision/self.rs
@@ -0,0 +1,36 @@
+// check-pass
+
+#![feature(arbitrary_self_types)]
+#![allow(non_snake_case)]
+
+use std::rc::Rc;
+
+struct Struct { }
+
+impl Struct {
+    fn take_self(self, f: &u32) -> &u32 {
+        f
+    }
+
+    fn take_Self(self: Self, f: &u32) -> &u32 {
+        f
+    }
+
+    fn take_Box_Self(self: Box<Self>, f: &u32) -> &u32 {
+        f
+    }
+
+    fn take_Box_Box_Self(self: Box<Box<Self>>, f: &u32) -> &u32 {
+        f
+    }
+
+    fn take_Rc_Self(self: Rc<Self>, f: &u32) -> &u32 {
+        f
+    }
+
+    fn take_Box_Rc_Self(self: Box<Rc<Self>>, f: &u32) -> &u32 {
+        f
+    }
+}
+
+fn main() { }
diff --git a/src/test/ui/self/elision/struct.rs b/src/test/ui/self/elision/struct.rs
new file mode 100644
index 00000000000..227e993bd3c
--- /dev/null
+++ b/src/test/ui/self/elision/struct.rs
@@ -0,0 +1,32 @@
+// check-pass
+
+#![feature(arbitrary_self_types)]
+#![allow(non_snake_case)]
+
+use std::rc::Rc;
+
+struct Struct { }
+
+impl Struct {
+    fn ref_Struct(self: Struct, f: &u32) -> &u32 {
+        f
+    }
+
+    fn box_Struct(self: Box<Struct>, f: &u32) -> &u32 {
+        f
+    }
+
+    fn rc_Struct(self: Rc<Struct>, f: &u32) -> &u32 {
+        f
+    }
+
+    fn box_box_Struct(self: Box<Box<Struct>>, f: &u32) -> &u32 {
+        f
+    }
+
+    fn box_rc_Struct(self: Box<Rc<Struct>>, f: &u32) -> &u32 {
+        f
+    }
+}
+
+fn main() { }
diff --git a/src/test/ui/self/self_lifetime.rs b/src/test/ui/self/self_lifetime.rs
new file mode 100644
index 00000000000..f04bd83ab6e
--- /dev/null
+++ b/src/test/ui/self/self_lifetime.rs
@@ -0,0 +1,15 @@
+// check-pass
+
+// https://github.com/rust-lang/rust/pull/60944#issuecomment-495346120
+
+struct Foo<'a>(&'a ());
+impl<'a> Foo<'a> {
+    fn foo<'b>(self: &'b Foo<'a>) -> &() { self.0 }
+}
+
+type Alias = Foo<'static>;
+impl Alias {
+    fn bar<'a>(self: &Alias, arg: &'a ()) -> &() { arg }
+}
+
+fn main() {}
diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs
index 06c1a8c18ba..3d40bdced63 100644
--- a/src/tools/tidy/src/lib.rs
+++ b/src/tools/tidy/src/lib.rs
@@ -38,8 +38,8 @@ pub mod pal;
 pub mod deps;
 pub mod extdeps;
 pub mod ui_tests;
+pub mod unit_tests;
 pub mod unstable_book;
-pub mod libcoretest;
 
 fn filter_dirs(path: &Path) -> bool {
     let skip = [
diff --git a/src/tools/tidy/src/libcoretest.rs b/src/tools/tidy/src/libcoretest.rs
deleted file mode 100644
index 579a20e1142..00000000000
--- a/src/tools/tidy/src/libcoretest.rs
+++ /dev/null
@@ -1,28 +0,0 @@
-//! Tidy check to ensure `#[test]` is not used directly inside `libcore`.
-//!
-//! `#![no_core]` libraries cannot be tested directly due to duplicating lang
-//! item. All tests must be written externally in `libcore/tests`.
-
-use std::path::Path;
-
-pub fn check(path: &Path, bad: &mut bool) {
-    let libcore_path = path.join("libcore");
-    super::walk(
-        &libcore_path,
-        &mut |subpath| t!(subpath.strip_prefix(&libcore_path)).starts_with("tests"),
-        &mut |entry, contents| {
-            let subpath = entry.path();
-            if let Some("rs") = subpath.extension().and_then(|e| e.to_str()) {
-                let contents = contents.trim();
-                if !contents.starts_with("//") && contents.contains("#[test]") {
-                    tidy_error!(
-                        bad,
-                        "`{}` contains `#[test]`; libcore tests must be placed inside \
-                        `src/libcore/tests/`",
-                        subpath.display()
-                    );
-                }
-            }
-        },
-    );
-}
diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs
index 918762ed6e6..19f02f0a96e 100644
--- a/src/tools/tidy/src/main.rs
+++ b/src/tools/tidy/src/main.rs
@@ -27,7 +27,7 @@ fn main() {
     let collected = features::check(&path, &mut bad, verbose);
     pal::check(&path, &mut bad);
     unstable_book::check(&path, collected, &mut bad);
-    libcoretest::check(&path, &mut bad);
+    unit_tests::check(&path, &mut bad);
     if !args.iter().any(|s| *s == "--no-vendor") {
         deps::check(&path, &mut bad);
     }
diff --git a/src/tools/tidy/src/unit_tests.rs b/src/tools/tidy/src/unit_tests.rs
new file mode 100644
index 00000000000..b789e5cfd48
--- /dev/null
+++ b/src/tools/tidy/src/unit_tests.rs
@@ -0,0 +1,95 @@
+//! Tidy check to ensure `#[test]` and `#[bench]` are not used directly inside
+//! `libcore` or `liballoc`.
+//!
+//! `#![no_std]` libraries cannot be tested directly due to duplicating lang
+//! items. All tests and benchmarks must be written externally in `libcore/{tests,benches}`
+//! or `liballoc/{tests,benches}`.
+//!
+//! Outside of libcore and liballoc tests and benchmarks should be outlined into separate files
+//! named `tests.rs` or `benches.rs`, or directories named `tests` or `benches` unconfigured
+//! during normal build.
+
+use std::path::Path;
+
+pub fn check(root_path: &Path, bad: &mut bool) {
+    let libcore = &root_path.join("libcore");
+    let liballoc = &root_path.join("liballoc");
+    let libcore_tests = &root_path.join("libcore/tests");
+    let liballoc_tests = &root_path.join("liballoc/tests");
+    let libcore_benches = &root_path.join("libcore/benches");
+    let liballoc_benches = &root_path.join("liballoc/benches");
+    let is_core_or_alloc = |path: &Path| {
+        let is_core = path.starts_with(libcore) &&
+                      !(path.starts_with(libcore_tests) || path.starts_with(libcore_benches));
+        let is_alloc = path.starts_with(liballoc) &&
+                       !(path.starts_with(liballoc_tests) || path.starts_with(liballoc_benches));
+        is_core || is_alloc
+    };
+    let fixme = [
+        "liballoc",
+        "libpanic_unwind/dwarf",
+        "librustc",
+        "librustc_data_structures",
+        "librustc_incremental/persist",
+        "librustc_lexer/src",
+        "librustc_target/spec",
+        "librustdoc",
+        "libserialize",
+        "libstd",
+        "libsyntax",
+        "libsyntax_pos",
+        "libterm/terminfo",
+        "libtest",
+        "tools/compiletest/src",
+        "tools/tidy/src",
+    ];
+
+    let mut skip = |path: &Path| {
+        let file_name = path.file_name().unwrap_or_default();
+        if path.is_dir() {
+            super::filter_dirs(path) ||
+            path.ends_with("src/test") ||
+            path.ends_with("src/doc") ||
+            (file_name == "tests" || file_name == "benches") && !is_core_or_alloc(path) ||
+            fixme.iter().any(|p| path.ends_with(p))
+        } else {
+            let extension = path.extension().unwrap_or_default();
+            extension != "rs" ||
+            (file_name == "tests.rs" || file_name == "benches.rs") && !is_core_or_alloc(path)
+        }
+    };
+
+    super::walk(
+        root_path,
+        &mut skip,
+        &mut |entry, contents| {
+            let path = entry.path();
+            let is_libcore = path.starts_with(libcore);
+            let is_liballoc = path.starts_with(liballoc);
+            for (i, line) in contents.lines().enumerate() {
+                let line = line.trim();
+                let is_test = || line.contains("#[test]") && !line.contains("`#[test]");
+                let is_bench = || line.contains("#[bench]") && !line.contains("`#[bench]");
+                if !line.starts_with("//") && (is_test() || is_bench()) {
+                    let explanation = if is_libcore {
+                        "libcore unit tests and benchmarks must be placed into \
+                         `libcore/tests` or `libcore/benches`"
+                    } else if is_liballoc {
+                        "liballoc unit tests and benchmarks must be placed into \
+                         `liballoc/tests` or `liballoc/benches`"
+                    } else {
+                        "unit tests and benchmarks must be placed into \
+                         separate files or directories named \
+                         `tests.rs`, `benches.rs`, `tests` or `benches`"
+                    };
+                    let name = if is_test() { "test" } else { "bench" };
+                    tidy_error!(
+                        bad, "`{}:{}` contains `#[{}]`; {}",
+                        path.display(), i + 1, name, explanation,
+                    );
+                    return;
+                }
+            }
+        },
+    );
+}