summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-08-05 11:48:01 +0000
committerbors <bors@rust-lang.org>2019-08-05 11:48:01 +0000
commit3f55461efb25b3c8b5c5c3d829065cb032ec953b (patch)
tree68f418e03e74fe674a8f2c9393ab4017f0e07c3d /src
parent61d1607e0f6a18bb4897d6f9b10abeac9e11eb8e (diff)
parent775ffd9df1b90e83c3145e3fefff30072c0683f8 (diff)
downloadrust-3f55461efb25b3c8b5c5c3d829065cb032ec953b.tar.gz
rust-3f55461efb25b3c8b5c5c3d829065cb032ec953b.zip
Auto merge of #63262 - pietroalbini:beta-rollup, r=pietroalbini
[beta] Rollup backports

Cherry picked:

*  Updated RELEASES.md for 1.37.0 #63147
*  Require a value for configure --debuginfo-level #62906
*  Make the parser TokenStream more resilient after mismatched delimiter recovery #62887
*  ci: move .azure-pipelines to src/ci/azure-pipelines #63242

Rolled up:

*  [BETA] Update cargo #62911
*  [beta] Backport #61207 #63254

r? @ghost
Diffstat (limited to 'src')
-rwxr-xr-xsrc/bootstrap/configure.py10
-rw-r--r--src/ci/azure-pipelines/auto.yml350
-rw-r--r--src/ci/azure-pipelines/master.yml25
-rw-r--r--src/ci/azure-pipelines/pr.yml33
-rw-r--r--src/ci/azure-pipelines/steps/install-clang.yml40
-rw-r--r--src/ci/azure-pipelines/steps/install-sccache.yml21
-rw-r--r--src/ci/azure-pipelines/steps/install-windows-build-deps.yml94
-rw-r--r--src/ci/azure-pipelines/steps/run.yml200
-rw-r--r--src/ci/azure-pipelines/try.yml78
-rwxr-xr-xsrc/ci/run.sh2
-rw-r--r--src/librustc/middle/resolve_lifetime.rs95
-rw-r--r--src/libsyntax/parse/parser.rs15
-rw-r--r--src/test/ui/parser/issue-62881.rs6
-rw-r--r--src/test/ui/parser/issue-62881.stderr29
-rw-r--r--src/test/ui/parser/issue-62895.rs11
-rw-r--r--src/test/ui/parser/issue-62895.stderr49
-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
m---------src/tools/cargo0
53 files changed, 2516 insertions, 40 deletions
diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py
index 53d3dbf60d1..907983d43ad 100755
--- a/src/bootstrap/configure.py
+++ b/src/bootstrap/configure.py
@@ -76,11 +76,11 @@ o("optimize-llvm", "llvm.optimize", "build optimized LLVM")
 o("llvm-assertions", "llvm.assertions", "build LLVM with assertions")
 o("debug-assertions", "rust.debug-assertions", "build with debugging assertions")
 o("llvm-release-debuginfo", "llvm.release-debuginfo", "build LLVM with debugger metadata")
-o("debuginfo-level", "rust.debuginfo-level", "debuginfo level for Rust code")
-o("debuginfo-level-rustc", "rust.debuginfo-level-rustc", "debuginfo level for the compiler")
-o("debuginfo-level-std", "rust.debuginfo-level-std", "debuginfo level for the standard library")
-o("debuginfo-level-tools", "rust.debuginfo-level-tools", "debuginfo level for the tools")
-o("debuginfo-level-tests", "rust.debuginfo-level-tests", "debuginfo level for the test suites run with compiletest")
+v("debuginfo-level", "rust.debuginfo-level", "debuginfo level for Rust code")
+v("debuginfo-level-rustc", "rust.debuginfo-level-rustc", "debuginfo level for the compiler")
+v("debuginfo-level-std", "rust.debuginfo-level-std", "debuginfo level for the standard library")
+v("debuginfo-level-tools", "rust.debuginfo-level-tools", "debuginfo level for the tools")
+v("debuginfo-level-tests", "rust.debuginfo-level-tests", "debuginfo level for the test suites run with compiletest")
 v("save-toolstates", "rust.save-toolstates", "save build and test status of external tools into this file")
 
 v("prefix", "install.prefix", "set installation prefix")
diff --git a/src/ci/azure-pipelines/auto.yml b/src/ci/azure-pipelines/auto.yml
new file mode 100644
index 00000000000..2e6c3b7a992
--- /dev/null
+++ b/src/ci/azure-pipelines/auto.yml
@@ -0,0 +1,350 @@
+#
+# Azure Pipelines "auto" branch build for Rust on Linux, macOS, and Windows.
+#
+
+pr: none
+trigger:
+  - auto
+
+variables:
+- group: real-prod-credentials
+
+jobs:
+- job: Linux
+  timeoutInMinutes: 600
+  pool:
+    vmImage: ubuntu-16.04
+  steps:
+  - template: steps/run.yml
+  strategy:
+    matrix:
+      x86_64-gnu-llvm-6.0:
+        IMAGE: x86_64-gnu-llvm-6.0
+        RUST_BACKTRACE: 1
+
+      dist-x86_64-linux:
+        IMAGE: dist-x86_64-linux
+        DEPLOY: 1
+
+      # "alternate" deployments, these are "nightlies" but have LLVM assertions
+      # turned on, they're deployed to a different location primarily for
+      # additional testing.
+      dist-x86_64-linux-alt:
+        IMAGE: dist-x86_64-linux
+        DEPLOY_ALT: 1
+
+      # Linux builders, remaining docker images
+      arm-android:
+        IMAGE: arm-android
+
+      armhf-gnu:
+        IMAGE: armhf-gnu
+
+      dist-various-1:
+        IMAGE: dist-various-1
+        DEPLOY: 1
+
+      dist-various-2:
+        IMAGE: dist-various-2
+        DEPLOY: 1
+
+      dist-aarch64-linux:
+        IMAGE: dist-aarch64-linux
+        DEPLOY: 1
+
+      dist-android:
+        IMAGE: dist-android
+        DEPLOY: 1
+
+      dist-arm-linux:
+        IMAGE: dist-arm-linux
+        DEPLOY: 1
+
+      dist-armhf-linux:
+        IMAGE: dist-armhf-linux
+        DEPLOY: 1
+
+      dist-armv7-linux:
+        IMAGE: dist-armv7-linux
+        DEPLOY: 1
+
+      dist-i586-gnu-i586-i686-musl:
+        IMAGE: dist-i586-gnu-i586-i686-musl
+        DEPLOY: 1
+
+      dist-i686-freebsd:
+        IMAGE: dist-i686-freebsd
+        DEPLOY: 1
+
+      dist-i686-linux:
+        IMAGE: dist-i686-linux
+        DEPLOY: 1
+
+      dist-mips-linux:
+        IMAGE: dist-mips-linux
+        DEPLOY: 1
+
+      dist-mips64-linux:
+        IMAGE: dist-mips64-linux
+        DEPLOY: 1
+
+      dist-mips64el-linux:
+        IMAGE: dist-mips64el-linux
+        DEPLOY: 1
+
+      dist-mipsel-linux:
+        IMAGE: dist-mipsel-linux
+        DEPLOY: 1
+
+      dist-powerpc-linux:
+        IMAGE: dist-powerpc-linux
+        DEPLOY: 1
+
+      dist-powerpc64-linux:
+        IMAGE: dist-powerpc64-linux
+        DEPLOY: 1
+
+      dist-powerpc64le-linux:
+        IMAGE: dist-powerpc64le-linux
+        DEPLOY: 1
+
+      dist-s390x-linux:
+        IMAGE: dist-s390x-linux
+        DEPLOY: 1
+
+      dist-x86_64-freebsd:
+        IMAGE: dist-x86_64-freebsd
+        DEPLOY: 1
+
+      dist-x86_64-musl:
+        IMAGE: dist-x86_64-musl
+        DEPLOY: 1
+
+      dist-x86_64-netbsd:
+        IMAGE: dist-x86_64-netbsd
+        DEPLOY: 1
+
+      asmjs:
+        IMAGE: asmjs
+      i686-gnu:
+        IMAGE: i686-gnu
+      i686-gnu-nopt:
+        IMAGE: i686-gnu-nopt
+      test-various:
+        IMAGE: test-various
+      x86_64-gnu:
+        IMAGE: x86_64-gnu
+      x86_64-gnu-full-bootstrap:
+        IMAGE: x86_64-gnu-full-bootstrap
+      x86_64-gnu-aux:
+        IMAGE: x86_64-gnu-aux
+      x86_64-gnu-tools:
+        IMAGE: x86_64-gnu-tools
+      x86_64-gnu-debug:
+        IMAGE: x86_64-gnu-debug
+      x86_64-gnu-nopt:
+        IMAGE: x86_64-gnu-nopt
+      x86_64-gnu-distcheck:
+        IMAGE: x86_64-gnu-distcheck
+      mingw-check:
+        IMAGE: mingw-check
+
+- job: macOS
+  timeoutInMinutes: 600
+  pool:
+    vmImage: macos-10.13
+  steps:
+  - template: steps/run.yml
+  strategy:
+    matrix:
+      # OSX builders running tests, these run the full test suite.
+      # NO_DEBUG_ASSERTIONS=1 to make them go faster, but also do have some
+      # runners that run `//ignore-debug` tests.
+      #
+      # Note that the compiler is compiled to target 10.8 here because the Xcode
+      # version that we're using, 8.2, cannot compile LLVM for OSX 10.7.
+      x86_64-apple:
+        SCRIPT: ./x.py test
+        RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc
+        RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+        MACOSX_DEPLOYMENT_TARGET: 10.8
+        MACOSX_STD_DEPLOYMENT_TARGET: 10.7
+        NO_LLVM_ASSERTIONS: 1
+        NO_DEBUG_ASSERTIONS: 1
+
+      dist-x86_64-apple:
+        SCRIPT: ./x.py dist
+        RUST_CONFIGURE_ARGS: --target=aarch64-apple-ios,armv7-apple-ios,armv7s-apple-ios,i386-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --enable-lldb --set rust.jemalloc
+        DEPLOY: 1
+        RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+        MACOSX_DEPLOYMENT_TARGET: 10.7
+        NO_LLVM_ASSERTIONS: 1
+        NO_DEBUG_ASSERTIONS: 1
+        DIST_REQUIRE_ALL_TOOLS: 1
+
+      dist-x86_64-apple-alt:
+        SCRIPT: ./x.py dist
+        RUST_CONFIGURE_ARGS: --enable-extended --enable-profiler --enable-lldb --set rust.jemalloc
+        DEPLOY_ALT: 1
+        RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+        MACOSX_DEPLOYMENT_TARGET: 10.7
+        NO_LLVM_ASSERTIONS: 1
+        NO_DEBUG_ASSERTIONS: 1
+
+      i686-apple:
+        SCRIPT: ./x.py test
+        RUST_CONFIGURE_ARGS: --build=i686-apple-darwin --set rust.jemalloc
+        RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+        MACOSX_DEPLOYMENT_TARGET: 10.8
+        MACOSX_STD_DEPLOYMENT_TARGET: 10.7
+        NO_LLVM_ASSERTIONS: 1
+        NO_DEBUG_ASSERTIONS: 1
+
+      dist-i686-apple:
+        SCRIPT: ./x.py dist
+        RUST_CONFIGURE_ARGS: --build=i686-apple-darwin --enable-full-tools --enable-profiler --enable-lldb --set rust.jemalloc
+        DEPLOY: 1
+        RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+        MACOSX_DEPLOYMENT_TARGET: 10.7
+        NO_LLVM_ASSERTIONS: 1
+        NO_DEBUG_ASSERTIONS: 1
+        DIST_REQUIRE_ALL_TOOLS: 1
+
+
+
+- job: Windows
+  timeoutInMinutes: 600
+  pool:
+    vmImage: 'vs2017-win2016'
+  steps:
+  - template: steps/run.yml
+  strategy:
+    matrix:
+      # 32/64 bit MSVC tests
+      x86_64-msvc-1:
+        MSYS_BITS: 64
+        RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-profiler
+        SCRIPT: make ci-subset-1
+        # FIXME(#59637)
+        NO_DEBUG_ASSERTIONS: 1
+        NO_LLVM_ASSERTIONS: 1
+      x86_64-msvc-2:
+        MSYS_BITS: 64
+        RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-profiler
+        SCRIPT: make ci-subset-2
+      i686-msvc-1:
+        MSYS_BITS: 32
+        RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc
+        SCRIPT: make ci-subset-1
+      i686-msvc-2:
+        MSYS_BITS: 32
+        RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc
+        SCRIPT: make ci-subset-2
+      # MSVC aux tests
+      x86_64-msvc-aux:
+        MSYS_BITS: 64
+        RUST_CHECK_TARGET: check-aux EXCLUDE_CARGO=1
+        RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc
+      x86_64-msvc-cargo:
+        MSYS_BITS: 64
+        SCRIPT: python x.py test src/tools/cargotest src/tools/cargo
+        RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc
+        VCVARS_BAT: vcvars64.bat
+      # MSVC tools tests
+      x86_64-msvc-tools:
+        MSYS_BITS: 64
+        SCRIPT: src/ci/docker/x86_64-gnu-tools/checktools.sh x.py /tmp/toolstates.json windows
+        RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --save-toolstates=/tmp/toolstates.json --enable-test-miri
+
+      # 32/64-bit MinGW builds.
+      #
+      # We are using MinGW with posix threads since LLVM does not compile with
+      # the win32 threads version due to missing support for C++'s std::thread.
+      #
+      # Instead of relying on the MinGW version installed on appveryor we download
+      # and install one ourselves so we won't be surprised by changes to appveyor's
+      # build image.
+      #
+      # Finally, note that the downloads below are all in the `rust-lang-ci` S3
+      # bucket, but they cleraly didn't originate there! The downloads originally
+      # came from the mingw-w64 SourceForge download site. Unfortunately
+      # SourceForge is notoriously flaky, so we mirror it on our own infrastructure.
+      i686-mingw-1:
+        MSYS_BITS: 32
+        RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu
+        SCRIPT: make ci-subset-1
+        MINGW_URL: https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror
+        MINGW_ARCHIVE: i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z
+        MINGW_DIR: mingw32
+        # FIXME(#59637)
+        NO_DEBUG_ASSERTIONS: 1
+        NO_LLVM_ASSERTIONS: 1
+      i686-mingw-2:
+        MSYS_BITS: 32
+        RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu
+        SCRIPT: make ci-subset-2
+        MINGW_URL: https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror
+        MINGW_ARCHIVE: i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z
+        MINGW_DIR: mingw32
+      x86_64-mingw-1:
+        MSYS_BITS: 64
+        SCRIPT: make ci-subset-1
+        RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu
+        MINGW_URL: https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror
+        MINGW_ARCHIVE: x86_64-6.3.0-release-posix-seh-rt_v5-rev2.7z
+        MINGW_DIR: mingw64
+        # FIXME(#59637)
+        NO_DEBUG_ASSERTIONS: 1
+        NO_LLVM_ASSERTIONS: 1
+      x86_64-mingw-2:
+        MSYS_BITS: 64
+        SCRIPT: make ci-subset-2
+        RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu
+        MINGW_URL: https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror
+        MINGW_ARCHIVE: x86_64-6.3.0-release-posix-seh-rt_v5-rev2.7z
+        MINGW_DIR: mingw64
+
+      # 32/64 bit MSVC and GNU deployment
+      dist-x86_64-msvc:
+        RUST_CONFIGURE_ARGS: >
+          --build=x86_64-pc-windows-msvc
+          --target=x86_64-pc-windows-msvc,aarch64-pc-windows-msvc
+          --enable-full-tools
+          --enable-profiler
+        SCRIPT: python x.py dist
+        DIST_REQUIRE_ALL_TOOLS: 1
+        DEPLOY: 1
+      dist-i686-msvc:
+        RUST_CONFIGURE_ARGS: >
+          --build=i686-pc-windows-msvc
+          --target=i586-pc-windows-msvc
+          --enable-full-tools
+          --enable-profiler
+        SCRIPT: python x.py dist
+        DIST_REQUIRE_ALL_TOOLS: 1
+        DEPLOY: 1
+      dist-i686-mingw:
+        MSYS_BITS: 32
+        RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-full-tools --enable-profiler
+        SCRIPT: python x.py dist
+        MINGW_URL: https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror
+        MINGW_ARCHIVE: i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z
+        MINGW_DIR: mingw32
+        DIST_REQUIRE_ALL_TOOLS: 1
+        DEPLOY: 1
+      dist-x86_64-mingw:
+        MSYS_BITS: 64
+        SCRIPT: python x.py dist
+        RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-full-tools --enable-profiler
+        MINGW_URL: https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror
+        MINGW_ARCHIVE: x86_64-6.3.0-release-posix-seh-rt_v5-rev2.7z
+        MINGW_DIR: mingw64
+        DIST_REQUIRE_ALL_TOOLS: 1
+        DEPLOY: 1
+
+      # "alternate" deployment, see .travis.yml for more info
+      dist-x86_64-msvc-alt:
+        MSYS_BITS: 64
+        RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-extended --enable-profiler
+        SCRIPT: python x.py dist
+        DEPLOY_ALT: 1
diff --git a/src/ci/azure-pipelines/master.yml b/src/ci/azure-pipelines/master.yml
new file mode 100644
index 00000000000..9742c719658
--- /dev/null
+++ b/src/ci/azure-pipelines/master.yml
@@ -0,0 +1,25 @@
+#
+# Azure Pipelines job to publish toolstate. Only triggers on pushes to master.
+#
+
+pr: none
+trigger:
+  - master
+
+variables:
+- group: real-prod-credentials
+
+pool:
+  vmImage: ubuntu-16.04
+
+steps:
+- checkout: self
+  fetchDepth: 2
+
+- script: |
+    export MESSAGE_FILE=$(mktemp -t msg.XXXXXX)
+    . src/ci/docker/x86_64-gnu-tools/repo.sh
+    commit_toolstate_change "$MESSAGE_FILE" "$BUILD_SOURCESDIRECTORY/src/tools/publish_toolstate.py" "$(git rev-parse HEAD)" "$(git log --format=%s -n1 HEAD)" "$MESSAGE_FILE" "$TOOLSTATE_REPO_ACCESS_TOKEN"
+  displayName: Publish toolstate
+  env:
+    TOOLSTATE_REPO_ACCESS_TOKEN: $(TOOLSTATE_REPO_ACCESS_TOKEN)
diff --git a/src/ci/azure-pipelines/pr.yml b/src/ci/azure-pipelines/pr.yml
new file mode 100644
index 00000000000..88b5067b4a3
--- /dev/null
+++ b/src/ci/azure-pipelines/pr.yml
@@ -0,0 +1,33 @@
+#
+# Azure Pipelines pull request build for Rust
+#
+
+trigger: none
+pr:
+- master
+
+jobs:
+- job: Linux
+  timeoutInMinutes: 600
+  pool:
+    vmImage: ubuntu-16.04
+  steps:
+    - template: steps/run.yml
+  strategy:
+    matrix:
+      x86_64-gnu-llvm-6.0:
+        IMAGE: x86_64-gnu-llvm-6.0
+      mingw-check:
+        IMAGE: mingw-check
+
+# TODO: enable this job if the commit message matches this regex, need tools
+# figure out how to get the current commit message on azure and stick it in a
+# condition somewhere
+#     if: commit_message =~ /(?i:^update.*\b(rls|rustfmt|clippy|miri|cargo)\b)/
+# - job: Linux-x86_64-gnu-tools
+#   pool:
+#     vmImage: ubuntu-16.04
+#   steps:
+#     - template: steps/run.yml
+#   variables:
+#     IMAGE: x86_64-gnu-tools
diff --git a/src/ci/azure-pipelines/steps/install-clang.yml b/src/ci/azure-pipelines/steps/install-clang.yml
new file mode 100644
index 00000000000..0cd6f24e32c
--- /dev/null
+++ b/src/ci/azure-pipelines/steps/install-clang.yml
@@ -0,0 +1,40 @@
+steps:
+
+- bash: |
+    set -e
+    curl -f http://releases.llvm.org/7.0.0/clang+llvm-7.0.0-x86_64-apple-darwin.tar.xz | tar xJf -
+
+    export CC=`pwd`/clang+llvm-7.0.0-x86_64-apple-darwin/bin/clang
+    echo "##vso[task.setvariable variable=CC]$CC"
+
+    export CXX=`pwd`/clang+llvm-7.0.0-x86_64-apple-darwin/bin/clang++
+    echo "##vso[task.setvariable variable=CXX]$CXX"
+
+    # Configure `AR` specifically so rustbuild doesn't try to infer it as
+    # `clang-ar` by accident.
+    echo "##vso[task.setvariable variable=AR]ar"
+  displayName: Install clang (OSX)
+  condition: and(succeeded(), eq(variables['Agent.OS'], 'Darwin'))
+
+# If we're compiling for MSVC then we, like most other distribution builders,
+# switch to clang as the compiler. This'll allow us eventually to enable LTO
+# amongst LLVM and rustc. Note that we only do this on MSVC as I don't think
+# clang has an output mode compatible with MinGW that we need. If it does we
+# should switch to clang for MinGW as well!
+#
+# Note that the LLVM installer is an NSIS installer
+#
+# Original downloaded here came from
+# http://releases.llvm.org/7.0.0/LLVM-7.0.0-win64.exe
+- script: |
+    powershell -Command "$ProgressPreference = 'SilentlyContinue'; iwr -outf %TEMP%\LLVM-7.0.0-win64.exe https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/LLVM-7.0.0-win64.exe"
+    set CLANG_DIR=%CD%\citools\clang-rust
+    %TEMP%\LLVM-7.0.0-win64.exe /S /NCRC /D=%CLANG_DIR%
+    set RUST_CONFIGURE_ARGS=%RUST_CONFIGURE_ARGS% --set llvm.clang-cl=%CLANG_DIR%\bin\clang-cl.exe
+    echo ##vso[task.setvariable variable=RUST_CONFIGURE_ARGS]%RUST_CONFIGURE_ARGS%
+  condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'), eq(variables['MINGW_URL'],''))
+  displayName: Install clang (Windows)
+
+# Note that we don't install clang on Linux since its compiler story is just so
+# different. Each container has its own toolchain configured appropriately
+# already.
diff --git a/src/ci/azure-pipelines/steps/install-sccache.yml b/src/ci/azure-pipelines/steps/install-sccache.yml
new file mode 100644
index 00000000000..427e50f571f
--- /dev/null
+++ b/src/ci/azure-pipelines/steps/install-sccache.yml
@@ -0,0 +1,21 @@
+steps:
+
+- bash: |
+    set -e
+    curl -fo /usr/local/bin/sccache https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/2018-04-02-sccache-x86_64-apple-darwin
+    chmod +x /usr/local/bin/sccache
+  displayName: Install sccache (OSX)
+  condition: and(succeeded(), eq(variables['Agent.OS'], 'Darwin'))
+
+- script: |
+    md sccache
+    powershell -Command "$ProgressPreference = 'SilentlyContinue'; iwr -outf sccache\sccache.exe https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/2018-04-26-sccache-x86_64-pc-windows-msvc"
+    echo ##vso[task.prependpath]%CD%\sccache
+  displayName: Install sccache (Windows)
+  condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
+
+# Note that we don't install sccache on Linux since it's installed elsewhere
+# through all the containers.
+#
+# FIXME: we should probably install sccache outside the containers and then
+# mount it inside the containers so we can centralize all installation here.
diff --git a/src/ci/azure-pipelines/steps/install-windows-build-deps.yml b/src/ci/azure-pipelines/steps/install-windows-build-deps.yml
new file mode 100644
index 00000000000..ed06679464c
--- /dev/null
+++ b/src/ci/azure-pipelines/steps/install-windows-build-deps.yml
@@ -0,0 +1,94 @@
+steps:
+# We've had issues with the default drive in use running out of space during a
+# build, and it looks like the `C:` drive has more space than the default `D:`
+# drive. We should probably confirm this with the azure pipelines team at some
+# point, but this seems to fix our "disk space full" problems.
+- script: |
+    mkdir c:\MORE_SPACE
+    mklink /J build c:\MORE_SPACE
+  displayName: "Ensure build happens on C:/ instead of D:/"
+  condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
+
+- bash: git config --replace-all --global core.autocrlf false
+  displayName: "Disable git automatic line ending conversion (on C:/)"
+
+# Download and install MSYS2, needed primarily for the test suite (run-make) but
+# also used by the MinGW toolchain for assembling things.
+#
+# FIXME: we should probe the default azure image and see if we can use the MSYS2
+# toolchain there. (if there's even one there). For now though this gets the job
+# done.
+- script: |
+    set MSYS_PATH=%CD%\citools\msys64
+    choco install msys2 --params="/InstallDir:%MSYS_PATH% /NoPath" -y
+    set PATH=%MSYS_PATH%\usr\bin;%PATH%
+    pacman -S --noconfirm --needed base-devel ca-certificates make diffutils tar
+    IF "%MINGW_URL%"=="" (
+      IF "%MSYS_BITS%"=="32" pacman -S --noconfirm --needed mingw-w64-i686-toolchain mingw-w64-i686-cmake mingw-w64-i686-gcc mingw-w64-i686-python2
+      IF "%MSYS_BITS%"=="64" pacman -S --noconfirm --needed mingw-w64-x86_64-toolchain mingw-w64-x86_64-cmake mingw-w64-x86_64-gcc mingw-w64-x86_64-python2
+    )
+    where rev
+    rev --help
+    where make
+
+    echo ##vso[task.setvariable variable=MSYS_PATH]%MSYS_PATH%
+    echo ##vso[task.prependpath]%MSYS_PATH%\usr\bin
+  displayName: Install msys2
+  condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
+
+# If we need to download a custom MinGW, do so here and set the path
+# appropriately.
+#
+# Here we also do a pretty heinous thing which is to mangle the MinGW
+# installation we just downloaded. Currently, as of this writing, we're using
+# MinGW-w64 builds of gcc, and that's currently at 6.3.0. We use 6.3.0 as it
+# appears to be the first version which contains a fix for #40546, builds
+# randomly failing during LLVM due to ar.exe/ranlib.exe failures.
+#
+# Unfortunately, though, 6.3.0 *also* is the first version of MinGW-w64 builds
+# to contain a regression in gdb (#40184). As a result if we were to use the
+# gdb provided (7.11.1) then we would fail all debuginfo tests.
+#
+# In order to fix spurious failures (pretty high priority) we use 6.3.0. To
+# avoid disabling gdb tests we download an *old* version of gdb, specifically
+# that found inside the 6.2.0 distribution. We then overwrite the 6.3.0 gdb
+# with the 6.2.0 gdb to get tests passing.
+#
+# Note that we don't literally overwrite the gdb.exe binary because it appears
+# to just use gdborig.exe, so that's the binary we deal with instead.
+- script: |
+    powershell -Command "$ProgressPreference = 'SilentlyContinue'; iwr -outf %MINGW_ARCHIVE% %MINGW_URL%/%MINGW_ARCHIVE%"
+    7z x -y %MINGW_ARCHIVE% > nul
+    powershell -Command "$ProgressPreference = 'SilentlyContinue'; iwr -outf 2017-04-20-%MSYS_BITS%bit-gdborig.exe %MINGW_URL%/2017-04-20-%MSYS_BITS%bit-gdborig.exe"
+    mv 2017-04-20-%MSYS_BITS%bit-gdborig.exe %MINGW_DIR%\bin\gdborig.exe
+    echo ##vso[task.prependpath]%CD%\%MINGW_DIR%\bin
+  condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'), ne(variables['MINGW_URL'],''))
+  displayName: Download custom MinGW
+
+# Otherwise pull in the MinGW installed on appveyor
+- script: |
+    echo ##vso[task.prependpath]%MSYS_PATH%\mingw%MSYS_BITS%\bin
+  condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'), eq(variables['MINGW_URL'],''))
+  displayName: Add MinGW to path
+
+# Make sure we use the native python interpreter instead of some msys equivalent
+# one way or another. The msys interpreters seem to have weird path conversions
+# baked in which break LLVM's build system one way or another, so let's use the
+# native version which keeps everything as native as possible.
+- script: |
+    copy C:\Python27amd64\python.exe C:\Python27amd64\python2.7.exe
+    echo ##vso[task.prependpath]C:\Python27amd64
+  displayName: Prefer the "native" Python as LLVM has trouble building with MSYS sometimes
+  condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
+
+# Note that this is originally from the github releases patch of Ninja
+- script: |
+    md ninja
+    powershell -Command "$ProgressPreference = 'SilentlyContinue'; iwr -outf 2017-03-15-ninja-win.zip https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/2017-03-15-ninja-win.zip"
+    7z x -oninja 2017-03-15-ninja-win.zip
+    del 2017-03-15-ninja-win.zip
+    set RUST_CONFIGURE_ARGS=%RUST_CONFIGURE_ARGS% --enable-ninja
+    echo ##vso[task.setvariable variable=RUST_CONFIGURE_ARGS]%RUST_CONFIGURE_ARGS%
+    echo ##vso[task.prependpath]%CD%\ninja
+  displayName: Download and install ninja
+  condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
diff --git a/src/ci/azure-pipelines/steps/run.yml b/src/ci/azure-pipelines/steps/run.yml
new file mode 100644
index 00000000000..18385f078bf
--- /dev/null
+++ b/src/ci/azure-pipelines/steps/run.yml
@@ -0,0 +1,200 @@
+# FIXME(linux): need to configure core dumps, enable them, and then dump
+# backtraces on failure from all core dumps:
+#
+# - bash: sudo apt install gdb
+# - bash: sudo sh -c 'echo "/checkout/obj/cores/core.%p.%E" > /proc/sys/kernel/core_pattern'
+#
+# Check travis config for `gdb --batch` command to print all crash logs
+
+steps:
+
+# Disable automatic line ending conversion, which is enabled by default on
+# Azure's Windows image. Having the conversion enabled caused regressions both
+# in our test suite (it broke miri tests) and in the ecosystem, since we
+# started shipping install scripts with CRLF endings instead of the old LF.
+#
+# Note that we do this a couple times during the build as the PATH and current
+# user/directory change, e.g. when mingw is enabled.
+- bash: git config --global core.autocrlf false
+  displayName: "Disable git automatic line ending conversion"
+
+- checkout: self
+  fetchDepth: 2
+
+# Spawn a background process to collect CPU usage statistics which we'll upload
+# at the end of the build. See the comments in the script here for more
+# information.
+- bash: python src/ci/cpu-usage-over-time.py &> cpu-usage.csv &
+  displayName: "Collect CPU-usage statistics in the background"
+
+- bash: printenv | sort
+  displayName: Show environment variables
+
+- bash: |
+    set -e
+    df -h
+    du . | sort -nr | head -n100
+  displayName: Show disk usage
+  # FIXME: this hasn't been tested, but maybe it works on Windows? Should test!
+  condition: and(succeeded(), ne(variables['Agent.OS'], 'Windows_NT'))
+
+- template: install-sccache.yml
+- template: install-clang.yml
+
+# Install some dependencies needed to build LLDB/Clang, currently only needed
+# during the `dist` target
+- bash: |
+    set -e
+    brew update
+    brew install xz
+    brew install swig@3
+    brew link --force swig@3
+  displayName: Install build dependencies (OSX)
+  condition: and(succeeded(), eq(variables['Agent.OS'], 'Darwin'), eq(variables['SCRIPT'],'./x.py dist'))
+
+# Switch to XCode 9.3 on OSX since it seems to be the last version that supports
+# i686-apple-darwin. We'll eventually want to upgrade this and it will probably
+# force us to drop i686-apple-darwin, but let's keep the wheels turning for now.
+- bash: |
+    set -e
+    sudo xcode-select --switch /Applications/Xcode_9.3.app
+  displayName: Switch to Xcode 9.3 (OSX)
+  condition: and(succeeded(), eq(variables['Agent.OS'], 'Darwin'))
+
+- template: install-windows-build-deps.yml
+
+# Looks like docker containers have IPv6 disabled by default, so let's turn it
+# on since libstd tests require it
+- bash: |
+    set -e
+    sudo mkdir -p /etc/docker
+    echo '{"ipv6":true,"fixed-cidr-v6":"fd9a:8454:6789:13f7::/64"}' | sudo tee /etc/docker/daemon.json
+    sudo service docker restart
+  displayName: Enable IPv6
+  condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux'))
+
+# Disable automatic line ending conversion (again). On Windows, when we're
+# installing dependencies, something switches the git configuration directory or
+# re-enables autocrlf. We've not tracked down the exact cause -- and there may
+# be multiple -- but this should ensure submodules are checked out with the
+# appropriate line endings.
+- bash: git config --replace-all --global core.autocrlf false
+  displayName: "Disable git automatic line ending conversion"
+
+# Check out all our submodules, but more quickly than using git by using one of
+# our custom scripts
+- bash: |
+    set -e
+    mkdir -p $HOME/rustsrc
+    $BUILD_SOURCESDIRECTORY/src/ci/init_repo.sh . $HOME/rustsrc
+  condition: and(succeeded(), ne(variables['Agent.OS'], 'Windows_NT'))
+  displayName: Check out submodules (Unix)
+- script: |
+    if not exist D:\cache\rustsrc\NUL mkdir D:\cache\rustsrc
+    sh src/ci/init_repo.sh . /d/cache/rustsrc
+  condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
+  displayName: Check out submodules (Windows)
+
+# See also the disable for autocrlf above, this just checks that it worked
+#
+# We check both in rust-lang/rust and in a submodule to make sure both are
+# accurate. Submodules are checked out significantly later than the main
+# repository in this script, so settings can (and do!) change between then.
+#
+# Linux (and maybe macOS) builders don't currently have dos2unix so just only
+# run this step on Windows.
+- bash: |
+    set -x
+    # print out the git configuration so we can better investigate failures in
+    # the following
+    git config --list --show-origin
+    dos2unix -ih Cargo.lock src/tools/rust-installer/install-template.sh
+    endings=$(dos2unix -ic Cargo.lock src/tools/rust-installer/install-template.sh)
+    # if endings has non-zero length, error out
+    if [ -n "$endings" ]; then exit 1 ; fi
+  condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
+  displayName: Verify line endings are LF
+
+# Ensure the `aws` CLI is installed so we can deploy later on, cache docker
+# images, etc.
+- bash: |
+    set -e
+    source src/ci/shared.sh
+    sudo apt-get install -y python3-setuptools
+    retry pip3 install -r src/ci/awscli-requirements.txt --upgrade --user
+    echo "##vso[task.prependpath]$HOME/.local/bin"
+  displayName: Install awscli (Linux)
+  condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux'))
+- script: pip install -r src/ci/awscli-requirements.txt
+  displayName: Install awscli (non-Linux)
+  condition: and(succeeded(), ne(variables['Agent.OS'], 'Linux'))
+
+# Configure our CI_JOB_NAME variable which log analyzers can use for the main
+# step to see what's going on.
+- bash: echo "##vso[task.setvariable variable=CI_JOB_NAME]$SYSTEM_JOBNAME"
+  displayName: Configure Job Name
+
+# As a quick smoke check on the otherwise very fast mingw-check linux builder
+# check our own internal scripts.
+- bash: |
+    set -e
+    git clone --depth=1 https://github.com/rust-lang-nursery/rust-toolstate.git
+    cd rust-toolstate
+    python2.7 "$BUILD_SOURCESDIRECTORY/src/tools/publish_toolstate.py" "$(git rev-parse HEAD)" "$(git log --format=%s -n1 HEAD)" "" ""
+    cd ..
+    rm -rf rust-toolstate
+  condition: and(succeeded(), eq(variables['IMAGE'], 'mingw-check'))
+  displayName: Verify the publish_toolstate script works
+
+- bash: |
+    set -e
+    # Remove any preexisting rustup installation since it can interfere
+    # with the cargotest step and its auto-detection of things like Clippy in
+    # the environment
+    rustup self uninstall -y || true
+    if [ "$IMAGE" = "" ]; then
+      src/ci/run.sh
+    else
+      src/ci/docker/run.sh $IMAGE
+    fi
+  #timeoutInMinutes: 180
+  timeoutInMinutes: 600
+  env:
+    CI: true
+    SRC: .
+    AWS_SECRET_ACCESS_KEY: $(AWS_SECRET_ACCESS_KEY)
+    TOOLSTATE_REPO_ACCESS_TOKEN: $(TOOLSTATE_REPO_ACCESS_TOKEN)
+  displayName: Run build
+
+# If we're a deploy builder, use the `aws` command to publish everything to our
+# bucket.
+- bash: |
+    set -e
+    source src/ci/shared.sh
+    if [ "$AGENT_OS" = "Linux" ]; then
+        rm -rf obj/build/dist/doc
+        upload_dir=obj/build/dist
+    else
+        rm -rf build/dist/doc
+        upload_dir=build/dist
+    fi
+    ls -la $upload_dir
+    deploy_dir=rustc-builds
+    if [ "$DEPLOY_ALT" == "1" ]; then
+        deploy_dir=rustc-builds-alt
+    fi
+    retry aws s3 cp --no-progress --recursive --acl public-read ./$upload_dir s3://$DEPLOY_BUCKET/$deploy_dir/$BUILD_SOURCEVERSION
+  env:
+    AWS_SECRET_ACCESS_KEY: $(AWS_SECRET_ACCESS_KEY)
+  condition: and(succeeded(), or(eq(variables.DEPLOY, '1'), eq(variables.DEPLOY_ALT, '1')))
+  displayName: Upload artifacts
+
+# Upload CPU usage statistics that we've been gathering this whole time. Always
+# execute this step in case we want to inspect failed builds, but don't let
+# errors here ever fail the build since this is just informational.
+- bash: aws s3 cp --acl public-read cpu-usage.csv s3://$DEPLOY_BUCKET/rustc-builds/$BUILD_SOURCEVERSION/cpu-$SYSTEM_JOBNAME.csv
+  env:
+    AWS_SECRET_ACCESS_KEY: $(AWS_SECRET_ACCESS_KEY)
+  condition: variables['AWS_SECRET_ACCESS_KEY']
+  continueOnError: true
+  displayName: Upload CPU usage statistics
diff --git a/src/ci/azure-pipelines/try.yml b/src/ci/azure-pipelines/try.yml
new file mode 100644
index 00000000000..6a22e57c124
--- /dev/null
+++ b/src/ci/azure-pipelines/try.yml
@@ -0,0 +1,78 @@
+pr: none
+trigger:
+- try
+
+variables:
+- group: real-prod-credentials
+
+jobs:
+- job: Linux
+  timeoutInMinutes: 600
+  pool:
+    vmImage: ubuntu-16.04
+  steps:
+  - template: steps/run.yml
+  strategy:
+    matrix:
+      dist-x86_64-linux:
+        IMAGE: dist-x86_64-linux
+        DEPLOY: 1
+
+      dist-x86_64-linux-alt:
+        IMAGE: dist-x86_64-linux
+        DEPLOY_ALT: 1
+
+# The macOS and Windows builds here are currently disabled due to them not being
+# overly necessary on `try` builds. We also don't actually have anything that
+# consumes the artifacts currently. Perhaps one day we can reenable, but for now
+# it helps free up capacity on Azure.
+# - job: macOS
+#   timeoutInMinutes: 600
+#   pool:
+#     vmImage: macos-10.13
+#   steps:
+#   - template: steps/run.yml
+#   strategy:
+#     matrix:
+#       dist-x86_64-apple:
+#         SCRIPT: ./x.py dist
+#         RUST_CONFIGURE_ARGS: --target=aarch64-apple-ios,armv7-apple-ios,armv7s-apple-ios,i386-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --enable-lldb --set rust.jemalloc
+#         DEPLOY: 1
+#         RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+#         MACOSX_DEPLOYMENT_TARGET: 10.7
+#         NO_LLVM_ASSERTIONS: 1
+#         NO_DEBUG_ASSERTIONS: 1
+#         DIST_REQUIRE_ALL_TOOLS: 1
+#
+#       dist-x86_64-apple-alt:
+#         SCRIPT: ./x.py dist
+#         RUST_CONFIGURE_ARGS: --enable-extended --enable-profiler --enable-lldb --set rust.jemalloc
+#         DEPLOY_ALT: 1
+#         RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+#         MACOSX_DEPLOYMENT_TARGET: 10.7
+#         NO_LLVM_ASSERTIONS: 1
+#         NO_DEBUG_ASSERTIONS: 1
+#
+# - job: Windows
+#   timeoutInMinutes: 600
+#   pool:
+#     vmImage: 'vs2017-win2016'
+#   steps:
+#   - template: steps/run.yml
+#   strategy:
+#     matrix:
+#       dist-x86_64-msvc:
+#         RUST_CONFIGURE_ARGS: >
+#           --build=x86_64-pc-windows-msvc
+#           --target=x86_64-pc-windows-msvc,aarch64-pc-windows-msvc
+#           --enable-full-tools
+#           --enable-profiler
+#         SCRIPT: python x.py dist
+#         DIST_REQUIRE_ALL_TOOLS: 1
+#         DEPLOY: 1
+#
+#       dist-x86_64-msvc-alt:
+#         MSYS_BITS: 64
+#         RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-extended --enable-profiler
+#         SCRIPT: python x.py dist
+#         DEPLOY_ALT: 1
diff --git a/src/ci/run.sh b/src/ci/run.sh
index b91859bfceb..e5e0e6cf603 100755
--- a/src/ci/run.sh
+++ b/src/ci/run.sh
@@ -50,7 +50,7 @@ if [ "$DEPLOY$DEPLOY_ALT" = "1" ]; then
   RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --release-channel=$RUST_RELEASE_CHANNEL"
   RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-llvm-static-stdcpp"
   RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.remap-debuginfo"
-  RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.debuginfo-level-std=1"
+  RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --debuginfo-level-std=1"
 
   if [ "$NO_LLVM_ASSERTIONS" = "1" ]; then
     RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-llvm-assertions"
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index 412346bab25..3d80fb28c73 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -2117,48 +2117,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/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 26c76ae5606..b2e319a478e 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -7716,6 +7716,11 @@ impl<'a> Parser<'a> {
         let ret = f(self);
         let last_token = if self.token_cursor.stack.len() == prev {
             &mut self.token_cursor.frame.last_token
+        } else if self.token_cursor.stack.get(prev).is_none() {
+            // This can happen due to a bad interaction of two unrelated recovery mechanisms with
+            // mismatched delimiters *and* recovery lookahead on the likely typo `pub ident(`
+            // (#62881).
+            return Ok((ret?, TokenStream::new(vec![])));
         } else {
             &mut self.token_cursor.stack[prev].last_token
         };
@@ -7723,7 +7728,15 @@ impl<'a> Parser<'a> {
         // Pull out the tokens that we've collected from the call to `f` above.
         let mut collected_tokens = match *last_token {
             LastToken::Collecting(ref mut v) => mem::replace(v, Vec::new()),
-            LastToken::Was(_) => panic!("our vector went away?"),
+            LastToken::Was(ref was) => {
+                let msg = format!("our vector went away? - found Was({:?})", was);
+                debug!("collect_tokens: {}", msg);
+                self.sess.span_diagnostic.delay_span_bug(self.token.span, &msg);
+                // This can happen due to a bad interaction of two unrelated recovery mechanisms
+                // with mismatched delimiters *and* recovery lookahead on the likely typo
+                // `pub ident(` (#62895, different but similar to the case above).
+                return Ok((ret?, TokenStream::new(vec![])));
+            }
         };
 
         // If we're not at EOF our current token wasn't actually consumed by
diff --git a/src/test/ui/parser/issue-62881.rs b/src/test/ui/parser/issue-62881.rs
new file mode 100644
index 00000000000..1782c2e375d
--- /dev/null
+++ b/src/test/ui/parser/issue-62881.rs
@@ -0,0 +1,6 @@
+fn main() {}
+
+fn f() -> isize { fn f() -> isize {} pub f<
+//~^ ERROR missing `fn` or `struct` for function or struct definition
+//~| ERROR mismatched types
+//~ ERROR this file contains an un-closed delimiter
diff --git a/src/test/ui/parser/issue-62881.stderr b/src/test/ui/parser/issue-62881.stderr
new file mode 100644
index 00000000000..85c3575fd92
--- /dev/null
+++ b/src/test/ui/parser/issue-62881.stderr
@@ -0,0 +1,29 @@
+error: this file contains an un-closed delimiter
+  --> $DIR/issue-62881.rs:6:53
+   |
+LL | fn f() -> isize { fn f() -> isize {} pub f<
+   |                 - un-closed delimiter
+...
+LL |
+   |                                                     ^
+
+error: missing `fn` or `struct` for function or struct definition
+  --> $DIR/issue-62881.rs:3:41
+   |
+LL | fn f() -> isize { fn f() -> isize {} pub f<
+   |                                         ^
+
+error[E0308]: mismatched types
+  --> $DIR/issue-62881.rs:3:29
+   |
+LL | fn f() -> isize { fn f() -> isize {} pub f<
+   |                      -      ^^^^^ expected isize, found ()
+   |                      |
+   |                      this function's body doesn't return
+   |
+   = note: expected type `isize`
+              found type `()`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/parser/issue-62895.rs b/src/test/ui/parser/issue-62895.rs
new file mode 100644
index 00000000000..53f17405d79
--- /dev/null
+++ b/src/test/ui/parser/issue-62895.rs
@@ -0,0 +1,11 @@
+fn main() {}
+
+fn v() -> isize { //~ ERROR mismatched types
+mod _ { //~ ERROR expected identifier
+pub fn g() -> isizee { //~ ERROR cannot find type `isizee` in this scope
+mod _ { //~ ERROR expected identifier
+pub    g() -> is //~ ERROR missing `fn` for function definition
+(), w20);
+}
+(), w20); //~ ERROR expected item, found `;`
+}
diff --git a/src/test/ui/parser/issue-62895.stderr b/src/test/ui/parser/issue-62895.stderr
new file mode 100644
index 00000000000..882764cb946
--- /dev/null
+++ b/src/test/ui/parser/issue-62895.stderr
@@ -0,0 +1,49 @@
+error: expected identifier, found reserved identifier `_`
+  --> $DIR/issue-62895.rs:4:5
+   |
+LL | mod _ {
+   |     ^ expected identifier, found reserved identifier
+
+error: expected identifier, found reserved identifier `_`
+  --> $DIR/issue-62895.rs:6:5
+   |
+LL | mod _ {
+   |     ^ expected identifier, found reserved identifier
+
+error: missing `fn` for function definition
+  --> $DIR/issue-62895.rs:7:4
+   |
+LL | pub    g() -> is
+   |    ^^^^
+help: add `fn` here to parse `g` as a public function
+   |
+LL | pub fn g() -> is
+   |     ^^
+
+error: expected item, found `;`
+  --> $DIR/issue-62895.rs:10:9
+   |
+LL | (), w20);
+   |         ^ help: remove this semicolon
+
+error[E0412]: cannot find type `isizee` in this scope
+  --> $DIR/issue-62895.rs:5:15
+   |
+LL | pub fn g() -> isizee {
+   |               ^^^^^^ help: a primitive type with a similar name exists: `isize`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-62895.rs:3:11
+   |
+LL | fn v() -> isize {
+   |    -      ^^^^^ expected isize, found ()
+   |    |
+   |    this function's body doesn't return
+   |
+   = note: expected type `isize`
+              found type `()`
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0308, E0412.
+For more information about an error, try `rustc --explain E0308`.
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/cargo b/src/tools/cargo
-Subproject 4c1fa54d10f58d69ac9ff55be68e1b1c25ecb81
+Subproject 9edd089168f8795b3890bc3daf5b99f03e9f876