diff --git a/src/ci/azure-pipelines/auto.yml b/src/ci/azure-pipelines/auto.yml
index 836f81a781656..946eb483c2946 100644
--- a/src/ci/azure-pipelines/auto.yml
+++ b/src/ci/azure-pipelines/auto.yml
@@ -223,25 +223,21 @@ jobs:
     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
         # FIXME(#59637)
         NO_DEBUG_ASSERTIONS: 1
         NO_LLVM_ASSERTIONS: 1
       i686-msvc-2:
-        MSYS_BITS: 32
         RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc
         SCRIPT: make ci-subset-2
         # FIXME(#59637)
@@ -249,11 +245,9 @@ jobs:
         NO_LLVM_ASSERTIONS: 1
       # 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
@@ -262,10 +256,8 @@ jobs:
         NO_LLVM_ASSERTIONS: 1
       # MSVC tools tests
       x86_64-msvc-tools:
-        MSYS_BITS: 64
         SCRIPT: src/ci/docker/x86_64-gnu-tools/checktools.sh x.py /tmp/toolstate/toolstates.json windows
         RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --save-toolstates=/tmp/toolstate/toolstates.json
-        DEPLOY_TOOLSTATES_JSON: toolstates-windows.json
 
       # 32/64-bit MinGW builds.
       #
@@ -281,43 +273,30 @@ jobs:
       # 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-mingw-subset-1
-        MINGW_URL: https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc
-        MINGW_ARCHIVE: i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z
-        MINGW_DIR: mingw32
+        CUSTOM_MINGW: 1
         # 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-mingw-subset-2
-        MINGW_URL: https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc
-        MINGW_ARCHIVE: i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z
-        MINGW_DIR: mingw32
+        CUSTOM_MINGW: 1
       x86_64-mingw-1:
-        MSYS_BITS: 64
         SCRIPT: make ci-mingw-subset-1
         RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu
-        MINGW_URL: https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc
-        MINGW_ARCHIVE: x86_64-6.3.0-release-posix-seh-rt_v5-rev2.7z
-        MINGW_DIR: mingw64
+        CUSTOM_MINGW: 1
         # FIXME(#59637)
         NO_DEBUG_ASSERTIONS: 1
         NO_LLVM_ASSERTIONS: 1
       x86_64-mingw-2:
-        MSYS_BITS: 64
         SCRIPT: make ci-mingw-subset-2
         RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu
-        MINGW_URL: https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc
-        MINGW_ARCHIVE: x86_64-6.3.0-release-posix-seh-rt_v5-rev2.7z
-        MINGW_DIR: mingw64
+        CUSTOM_MINGW: 1
 
       # 32/64 bit MSVC and GNU deployment
       dist-x86_64-msvc:
-        MSYS_BITS: 64
         RUST_CONFIGURE_ARGS: >-
           --build=x86_64-pc-windows-msvc
           --target=x86_64-pc-windows-msvc,aarch64-pc-windows-msvc
@@ -327,7 +306,6 @@ jobs:
         DIST_REQUIRE_ALL_TOOLS: 1
         DEPLOY: 1
       dist-i686-msvc:
-        MSYS_BITS: 32
         RUST_CONFIGURE_ARGS: >-
           --build=i686-pc-windows-msvc
           --target=i586-pc-windows-msvc
@@ -337,27 +315,20 @@ jobs:
         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-ci-mirrors.s3-us-west-1.amazonaws.com/rustc
-        MINGW_ARCHIVE: i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z
-        MINGW_DIR: mingw32
+        CUSTOM_MINGW: 1
         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-ci-mirrors.s3-us-west-1.amazonaws.com/rustc
-        MINGW_ARCHIVE: x86_64-6.3.0-release-posix-seh-rt_v5-rev2.7z
-        MINGW_DIR: mingw64
+        CUSTOM_MINGW: 1
         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/steps/run.yml b/src/ci/azure-pipelines/steps/run.yml
index cef2d235602f1..214c11fd69024 100644
--- a/src/ci/azure-pipelines/steps/run.yml
+++ b/src/ci/azure-pipelines/steps/run.yml
@@ -8,6 +8,13 @@
 
 steps:
 
+# Configure our CI_JOB_NAME variable which log analyzers can use for the main
+# step to see what's going on.
+- bash: |
+    builder=$(echo $AGENT_JOBNAME | cut -d ' ' -f 2)
+    echo "##vso[task.setvariable variable=CI_JOB_NAME]$builder"
+  displayName: Configure Job Name
+
 # 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
@@ -24,11 +31,8 @@ steps:
 - bash: src/ci/scripts/should-skip-this.sh
   displayName: Decide whether to run this job
 
-# 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: src/ci/scripts/collect-cpu-stats.sh
+  displayName: Collect CPU-usage statistics in the background
 
 - bash: src/ci/scripts/dump-environment.sh
   displayName: Show the current environment
@@ -135,48 +139,9 @@ steps:
   condition: and(succeeded(), not(variables.SKIP_JOB))
   displayName: Install awscli
 
-# Configure our CI_JOB_NAME variable which log analyzers can use for the main
-# step to see what's going on.
-- bash: |
-    builder=$(echo $AGENT_JOBNAME | cut -d ' ' -f 2)
-    echo "##vso[task.setvariable variable=CI_JOB_NAME]$builder"
-  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)" "" ""
-    # Only check maintainers if this build is supposed to publish toolstate.
-    # Builds that are not supposed to publish don't have the access token.
-    if [ -n "${TOOLSTATE_PUBLISH+is_set}" ]; then
-      TOOLSTATE_VALIDATE_MAINTAINERS_REPO=rust-lang/rust python2.7 "${BUILD_SOURCESDIRECTORY}/src/tools/publish_toolstate.py"
-    fi
-    cd ..
-    rm -rf rust-toolstate
-  env:
-    TOOLSTATE_REPO_ACCESS_TOKEN: $(TOOLSTATE_REPO_ACCESS_TOKEN)
-  condition: and(succeeded(), not(variables.SKIP_JOB), 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
+- bash: src/ci/scripts/run-build-from-ci.sh
   timeoutInMinutes: 600
   env:
-    CI: true
-    SRC: .
     AWS_ACCESS_KEY_ID: $(SCCACHE_AWS_ACCESS_KEY_ID)
     AWS_SECRET_ACCESS_KEY: $(SCCACHE_AWS_SECRET_ACCESS_KEY)
     TOOLSTATE_REPO_ACCESS_TOKEN: $(TOOLSTATE_REPO_ACCESS_TOKEN)
diff --git a/src/ci/azure-pipelines/try.yml b/src/ci/azure-pipelines/try.yml
index c919b1023a0eb..fe39ce3e24116 100644
--- a/src/ci/azure-pipelines/try.yml
+++ b/src/ci/azure-pipelines/try.yml
@@ -72,7 +72,6 @@ jobs:
 #         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/docker/armhf-gnu/Dockerfile b/src/ci/docker/armhf-gnu/Dockerfile
index 9493b33698708..5373612279bca 100644
--- a/src/ci/docker/armhf-gnu/Dockerfile
+++ b/src/ci/docker/armhf-gnu/Dockerfile
@@ -72,7 +72,7 @@ RUN arm-linux-gnueabihf-gcc addentropy.c -o rootfs/addentropy -static
 
 # TODO: What is this?!
 # Source of the file: https://github.com/vfdev-5/qemu-rpi2-vexpress/raw/master/vexpress-v2p-ca15-tc1.dtb
-RUN curl -O https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/vexpress-v2p-ca15-tc1.dtb
+RUN curl -O https://ci-mirrors.rust-lang.org/rustc/vexpress-v2p-ca15-tc1.dtb
 
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
diff --git a/src/ci/docker/dist-armv7-linux/crosstool-ng.sh b/src/ci/docker/dist-armv7-linux/crosstool-ng.sh
index ae737d9677d87..fb067a79a5c85 100644
--- a/src/ci/docker/dist-armv7-linux/crosstool-ng.sh
+++ b/src/ci/docker/dist-armv7-linux/crosstool-ng.sh
@@ -1,7 +1,7 @@
 set -ex
 
 # Mirrored from https://github.com/crosstool-ng/crosstool-ng/archive/crosstool-ng-1.24.0.tar.gz
-url="https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/crosstool-ng-1.24.0.tar.gz"
+url="https://ci-mirrors.rust-lang.org/rustc/crosstool-ng-1.24.0.tar.gz"
 curl -Lf $url | tar xzf -
 cd crosstool-ng-crosstool-ng-1.24.0
 ./bootstrap
diff --git a/src/ci/docker/dist-various-1/install-mips-musl.sh b/src/ci/docker/dist-various-1/install-mips-musl.sh
index 29cfb5d96083e..9584258d23403 100755
--- a/src/ci/docker/dist-various-1/install-mips-musl.sh
+++ b/src/ci/docker/dist-various-1/install-mips-musl.sh
@@ -5,7 +5,7 @@ mkdir /usr/local/mips-linux-musl
 # originally from
 # https://downloads.openwrt.org/snapshots/trunk/ar71xx/generic/
 # OpenWrt-Toolchain-ar71xx-generic_gcc-5.3.0_musl-1.1.16.Linux-x86_64.tar.bz2
-URL="https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc"
+URL="https://ci-mirrors.rust-lang.org/rustc"
 FILE="OpenWrt-Toolchain-ar71xx-generic_gcc-5.3.0_musl-1.1.16.Linux-x86_64.tar.bz2"
 curl -L "$URL/$FILE" | tar xjf - -C /usr/local/mips-linux-musl --strip-components=2
 
diff --git a/src/ci/docker/dist-various-1/install-mipsel-musl.sh b/src/ci/docker/dist-various-1/install-mipsel-musl.sh
index de8c359d16757..50a8e554b1675 100755
--- a/src/ci/docker/dist-various-1/install-mipsel-musl.sh
+++ b/src/ci/docker/dist-various-1/install-mipsel-musl.sh
@@ -5,7 +5,7 @@ mkdir /usr/local/mipsel-linux-musl
 # Note that this originally came from:
 # https://downloads.openwrt.org/snapshots/trunk/malta/generic/
 # OpenWrt-Toolchain-malta-le_gcc-5.3.0_musl-1.1.15.Linux-x86_64.tar.bz2
-URL="https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc"
+URL="https://ci-mirrors.rust-lang.org/rustc"
 FILE="OpenWrt-Toolchain-malta-le_gcc-5.3.0_musl-1.1.15.Linux-x86_64.tar.bz2"
 curl -L "$URL/$FILE" | tar xjf - -C /usr/local/mipsel-linux-musl --strip-components=2
 
diff --git a/src/ci/docker/dist-various-2/build-wasi-toolchain.sh b/src/ci/docker/dist-various-2/build-wasi-toolchain.sh
index c63ea6facca64..17aa78945cf21 100755
--- a/src/ci/docker/dist-various-2/build-wasi-toolchain.sh
+++ b/src/ci/docker/dist-various-2/build-wasi-toolchain.sh
@@ -5,7 +5,7 @@
 set -ex
 
 # Originally from https://releases.llvm.org/9.0.0/clang+llvm-9.0.0-x86_64-linux-gnu-ubuntu-14.04.tar.xz
-curl https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/clang%2Bllvm-9.0.0-x86_64-linux-gnu-ubuntu-14.04.tar.xz | \
+curl https://ci-mirrors.rust-lang.org/rustc/clang%2Bllvm-9.0.0-x86_64-linux-gnu-ubuntu-14.04.tar.xz | \
   tar xJf -
 export PATH=`pwd`/clang+llvm-9.0.0-x86_64-linux-gnu-ubuntu-14.04/bin:$PATH
 
diff --git a/src/ci/docker/dist-x86_64-linux/build-curl.sh b/src/ci/docker/dist-x86_64-linux/build-curl.sh
index 8200bbe2fdce5..0c7eb5fdac9be 100755
--- a/src/ci/docker/dist-x86_64-linux/build-curl.sh
+++ b/src/ci/docker/dist-x86_64-linux/build-curl.sh
@@ -5,6 +5,9 @@ source shared.sh
 
 VERSION=7.66.0
 
+# This needs to be downloaded directly from S3, it can't go through the CDN.
+# That's because the CDN is backed by CloudFront, which requires SNI and TLSv1
+# (without paying an absurd amount of money).
 curl https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/curl-$VERSION.tar.xz \
   | xz --decompress \
   | tar xf -
diff --git a/src/ci/docker/dist-x86_64-linux/build-openssl.sh b/src/ci/docker/dist-x86_64-linux/build-openssl.sh
index be8a6c93945e9..d8f6bdb51b8d5 100755
--- a/src/ci/docker/dist-x86_64-linux/build-openssl.sh
+++ b/src/ci/docker/dist-x86_64-linux/build-openssl.sh
@@ -4,6 +4,10 @@ set -ex
 source shared.sh
 
 VERSION=1.0.2k
+
+# This needs to be downloaded directly from S3, it can't go through the CDN.
+# That's because the CDN is backed by CloudFront, which requires SNI and TLSv1
+# (without paying an absurd amount of money).
 URL=https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/openssl-$VERSION.tar.gz
 
 curl $URL | tar xzf -
diff --git a/src/ci/docker/dist-x86_64-netbsd/build-netbsd-toolchain.sh b/src/ci/docker/dist-x86_64-netbsd/build-netbsd-toolchain.sh
index 797f674b954f2..f8697c698b9fb 100755
--- a/src/ci/docker/dist-x86_64-netbsd/build-netbsd-toolchain.sh
+++ b/src/ci/docker/dist-x86_64-netbsd/build-netbsd-toolchain.sh
@@ -25,7 +25,7 @@ cd netbsd
 
 mkdir -p /x-tools/x86_64-unknown-netbsd/sysroot
 
-URL=https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc
+URL=https://ci-mirrors.rust-lang.org/rustc
 
 # Originally from ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-$BSD/source/sets/*.tgz
 curl $URL/2018-03-01-netbsd-src.tgz | tar xzf -
diff --git a/src/ci/docker/mingw-check/Dockerfile b/src/ci/docker/mingw-check/Dockerfile
index 24e2dea4ca773..b2d96aed2a9e8 100644
--- a/src/ci/docker/mingw-check/Dockerfile
+++ b/src/ci/docker/mingw-check/Dockerfile
@@ -19,7 +19,10 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
+COPY mingw-check/validate-toolstate.sh /scripts/
+
 ENV RUN_CHECK_WITH_PARALLEL_QUERIES 1
 ENV SCRIPT python2.7 ../x.py check --target=i686-pc-windows-gnu --host=i686-pc-windows-gnu && \
            python2.7 ../x.py build --stage 0 src/tools/build-manifest && \
-           python2.7 ../x.py test --stage 0 src/tools/compiletest
+           python2.7 ../x.py test --stage 0 src/tools/compiletest && \
+           /scripts/validate-toolstate.sh
diff --git a/src/ci/docker/mingw-check/validate-toolstate.sh b/src/ci/docker/mingw-check/validate-toolstate.sh
new file mode 100755
index 0000000000000..2ebf1d6d5ae7f
--- /dev/null
+++ b/src/ci/docker/mingw-check/validate-toolstate.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+# A quick smoke test to make sure publish_tooolstate.py works.
+
+set -euo pipefail
+IFS=$'\n\t'
+
+rm -rf rust-toolstate
+git clone --depth=1 https://github.com/rust-lang-nursery/rust-toolstate.git
+cd rust-toolstate
+python2.7 "../../src/tools/publish_toolstate.py" "$(git rev-parse HEAD)" \
+    "$(git log --format=%s -n1 HEAD)" "" ""
+# Only check maintainers if this build is supposed to publish toolstate.
+# Builds that are not supposed to publish don't have the access token.
+if [ -n "${TOOLSTATE_PUBLISH+is_set}" ]; then
+  TOOLSTATE_VALIDATE_MAINTAINERS_REPO=rust-lang/rust python2.7 \
+      "../../src/tools/publish_toolstate.py"
+fi
+cd ..
+rm -rf rust-toolstate
diff --git a/src/ci/docker/scripts/freebsd-toolchain.sh b/src/ci/docker/scripts/freebsd-toolchain.sh
index 70155e770a960..5670e10be23cf 100755
--- a/src/ci/docker/scripts/freebsd-toolchain.sh
+++ b/src/ci/docker/scripts/freebsd-toolchain.sh
@@ -59,7 +59,7 @@ done
 
 # Originally downloaded from:
 # https://download.freebsd.org/ftp/releases/${freebsd_arch}/${freebsd_version}-RELEASE/base.txz
-URL=https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/2019-04-04-freebsd-${freebsd_arch}-${freebsd_version}-RELEASE-base.txz
+URL=https://ci-mirrors.rust-lang.org/rustc/2019-04-04-freebsd-${freebsd_arch}-${freebsd_version}-RELEASE-base.txz
 curl "$URL" | tar xJf - -C "$sysroot" --wildcards "${files_to_extract[@]}"
 
 # Fix up absolute symlinks from the system image.  This can be removed
diff --git a/src/ci/docker/scripts/sccache.sh b/src/ci/docker/scripts/sccache.sh
index efeb0ed0d72d0..552afbfee7c17 100644
--- a/src/ci/docker/scripts/sccache.sh
+++ b/src/ci/docker/scripts/sccache.sh
@@ -1,6 +1,6 @@
 set -ex
 
 curl -fo /usr/local/bin/sccache \
-  https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/2018-04-02-sccache-x86_64-unknown-linux-musl
+  https://ci-mirrors.rust-lang.org/rustc/2018-04-02-sccache-x86_64-unknown-linux-musl
 
 chmod +x /usr/local/bin/sccache
diff --git a/src/ci/scripts/collect-cpu-stats.sh b/src/ci/scripts/collect-cpu-stats.sh
new file mode 100755
index 0000000000000..08065431f9816
--- /dev/null
+++ b/src/ci/scripts/collect-cpu-stats.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+# 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.
+
+set -euo pipefail
+IFS=$'\n\t'
+
+python src/ci/cpu-usage-over-time.py &> cpu-usage.csv &
diff --git a/src/ci/scripts/install-clang.sh b/src/ci/scripts/install-clang.sh
index b1e9bf92ca5d2..f0179994e8e4c 100755
--- a/src/ci/scripts/install-clang.sh
+++ b/src/ci/scripts/install-clang.sh
@@ -17,7 +17,7 @@ if isMacOS; then
     # Configure `AR` specifically so rustbuild doesn't try to infer it as
     # `clang-ar` by accident.
     ciCommandSetEnv AR "ar"
-elif isWindows && [[ -z ${MINGW_URL+x} ]]; then
+elif isWindows && [[ ${CUSTOM_MINGW-0} -ne 1 ]]; then
     # 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
diff --git a/src/ci/scripts/install-mingw.sh b/src/ci/scripts/install-mingw.sh
index b4e8b889f520a..8b579587b9e1f 100755
--- a/src/ci/scripts/install-mingw.sh
+++ b/src/ci/scripts/install-mingw.sh
@@ -27,19 +27,38 @@ IFS=$'\n\t'
 
 source "$(cd "$(dirname "$0")" && pwd)/../shared.sh"
 
+MINGW_ARCHIVE_32="i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z"
+MINGW_ARCHIVE_64="x86_64-6.3.0-release-posix-seh-rt_v5-rev2.7z"
+
 if isWindows; then
-    if [[ -z "${MINGW_URL+x}" ]]; then
-        arch=i686
-        if [ "$MSYS_BITS" = "64" ]; then
-          arch=x86_64
-        fi
+    case "${CI_JOB_NAME}" in
+        *i686*)
+            bits=32
+            arch=i686
+            mingw_archive="${MINGW_ARCHIVE_32}"
+            ;;
+        *x86_64*)
+            bits=64
+            arch=x86_64
+            mingw_archive="${MINGW_ARCHIVE_64}"
+            ;;
+        *)
+            echo "src/ci/scripts/install-mingw.sh can't detect the builder's architecture"
+            echo "please tweak it to recognize the builder named '${CI_JOB_NAME}'"
+            exit 1
+            ;;
+    esac
+
+    if [[ "${CUSTOM_MINGW-0}" -ne 1 ]]; then
         pacman -S --noconfirm --needed mingw-w64-$arch-toolchain mingw-w64-$arch-cmake \
             mingw-w64-$arch-gcc mingw-w64-$arch-python2
-        ciCommandAddPath "${SYSTEM_WORKFOLDER}/msys2/mingw${MSYS_BITS}/bin"
+        ciCommandAddPath "${SYSTEM_WORKFOLDER}/msys2/mingw${bits}/bin"
     else
-        curl -o mingw.7z "${MINGW_URL}/${MINGW_ARCHIVE}"
+        mingw_dir="mingw${bits}"
+
+        curl -o mingw.7z "${MIRRORS_BASE}/${mingw_archive}"
         7z x -y mingw.7z > /dev/null
-        curl -o "${MINGW_DIR}/bin/gdborig.exe" "${MINGW_URL}/2017-04-20-${MSYS_BITS}bit-gdborig.exe"
-        ciCommandAddPath "$(pwd)/${MINGW_DIR}/bin"
+        curl -o "${mingw_dir}/bin/gdborig.exe" "${MIRRORS_BASE}/2017-04-20-${bits}bit-gdborig.exe"
+        ciCommandAddPath "$(pwd)/${mingw_dir}/bin"
     fi
 fi
diff --git a/src/ci/scripts/run-build-from-ci.sh b/src/ci/scripts/run-build-from-ci.sh
new file mode 100755
index 0000000000000..c02117f459de0
--- /dev/null
+++ b/src/ci/scripts/run-build-from-ci.sh
@@ -0,0 +1,21 @@
+#!/bin/bash
+# Start the CI build. You shouldn't run this locally: call either src/ci/run.sh
+# or src/ci/docker/run.sh instead.
+
+set -euo pipefail
+IFS=$'\n\t'
+
+source "$(cd "$(dirname "$0")" && pwd)/../shared.sh"
+
+export CI="true"
+export SRC=.
+
+# 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 [ -z "${IMAGE+x}" ]; then
+    src/ci/run.sh
+else
+    src/ci/docker/run.sh "${IMAGE}"
+fi
diff --git a/src/ci/shared.sh b/src/ci/shared.sh
index 718a5379ae558..862ded0d5dbf0 100644
--- a/src/ci/shared.sh
+++ b/src/ci/shared.sh
@@ -4,7 +4,7 @@
 # `source shared.sh`, hence the invalid shebang and not being
 # marked as an executable file in git.
 
-export MIRRORS_BASE="https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc"
+export MIRRORS_BASE="https://ci-mirrors.rust-lang.org/rustc"
 
 # See http://unix.stackexchange.com/questions/82598
 # Duplicated in docker/dist-various-2/shared.sh
diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs
index 9ed60b1f0c112..9b197c1ecb140 100644
--- a/src/librustc/infer/opaque_types/mod.rs
+++ b/src/librustc/infer/opaque_types/mod.rs
@@ -24,6 +24,10 @@ pub type OpaqueTypeMap<'tcx> = DefIdMap<OpaqueTypeDecl<'tcx>>;
 /// appear in the return type).
 #[derive(Copy, Clone, Debug)]
 pub struct OpaqueTypeDecl<'tcx> {
+
+    /// The opaque type (`ty::Opaque`) for this declaration.
+    pub opaque_type: Ty<'tcx>,
+
     /// The substitutions that we apply to the opaque type that this
     /// `impl Trait` desugars to. e.g., if:
     ///
@@ -1150,6 +1154,7 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
         self.opaque_types.insert(
             def_id,
             OpaqueTypeDecl {
+                opaque_type: ty,
                 substs,
                 definition_span,
                 concrete_ty: ty_var,
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index ea29cc0d93f53..0144d51a9693f 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -1245,6 +1245,60 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         }
     }
 
+    fn mk_obligation_for_def_id(
+        &self,
+        def_id: DefId,
+        output_ty: Ty<'tcx>,
+        cause: ObligationCause<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+    ) -> PredicateObligation<'tcx> {
+        let new_trait_ref = ty::TraitRef {
+            def_id,
+            substs: self.tcx.mk_substs_trait(output_ty, &[]),
+        };
+        Obligation::new(cause, param_env, new_trait_ref.to_predicate())
+    }
+
+    /// Given a closure's `DefId`, return the given name of the closure.
+    ///
+    /// This doesn't account for reassignments, but it's only used for suggestions.
+    fn get_closure_name(
+        &self,
+        def_id: DefId,
+        err: &mut DiagnosticBuilder<'_>,
+        msg: &str,
+    ) -> Option<String> {
+        let get_name = |err: &mut DiagnosticBuilder<'_>, kind: &hir::PatKind| -> Option<String> {
+            // Get the local name of this closure. This can be inaccurate because
+            // of the possibility of reassignment, but this should be good enough.
+            match &kind {
+                hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, name, None) => {
+                    Some(format!("{}", name))
+                }
+                _ => {
+                    err.note(&msg);
+                    None
+                }
+            }
+        };
+
+        let hir = self.tcx.hir();
+        let hir_id = hir.as_local_hir_id(def_id)?;
+        let parent_node = hir.get_parent_node(hir_id);
+        match hir.find(parent_node) {
+            Some(hir::Node::Stmt(hir::Stmt {
+                kind: hir::StmtKind::Local(local), ..
+            })) => get_name(err, &local.pat.kind),
+            // Different to previous arm because one is `&hir::Local` and the other
+            // is `P<hir::Local>`.
+            Some(hir::Node::Local(local)) => get_name(err, &local.pat.kind),
+            _ => return None,
+        }
+    }
+
+    /// We tried to apply the bound to an `fn` or closure. Check whether calling it would
+    /// evaluate to a type that *would* satisfy the trait binding. If it would, suggest calling
+    /// it: `bar(foo)` → `bar(foo())`. This case is *very* likely to be hit if `foo` is `async`.
     fn suggest_fn_call(
         &self,
         obligation: &PredicateObligation<'tcx>,
@@ -1253,63 +1307,82 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         points_at_arg: bool,
     ) {
         let self_ty = trait_ref.self_ty();
-        match self_ty.kind {
+        let (def_id, output_ty, callable) = match self_ty.kind {
+            ty::Closure(def_id, substs) => {
+                (def_id, self.closure_sig(def_id, substs).output(), "closure")
+            }
             ty::FnDef(def_id, _) => {
-                // We tried to apply the bound to an `fn`. Check whether calling it would evaluate
-                // to a type that *would* satisfy the trait binding. If it would, suggest calling
-                // it: `bar(foo)` -> `bar(foo)`. This case is *very* likely to be hit if `foo` is
-                // `async`.
-                let output_ty = self_ty.fn_sig(self.tcx).output();
-                let new_trait_ref = ty::TraitRef {
-                    def_id: trait_ref.def_id(),
-                    substs: self.tcx.mk_substs_trait(output_ty.skip_binder(), &[]),
+                (def_id, self_ty.fn_sig(self.tcx).output(), "function")
+            }
+            _ => return,
+        };
+        let msg = format!("use parentheses to call the {}", callable);
+
+        let obligation = self.mk_obligation_for_def_id(
+            trait_ref.def_id(),
+            output_ty.skip_binder(),
+            obligation.cause.clone(),
+            obligation.param_env,
+        );
+
+        match self.evaluate_obligation(&obligation) {
+            Ok(EvaluationResult::EvaluatedToOk) |
+            Ok(EvaluationResult::EvaluatedToOkModuloRegions) |
+            Ok(EvaluationResult::EvaluatedToAmbig) => {}
+            _ => return,
+        }
+        let hir = self.tcx.hir();
+        // Get the name of the callable and the arguments to be used in the suggestion.
+        let snippet = match hir.get_if_local(def_id) {
+            Some(hir::Node::Expr(hir::Expr {
+                kind: hir::ExprKind::Closure(_, decl, _, span, ..),
+                ..
+            })) => {
+                err.span_label(*span, "consider calling this closure");
+                let name = match self.get_closure_name(def_id, err, &msg) {
+                    Some(name) => name,
+                    None => return,
                 };
-                let obligation = Obligation::new(
-                    obligation.cause.clone(),
-                    obligation.param_env,
-                    new_trait_ref.to_predicate(),
-                );
-                match self.evaluate_obligation(&obligation) {
-                    Ok(EvaluationResult::EvaluatedToOk) |
-                    Ok(EvaluationResult::EvaluatedToOkModuloRegions) |
-                    Ok(EvaluationResult::EvaluatedToAmbig) => {
-                        if let Some(hir::Node::Item(hir::Item {
-                            ident,
-                            kind: hir::ItemKind::Fn(.., body_id),
-                            ..
-                        })) = self.tcx.hir().get_if_local(def_id) {
-                            let body = self.tcx.hir().body(*body_id);
-                            let msg = "use parentheses to call the function";
-                            let snippet = format!(
-                                "{}({})",
-                                ident,
-                                body.params.iter()
-                                    .map(|arg| match &arg.pat.kind {
-                                        hir::PatKind::Binding(_, _, ident, None)
-                                        if ident.name != kw::SelfLower => ident.to_string(),
-                                        _ => "_".to_string(),
-                                    }).collect::<Vec<_>>().join(", "),
-                            );
-                            // When the obligation error has been ensured to have been caused by
-                            // an argument, the `obligation.cause.span` points at the expression
-                            // of the argument, so we can provide a suggestion. This is signaled
-                            // by `points_at_arg`. Otherwise, we give a more general note.
-                            if points_at_arg {
-                                err.span_suggestion(
-                                    obligation.cause.span,
-                                    msg,
-                                    snippet,
-                                    Applicability::HasPlaceholders,
-                                );
-                            } else {
-                                err.help(&format!("{}: `{}`", msg, snippet));
-                            }
-                        }
-                    }
-                    _ => {}
-                }
+                let args = decl.inputs.iter()
+                    .map(|_| "_")
+                    .collect::<Vec<_>>()
+                    .join(", ");
+                format!("{}({})", name, args)
+            }
+            Some(hir::Node::Item(hir::Item {
+                ident,
+                kind: hir::ItemKind::Fn(.., body_id),
+                ..
+            })) => {
+                err.span_label(ident.span, "consider calling this function");
+                let body = hir.body(*body_id);
+                let args = body.params.iter()
+                    .map(|arg| match &arg.pat.kind {
+                        hir::PatKind::Binding(_, _, ident, None)
+                        // FIXME: provide a better suggestion when encountering `SelfLower`, it
+                        // should suggest a method call.
+                        if ident.name != kw::SelfLower => ident.to_string(),
+                        _ => "_".to_string(),
+                    })
+                    .collect::<Vec<_>>()
+                    .join(", ");
+                format!("{}({})", ident, args)
             }
-            _ => {}
+            _ => return,
+        };
+        if points_at_arg {
+            // When the obligation error has been ensured to have been caused by
+            // an argument, the `obligation.cause.span` points at the expression
+            // of the argument, so we can provide a suggestion. This is signaled
+            // by `points_at_arg`. Otherwise, we give a more general note.
+            err.span_suggestion(
+                obligation.cause.span,
+                &msg,
+                snippet,
+                Applicability::HasPlaceholders,
+            );
+        } else {
+            err.help(&format!("{}: `{}`", msg, snippet));
         }
     }
 
@@ -1410,12 +1483,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 if let ty::Ref(_, t_type, _) = trait_type.kind {
                     trait_type = t_type;
 
-                    let substs = self.tcx.mk_substs_trait(trait_type, &[]);
-                    let new_trait_ref = ty::TraitRef::new(trait_ref.def_id, substs);
-                    let new_obligation = Obligation::new(
+                    let new_obligation = self.mk_obligation_for_def_id(
+                        trait_ref.def_id,
+                        trait_type,
                         ObligationCause::dummy(),
                         obligation.param_env,
-                        new_trait_ref.to_predicate(),
                     );
 
                     if self.predicate_may_hold(&new_obligation) {
@@ -1473,12 +1545,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     hir::Mutability::Immutable => self.tcx.mk_mut_ref(region, t_type),
                 };
 
-                let substs = self.tcx.mk_substs_trait(&trait_type, &[]);
-                let new_trait_ref = ty::TraitRef::new(trait_ref.skip_binder().def_id, substs);
-                let new_obligation = Obligation::new(
+                let new_obligation = self.mk_obligation_for_def_id(
+                    trait_ref.skip_binder().def_id,
+                    trait_type,
                     ObligationCause::dummy(),
                     obligation.param_env,
-                    new_trait_ref.to_predicate(),
                 );
 
                 if self.evaluate_obligation_no_overflow(
diff --git a/src/librustc/ty/query/job.rs b/src/librustc/ty/query/job.rs
index 391ea762a083b..e5f4e793132f4 100644
--- a/src/librustc/ty/query/job.rs
+++ b/src/librustc/ty/query/job.rs
@@ -22,16 +22,6 @@ use {
     std::iter::FromIterator,
 };
 
-/// Indicates the state of a query for a given key in a query map.
-pub(super) enum QueryResult<'tcx> {
-    /// An already executing query. The query job can be used to await for its completion.
-    Started(Lrc<QueryJob<'tcx>>),
-
-    /// The query panicked. Queries trying to wait on this will raise a fatal error or
-    /// silently panic.
-    Poisoned,
-}
-
 /// Represents a span and a query key.
 #[derive(Clone, Debug)]
 pub struct QueryInfo<'tcx> {
diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs
index 52a784d3fc0be..fc55b665c1d0e 100644
--- a/src/librustc/ty/query/plumbing.rs
+++ b/src/librustc/ty/query/plumbing.rs
@@ -7,7 +7,7 @@ use crate::ty::tls;
 use crate::ty::{self, TyCtxt};
 use crate::ty::query::Query;
 use crate::ty::query::config::{QueryConfig, QueryDescription};
-use crate::ty::query::job::{QueryJob, QueryResult, QueryInfo};
+use crate::ty::query::job::{QueryJob, QueryInfo};
 
 use errors::DiagnosticBuilder;
 use errors::Level;
@@ -52,6 +52,16 @@ impl<T> QueryValue<T> {
     }
 }
 
+/// Indicates the state of a query for a given key in a query map.
+pub(super) enum QueryResult<'tcx> {
+    /// An already executing query. The query job can be used to await for its completion.
+    Started(Lrc<QueryJob<'tcx>>),
+
+    /// The query panicked. Queries trying to wait on this will raise a fatal error or
+    /// silently panic.
+    Poisoned,
+}
+
 impl<'tcx, M: QueryConfig<'tcx>> Default for QueryCache<'tcx, M> {
     fn default() -> QueryCache<'tcx, M> {
         QueryCache {
@@ -676,8 +686,6 @@ macro_rules! define_queries_inner {
         [$($modifiers:tt)*] fn $name:ident: $node:ident($K:ty) -> $V:ty,)*) => {
 
         use std::mem;
-        #[cfg(parallel_compiler)]
-        use ty::query::job::QueryResult;
         use rustc_data_structures::sharded::Sharded;
         use crate::{
             rustc_data_structures::stable_hasher::HashStable,
diff --git a/src/librustc_error_codes/error_codes.rs b/src/librustc_error_codes/error_codes.rs
index 428cecf13a3b0..e575528a4633c 100644
--- a/src/librustc_error_codes/error_codes.rs
+++ b/src/librustc_error_codes/error_codes.rs
@@ -318,6 +318,7 @@ E0590: include_str!("./error_codes/E0590.md"),
 E0591: include_str!("./error_codes/E0591.md"),
 E0592: include_str!("./error_codes/E0592.md"),
 E0593: include_str!("./error_codes/E0593.md"),
+E0594: include_str!("./error_codes/E0594.md"),
 E0595: include_str!("./error_codes/E0595.md"),
 E0596: include_str!("./error_codes/E0596.md"),
 E0597: include_str!("./error_codes/E0597.md"),
@@ -350,6 +351,7 @@ E0635: include_str!("./error_codes/E0635.md"),
 E0636: include_str!("./error_codes/E0636.md"),
 E0638: include_str!("./error_codes/E0638.md"),
 E0639: include_str!("./error_codes/E0639.md"),
+E0641: include_str!("./error_codes/E0641.md"),
 E0642: include_str!("./error_codes/E0642.md"),
 E0643: include_str!("./error_codes/E0643.md"),
 E0644: include_str!("./error_codes/E0644.md"),
@@ -566,7 +568,6 @@ E0744: include_str!("./error_codes/E0744.md"),
 //  E0563, // cannot determine a type for this `impl Trait` removed in 6383de15
 //  E0564, // only named lifetimes are allowed in `impl Trait`,
            // but `{}` was found in the type `{}`
-    E0594, // cannot assign to {}
 //  E0598, // lifetime of {} is too short to guarantee its contents can be...
 //  E0611, // merged into E0616
 //  E0612, // merged into E0609
@@ -584,7 +585,6 @@ E0744: include_str!("./error_codes/E0744.md"),
     E0634, // type has conflicting packed representaton hints
     E0637, // "'_" is not a valid lifetime bound
     E0640, // infer outlives requirements
-    E0641, // cannot cast to/from a pointer with an unknown kind
 //  E0645, // trait aliases not finished
     E0657, // `impl Trait` can only capture lifetimes bound at the fn level
     E0667, // `impl Trait` in projections
diff --git a/src/librustc_error_codes/error_codes/E0594.md b/src/librustc_error_codes/error_codes/E0594.md
new file mode 100644
index 0000000000000..ad8eb631e63b1
--- /dev/null
+++ b/src/librustc_error_codes/error_codes/E0594.md
@@ -0,0 +1,23 @@
+A non-mutable value was assigned a value.
+
+Erroneous code example:
+
+```compile_fail,E0594
+struct SolarSystem {
+    earth: i32,
+}
+
+let ss = SolarSystem { earth: 3 };
+ss.earth = 2; // error!
+```
+
+To fix this error, declare `ss` as mutable by using the `mut` keyword:
+
+```
+struct SolarSystem {
+    earth: i32,
+}
+
+let mut ss = SolarSystem { earth: 3 }; // declaring `ss` as mutable
+ss.earth = 2; // ok!
+```
diff --git a/src/librustc_error_codes/error_codes/E0641.md b/src/librustc_error_codes/error_codes/E0641.md
new file mode 100644
index 0000000000000..e39bebce1fea6
--- /dev/null
+++ b/src/librustc_error_codes/error_codes/E0641.md
@@ -0,0 +1,19 @@
+Attempted to cast to/from a pointer with an unknown kind.
+
+Erroneous code examples:
+
+```compile_fail,E0641
+let b = 0 as *const _; // error
+```
+
+Must give information for type of pointer that is being cast from/to if the
+type cannot be inferred.
+
+```
+// Creating a pointer from reference: type can be inferred
+let a = &(String::from("Hello world!")) as *const _; // Ok
+
+let b = 0 as *const i32; // Ok
+
+let c: *const i32 = 0 as *const _; // Ok
+```
\ No newline at end of file
diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs
index 4f687b5ba9200..8dc0fb9bd77f5 100644
--- a/src/librustc_resolve/macros.rs
+++ b/src/librustc_resolve/macros.rs
@@ -466,11 +466,12 @@ impl<'a> Resolver<'a> {
     ) -> Result<&'a NameBinding<'a>, Determinacy> {
         bitflags::bitflags! {
             struct Flags: u8 {
-                const MACRO_RULES        = 1 << 0;
-                const MODULE             = 1 << 1;
-                const MISC_SUGGEST_CRATE = 1 << 2;
-                const MISC_SUGGEST_SELF  = 1 << 3;
-                const MISC_FROM_PRELUDE  = 1 << 4;
+                const MACRO_RULES          = 1 << 0;
+                const MODULE               = 1 << 1;
+                const DERIVE_HELPER_COMPAT = 1 << 2;
+                const MISC_SUGGEST_CRATE   = 1 << 3;
+                const MISC_SUGGEST_SELF    = 1 << 4;
+                const MISC_FROM_PRELUDE    = 1 << 5;
             }
         }
 
@@ -528,8 +529,10 @@ impl<'a> Resolver<'a> {
                         match this.resolve_macro_path(derive, Some(MacroKind::Derive),
                                                       parent_scope, true, force) {
                             Ok((Some(ext), _)) => if ext.helper_attrs.contains(&ident.name) {
-                                let res = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper);
-                                result = ok(res, derive.span, this.arenas);
+                                let binding = (Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper),
+                                               ty::Visibility::Public, derive.span, ExpnId::root())
+                                               .to_name_binding(this.arenas);
+                                result = Ok((binding, Flags::DERIVE_HELPER_COMPAT));
                                 break;
                             }
                             Ok(_) | Err(Determinacy::Determined) => {}
@@ -659,13 +662,17 @@ impl<'a> Resolver<'a> {
                         let (res, innermost_res) = (binding.res(), innermost_binding.res());
                         if res != innermost_res {
                             let builtin = Res::NonMacroAttr(NonMacroAttrKind::Builtin);
-                            let derive_helper = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper);
+                            let is_derive_helper_compat = |res, flags: Flags| {
+                                res == Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper) &&
+                                flags.contains(Flags::DERIVE_HELPER_COMPAT)
+                            };
 
                             let ambiguity_error_kind = if is_import {
                                 Some(AmbiguityKind::Import)
                             } else if innermost_res == builtin || res == builtin {
                                 Some(AmbiguityKind::BuiltinAttr)
-                            } else if innermost_res == derive_helper || res == derive_helper {
+                            } else if is_derive_helper_compat(innermost_res, innermost_flags) ||
+                                      is_derive_helper_compat(res, flags) {
                                 Some(AmbiguityKind::DeriveHelper)
                             } else if innermost_flags.contains(Flags::MACRO_RULES) &&
                                       flags.contains(Flags::MODULE) &&
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index a8418c5f3499b..50c1a74fe911b 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -147,7 +147,7 @@ use crate::TypeAndSubsts;
 use crate::lint;
 use crate::util::captures::Captures;
 use crate::util::common::{ErrorReported, indenter};
-use crate::util::nodemap::{DefIdMap, DefIdSet, FxHashSet, HirIdMap};
+use crate::util::nodemap::{DefIdMap, DefIdSet, FxHashMap, FxHashSet, HirIdMap};
 
 pub use self::Expectation::*;
 use self::autoderef::Autoderef;
@@ -231,6 +231,13 @@ pub struct Inherited<'a, 'tcx> {
     // 'de-opaque' OpaqueTypeDecl, after typeck is done with all functions.
     opaque_types: RefCell<DefIdMap<OpaqueTypeDecl<'tcx>>>,
 
+    /// A map from inference variables created from opaque
+    /// type instantiations (`ty::Infer`) to the actual opaque
+    /// type (`ty::Opaque`). Used during fallback to map unconstrained
+    /// opaque type inference variables to their corresponding
+    /// opaque type.
+    opaque_types_vars: RefCell<FxHashMap<Ty<'tcx>, Ty<'tcx>>>,
+
     /// Each type parameter has an implicit region bound that
     /// indicates it must outlive at least the function body (the user
     /// may specify stronger requirements). This field indicates the
@@ -696,6 +703,7 @@ impl Inherited<'a, 'tcx> {
             deferred_cast_checks: RefCell::new(Vec::new()),
             deferred_generator_interiors: RefCell::new(Vec::new()),
             opaque_types: RefCell::new(Default::default()),
+            opaque_types_vars: RefCell::new(Default::default()),
             implicit_region_bound,
             body_id,
         }
@@ -937,9 +945,46 @@ fn typeck_tables_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::TypeckTables<'_> {
         // All type checking constraints were added, try to fallback unsolved variables.
         fcx.select_obligations_where_possible(false, |_| {});
         let mut fallback_has_occurred = false;
+
+        // We do fallback in two passes, to try to generate
+        // better error messages.
+        // The first time, we do *not* replace opaque types.
         for ty in &fcx.unsolved_variables() {
-            fallback_has_occurred |= fcx.fallback_if_possible(ty);
+            fallback_has_occurred |= fcx.fallback_if_possible(ty, FallbackMode::NoOpaque);
+        }
+        // We now see if we can make progress. This might
+        // cause us to unify inference variables for opaque types,
+        // since we may have unified some other type variables
+        // during the first phase of fallback.
+        // This means that we only replace inference variables with their underlying
+        // opaque types as a last resort.
+        //
+        // In code like this:
+        //
+        // ```rust
+        // type MyType = impl Copy;
+        // fn produce() -> MyType { true }
+        // fn bad_produce() -> MyType { panic!() }
+        // ```
+        //
+        // we want to unify the opaque inference variable in `bad_produce`
+        // with the diverging fallback for `panic!` (e.g. `()` or `!`).
+        // This will produce a nice error message about conflicting concrete
+        // types for `MyType`.
+        //
+        // If we had tried to fallback the opaque inference variable to `MyType`,
+        // we will generate a confusing type-check error that does not explicitly
+        // refer to opaque types.
+        fcx.select_obligations_where_possible(fallback_has_occurred, |_| {});
+
+        // We now run fallback again, but this time we allow it to replace
+        // unconstrained opaque type variables, in addition to performing
+        // other kinds of fallback.
+        for ty in &fcx.unsolved_variables() {
+            fallback_has_occurred |= fcx.fallback_if_possible(ty, FallbackMode::All);
         }
+
+        // See if we can make any more progress.
         fcx.select_obligations_where_possible(fallback_has_occurred, |_| {});
 
         // Even though coercion casts provide type hints, we check casts after fallback for
@@ -2499,6 +2544,16 @@ enum TupleArgumentsFlag {
     TupleArguments,
 }
 
+/// Controls how we perform fallback for unconstrained
+/// type variables.
+enum FallbackMode {
+    /// Do not fallback type variables to opaque types.
+    NoOpaque,
+    /// Perform all possible kinds of fallback, including
+    /// turning type variables to opaque types.
+    All,
+}
+
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub fn new(
         inh: &'a Inherited<'a, 'tcx>,
@@ -2864,8 +2919,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         );
 
         let mut opaque_types = self.opaque_types.borrow_mut();
+        let mut opaque_types_vars = self.opaque_types_vars.borrow_mut();
         for (ty, decl) in opaque_type_map {
             let _ = opaque_types.insert(ty, decl);
+            let _ = opaque_types_vars.insert(decl.concrete_ty, decl.opaque_type);
         }
 
         value
@@ -3078,7 +3135,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     // Fallback becomes very dubious if we have encountered type-checking errors.
     // In that case, fallback to Error.
     // The return value indicates whether fallback has occurred.
-    fn fallback_if_possible(&self, ty: Ty<'tcx>) -> bool {
+    fn fallback_if_possible(&self, ty: Ty<'tcx>, mode: FallbackMode) -> bool {
         use rustc::ty::error::UnconstrainedNumeric::Neither;
         use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat};
 
@@ -3088,7 +3145,53 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             UnconstrainedInt => self.tcx.types.i32,
             UnconstrainedFloat => self.tcx.types.f64,
             Neither if self.type_var_diverges(ty) => self.tcx.mk_diverging_default(),
-            Neither => return false,
+            Neither => {
+                // This type variable was created from the instantiation of an opaque
+                // type. The fact that we're attempting to perform fallback for it
+                // means that the function neither constrained it to a concrete
+                // type, nor to the opaque type itself.
+                //
+                // For example, in this code:
+                //
+                //```
+                // type MyType = impl Copy;
+                // fn defining_use() -> MyType { true }
+                // fn other_use() -> MyType { defining_use() }
+                // ```
+                //
+                // `defining_use` will constrain the instantiated inference
+                // variable to `bool`, while `other_use` will constrain
+                // the instantiated inference variable to `MyType`.
+                //
+                // When we process opaque types during writeback, we
+                // will handle cases like `other_use`, and not count
+                // them as defining usages
+                //
+                // However, we also need to handle cases like this:
+                //
+                // ```rust
+                // pub type Foo = impl Copy;
+                // fn produce() -> Option<Foo> {
+                //     None
+                //  }
+                //  ```
+                //
+                // In the above snippet, the inference varaible created by
+                // instantiating `Option<Foo>` will be completely unconstrained.
+                // We treat this as a non-defining use by making the inference
+                // variable fall back to the opaque type itself.
+                if let FallbackMode::All = mode {
+                    if let Some(opaque_ty) = self.opaque_types_vars.borrow().get(ty) {
+                        debug!("fallback_if_possible: falling back opaque type var {:?} to {:?}",
+                               ty, opaque_ty);
+                        *opaque_ty
+                    } else {
+                        return false;
+                    }
+                } else {
+                    return false;
+                }
+            },
         };
         debug!("fallback_if_possible: defaulting `{:?}` to `{:?}`", ty, fallback);
         self.demand_eqtype(syntax_pos::DUMMY_SP, ty, fallback);
diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js
index 752b93f2ac5e3..197efb7cac80d 100644
--- a/src/librustdoc/html/static/main.js
+++ b/src/librustdoc/html/static/main.js
@@ -396,38 +396,51 @@ function getSearchElement() {
 
     document.onkeypress = handleShortcut;
     document.onkeydown = handleShortcut;
-    document.onclick = function(ev) {
-        if (hasClass(ev.target, "collapse-toggle")) {
-            collapseDocs(ev.target, "toggle");
-        } else if (hasClass(ev.target.parentNode, "collapse-toggle")) {
-            collapseDocs(ev.target.parentNode, "toggle");
-        } else if (ev.target.tagName === "SPAN" && hasClass(ev.target.parentNode, "line-numbers")) {
-            var prev_id = 0;
 
-            var set_fragment = function(name) {
-                if (browserSupportsHistoryApi()) {
-                    history.replaceState(null, null, "#" + name);
-                    highlightSourceLines();
-                } else {
-                    location.replace("#" + name);
-                }
-            };
+    var handleSourceHighlight = (function() {
+        var prev_line_id = 0;
 
-            var cur_id = parseInt(ev.target.id, 10);
+        var set_fragment = function(name) {
+            var x = window.scrollX,
+                y = window.scrollY;
+            if (browserSupportsHistoryApi()) {
+                history.replaceState(null, null, "#" + name);
+                highlightSourceLines();
+            } else {
+                location.replace("#" + name);
+            }
+            // Prevent jumps when selecting one or many lines
+            window.scrollTo(x, y);
+        };
+
+        return function(ev) {
+            var cur_line_id = parseInt(ev.target.id, 10);
+            ev.preventDefault();
 
-            if (ev.shiftKey && prev_id) {
-                if (prev_id > cur_id) {
-                    var tmp = prev_id;
-                    prev_id = cur_id;
-                    cur_id = tmp;
+            if (ev.shiftKey && prev_line_id) {
+                // Swap selection if needed
+                if (prev_line_id > cur_line_id) {
+                    var tmp = prev_line_id;
+                    prev_line_id = cur_line_id;
+                    cur_line_id = tmp;
                 }
 
-                set_fragment(prev_id + "-" + cur_id);
+                set_fragment(prev_line_id + "-" + cur_line_id);
             } else {
-                prev_id = cur_id;
+                prev_line_id = cur_line_id;
 
-                set_fragment(cur_id);
+                set_fragment(cur_line_id);
             }
+        }
+    })();
+
+    document.onclick = function(ev) {
+        if (hasClass(ev.target, "collapse-toggle")) {
+            collapseDocs(ev.target, "toggle");
+        } else if (hasClass(ev.target.parentNode, "collapse-toggle")) {
+            collapseDocs(ev.target.parentNode, "toggle");
+        } else if (ev.target.tagName === "SPAN" && hasClass(ev.target.parentNode, "line-numbers")) {
+            handleSourceHighlight(ev);
         } else if (hasClass(getHelpElement(), "hidden") === false) {
             var help = getHelpElement();
             var is_inside_help_popup = ev.target !== help && help.contains(ev.target);
diff --git a/src/libstd/error.rs b/src/libstd/error.rs
index df24b6635f411..d1cb0862d82a8 100644
--- a/src/libstd/error.rs
+++ b/src/libstd/error.rs
@@ -791,7 +791,7 @@ impl dyn Error {
 ///
 /// [`Error`]: trait.Error.html
 #[unstable(feature = "error_iter", issue = "58520")]
-#[derive(Copy, Clone, Debug)]
+#[derive(Clone, Debug)]
 pub struct Chain<'a> {
     current: Option<&'a (dyn Error + 'static)>,
 }
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index 72d998de9c4b7..32023a5b75bfb 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -244,7 +244,6 @@
 #![feature(cfg_target_thread_local)]
 #![feature(char_error_internals)]
 #![feature(clamp)]
-#![feature(compiler_builtins_lib)]
 #![feature(concat_idents)]
 #![feature(const_cstr_unchecked)]
 #![feature(const_raw_ptr_deref)]
diff --git a/src/test/ui/borrowck/borrow-immutable-upvar-mutation.stderr b/src/test/ui/borrowck/borrow-immutable-upvar-mutation.stderr
index 17969137a9881..097e4c75065c9 100644
--- a/src/test/ui/borrowck/borrow-immutable-upvar-mutation.stderr
+++ b/src/test/ui/borrowck/borrow-immutable-upvar-mutation.stderr
@@ -72,4 +72,5 @@ LL |         let _h = to_fn_mut(move || { set(&mut z); to_fn(move || z = 42); })
 
 error: aborting due to 6 previous errors
 
-For more information about this error, try `rustc --explain E0596`.
+Some errors have detailed explanations: E0594, E0596.
+For more information about an error, try `rustc --explain E0594`.
diff --git a/src/test/ui/borrowck/borrowck-assign-to-andmut-in-aliasable-loc.stderr b/src/test/ui/borrowck/borrowck-assign-to-andmut-in-aliasable-loc.stderr
index 38fcfbfc2a026..d8ccf36852a51 100644
--- a/src/test/ui/borrowck/borrowck-assign-to-andmut-in-aliasable-loc.stderr
+++ b/src/test/ui/borrowck/borrowck-assign-to-andmut-in-aliasable-loc.stderr
@@ -16,3 +16,4 @@ LL |     *s.pointer += 1;
 
 error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0594`.
diff --git a/src/test/ui/borrowck/borrowck-assign-to-constants.stderr b/src/test/ui/borrowck/borrowck-assign-to-constants.stderr
index 800003caa0f34..864d933da127f 100644
--- a/src/test/ui/borrowck/borrowck-assign-to-constants.stderr
+++ b/src/test/ui/borrowck/borrowck-assign-to-constants.stderr
@@ -6,3 +6,4 @@ LL |     foo = 6;
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0594`.
diff --git a/src/test/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.stderr b/src/test/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.stderr
index 8115e3150fbce..1fdeb812bf8bb 100644
--- a/src/test/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.stderr
+++ b/src/test/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.stderr
@@ -27,5 +27,5 @@ LL |     let x:  &mut isize = &mut **t0;
 
 error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0502, E0596.
+Some errors have detailed explanations: E0502, E0594, E0596.
 For more information about an error, try `rustc --explain E0502`.
diff --git a/src/test/ui/borrowck/borrowck-borrow-overloaded-auto-deref.stderr b/src/test/ui/borrowck/borrowck-borrow-overloaded-auto-deref.stderr
index d262c578843a0..6f2b20285b931 100644
--- a/src/test/ui/borrowck/borrowck-borrow-overloaded-auto-deref.stderr
+++ b/src/test/ui/borrowck/borrowck-borrow-overloaded-auto-deref.stderr
@@ -112,4 +112,5 @@ LL |     *x.y_mut() = 3;
 
 error: aborting due to 14 previous errors
 
-For more information about this error, try `rustc --explain E0596`.
+Some errors have detailed explanations: E0594, E0596.
+For more information about an error, try `rustc --explain E0594`.
diff --git a/src/test/ui/borrowck/borrowck-borrow-overloaded-deref.stderr b/src/test/ui/borrowck/borrowck-borrow-overloaded-deref.stderr
index 8cacc29414d75..246a7981ae3c8 100644
--- a/src/test/ui/borrowck/borrowck-borrow-overloaded-deref.stderr
+++ b/src/test/ui/borrowck/borrowck-borrow-overloaded-deref.stderr
@@ -56,4 +56,5 @@ LL |     **x = 3;
 
 error: aborting due to 7 previous errors
 
-For more information about this error, try `rustc --explain E0596`.
+Some errors have detailed explanations: E0594, E0596.
+For more information about an error, try `rustc --explain E0594`.
diff --git a/src/test/ui/borrowck/borrowck-closures-unique.stderr b/src/test/ui/borrowck/borrowck-closures-unique.stderr
index 2ed08b83c58b9..64c2f419ffa65 100644
--- a/src/test/ui/borrowck/borrowck-closures-unique.stderr
+++ b/src/test/ui/borrowck/borrowck-closures-unique.stderr
@@ -50,5 +50,5 @@ LL |     let c1 = |y: &'static mut isize| x = y;
 
 error: aborting due to 4 previous errors
 
-Some errors have detailed explanations: E0500, E0524.
+Some errors have detailed explanations: E0500, E0524, E0594.
 For more information about an error, try `rustc --explain E0500`.
diff --git a/src/test/ui/borrowck/borrowck-issue-14498.stderr b/src/test/ui/borrowck/borrowck-issue-14498.stderr
index fec4c27520cf3..ae9167757a0ae 100644
--- a/src/test/ui/borrowck/borrowck-issue-14498.stderr
+++ b/src/test/ui/borrowck/borrowck-issue-14498.stderr
@@ -96,4 +96,5 @@ LL |     drop(p);
 
 error: aborting due to 9 previous errors
 
-For more information about this error, try `rustc --explain E0506`.
+Some errors have detailed explanations: E0506, E0594.
+For more information about an error, try `rustc --explain E0506`.
diff --git a/src/test/ui/borrowck/borrowck-overloaded-index-ref-index.stderr b/src/test/ui/borrowck/borrowck-overloaded-index-ref-index.stderr
index 84fe17d85448e..2f92c1ebe5e18 100644
--- a/src/test/ui/borrowck/borrowck-overloaded-index-ref-index.stderr
+++ b/src/test/ui/borrowck/borrowck-overloaded-index-ref-index.stderr
@@ -31,4 +31,5 @@ LL |     s[2] = 20;
 
 error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0502`.
+Some errors have detailed explanations: E0502, E0594.
+For more information about an error, try `rustc --explain E0502`.
diff --git a/src/test/ui/borrowck/index-mut-help.stderr b/src/test/ui/borrowck/index-mut-help.stderr
index 47f2171f88c86..baf649f9127a5 100644
--- a/src/test/ui/borrowck/index-mut-help.stderr
+++ b/src/test/ui/borrowck/index-mut-help.stderr
@@ -24,4 +24,5 @@ LL |     let _ = &mut map["peter"];
 
 error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0596`.
+Some errors have detailed explanations: E0594, E0596.
+For more information about an error, try `rustc --explain E0594`.
diff --git a/src/test/ui/borrowck/issue-45983.nll.stderr b/src/test/ui/borrowck/issue-45983.nll.stderr
index dff0b4cebace9..49d6c2473f6a3 100644
--- a/src/test/ui/borrowck/issue-45983.nll.stderr
+++ b/src/test/ui/borrowck/issue-45983.nll.stderr
@@ -18,3 +18,4 @@ LL |     give_any(|y| x = Some(y));
 
 error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0594`.
diff --git a/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out.stderr b/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out.stderr
index 7dfd71c81c30d..b7623a54056d8 100644
--- a/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out.stderr
+++ b/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out.stderr
@@ -84,4 +84,5 @@ LL |         v.y = 2;
 
 error: aborting due to 9 previous errors
 
-For more information about this error, try `rustc --explain E0382`.
+Some errors have detailed explanations: E0382, E0594.
+For more information about an error, try `rustc --explain E0382`.
diff --git a/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.migrate.stderr b/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.migrate.stderr
index f1d28eed922af..1cdcc18632c62 100644
--- a/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.migrate.stderr
+++ b/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.migrate.stderr
@@ -50,4 +50,5 @@ LL |         || { &mut x.0; };
 
 error: aborting due to 6 previous errors
 
-For more information about this error, try `rustc --explain E0596`.
+Some errors have detailed explanations: E0594, E0596.
+For more information about an error, try `rustc --explain E0594`.
diff --git a/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.nll.stderr b/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.nll.stderr
index f1d28eed922af..1cdcc18632c62 100644
--- a/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.nll.stderr
+++ b/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.nll.stderr
@@ -50,4 +50,5 @@ LL |         || { &mut x.0; };
 
 error: aborting due to 6 previous errors
 
-For more information about this error, try `rustc --explain E0596`.
+Some errors have detailed explanations: E0594, E0596.
+For more information about an error, try `rustc --explain E0594`.
diff --git a/src/test/ui/borrowck/mutability-errors.stderr b/src/test/ui/borrowck/mutability-errors.stderr
index 545de5d0e75bf..72547a40352c9 100644
--- a/src/test/ui/borrowck/mutability-errors.stderr
+++ b/src/test/ui/borrowck/mutability-errors.stderr
@@ -375,4 +375,5 @@ LL |     &mut X.0;
 
 error: aborting due to 38 previous errors
 
-For more information about this error, try `rustc --explain E0596`.
+Some errors have detailed explanations: E0594, E0596.
+For more information about an error, try `rustc --explain E0594`.
diff --git a/src/test/ui/borrowck/reassignment_immutable_fields_overlapping.stderr b/src/test/ui/borrowck/reassignment_immutable_fields_overlapping.stderr
index 5f346708eb610..0eae2c71e4a19 100644
--- a/src/test/ui/borrowck/reassignment_immutable_fields_overlapping.stderr
+++ b/src/test/ui/borrowck/reassignment_immutable_fields_overlapping.stderr
@@ -15,4 +15,5 @@ LL |     x.b = 22;
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0381`.
+Some errors have detailed explanations: E0381, E0594.
+For more information about an error, try `rustc --explain E0381`.
diff --git a/src/test/ui/borrowck/reassignment_immutable_fields_twice.stderr b/src/test/ui/borrowck/reassignment_immutable_fields_twice.stderr
index 14f0fee84c9aa..f55e1a27f475e 100644
--- a/src/test/ui/borrowck/reassignment_immutable_fields_twice.stderr
+++ b/src/test/ui/borrowck/reassignment_immutable_fields_twice.stderr
@@ -15,4 +15,5 @@ LL |     x.0 = 1;
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0381`.
+Some errors have detailed explanations: E0381, E0594.
+For more information about an error, try `rustc --explain E0381`.
diff --git a/src/test/ui/cannot-mutate-captured-non-mut-var.stderr b/src/test/ui/cannot-mutate-captured-non-mut-var.stderr
index 2961497ef9f5c..2d6e83c9e82f9 100644
--- a/src/test/ui/cannot-mutate-captured-non-mut-var.stderr
+++ b/src/test/ui/cannot-mutate-captured-non-mut-var.stderr
@@ -16,4 +16,5 @@ LL |     to_fn_once(move|| { s.read_to_end(&mut Vec::new()); });
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0596`.
+Some errors have detailed explanations: E0594, E0596.
+For more information about an error, try `rustc --explain E0594`.
diff --git a/src/test/ui/closures/closure-immutable-outer-variable.stderr b/src/test/ui/closures/closure-immutable-outer-variable.stderr
index 558c9caeff336..7e60f3cd8ffa4 100644
--- a/src/test/ui/closures/closure-immutable-outer-variable.stderr
+++ b/src/test/ui/closures/closure-immutable-outer-variable.stderr
@@ -8,3 +8,4 @@ LL |     foo(Box::new(move || y = false) as Box<_>);
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0594`.
diff --git a/src/test/ui/consts/miri_unleashed/mutable_references.stderr b/src/test/ui/consts/miri_unleashed/mutable_references.stderr
index e8a867307ce19..b9c0af33c39cd 100644
--- a/src/test/ui/consts/miri_unleashed/mutable_references.stderr
+++ b/src/test/ui/consts/miri_unleashed/mutable_references.stderr
@@ -36,3 +36,4 @@ LL |     *OH_YES = 99;
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0594`.
diff --git a/src/test/ui/did_you_mean/issue-35937.stderr b/src/test/ui/did_you_mean/issue-35937.stderr
index 4f9b6a6134dc8..1f578d18a1ce5 100644
--- a/src/test/ui/did_you_mean/issue-35937.stderr
+++ b/src/test/ui/did_you_mean/issue-35937.stderr
@@ -24,4 +24,5 @@ LL |     s.x += 1;
 
 error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0596`.
+Some errors have detailed explanations: E0594, E0596.
+For more information about an error, try `rustc --explain E0594`.
diff --git a/src/test/ui/did_you_mean/issue-39544.stderr b/src/test/ui/did_you_mean/issue-39544.stderr
index dfaaf6b17dc31..ce0d697238c6b 100644
--- a/src/test/ui/did_you_mean/issue-39544.stderr
+++ b/src/test/ui/did_you_mean/issue-39544.stderr
@@ -98,4 +98,5 @@ LL |     *x.0 = 1;
 
 error: aborting due to 12 previous errors
 
-For more information about this error, try `rustc --explain E0596`.
+Some errors have detailed explanations: E0594, E0596.
+For more information about an error, try `rustc --explain E0594`.
diff --git a/src/test/ui/error-codes/E0389.stderr b/src/test/ui/error-codes/E0389.stderr
index 5310367d51a55..c47750b6f4e69 100644
--- a/src/test/ui/error-codes/E0389.stderr
+++ b/src/test/ui/error-codes/E0389.stderr
@@ -8,3 +8,4 @@ LL |     fancy_ref.num = 6;
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0594`.
diff --git a/src/test/ui/error-codes/E0594.stderr b/src/test/ui/error-codes/E0594.stderr
index c00ec4250a70b..f4d96f4e45a56 100644
--- a/src/test/ui/error-codes/E0594.stderr
+++ b/src/test/ui/error-codes/E0594.stderr
@@ -6,3 +6,4 @@ LL |     NUM = 20;
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0594`.
diff --git a/src/test/ui/fn/fn-closure-mutable-capture.stderr b/src/test/ui/fn/fn-closure-mutable-capture.stderr
index 8dfae0cbdf294..f7ab56da8de97 100644
--- a/src/test/ui/fn/fn-closure-mutable-capture.stderr
+++ b/src/test/ui/fn/fn-closure-mutable-capture.stderr
@@ -12,3 +12,4 @@ LL |     bar(move || x = 1);
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0594`.
diff --git a/src/test/ui/immut-function-arguments.stderr b/src/test/ui/immut-function-arguments.stderr
index 7871ba52db9c9..7238dd14433ce 100644
--- a/src/test/ui/immut-function-arguments.stderr
+++ b/src/test/ui/immut-function-arguments.stderr
@@ -16,3 +16,4 @@ LL |     let _frob = |q: Box<isize>| { *q = 2; };
 
 error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0594`.
diff --git a/src/test/ui/impl-trait/where-allowed-2.rs b/src/test/ui/impl-trait/where-allowed-2.rs
new file mode 100644
index 0000000000000..f7744ef1b3eae
--- /dev/null
+++ b/src/test/ui/impl-trait/where-allowed-2.rs
@@ -0,0 +1,9 @@
+//! Ideally, these tests would go in `where-allowed.rs`, but we bail out
+//! too early to display them.
+use std::fmt::Debug;
+
+// Disallowed
+fn in_adt_in_return() -> Vec<impl Debug> { panic!() }
+//~^ ERROR opaque type expands to a recursive type
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/where-allowed-2.stderr b/src/test/ui/impl-trait/where-allowed-2.stderr
new file mode 100644
index 0000000000000..1de15014c1f8d
--- /dev/null
+++ b/src/test/ui/impl-trait/where-allowed-2.stderr
@@ -0,0 +1,11 @@
+error[E0720]: opaque type expands to a recursive type
+  --> $DIR/where-allowed-2.rs:6:30
+   |
+LL | fn in_adt_in_return() -> Vec<impl Debug> { panic!() }
+   |                              ^^^^^^^^^^ expands to a recursive type
+   |
+   = note: type resolves to itself
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0720`.
diff --git a/src/test/ui/impl-trait/where-allowed.rs b/src/test/ui/impl-trait/where-allowed.rs
index 5ab74e02e0e40..211a14ed4dd99 100644
--- a/src/test/ui/impl-trait/where-allowed.rs
+++ b/src/test/ui/impl-trait/where-allowed.rs
@@ -11,10 +11,6 @@ fn in_return() -> impl Debug { panic!() }
 // Allowed
 fn in_adt_in_parameters(_: Vec<impl Debug>) { panic!() }
 
-// Disallowed
-fn in_adt_in_return() -> Vec<impl Debug> { panic!() }
-//~^ ERROR type annotations needed
-
 // Disallowed
 fn in_fn_parameter_in_parameters(_: fn(impl Debug)) { panic!() }
 //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
@@ -60,7 +56,6 @@ fn in_impl_Fn_return_in_parameters(_: &impl Fn() -> impl Debug) { panic!() }
 fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() }
 //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
 //~| ERROR nested `impl Trait` is not allowed
-//~| ERROR type annotations needed
 
 // Disallowed
 fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { panic!() }
diff --git a/src/test/ui/impl-trait/where-allowed.stderr b/src/test/ui/impl-trait/where-allowed.stderr
index fcd4c357afdbe..e5d2feff51cc4 100644
--- a/src/test/ui/impl-trait/where-allowed.stderr
+++ b/src/test/ui/impl-trait/where-allowed.stderr
@@ -1,5 +1,5 @@
 error[E0666]: nested `impl Trait` is not allowed
-  --> $DIR/where-allowed.rs:51:51
+  --> $DIR/where-allowed.rs:47:51
    |
 LL | fn in_impl_Fn_parameter_in_parameters(_: &impl Fn(impl Debug)) { panic!() }
    |                                           --------^^^^^^^^^^-
@@ -8,7 +8,7 @@ LL | fn in_impl_Fn_parameter_in_parameters(_: &impl Fn(impl Debug)) { panic!() }
    |                                           outer `impl Trait`
 
 error[E0666]: nested `impl Trait` is not allowed
-  --> $DIR/where-allowed.rs:60:57
+  --> $DIR/where-allowed.rs:56:57
    |
 LL | fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() }
    |                                                 --------^^^^^^^^^^-
@@ -17,7 +17,7 @@ LL | fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic
    |                                                 outer `impl Trait`
 
 error[E0658]: `impl Trait` in type aliases is unstable
-  --> $DIR/where-allowed.rs:124:16
+  --> $DIR/where-allowed.rs:119:16
    |
 LL |     type Out = impl Debug;
    |                ^^^^^^^^^^
@@ -26,7 +26,7 @@ LL |     type Out = impl Debug;
    = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable
 
 error[E0658]: `impl Trait` in type aliases is unstable
-  --> $DIR/where-allowed.rs:160:23
+  --> $DIR/where-allowed.rs:155:23
    |
 LL | type InTypeAlias<R> = impl Debug;
    |                       ^^^^^^^^^^
@@ -35,7 +35,7 @@ LL | type InTypeAlias<R> = impl Debug;
    = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable
 
 error[E0658]: `impl Trait` in type aliases is unstable
-  --> $DIR/where-allowed.rs:164:39
+  --> $DIR/where-allowed.rs:159:39
    |
 LL | type InReturnInTypeAlias<R> = fn() -> impl Debug;
    |                                       ^^^^^^^^^^
@@ -44,205 +44,205 @@ LL | type InReturnInTypeAlias<R> = fn() -> impl Debug;
    = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:19:40
+  --> $DIR/where-allowed.rs:15:40
    |
 LL | fn in_fn_parameter_in_parameters(_: fn(impl Debug)) { panic!() }
    |                                        ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:23:42
+  --> $DIR/where-allowed.rs:19:42
    |
 LL | fn in_fn_return_in_parameters(_: fn() -> impl Debug) { panic!() }
    |                                          ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:27:38
+  --> $DIR/where-allowed.rs:23:38
    |
 LL | fn in_fn_parameter_in_return() -> fn(impl Debug) { panic!() }
    |                                      ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:31:40
+  --> $DIR/where-allowed.rs:27:40
    |
 LL | fn in_fn_return_in_return() -> fn() -> impl Debug { panic!() }
    |                                        ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:35:49
+  --> $DIR/where-allowed.rs:31:49
    |
 LL | fn in_dyn_Fn_parameter_in_parameters(_: &dyn Fn(impl Debug)) { panic!() }
    |                                                 ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:39:51
+  --> $DIR/where-allowed.rs:35:51
    |
 LL | fn in_dyn_Fn_return_in_parameters(_: &dyn Fn() -> impl Debug) { panic!() }
    |                                                   ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:43:55
+  --> $DIR/where-allowed.rs:39:55
    |
 LL | fn in_dyn_Fn_parameter_in_return() -> &'static dyn Fn(impl Debug) { panic!() }
    |                                                       ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:47:57
+  --> $DIR/where-allowed.rs:43:57
    |
 LL | fn in_dyn_Fn_return_in_return() -> &'static dyn Fn() -> impl Debug { panic!() }
    |                                                         ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:51:51
+  --> $DIR/where-allowed.rs:47:51
    |
 LL | fn in_impl_Fn_parameter_in_parameters(_: &impl Fn(impl Debug)) { panic!() }
    |                                                   ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:56:53
+  --> $DIR/where-allowed.rs:52:53
    |
 LL | fn in_impl_Fn_return_in_parameters(_: &impl Fn() -> impl Debug) { panic!() }
    |                                                     ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:60:57
+  --> $DIR/where-allowed.rs:56:57
    |
 LL | fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() }
    |                                                         ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:66:59
+  --> $DIR/where-allowed.rs:61:59
    |
 LL | fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { panic!() }
    |                                                           ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:70:38
+  --> $DIR/where-allowed.rs:65:38
    |
 LL | fn in_Fn_parameter_in_generics<F: Fn(impl Debug)> (_: F) { panic!() }
    |                                      ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:74:40
+  --> $DIR/where-allowed.rs:69:40
    |
 LL | fn in_Fn_return_in_generics<F: Fn() -> impl Debug> (_: F) { panic!() }
    |                                        ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:87:32
+  --> $DIR/where-allowed.rs:82:32
    |
 LL | struct InBraceStructField { x: impl Debug }
    |                                ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:91:41
+  --> $DIR/where-allowed.rs:86:41
    |
 LL | struct InAdtInBraceStructField { x: Vec<impl Debug> }
    |                                         ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:95:27
+  --> $DIR/where-allowed.rs:90:27
    |
 LL | struct InTupleStructField(impl Debug);
    |                           ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:100:25
+  --> $DIR/where-allowed.rs:95:25
    |
 LL |     InBraceVariant { x: impl Debug },
    |                         ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:102:20
+  --> $DIR/where-allowed.rs:97:20
    |
 LL |     InTupleVariant(impl Debug),
    |                    ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:113:23
+  --> $DIR/where-allowed.rs:108:23
    |
 LL |     fn in_return() -> impl Debug;
    |                       ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:131:34
+  --> $DIR/where-allowed.rs:126:34
    |
 LL |     fn in_trait_impl_return() -> impl Debug { () }
    |                                  ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:144:33
+  --> $DIR/where-allowed.rs:139:33
    |
 LL |     fn in_foreign_parameters(_: impl Debug);
    |                                 ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:147:31
+  --> $DIR/where-allowed.rs:142:31
    |
 LL |     fn in_foreign_return() -> impl Debug;
    |                               ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:164:39
+  --> $DIR/where-allowed.rs:159:39
    |
 LL | type InReturnInTypeAlias<R> = fn() -> impl Debug;
    |                                       ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:169:16
+  --> $DIR/where-allowed.rs:164:16
    |
 LL | impl PartialEq<impl Debug> for () {
    |                ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:174:24
+  --> $DIR/where-allowed.rs:169:24
    |
 LL | impl PartialEq<()> for impl Debug {
    |                        ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:179:6
+  --> $DIR/where-allowed.rs:174:6
    |
 LL | impl impl Debug {
    |      ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:185:24
+  --> $DIR/where-allowed.rs:180:24
    |
 LL | impl InInherentImplAdt<impl Debug> {
    |                        ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:191:11
+  --> $DIR/where-allowed.rs:186:11
    |
 LL |     where impl Debug: Debug
    |           ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:198:15
+  --> $DIR/where-allowed.rs:193:15
    |
 LL |     where Vec<impl Debug>: Debug
    |               ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:205:24
+  --> $DIR/where-allowed.rs:200:24
    |
 LL |     where T: PartialEq<impl Debug>
    |                        ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:212:17
+  --> $DIR/where-allowed.rs:207:17
    |
 LL |     where T: Fn(impl Debug)
    |                 ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:219:22
+  --> $DIR/where-allowed.rs:214:22
    |
 LL |     where T: Fn() -> impl Debug
    |                      ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:225:29
+  --> $DIR/where-allowed.rs:220:29
    |
 LL |     let _in_local_variable: impl Fn() = || {};
    |                             ^^^^^^^^^
@@ -250,36 +250,24 @@ LL |     let _in_local_variable: impl Fn() = || {};
    = help: add `#![feature(impl_trait_in_bindings)]` to the crate attributes to enable
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:227:46
+  --> $DIR/where-allowed.rs:222:46
    |
 LL |     let _in_return_in_local_variable = || -> impl Fn() { || {} };
    |                                              ^^^^^^^^^
 
-error[E0282]: type annotations needed
-  --> $DIR/where-allowed.rs:15:30
-   |
-LL | fn in_adt_in_return() -> Vec<impl Debug> { panic!() }
-   |                              ^^^^^^^^^^ cannot infer type
-
-error[E0282]: type annotations needed
-  --> $DIR/where-allowed.rs:60:49
-   |
-LL | fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() }
-   |                                                 ^^^^^^^^^^^^^^^^^^^ cannot infer type
-
 error: could not find defining uses
-  --> $DIR/where-allowed.rs:160:1
+  --> $DIR/where-allowed.rs:155:1
    |
 LL | type InTypeAlias<R> = impl Debug;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: could not find defining uses
-  --> $DIR/where-allowed.rs:124:5
+  --> $DIR/where-allowed.rs:119:5
    |
 LL |     type Out = impl Debug;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 44 previous errors
+error: aborting due to 42 previous errors
 
-Some errors have detailed explanations: E0282, E0562, E0658, E0666.
-For more information about an error, try `rustc --explain E0282`.
+Some errors have detailed explanations: E0562, E0658, E0666.
+For more information about an error, try `rustc --explain E0562`.
diff --git a/src/test/ui/issues/issue-45730.stderr b/src/test/ui/issues/issue-45730.stderr
index 4fc1e3835f7ad..3c400d6eefaa8 100644
--- a/src/test/ui/issues/issue-45730.stderr
+++ b/src/test/ui/issues/issue-45730.stderr
@@ -30,3 +30,4 @@ LL |     let x = 0 as *const i32 as *const _ as *mut _;
 
 error: aborting due to 3 previous errors
 
+For more information about this error, try `rustc --explain E0641`.
diff --git a/src/test/ui/issues/issue-46023.stderr b/src/test/ui/issues/issue-46023.stderr
index fac696c6fdcbf..ca19c2501205d 100644
--- a/src/test/ui/issues/issue-46023.stderr
+++ b/src/test/ui/issues/issue-46023.stderr
@@ -9,3 +9,4 @@ LL |         x = 1;
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0594`.
diff --git a/src/test/ui/issues/issue-46604.stderr b/src/test/ui/issues/issue-46604.stderr
index 961b249daeb0c..c72f580f24391 100644
--- a/src/test/ui/issues/issue-46604.stderr
+++ b/src/test/ui/issues/issue-46604.stderr
@@ -12,4 +12,5 @@ LL |     buf[0]=2;
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0017`.
+Some errors have detailed explanations: E0017, E0594.
+For more information about an error, try `rustc --explain E0017`.
diff --git a/src/test/ui/issues/issue-51244.stderr b/src/test/ui/issues/issue-51244.stderr
index 8a7e71e0326a0..c91083955b820 100644
--- a/src/test/ui/issues/issue-51244.stderr
+++ b/src/test/ui/issues/issue-51244.stderr
@@ -8,3 +8,4 @@ LL |     *my_ref = 0;
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0594`.
diff --git a/src/test/ui/issues/issue-51515.stderr b/src/test/ui/issues/issue-51515.stderr
index 827bb8fe2b892..3c208935f31f6 100644
--- a/src/test/ui/issues/issue-51515.stderr
+++ b/src/test/ui/issues/issue-51515.stderr
@@ -18,3 +18,4 @@ LL |     *bar = 64;
 
 error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0594`.
diff --git a/src/test/ui/mut/mutable-class-fields-2.stderr b/src/test/ui/mut/mutable-class-fields-2.stderr
index a27a82ffe4642..15323ce9a9755 100644
--- a/src/test/ui/mut/mutable-class-fields-2.stderr
+++ b/src/test/ui/mut/mutable-class-fields-2.stderr
@@ -8,3 +8,4 @@ LL |     self.how_hungry -= 5;
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0594`.
diff --git a/src/test/ui/mut/mutable-class-fields.stderr b/src/test/ui/mut/mutable-class-fields.stderr
index 5391ccc80c5f9..40a0dc9b29c23 100644
--- a/src/test/ui/mut/mutable-class-fields.stderr
+++ b/src/test/ui/mut/mutable-class-fields.stderr
@@ -8,3 +8,4 @@ LL |   nyan.how_hungry = 0;
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0594`.
diff --git a/src/test/ui/nll/closure-captures.stderr b/src/test/ui/nll/closure-captures.stderr
index 77f7d815eeb4c..b8f5cc86500c5 100644
--- a/src/test/ui/nll/closure-captures.stderr
+++ b/src/test/ui/nll/closure-captures.stderr
@@ -156,4 +156,5 @@ LL | |         *x = 1;});
 
 error: aborting due to 12 previous errors
 
-For more information about this error, try `rustc --explain E0596`.
+Some errors have detailed explanations: E0594, E0596.
+For more information about an error, try `rustc --explain E0594`.
diff --git a/src/test/ui/nll/constant-thread-locals-issue-47053.stderr b/src/test/ui/nll/constant-thread-locals-issue-47053.stderr
index 8afb42d66a61a..a44acfb5fc354 100644
--- a/src/test/ui/nll/constant-thread-locals-issue-47053.stderr
+++ b/src/test/ui/nll/constant-thread-locals-issue-47053.stderr
@@ -6,3 +6,4 @@ LL |     FOO = 6;
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0594`.
diff --git a/src/test/ui/nll/generator-upvar-mutability.stderr b/src/test/ui/nll/generator-upvar-mutability.stderr
index 1b4e5b89984e7..31b061b61d19d 100644
--- a/src/test/ui/nll/generator-upvar-mutability.stderr
+++ b/src/test/ui/nll/generator-upvar-mutability.stderr
@@ -9,3 +9,4 @@ LL |         x = 1;
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0594`.
diff --git a/src/test/ui/nll/issue-47388.stderr b/src/test/ui/nll/issue-47388.stderr
index d4064b3f50a34..8d48b00f8d1f1 100644
--- a/src/test/ui/nll/issue-47388.stderr
+++ b/src/test/ui/nll/issue-47388.stderr
@@ -8,3 +8,4 @@ LL |     fancy_ref.num = 6;
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0594`.
diff --git a/src/test/ui/nll/issue-51244.stderr b/src/test/ui/nll/issue-51244.stderr
index 8a7e71e0326a0..c91083955b820 100644
--- a/src/test/ui/nll/issue-51244.stderr
+++ b/src/test/ui/nll/issue-51244.stderr
@@ -8,3 +8,4 @@ LL |     *my_ref = 0;
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0594`.
diff --git a/src/test/ui/nll/issue-57989.stderr b/src/test/ui/nll/issue-57989.stderr
index 00a9bab486855..4c416105035d7 100644
--- a/src/test/ui/nll/issue-57989.stderr
+++ b/src/test/ui/nll/issue-57989.stderr
@@ -20,4 +20,5 @@ LL |     g;
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0506`.
+Some errors have detailed explanations: E0506, E0594.
+For more information about an error, try `rustc --explain E0506`.
diff --git a/src/test/ui/order-dependent-cast-inference.stderr b/src/test/ui/order-dependent-cast-inference.stderr
index 01e59f8f022fd..081038c573acf 100644
--- a/src/test/ui/order-dependent-cast-inference.stderr
+++ b/src/test/ui/order-dependent-cast-inference.stderr
@@ -10,3 +10,4 @@ LL |     let mut y = 0 as *const _;
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0641`.
diff --git a/src/test/ui/proc-macro/auxiliary/derive-helper-shadowing-2.rs b/src/test/ui/proc-macro/auxiliary/derive-helper-shadowing-2.rs
new file mode 100644
index 0000000000000..370a1a2794dcf
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/derive-helper-shadowing-2.rs
@@ -0,0 +1,12 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::*;
+
+#[proc_macro_derive(same_name, attributes(same_name))]
+pub fn derive_a(_: TokenStream) -> TokenStream {
+    TokenStream::new()
+}
diff --git a/src/test/ui/proc-macro/derive-helper-shadowing-2.rs b/src/test/ui/proc-macro/derive-helper-shadowing-2.rs
new file mode 100644
index 0000000000000..5204d72b980c1
--- /dev/null
+++ b/src/test/ui/proc-macro/derive-helper-shadowing-2.rs
@@ -0,0 +1,16 @@
+// If a derive macro introduces a helper attribute with the same name as that macro,
+// then make sure that it's usable without ambiguities.
+
+// check-pass
+// aux-build:derive-helper-shadowing-2.rs
+
+#[macro_use]
+extern crate derive_helper_shadowing_2;
+
+#[derive(same_name)]
+struct S {
+    #[same_name] // OK, no ambiguity, derive helpers have highest priority
+    field: u8,
+}
+
+fn main() {}
diff --git a/src/test/ui/proc-macro/derive-helper-shadowing.rs b/src/test/ui/proc-macro/derive-helper-shadowing.rs
index f0ca34db414d4..6147e96a74bf1 100644
--- a/src/test/ui/proc-macro/derive-helper-shadowing.rs
+++ b/src/test/ui/proc-macro/derive-helper-shadowing.rs
@@ -19,11 +19,11 @@ macro_rules! gen_helper_use {
 #[empty_helper] //~ ERROR `empty_helper` is ambiguous
 #[derive(Empty)]
 struct S {
-    #[empty_helper] //~ ERROR `empty_helper` is ambiguous
+    #[empty_helper] // OK, no ambiguity, derive helpers have highest priority
     field: [u8; {
         use empty_helper; //~ ERROR `empty_helper` is ambiguous
 
-        #[empty_helper] //~ ERROR `empty_helper` is ambiguous
+        #[empty_helper] // OK, no ambiguity, derive helpers have highest priority
         struct U;
 
         mod inner {
diff --git a/src/test/ui/proc-macro/derive-helper-shadowing.stderr b/src/test/ui/proc-macro/derive-helper-shadowing.stderr
index 9048830bee24d..76434860a4956 100644
--- a/src/test/ui/proc-macro/derive-helper-shadowing.stderr
+++ b/src/test/ui/proc-macro/derive-helper-shadowing.stderr
@@ -61,42 +61,6 @@ LL | use test_macros::empty_attr as empty_helper;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = help: use `crate::empty_helper` to refer to this attribute macro unambiguously
 
-error[E0659]: `empty_helper` is ambiguous (derive helper attribute vs any other name)
-  --> $DIR/derive-helper-shadowing.rs:22:7
-   |
-LL |     #[empty_helper]
-   |       ^^^^^^^^^^^^ ambiguous name
-   |
-note: `empty_helper` could refer to the derive helper attribute defined here
-  --> $DIR/derive-helper-shadowing.rs:20:10
-   |
-LL | #[derive(Empty)]
-   |          ^^^^^
-note: `empty_helper` could also refer to the attribute macro imported here
-  --> $DIR/derive-helper-shadowing.rs:10:5
-   |
-LL | use test_macros::empty_attr as empty_helper;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = help: use `crate::empty_helper` to refer to this attribute macro unambiguously
-
-error[E0659]: `empty_helper` is ambiguous (derive helper attribute vs any other name)
-  --> $DIR/derive-helper-shadowing.rs:26:11
-   |
-LL |         #[empty_helper]
-   |           ^^^^^^^^^^^^ ambiguous name
-   |
-note: `empty_helper` could refer to the derive helper attribute defined here
-  --> $DIR/derive-helper-shadowing.rs:20:10
-   |
-LL | #[derive(Empty)]
-   |          ^^^^^
-note: `empty_helper` could also refer to the attribute macro imported here
-  --> $DIR/derive-helper-shadowing.rs:10:5
-   |
-LL | use test_macros::empty_attr as empty_helper;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = help: use `crate::empty_helper` to refer to this attribute macro unambiguously
-
-error: aborting due to 7 previous errors
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0659`.
diff --git a/src/test/ui/rfc-2005-default-binding-mode/enum.stderr b/src/test/ui/rfc-2005-default-binding-mode/enum.stderr
index 9d53e6d7887df..d6a89006bc0fb 100644
--- a/src/test/ui/rfc-2005-default-binding-mode/enum.stderr
+++ b/src/test/ui/rfc-2005-default-binding-mode/enum.stderr
@@ -18,3 +18,4 @@ LL |         *x += 1;
 
 error: aborting due to 3 previous errors
 
+For more information about this error, try `rustc --explain E0594`.
diff --git a/src/test/ui/rfc-2005-default-binding-mode/explicit-mut.stderr b/src/test/ui/rfc-2005-default-binding-mode/explicit-mut.stderr
index 5eace3d263d46..a6f2f3ec30968 100644
--- a/src/test/ui/rfc-2005-default-binding-mode/explicit-mut.stderr
+++ b/src/test/ui/rfc-2005-default-binding-mode/explicit-mut.stderr
@@ -18,3 +18,4 @@ LL |             *n += 1;
 
 error: aborting due to 3 previous errors
 
+For more information about this error, try `rustc --explain E0594`.
diff --git a/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs b/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs
index a2d2ba145bc5e..156162c9027c3 100644
--- a/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs
+++ b/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs
@@ -1,4 +1,5 @@
 // edition:2018
+#![feature(async_closure)]
 use std::future::Future;
 
 async fn foo() {}
@@ -7,4 +8,6 @@ fn bar(f: impl Future<Output=()>) {}
 
 fn main() {
     bar(foo); //~ERROR E0277
+    let async_closure = async || ();
+    bar(async_closure); //~ERROR E0277
 }
diff --git a/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr b/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr
index 1cc704b443366..05583876a066c 100644
--- a/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr
+++ b/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr
@@ -1,6 +1,9 @@
 error[E0277]: the trait bound `fn() -> impl std::future::Future {foo}: std::future::Future` is not satisfied
-  --> $DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:9:9
+  --> $DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:10:9
    |
+LL | async fn foo() {}
+   |          --- consider calling this function
+LL | 
 LL | fn bar(f: impl Future<Output=()>) {}
    |    ---         ----------------- required by this bound in `bar`
 ...
@@ -10,6 +13,20 @@ LL |     bar(foo);
    |         the trait `std::future::Future` is not implemented for `fn() -> impl std::future::Future {foo}`
    |         help: use parentheses to call the function: `foo()`
 
-error: aborting due to previous error
+error[E0277]: the trait bound `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:36]: std::future::Future` is not satisfied
+  --> $DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:12:9
+   |
+LL | fn bar(f: impl Future<Output=()>) {}
+   |    ---         ----------------- required by this bound in `bar`
+...
+LL |     let async_closure = async || ();
+   |                         -------- consider calling this closure
+LL |     bar(async_closure);
+   |         ^^^^^^^^^^^^^
+   |         |
+   |         the trait `std::future::Future` is not implemented for `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:36]`
+   |         help: use parentheses to call the closure: `async_closure()`
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.rs b/src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.rs
index acd149c5854e8..4303e5c540569 100644
--- a/src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.rs
+++ b/src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.rs
@@ -15,4 +15,6 @@ fn bar(f: impl T<O=()>) {}
 
 fn main() {
     bar(foo); //~ERROR E0277
+    let closure = || S;
+    bar(closure); //~ERROR E0277
 }
diff --git a/src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr b/src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr
index 7a49031bde7c2..91f60e8f426c4 100644
--- a/src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr
+++ b/src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr
@@ -1,6 +1,9 @@
 error[E0277]: the trait bound `fn() -> impl T {foo}: T` is not satisfied
   --> $DIR/fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:17:9
    |
+LL | fn foo() -> impl T<O=()> { S }
+   |    --- consider calling this function
+LL | 
 LL | fn bar(f: impl T<O=()>) {}
    |    ---         ------- required by this bound in `bar`
 ...
@@ -10,6 +13,20 @@ LL |     bar(foo);
    |         the trait `T` is not implemented for `fn() -> impl T {foo}`
    |         help: use parentheses to call the function: `foo()`
 
-error: aborting due to previous error
+error[E0277]: the trait bound `[closure@$DIR/fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:18:19: 18:23]: T` is not satisfied
+  --> $DIR/fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:19:9
+   |
+LL | fn bar(f: impl T<O=()>) {}
+   |    ---         ------- required by this bound in `bar`
+...
+LL |     let closure = || S;
+   |                   -- consider calling this closure
+LL |     bar(closure);
+   |         ^^^^^^^
+   |         |
+   |         the trait `T` is not implemented for `[closure@$DIR/fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:18:19: 18:23]`
+   |         help: use parentheses to call the closure: `closure()`
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/suggestions/suggest-ref-mut.stderr b/src/test/ui/suggestions/suggest-ref-mut.stderr
index 2414367875718..b4981279a238b 100644
--- a/src/test/ui/suggestions/suggest-ref-mut.stderr
+++ b/src/test/ui/suggestions/suggest-ref-mut.stderr
@@ -35,3 +35,4 @@ LL |         ref quo => { *quo = 32; },
 
 error: aborting due to 4 previous errors
 
+For more information about this error, try `rustc --explain E0594`.
diff --git a/src/test/ui/thread-local-mutation.stderr b/src/test/ui/thread-local-mutation.stderr
index 7f7738b5d6509..e5dc0e72edfc7 100644
--- a/src/test/ui/thread-local-mutation.stderr
+++ b/src/test/ui/thread-local-mutation.stderr
@@ -6,3 +6,4 @@ LL |     S = "after";
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0594`.
diff --git a/src/test/ui/type-alias-impl-trait/fallback.rs b/src/test/ui/type-alias-impl-trait/fallback.rs
new file mode 100644
index 0000000000000..fe1ca2230daca
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/fallback.rs
@@ -0,0 +1,28 @@
+// Tests that we correctly handle the instantiated
+// inference variable being completely unconstrained.
+//
+// check-pass
+#![feature(type_alias_impl_trait)]
+
+type Foo = impl Copy;
+
+enum Wrapper<T> {
+    First(T),
+    Second
+}
+
+// This method constrains `Foo` to be `bool`
+fn constrained_foo() -> Foo {
+    true
+}
+
+
+// This method does not constrain `Foo`.
+// Per RFC 2071, function bodies may either
+// fully constrain an opaque type, or place no
+// constraints on it.
+fn unconstrained_foo() -> Wrapper<Foo> {
+    Wrapper::Second
+}
+
+fn main() {}
diff --git a/src/test/ui/unboxed-closures/unboxed-closure-immutable-capture.stderr b/src/test/ui/unboxed-closures/unboxed-closure-immutable-capture.stderr
index 9fd8aa562f4e4..ad5451ced55d0 100644
--- a/src/test/ui/unboxed-closures/unboxed-closure-immutable-capture.stderr
+++ b/src/test/ui/unboxed-closures/unboxed-closure-immutable-capture.stderr
@@ -71,4 +71,5 @@ LL |     || set(&mut x);
 
 error: aborting due to 8 previous errors
 
-For more information about this error, try `rustc --explain E0596`.
+Some errors have detailed explanations: E0594, E0596.
+For more information about an error, try `rustc --explain E0594`.
diff --git a/src/test/ui/unboxed-closures/unboxed-closures-mutate-upvar.stderr b/src/test/ui/unboxed-closures/unboxed-closures-mutate-upvar.stderr
index fef6c23a50130..6bba38510b676 100644
--- a/src/test/ui/unboxed-closures/unboxed-closures-mutate-upvar.stderr
+++ b/src/test/ui/unboxed-closures/unboxed-closures-mutate-upvar.stderr
@@ -42,3 +42,4 @@ LL | |     });
 
 error: aborting due to 4 previous errors
 
+For more information about this error, try `rustc --explain E0594`.
diff --git a/src/test/ui/unboxed-closures/unboxed-closures-mutated-upvar-from-fn-closure.stderr b/src/test/ui/unboxed-closures/unboxed-closures-mutated-upvar-from-fn-closure.stderr
index 2bc1f01af9815..a38c612e1dea9 100644
--- a/src/test/ui/unboxed-closures/unboxed-closures-mutated-upvar-from-fn-closure.stderr
+++ b/src/test/ui/unboxed-closures/unboxed-closures-mutated-upvar-from-fn-closure.stderr
@@ -16,3 +16,4 @@ LL | |     });
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0594`.
diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py
index 4383cd9d5be43..61762ae1d9b04 100755
--- a/src/tools/publish_toolstate.py
+++ b/src/tools/publish_toolstate.py
@@ -41,7 +41,7 @@
         'ryankurte', 'thejpster', 'therealprof',
     },
     'edition-guide': {'ehuss', 'Centril', 'steveklabnik'},
-    'rustc-guide': {'mark-i-m', 'spastorino', 'amanjeev'},
+    'rustc-guide': {'mark-i-m', 'spastorino', 'amanjeev', 'JohnTitor'},
 }
 
 REPOS = {
@@ -50,11 +50,11 @@
     'rls': 'https://github.com/rust-lang/rls',
     'rustfmt': 'https://github.com/rust-lang/rustfmt',
     'book': 'https://github.com/rust-lang/book',
-    'nomicon': 'https://github.com/rust-lang-nursery/nomicon',
-    'reference': 'https://github.com/rust-lang-nursery/reference',
+    'nomicon': 'https://github.com/rust-lang/nomicon',
+    'reference': 'https://github.com/rust-lang/reference',
     'rust-by-example': 'https://github.com/rust-lang/rust-by-example',
     'embedded-book': 'https://github.com/rust-embedded/book',
-    'edition-guide': 'https://github.com/rust-lang-nursery/edition-guide',
+    'edition-guide': 'https://github.com/rust-lang/edition-guide',
     'rustc-guide': 'https://github.com/rust-lang/rustc-guide',
 }