about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci.yml158
-rw-r--r--src/ci/github-actions/ci.yml81
-rw-r--r--src/libcore/result.rs8
-rw-r--r--src/libcore/time.rs43
-rw-r--r--src/librustc_arena/lib.rs95
-rw-r--r--src/librustc_ast_lowering/lib.rs12
-rw-r--r--src/librustc_builtin_macros/asm.rs89
-rw-r--r--src/librustc_hir/definitions.rs61
-rw-r--r--src/librustc_hir/hir.rs4
-rw-r--r--src/librustc_infer/infer/outlives/verify.rs21
-rw-r--r--src/librustc_infer/traits/mod.rs2
-rw-r--r--src/librustc_lint/types.rs27
-rw-r--r--src/librustc_middle/hir/map/collector.rs18
-rw-r--r--src/librustc_middle/lib.rs1
-rw-r--r--src/librustc_middle/query/mod.rs17
-rw-r--r--src/librustc_middle/ty/context.rs4
-rw-r--r--src/librustc_middle/ty/flags.rs2
-rw-r--r--src/librustc_middle/ty/mod.rs1
-rw-r--r--src/librustc_middle/ty/sty.rs3
-rw-r--r--src/librustc_middle/ty/subst.rs11
-rw-r--r--src/librustc_resolve/late/lifetimes.rs13
-rw-r--r--src/librustc_resolve/lib.rs15
-rw-r--r--src/librustc_trait_selection/autoderef.rs229
-rw-r--r--src/librustc_trait_selection/lib.rs1
-rw-r--r--src/librustc_trait_selection/traits/error_reporting/mod.rs1
-rw-r--r--src/librustc_trait_selection/traits/error_reporting/suggestions.rs67
-rw-r--r--src/librustc_trait_selection/traits/project.rs21
-rw-r--r--src/librustc_trait_selection/traits/select/mod.rs50
-rw-r--r--src/librustc_ty/ty.rs132
-rw-r--r--src/librustc_typeck/check/autoderef.rs246
-rw-r--r--src/librustc_typeck/check/callee.rs13
-rw-r--r--src/librustc_typeck/check/coercion.rs2
-rw-r--r--src/librustc_typeck/check/compare_method.rs151
-rw-r--r--src/librustc_typeck/check/expr.rs10
-rw-r--r--src/librustc_typeck/check/method/confirm.rs7
-rw-r--r--src/librustc_typeck/check/method/probe.rs4
-rw-r--r--src/librustc_typeck/check/mod.rs2
-rw-r--r--src/librustc_typeck/check/place_op.rs9
-rw-r--r--src/librustc_typeck/check/wfcheck.rs2
-rw-r--r--src/librustc_typeck/collect.rs129
-rw-r--r--src/stage0.txt2
-rw-r--r--src/test/codegen/asm-multiple-options.rs53
-rw-r--r--src/test/ui/asm/duplicate-options.fixed26
-rw-r--r--src/test/ui/asm/duplicate-options.rs26
-rw-r--r--src/test/ui/asm/duplicate-options.stderr56
-rw-r--r--src/test/ui/asm/parse-error.rs5
-rw-r--r--src/test/ui/asm/parse-error.stderr48
-rw-r--r--src/test/ui/associated-types/hr-associated-type-bound-1.rs18
-rw-r--r--src/test/ui/associated-types/hr-associated-type-bound-1.stderr19
-rw-r--r--src/test/ui/associated-types/hr-associated-type-bound-2.rs21
-rw-r--r--src/test/ui/associated-types/hr-associated-type-bound-2.stderr13
-rw-r--r--src/test/ui/associated-types/hr-associated-type-bound-object.rs14
-rw-r--r--src/test/ui/associated-types/hr-associated-type-bound-object.stderr19
-rw-r--r--src/test/ui/associated-types/hr-associated-type-bound-param-1.rs20
-rw-r--r--src/test/ui/associated-types/hr-associated-type-bound-param-1.stderr19
-rw-r--r--src/test/ui/associated-types/hr-associated-type-bound-param-2.rs21
-rw-r--r--src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr51
-rw-r--r--src/test/ui/associated-types/hr-associated-type-bound-param-3.rs21
-rw-r--r--src/test/ui/associated-types/hr-associated-type-bound-param-3.stderr19
-rw-r--r--src/test/ui/associated-types/hr-associated-type-bound-param-4.rs19
-rw-r--r--src/test/ui/associated-types/hr-associated-type-bound-param-4.stderr19
-rw-r--r--src/test/ui/associated-types/hr-associated-type-bound-param-5.rs41
-rw-r--r--src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr67
-rw-r--r--src/test/ui/associated-types/hr-associated-type-bound-param-6.rs20
-rw-r--r--src/test/ui/associated-types/hr-associated-type-bound-param-6.stderr36
-rw-r--r--src/test/ui/associated-types/hr-associated-type-projection-1.rs21
-rw-r--r--src/test/ui/associated-types/hr-associated-type-projection-1.stderr30
-rw-r--r--src/test/ui/feature-gates/feature-gate-generic_associated_types.rs2
-rw-r--r--src/test/ui/feature-gates/feature-gate-generic_associated_types.stderr30
-rw-r--r--src/test/ui/generic-associated-types/collections-project-default.rs72
-rw-r--r--src/test/ui/generic-associated-types/collections-project-default.stderr15
-rw-r--r--src/test/ui/generic-associated-types/collections.rs33
-rw-r--r--src/test/ui/generic-associated-types/collections.stderr19
-rw-r--r--src/test/ui/generic-associated-types/construct_with_other_type.rs3
-rw-r--r--src/test/ui/generic-associated-types/construct_with_other_type.stderr18
-rw-r--r--src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature-2.rs1
-rw-r--r--src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature-2.stderr12
-rw-r--r--src/test/ui/generic-associated-types/generic-associated-types-where.rs6
-rw-r--r--src/test/ui/generic-associated-types/generic-associated-types-where.stderr30
-rw-r--r--src/test/ui/generic-associated-types/issue-47206-where-clause.rs2
-rw-r--r--src/test/ui/generic-associated-types/issue-47206-where-clause.stderr12
-rw-r--r--src/test/ui/generic-associated-types/issue-62326-parameter-out-of-range.rs7
-rw-r--r--src/test/ui/generic-associated-types/issue-62326-parameter-out-of-range.stderr10
-rw-r--r--src/test/ui/generic-associated-types/issue-67424.rs1
-rw-r--r--src/test/ui/generic-associated-types/issue-67424.stderr10
-rw-r--r--src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.rs32
-rw-r--r--src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr26
-rw-r--r--src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.rs21
-rw-r--r--src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr28
-rw-r--r--src/test/ui/generic-associated-types/issue-68643-broken-mir.rs21
-rw-r--r--src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr28
-rw-r--r--src/test/ui/generic-associated-types/issue-68644-codegen-selection.rs21
-rw-r--r--src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr28
-rw-r--r--src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.rs21
-rw-r--r--src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr28
-rw-r--r--src/test/ui/generic-associated-types/issue-68656-unsized-values.rs22
-rw-r--r--src/test/ui/generic-associated-types/issue-68656-unsized-values.stderr30
-rw-r--r--src/test/ui/generic-associated-types/iterable.rs20
-rw-r--r--src/test/ui/generic-associated-types/iterable.stderr59
-rw-r--r--src/test/ui/generic-associated-types/missing-bounds.fixed5
-rw-r--r--src/test/ui/generic-associated-types/missing-bounds.rs5
-rw-r--r--src/test/ui/generic-associated-types/missing-bounds.stderr30
-rw-r--r--src/test/ui/generic-associated-types/parameter_number_and_kind.rs6
-rw-r--r--src/test/ui/generic-associated-types/parameter_number_and_kind.stderr40
-rw-r--r--src/test/ui/generic-associated-types/pointer_family.rs3
-rw-r--r--src/test/ui/generic-associated-types/pointer_family.stderr10
-rw-r--r--src/test/ui/generic-associated-types/shadowing.rs2
-rw-r--r--src/test/ui/generic-associated-types/shadowing.stderr20
-rw-r--r--src/test/ui/generic-associated-types/unsatisfied-outlives-bound.rs22
-rw-r--r--src/test/ui/generic-associated-types/unsatisfied-outlives-bound.stderr23
-rw-r--r--src/test/ui/issues/issue-38091.rs2
-rw-r--r--src/test/ui/issues/issue-38091.stderr14
-rw-r--r--src/test/ui/lint/lint-ctypes-73251-1.rs24
-rw-r--r--src/test/ui/lint/lint-ctypes-73251-1.stderr15
-rw-r--r--src/test/ui/lint/lint-ctypes-73251-2.rs32
-rw-r--r--src/test/ui/lint/lint-ctypes-73251-2.stderr15
-rw-r--r--src/test/ui/lint/lint-ctypes-73251.rs22
-rw-r--r--src/test/ui/specialization/deafult-associated-type-bound-1.rs24
-rw-r--r--src/test/ui/specialization/deafult-associated-type-bound-1.stderr21
-rw-r--r--src/test/ui/specialization/deafult-associated-type-bound-2.rs22
-rw-r--r--src/test/ui/specialization/deafult-associated-type-bound-2.stderr23
-rw-r--r--src/test/ui/specialization/deafult-generic-associated-type-bound.rs27
-rw-r--r--src/test/ui/specialization/deafult-generic-associated-type-bound.stderr36
-rw-r--r--src/test/ui/traits/trait-suggest-deferences-issue-39029.fixed18
-rw-r--r--src/test/ui/traits/trait-suggest-deferences-issue-39029.rs18
-rw-r--r--src/test/ui/traits/trait-suggest-deferences-issue-39029.stderr19
-rw-r--r--src/test/ui/traits/trait-suggest-deferences-issue-62530.fixed15
-rw-r--r--src/test/ui/traits/trait-suggest-deferences-issue-62530.rs15
-rw-r--r--src/test/ui/traits/trait-suggest-deferences-issue-62530.stderr15
-rw-r--r--src/test/ui/traits/trait-suggest-deferences-multiple-0.fixed36
-rw-r--r--src/test/ui/traits/trait-suggest-deferences-multiple-0.rs36
-rw-r--r--src/test/ui/traits/trait-suggest-deferences-multiple-0.stderr15
-rw-r--r--src/test/ui/traits/trait-suggest-deferences-multiple-1.rs54
-rw-r--r--src/test/ui/traits/trait-suggest-deferences-multiple-1.stderr12
-rw-r--r--src/test/ui/where-clauses/where-lifetime-resolution.rs1
-rw-r--r--src/test/ui/where-clauses/where-lifetime-resolution.stderr8
136 files changed, 2864 insertions, 995 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 5f9311635f6..7b9f87c079e 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -369,35 +369,6 @@ jobs:
             env:
               DEPLOY_TOOLSTATES_JSON: toolstates-linux.json
             os: ubuntu-latest-xl
-          - name: dist-x86_64-apple
-            env:
-              SCRIPT: "./x.py dist"
-              RUST_CONFIGURE_ARGS: "--target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc"
-              RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
-              MACOSX_DEPLOYMENT_TARGET: 10.7
-              NO_LLVM_ASSERTIONS: 1
-              NO_DEBUG_ASSERTIONS: 1
-              DIST_REQUIRE_ALL_TOOLS: 1
-            os: macos-latest
-          - name: dist-x86_64-apple-alt
-            env:
-              SCRIPT: "./x.py dist"
-              RUST_CONFIGURE_ARGS: "--enable-extended --enable-profiler --set rust.jemalloc"
-              RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
-              MACOSX_DEPLOYMENT_TARGET: 10.7
-              NO_LLVM_ASSERTIONS: 1
-              NO_DEBUG_ASSERTIONS: 1
-            os: macos-latest
-          - name: x86_64-apple
-            env:
-              SCRIPT: "./x.py test"
-              RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc"
-              RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
-              MACOSX_DEPLOYMENT_TARGET: 10.8
-              MACOSX_STD_DEPLOYMENT_TARGET: 10.7
-              NO_LLVM_ASSERTIONS: 1
-              NO_DEBUG_ASSERTIONS: 1
-            os: macos-latest
           - name: x86_64-msvc-1
             env:
               RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-profiler"
@@ -580,6 +551,135 @@ jobs:
           AWS_ACCESS_KEY_ID: "${{ env.ARTIFACTS_AWS_ACCESS_KEY_ID }}"
           AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }}"
         if: "success() && !env.SKIP_JOB && (github.event_name == 'push' || env.DEPLOY == '1' || env.DEPLOY_ALT == '1')"
+  auto-fallible:
+    name: auto-fallible
+    env:
+      CI_JOB_NAME: "${{ matrix.name }}"
+      SCCACHE_BUCKET: rust-lang-gha-caches
+      DEPLOY_BUCKET: rust-lang-gha
+      TOOLSTATE_REPO: "https://github.com/pietroalbini/rust-toolstate"
+      TOOLSTATE_ISSUES_API_URL: "https://api.github.com/repos/pietroalbini/rust-toolstate/issues"
+      TOOLSTATE_PUBLISH: 1
+      CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZOMUQATD5
+      ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZH5AYXDVF
+      CACHE_DOMAIN: ci-caches-gha.rust-lang.org
+    if: "github.event_name == 'push' && github.ref == 'refs/heads/auto' && github.repository == 'rust-lang-ci/rust'"
+    strategy:
+      matrix:
+        include:
+          - name: dist-x86_64-apple
+            env:
+              SCRIPT: "./x.py dist"
+              RUST_CONFIGURE_ARGS: "--target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc"
+              RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+              MACOSX_DEPLOYMENT_TARGET: 10.7
+              NO_LLVM_ASSERTIONS: 1
+              NO_DEBUG_ASSERTIONS: 1
+              DIST_REQUIRE_ALL_TOOLS: 1
+            os: macos-latest
+          - name: dist-x86_64-apple-alt
+            env:
+              SCRIPT: "./x.py dist"
+              RUST_CONFIGURE_ARGS: "--enable-extended --enable-profiler --set rust.jemalloc"
+              RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+              MACOSX_DEPLOYMENT_TARGET: 10.7
+              NO_LLVM_ASSERTIONS: 1
+              NO_DEBUG_ASSERTIONS: 1
+            os: macos-latest
+          - name: x86_64-apple
+            env:
+              SCRIPT: "./x.py test"
+              RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc"
+              RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+              MACOSX_DEPLOYMENT_TARGET: 10.8
+              MACOSX_STD_DEPLOYMENT_TARGET: 10.7
+              NO_LLVM_ASSERTIONS: 1
+              NO_DEBUG_ASSERTIONS: 1
+            os: macos-latest
+    timeout-minutes: 600
+    runs-on: "${{ matrix.os }}"
+    steps:
+      - name: disable git crlf conversion
+        run: git config --global core.autocrlf false
+        shell: bash
+      - name: checkout the source code
+        uses: actions/checkout@v1
+        with:
+          fetch-depth: 2
+      - name: configure GitHub Actions to kill the build when outdated
+        uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
+        with:
+          github_token: "${{ secrets.github_token }}"
+        if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'"
+      - name: add extra environment variables
+        run: src/ci/scripts/setup-environment.sh
+        env:
+          EXTRA_VARIABLES: "${{ toJson(matrix.env) }}"
+        if: success() && !env.SKIP_JOB
+      - name: decide whether to skip this job
+        run: src/ci/scripts/should-skip-this.sh
+        if: success() && !env.SKIP_JOB
+      - name: collect CPU statistics
+        run: src/ci/scripts/collect-cpu-stats.sh
+        if: success() && !env.SKIP_JOB
+      - name: show the current environment
+        run: src/ci/scripts/dump-environment.sh
+        if: success() && !env.SKIP_JOB
+      - name: install awscli
+        run: src/ci/scripts/install-awscli.sh
+        if: success() && !env.SKIP_JOB
+      - name: install sccache
+        run: src/ci/scripts/install-sccache.sh
+        if: success() && !env.SKIP_JOB
+      - name: install clang
+        run: src/ci/scripts/install-clang.sh
+        if: success() && !env.SKIP_JOB
+      - name: install WIX
+        run: src/ci/scripts/install-wix.sh
+        if: success() && !env.SKIP_JOB
+      - name: install InnoSetup
+        run: src/ci/scripts/install-innosetup.sh
+        if: success() && !env.SKIP_JOB
+      - name: ensure the build happens on a partition with enough space
+        run: src/ci/scripts/symlink-build-dir.sh
+        if: success() && !env.SKIP_JOB
+      - name: disable git crlf conversion
+        run: src/ci/scripts/disable-git-crlf-conversion.sh
+        if: success() && !env.SKIP_JOB
+      - name: install MSYS2
+        run: src/ci/scripts/install-msys2.sh
+        if: success() && !env.SKIP_JOB
+      - name: install MinGW
+        run: src/ci/scripts/install-mingw.sh
+        if: success() && !env.SKIP_JOB
+      - name: install ninja
+        run: src/ci/scripts/install-ninja.sh
+        if: success() && !env.SKIP_JOB
+      - name: enable ipv6 on Docker
+        run: src/ci/scripts/enable-docker-ipv6.sh
+        if: success() && !env.SKIP_JOB
+      - name: disable git crlf conversion
+        run: src/ci/scripts/disable-git-crlf-conversion.sh
+        if: success() && !env.SKIP_JOB
+      - name: checkout submodules
+        run: src/ci/scripts/checkout-submodules.sh
+        if: success() && !env.SKIP_JOB
+      - name: ensure line endings are correct
+        run: src/ci/scripts/verify-line-endings.sh
+        if: success() && !env.SKIP_JOB
+      - name: run the build
+        run: src/ci/scripts/run-build-from-ci.sh
+        env:
+          AWS_ACCESS_KEY_ID: "${{ env.CACHES_AWS_ACCESS_KEY_ID }}"
+          AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }}"
+          TOOLSTATE_REPO_ACCESS_TOKEN: "${{ secrets.TOOLSTATE_REPO_ACCESS_TOKEN }}"
+        if: success() && !env.SKIP_JOB
+      - name: upload artifacts to S3
+        run: src/ci/scripts/upload-artifacts.sh
+        env:
+          AWS_ACCESS_KEY_ID: "${{ env.ARTIFACTS_AWS_ACCESS_KEY_ID }}"
+          AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }}"
+        if: "success() && !env.SKIP_JOB && (github.event_name == 'push' || env.DEPLOY == '1' || env.DEPLOY_ALT == '1')"
   master:
     name: master
     runs-on: ubuntu-latest
diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml
index daa2d55c043..5e67567c76b 100644
--- a/src/ci/github-actions/ci.yml
+++ b/src/ci/github-actions/ci.yml
@@ -414,42 +414,6 @@ jobs:
               DEPLOY_TOOLSTATES_JSON: toolstates-linux.json
             <<: *job-linux-xl
 
-          ####################
-          #  macOS Builders  #
-          ####################
-
-          - name: dist-x86_64-apple
-            env:
-              SCRIPT: ./x.py dist
-              RUST_CONFIGURE_ARGS: --target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc
-              RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
-              MACOSX_DEPLOYMENT_TARGET: 10.7
-              NO_LLVM_ASSERTIONS: 1
-              NO_DEBUG_ASSERTIONS: 1
-              DIST_REQUIRE_ALL_TOOLS: 1
-            <<: *job-macos-xl
-
-          - name: dist-x86_64-apple-alt
-            env:
-              SCRIPT: ./x.py dist
-              RUST_CONFIGURE_ARGS: --enable-extended --enable-profiler --set rust.jemalloc
-              RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
-              MACOSX_DEPLOYMENT_TARGET: 10.7
-              NO_LLVM_ASSERTIONS: 1
-              NO_DEBUG_ASSERTIONS: 1
-            <<: *job-macos-xl
-
-          - name: x86_64-apple
-            env:
-              SCRIPT: ./x.py test
-              RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc
-              RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
-              MACOSX_DEPLOYMENT_TARGET: 10.8
-              MACOSX_STD_DEPLOYMENT_TARGET: 10.7
-              NO_LLVM_ASSERTIONS: 1
-              NO_DEBUG_ASSERTIONS: 1
-            <<: *job-macos-xl
-
           ######################
           #  Windows Builders  #
           ######################
@@ -595,6 +559,51 @@ jobs:
               SCRIPT: python x.py dist
             <<: *job-windows-xl
 
+  auto-fallible:
+    <<: *base-ci-job
+    name: auto-fallible
+    env:
+      <<: [*shared-ci-variables, *prod-variables]
+    if: github.event_name == 'push' && github.ref == 'refs/heads/auto' && github.repository == 'rust-lang-ci/rust'
+    strategy:
+      matrix:
+        include:
+          ####################
+          #  macOS Builders  #
+          ####################
+
+          - name: dist-x86_64-apple
+            env:
+              SCRIPT: ./x.py dist
+              RUST_CONFIGURE_ARGS: --target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc
+              RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+              MACOSX_DEPLOYMENT_TARGET: 10.7
+              NO_LLVM_ASSERTIONS: 1
+              NO_DEBUG_ASSERTIONS: 1
+              DIST_REQUIRE_ALL_TOOLS: 1
+            <<: *job-macos-xl
+
+          - name: dist-x86_64-apple-alt
+            env:
+              SCRIPT: ./x.py dist
+              RUST_CONFIGURE_ARGS: --enable-extended --enable-profiler --set rust.jemalloc
+              RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+              MACOSX_DEPLOYMENT_TARGET: 10.7
+              NO_LLVM_ASSERTIONS: 1
+              NO_DEBUG_ASSERTIONS: 1
+            <<: *job-macos-xl
+
+          - name: x86_64-apple
+            env:
+              SCRIPT: ./x.py test
+              RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc
+              RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+              MACOSX_DEPLOYMENT_TARGET: 10.8
+              MACOSX_STD_DEPLOYMENT_TARGET: 10.7
+              NO_LLVM_ASSERTIONS: 1
+              NO_DEBUG_ASSERTIONS: 1
+            <<: *job-macos-xl
+
   master:
     name: master
     runs-on: ubuntu-latest
diff --git a/src/libcore/result.rs b/src/libcore/result.rs
index 2080ae19366..0c0e6d291bb 100644
--- a/src/libcore/result.rs
+++ b/src/libcore/result.rs
@@ -1155,6 +1155,7 @@ impl<T: Deref, E> Result<T, E> {
     /// # Examples
     ///
     /// ```
+    /// #![feature(inner_deref)]
     /// let x: Result<String, u32> = Ok("hello".to_string());
     /// let y: Result<&str, &u32> = Ok("hello");
     /// assert_eq!(x.as_deref(), y);
@@ -1189,12 +1190,15 @@ impl<T: DerefMut, E> Result<T, E> {
     /// # Examples
     ///
     /// ```
+    /// #![feature(inner_deref)]
+    /// let mut s = "HELLO".to_string();
     /// let mut x: Result<String, u32> = Ok("hello".to_string());
-    /// let y: Result<&mut str, &mut u32> = Ok("HELLO");
+    /// let y: Result<&mut str, &mut u32> = Ok(&mut s);
     /// assert_eq!(x.as_deref_mut().map(|x| { x.make_ascii_uppercase(); x }), y);
     ///
+    /// let mut i = 42;
     /// let mut x: Result<String, u32> = Err(42);
-    /// let y: Result<&mut str, &mut u32> = Err(&42);
+    /// let y: Result<&mut str, &mut u32> = Err(&mut i);
     /// assert_eq!(x.as_deref_mut().map(|x| { x.make_ascii_uppercase(); x }), y);
     /// ```
     pub fn as_deref_mut(&mut self) -> Result<&mut T::Target, &mut E> {
diff --git a/src/libcore/time.rs b/src/libcore/time.rs
index e2ceaf80c0c..3b6dafeee25 100644
--- a/src/libcore/time.rs
+++ b/src/libcore/time.rs
@@ -31,7 +31,7 @@ const MICROS_PER_SEC: u64 = 1_000_000;
 /// the number of nanoseconds.
 ///
 /// `Duration`s implement many common traits, including [`Add`], [`Sub`], and other
-/// [`ops`] traits.
+/// [`ops`] traits. It implements `Default` by returning a zero-length `Duration`.
 ///
 /// [`Add`]: ../../std/ops/trait.Add.html
 /// [`Sub`]: ../../std/ops/trait.Sub.html
@@ -138,6 +138,24 @@ impl Duration {
         Duration { secs, nanos }
     }
 
+    /// Creates a new `Duration` that spans no time.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(duration_zero)]
+    /// use std::time::Duration;
+    ///
+    /// let duration = Duration::zero();
+    /// assert!(duration.is_zero());
+    /// assert_eq!(duration.as_nanos(), 0);
+    /// ```
+    #[unstable(feature = "duration_zero", issue = "73544")]
+    #[inline]
+    pub const fn zero() -> Duration {
+        Duration { secs: 0, nanos: 0 }
+    }
+
     /// Creates a new `Duration` from the specified number of whole seconds.
     ///
     /// # Examples
@@ -223,6 +241,29 @@ impl Duration {
         }
     }
 
+    /// Returns true if this `Duration` spans no time.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(duration_zero)]
+    /// use std::time::Duration;
+    ///
+    /// assert!(Duration::zero().is_zero());
+    /// assert!(Duration::new(0, 0).is_zero());
+    /// assert!(Duration::from_nanos(0).is_zero());
+    /// assert!(Duration::from_secs(0).is_zero());
+    ///
+    /// assert!(!Duration::new(1, 1).is_zero());
+    /// assert!(!Duration::from_nanos(1).is_zero());
+    /// assert!(!Duration::from_secs(1).is_zero());
+    /// ```
+    #[unstable(feature = "duration_zero", issue = "73544")]
+    #[inline]
+    pub const fn is_zero(&self) -> bool {
+        self.secs == 0 && self.nanos == 0
+    }
+
     /// Returns the number of _whole_ seconds contained by this `Duration`.
     ///
     /// The returned value does not include the fractional (nanosecond) part of the
diff --git a/src/librustc_arena/lib.rs b/src/librustc_arena/lib.rs
index 6cf2db3e2da..5cf4f97fb88 100644
--- a/src/librustc_arena/lib.rs
+++ b/src/librustc_arena/lib.rs
@@ -611,7 +611,11 @@ macro_rules! which_arena_for_type {
 
 #[macro_export]
 macro_rules! declare_arena {
-    ([], [$($a:tt $name:ident: $ty:ty, $gen_ty:ty;)*], $tcx:lifetime) => {
+    // This macro has to take the same input as
+    // `impl_arena_allocatable_decoders` which requires a second version of
+    // each type. We ignore that type until we can fix
+    // `impl_arena_allocatable_decoders`.
+    ([], [$($a:tt $name:ident: $ty:ty, $_gen_ty:ty;)*], $tcx:lifetime) => {
         #[derive(Default)]
         pub struct Arena<$tcx> {
             pub dropless: $crate::DroplessArena,
@@ -619,39 +623,56 @@ macro_rules! declare_arena {
             $($name: $crate::arena_for_type!($a[$ty]),)*
         }
 
-        #[marker]
-        pub trait ArenaAllocatable<'tcx> {}
-
-        impl<'tcx, T: Copy> ArenaAllocatable<'tcx> for T {}
-
-        unsafe trait ArenaField<'tcx>: Sized + ArenaAllocatable<'tcx> {
-            /// Returns a specific arena to allocate from.
-            /// If `None` is returned, the `DropArena` will be used.
-            fn arena<'a>(arena: &'a Arena<'tcx>) -> Option<&'a $crate::TypedArena<Self>>;
+        pub trait ArenaAllocatable<'tcx, T = Self>: Sized {
+            fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self;
+            fn allocate_from_iter<'a>(
+                arena: &'a Arena<'tcx>,
+                iter: impl ::std::iter::IntoIterator<Item = Self>,
+            ) -> &'a mut [Self];
         }
 
-        unsafe impl<'tcx, T: ArenaAllocatable<'tcx>> ArenaField<'tcx> for T {
+        impl<'tcx, T: Copy> ArenaAllocatable<'tcx, ()> for T {
             #[inline]
-            default fn arena<'a>(_: &'a Arena<'tcx>) -> Option<&'a $crate::TypedArena<Self>> {
-                panic!()
+            fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self {
+                arena.dropless.alloc(self)
+            }
+            #[inline]
+            fn allocate_from_iter<'a>(
+                arena: &'a Arena<'tcx>,
+                iter: impl ::std::iter::IntoIterator<Item = Self>,
+            ) -> &'a mut [Self] {
+                arena.dropless.alloc_from_iter(iter)
             }
-        }
 
+        }
         $(
-            #[allow(unused_lifetimes)]
-            impl<$tcx> ArenaAllocatable<$tcx> for $ty {}
-            unsafe impl<$tcx, '_x, '_y, '_z, '_w> ArenaField<$tcx> for $gen_ty where Self: ArenaAllocatable<$tcx> {
+            impl<$tcx> ArenaAllocatable<$tcx, $ty> for $ty {
                 #[inline]
-                fn arena<'a>(_arena: &'a Arena<$tcx>) -> Option<&'a $crate::TypedArena<Self>> {
-                    // SAFETY: We only implement `ArenaAllocatable<$tcx>` for
-                    // `$ty`, so `$ty` and Self are the same type
-                    unsafe {
-                        ::std::mem::transmute::<
-                            Option<&'a $crate::TypedArena<$ty>>,
-                            Option<&'a $crate::TypedArena<Self>>,
-                        >(
-                            $crate::which_arena_for_type!($a[&_arena.$name])
-                        )
+                fn allocate_on<'a>(self, arena: &'a Arena<$tcx>) -> &'a mut Self {
+                    if !::std::mem::needs_drop::<Self>() {
+                        return arena.dropless.alloc(self);
+                    }
+                    match $crate::which_arena_for_type!($a[&arena.$name]) {
+                        ::std::option::Option::<&$crate::TypedArena<Self>>::Some(ty_arena) => {
+                            ty_arena.alloc(self)
+                        }
+                        ::std::option::Option::None => unsafe { arena.drop.alloc(self) },
+                    }
+                }
+
+                #[inline]
+                fn allocate_from_iter<'a>(
+                    arena: &'a Arena<$tcx>,
+                    iter: impl ::std::iter::IntoIterator<Item = Self>,
+                ) -> &'a mut [Self] {
+                    if !::std::mem::needs_drop::<Self>() {
+                        return arena.dropless.alloc_from_iter(iter);
+                    }
+                    match $crate::which_arena_for_type!($a[&arena.$name]) {
+                        ::std::option::Option::<&$crate::TypedArena<Self>>::Some(ty_arena) => {
+                            ty_arena.alloc_from_iter(iter)
+                        }
+                        ::std::option::Option::None => unsafe { arena.drop.alloc_from_iter(iter) },
                     }
                 }
             }
@@ -659,14 +680,8 @@ macro_rules! declare_arena {
 
         impl<'tcx> Arena<'tcx> {
             #[inline]
-            pub fn alloc<T: ArenaAllocatable<'tcx>>(&self, value: T) -> &mut T {
-                if !::std::mem::needs_drop::<T>() {
-                    return self.dropless.alloc(value);
-                }
-                match <T as ArenaField<'tcx>>::arena(self) {
-                    ::std::option::Option::Some(arena) => arena.alloc(value),
-                    ::std::option::Option::None => unsafe { self.drop.alloc(value) },
-                }
+            pub fn alloc<T: ArenaAllocatable<'tcx, U>, U>(&self, value: T) -> &mut T {
+                value.allocate_on(self)
             }
 
             #[inline]
@@ -677,17 +692,11 @@ macro_rules! declare_arena {
                 self.dropless.alloc_slice(value)
             }
 
-            pub fn alloc_from_iter<'a, T: ArenaAllocatable<'tcx>>(
+            pub fn alloc_from_iter<'a, T: ArenaAllocatable<'tcx, U>, U>(
                 &'a self,
                 iter: impl ::std::iter::IntoIterator<Item = T>,
             ) -> &'a mut [T] {
-                if !::std::mem::needs_drop::<T>() {
-                    return self.dropless.alloc_from_iter(iter);
-                }
-                match <T as ArenaField<'tcx>>::arena(self) {
-                    ::std::option::Option::Some(arena) => arena.alloc_from_iter(iter),
-                    ::std::option::Option::None => unsafe { self.drop.alloc_from_iter(iter) },
-                }
+                T::allocate_from_iter(self, iter)
             }
         }
     }
diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs
index a722a88a7a1..335cc3e6104 100644
--- a/src/librustc_ast_lowering/lib.rs
+++ b/src/librustc_ast_lowering/lib.rs
@@ -32,8 +32,6 @@
 
 #![feature(array_value_iter)]
 #![feature(crate_visibility_modifier)]
-#![feature(marker_trait_attr)]
-#![feature(min_specialization)]
 #![feature(or_patterns)]
 #![recursion_limit = "256"]
 
@@ -205,6 +203,8 @@ pub trait Resolver {
     fn lint_buffer(&mut self) -> &mut LintBuffer;
 
     fn next_node_id(&mut self) -> NodeId;
+
+    fn trait_map(&self) -> &NodeMap<Vec<hir::TraitCandidate>>;
 }
 
 type NtToTokenstream = fn(&Nonterminal, &ParseSess, Span) -> TokenStream;
@@ -557,6 +557,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         let proc_macros =
             c.proc_macros.iter().map(|id| self.node_id_to_hir_id[*id].unwrap()).collect();
 
+        let trait_map = self
+            .resolver
+            .trait_map()
+            .iter()
+            .map(|(&k, v)| (self.node_id_to_hir_id[k].unwrap(), v.clone()))
+            .collect();
+
         self.resolver.definitions().init_node_id_to_hir_id_mapping(self.node_id_to_hir_id);
 
         hir::Crate {
@@ -571,6 +578,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             trait_impls: self.trait_impls,
             modules: self.modules,
             proc_macros,
+            trait_map,
         }
     }
 
diff --git a/src/librustc_builtin_macros/asm.rs b/src/librustc_builtin_macros/asm.rs
index 29885679604..52f86aa7e06 100644
--- a/src/librustc_builtin_macros/asm.rs
+++ b/src/librustc_builtin_macros/asm.rs
@@ -16,7 +16,7 @@ struct AsmArgs {
     named_args: FxHashMap<Symbol, usize>,
     reg_args: FxHashSet<usize>,
     options: ast::InlineAsmOptions,
-    options_span: Option<Span>,
+    options_spans: Vec<Span>,
 }
 
 fn parse_args<'a>(
@@ -59,7 +59,7 @@ fn parse_args<'a>(
         named_args: FxHashMap::default(),
         reg_args: FxHashSet::default(),
         options: ast::InlineAsmOptions::empty(),
-        options_span: None,
+        options_spans: vec![],
     };
 
     let mut allow_templates = true;
@@ -174,9 +174,9 @@ fn parse_args<'a>(
 
         // Validate the order of named, positional & explicit register operands and options. We do
         // this at the end once we have the full span of the argument available.
-        if let Some(options_span) = args.options_span {
+        if !args.options_spans.is_empty() {
             ecx.struct_span_err(span, "arguments are not allowed after options")
-                .span_label(options_span, "previous options")
+                .span_labels(args.options_spans.clone(), "previous options")
                 .span_label(span, "argument")
                 .emit();
         }
@@ -227,23 +227,23 @@ fn parse_args<'a>(
     if args.options.contains(ast::InlineAsmOptions::NOMEM)
         && args.options.contains(ast::InlineAsmOptions::READONLY)
     {
-        let span = args.options_span.unwrap();
-        ecx.struct_span_err(span, "the `nomem` and `readonly` options are mutually exclusive")
+        let spans = args.options_spans.clone();
+        ecx.struct_span_err(spans, "the `nomem` and `readonly` options are mutually exclusive")
             .emit();
     }
     if args.options.contains(ast::InlineAsmOptions::PURE)
         && args.options.contains(ast::InlineAsmOptions::NORETURN)
     {
-        let span = args.options_span.unwrap();
-        ecx.struct_span_err(span, "the `pure` and `noreturn` options are mutually exclusive")
+        let spans = args.options_spans.clone();
+        ecx.struct_span_err(spans, "the `pure` and `noreturn` options are mutually exclusive")
             .emit();
     }
     if args.options.contains(ast::InlineAsmOptions::PURE)
         && !args.options.intersects(ast::InlineAsmOptions::NOMEM | ast::InlineAsmOptions::READONLY)
     {
-        let span = args.options_span.unwrap();
+        let spans = args.options_spans.clone();
         ecx.struct_span_err(
-            span,
+            spans,
             "the `pure` option must be combined with either `nomem` or `readonly`",
         )
         .emit();
@@ -267,7 +267,7 @@ fn parse_args<'a>(
     }
     if args.options.contains(ast::InlineAsmOptions::PURE) && !have_real_output {
         ecx.struct_span_err(
-            args.options_span.unwrap(),
+            args.options_spans.clone(),
             "asm with `pure` option must have at least one output",
         )
         .emit();
@@ -283,6 +283,50 @@ fn parse_args<'a>(
     Ok(args)
 }
 
+/// Report a duplicate option error.
+///
+/// This function must be called immediately after the option token is parsed.
+/// Otherwise, the suggestion will be incorrect.
+fn err_duplicate_option<'a>(p: &mut Parser<'a>, symbol: Symbol, span: Span) {
+    let mut err = p
+        .sess
+        .span_diagnostic
+        .struct_span_err(span, &format!("the `{}` option was already provided", symbol));
+    err.span_label(span, "this option was already provided");
+
+    // Tool-only output
+    let mut full_span = span;
+    if p.token.kind == token::Comma {
+        full_span = full_span.to(p.token.span);
+    }
+    err.tool_only_span_suggestion(
+        full_span,
+        "remove this option",
+        String::new(),
+        Applicability::MachineApplicable,
+    );
+
+    err.emit();
+}
+
+/// Try to set the provided option in the provided `AsmArgs`.
+/// If it is already set, report a duplicate option error.
+///
+/// This function must be called immediately after the option token is parsed.
+/// Otherwise, the error will not point to the correct spot.
+fn try_set_option<'a>(
+    p: &mut Parser<'a>,
+    args: &mut AsmArgs,
+    symbol: Symbol,
+    option: ast::InlineAsmOptions,
+) {
+    if !args.options.contains(option) {
+        args.options |= option;
+    } else {
+        err_duplicate_option(p, symbol, p.prev_token.span);
+    }
+}
+
 fn parse_options<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> Result<(), DiagnosticBuilder<'a>> {
     let span_start = p.prev_token.span;
 
@@ -290,20 +334,20 @@ fn parse_options<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> Result<(), Diagn
 
     while !p.eat(&token::CloseDelim(token::DelimToken::Paren)) {
         if p.eat(&token::Ident(sym::pure, false)) {
-            args.options |= ast::InlineAsmOptions::PURE;
+            try_set_option(p, args, sym::pure, ast::InlineAsmOptions::PURE);
         } else if p.eat(&token::Ident(sym::nomem, false)) {
-            args.options |= ast::InlineAsmOptions::NOMEM;
+            try_set_option(p, args, sym::nomem, ast::InlineAsmOptions::NOMEM);
         } else if p.eat(&token::Ident(sym::readonly, false)) {
-            args.options |= ast::InlineAsmOptions::READONLY;
+            try_set_option(p, args, sym::readonly, ast::InlineAsmOptions::READONLY);
         } else if p.eat(&token::Ident(sym::preserves_flags, false)) {
-            args.options |= ast::InlineAsmOptions::PRESERVES_FLAGS;
+            try_set_option(p, args, sym::preserves_flags, ast::InlineAsmOptions::PRESERVES_FLAGS);
         } else if p.eat(&token::Ident(sym::noreturn, false)) {
-            args.options |= ast::InlineAsmOptions::NORETURN;
+            try_set_option(p, args, sym::noreturn, ast::InlineAsmOptions::NORETURN);
         } else if p.eat(&token::Ident(sym::nostack, false)) {
-            args.options |= ast::InlineAsmOptions::NOSTACK;
+            try_set_option(p, args, sym::nostack, ast::InlineAsmOptions::NOSTACK);
         } else {
             p.expect(&token::Ident(sym::att_syntax, false))?;
-            args.options |= ast::InlineAsmOptions::ATT_SYNTAX;
+            try_set_option(p, args, sym::att_syntax, ast::InlineAsmOptions::ATT_SYNTAX);
         }
 
         // Allow trailing commas
@@ -314,14 +358,7 @@ fn parse_options<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> Result<(), Diagn
     }
 
     let new_span = span_start.to(p.prev_token.span);
-    if let Some(options_span) = args.options_span {
-        p.struct_span_err(new_span, "asm options cannot be specified multiple times")
-            .span_label(options_span, "previously here")
-            .span_label(new_span, "duplicate options")
-            .emit();
-    } else {
-        args.options_span = Some(new_span);
-    }
+    args.options_spans.push(new_span);
 
     Ok(())
 }
diff --git a/src/librustc_hir/definitions.rs b/src/librustc_hir/definitions.rs
index b63dd653c4d..5755a3db92a 100644
--- a/src/librustc_hir/definitions.rs
+++ b/src/librustc_hir/definitions.rs
@@ -81,14 +81,13 @@ pub struct Definitions {
 
     def_id_to_span: IndexVec<LocalDefId, Span>,
 
-    // FIXME(eddyb) don't go through `ast::NodeId` to convert between `HirId`
-    // and `LocalDefId` - ideally all `LocalDefId`s would be HIR owners.
     node_id_to_def_id: FxHashMap<ast::NodeId, LocalDefId>,
     def_id_to_node_id: IndexVec<LocalDefId, ast::NodeId>,
 
-    pub(super) node_id_to_hir_id: IndexVec<ast::NodeId, Option<hir::HirId>>,
-    /// The reverse mapping of `node_id_to_hir_id`.
-    pub(super) hir_id_to_node_id: FxHashMap<hir::HirId, ast::NodeId>,
+    // FIXME(eddyb) ideally all `LocalDefId`s would be HIR owners.
+    pub(super) def_id_to_hir_id: IndexVec<LocalDefId, Option<hir::HirId>>,
+    /// The reverse mapping of `def_id_to_hir_id`.
+    pub(super) hir_id_to_def_id: FxHashMap<hir::HirId, LocalDefId>,
 
     /// If `ExpnId` is an ID of some macro expansion,
     /// then `DefId` is the normal module (`mod`) in which the expanded macro was defined.
@@ -327,9 +326,7 @@ impl Definitions {
 
     #[inline]
     pub fn local_def_id(&self, node: ast::NodeId) -> LocalDefId {
-        self.opt_local_def_id(node).unwrap_or_else(|| {
-            panic!("no entry for node id: `{:?}` / `{:?}`", node, self.opt_node_id_to_hir_id(node))
-        })
+        self.opt_local_def_id(node).unwrap_or_else(|| panic!("no entry for node id: `{:?}`", node))
     }
 
     #[inline]
@@ -338,36 +335,18 @@ impl Definitions {
     }
 
     #[inline]
-    pub fn hir_id_to_node_id(&self, hir_id: hir::HirId) -> ast::NodeId {
-        self.hir_id_to_node_id[&hir_id]
-    }
-
-    #[inline]
-    pub fn node_id_to_hir_id(&self, node_id: ast::NodeId) -> hir::HirId {
-        self.node_id_to_hir_id[node_id].unwrap()
-    }
-
-    #[inline]
-    pub fn opt_node_id_to_hir_id(&self, node_id: ast::NodeId) -> Option<hir::HirId> {
-        self.node_id_to_hir_id[node_id]
-    }
-
-    #[inline]
     pub fn local_def_id_to_hir_id(&self, id: LocalDefId) -> hir::HirId {
-        let node_id = self.def_id_to_node_id[id];
-        self.node_id_to_hir_id[node_id].unwrap()
+        self.def_id_to_hir_id[id].unwrap()
     }
 
     #[inline]
     pub fn opt_local_def_id_to_hir_id(&self, id: LocalDefId) -> Option<hir::HirId> {
-        let node_id = self.def_id_to_node_id[id];
-        self.node_id_to_hir_id[node_id]
+        self.def_id_to_hir_id[id]
     }
 
     #[inline]
     pub fn opt_hir_id_to_local_def_id(&self, hir_id: hir::HirId) -> Option<LocalDefId> {
-        let node_id = self.hir_id_to_node_id(hir_id);
-        self.opt_local_def_id(node_id)
+        self.hir_id_to_def_id.get(&hir_id).copied()
     }
 
     /// Retrieves the span of the given `DefId` if `DefId` is in the local crate.
@@ -477,16 +456,24 @@ impl Definitions {
         mapping: IndexVec<ast::NodeId, Option<hir::HirId>>,
     ) {
         assert!(
-            self.node_id_to_hir_id.is_empty(),
-            "trying to initialize `NodeId` -> `HirId` mapping twice"
+            self.def_id_to_hir_id.is_empty(),
+            "trying to initialize `LocalDefId` <-> `HirId` mappings twice"
         );
-        self.node_id_to_hir_id = mapping;
 
-        // Build the reverse mapping of `node_id_to_hir_id`.
-        self.hir_id_to_node_id = self
-            .node_id_to_hir_id
-            .iter_enumerated()
-            .filter_map(|(node_id, &hir_id)| hir_id.map(|hir_id| (hir_id, node_id)))
+        self.def_id_to_hir_id = self
+            .def_id_to_node_id
+            .iter()
+            .map(|&node_id| mapping.get(node_id).and_then(|&hir_id| hir_id))
+            .collect();
+
+        // Build the reverse mapping of `def_id_to_hir_id`.
+        self.hir_id_to_def_id = mapping
+            .into_iter_enumerated()
+            .filter_map(|(node_id, hir_id)| {
+                hir_id.and_then(|hir_id| {
+                    self.node_id_to_def_id.get(&node_id).map(|&def_id| (hir_id, def_id))
+                })
+            })
             .collect();
     }
 
diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs
index eb1db46fd2b..7d1cb7738c3 100644
--- a/src/librustc_hir/hir.rs
+++ b/src/librustc_hir/hir.rs
@@ -639,6 +639,8 @@ pub struct Crate<'hir> {
     /// A list of proc macro HirIds, written out in the order in which
     /// they are declared in the static array generated by proc_macro_harness.
     pub proc_macros: Vec<HirId>,
+
+    pub trait_map: BTreeMap<HirId, Vec<TraitCandidate>>,
 }
 
 impl Crate<'hir> {
@@ -2651,7 +2653,7 @@ pub type CaptureModeMap = NodeMap<CaptureBy>;
 // The TraitCandidate's import_ids is empty if the trait is defined in the same module, and
 // has length > 0 if the trait is found through an chain of imports, starting with the
 // import/use statement in the scope where the trait is used.
-#[derive(Clone, Debug)]
+#[derive(RustcEncodable, RustcDecodable, Clone, Debug)]
 pub struct TraitCandidate {
     pub def_id: DefId,
     pub import_ids: SmallVec<[LocalDefId; 1]>,
diff --git a/src/librustc_infer/infer/outlives/verify.rs b/src/librustc_infer/infer/outlives/verify.rs
index 82d32b00808..383979f8640 100644
--- a/src/librustc_infer/infer/outlives/verify.rs
+++ b/src/librustc_infer/infer/outlives/verify.rs
@@ -1,9 +1,8 @@
 use crate::infer::outlives::env::RegionBoundPairs;
 use crate::infer::{GenericKind, VerifyBound};
-use crate::traits;
 use rustc_data_structures::captures::Captures;
 use rustc_hir::def_id::DefId;
-use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst};
+use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 
 /// The `TypeOutlives` struct has the job of "lowering" a `T: 'a`
@@ -311,18 +310,14 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
     fn region_bounds_declared_on_associated_item(
         &self,
         assoc_item_def_id: DefId,
-    ) -> impl Iterator<Item = ty::Region<'tcx>> + 'cx + Captures<'tcx> {
+    ) -> impl Iterator<Item = ty::Region<'tcx>> {
         let tcx = self.tcx;
-        let assoc_item = tcx.associated_item(assoc_item_def_id);
-        let trait_def_id = assoc_item.container.assert_trait();
-        let trait_predicates = tcx.predicates_of(trait_def_id).predicates.iter().map(|(p, _)| *p);
-        let identity_substs = InternalSubsts::identity_for_item(tcx, assoc_item_def_id);
-        let identity_proj = tcx.mk_projection(assoc_item_def_id, identity_substs);
-        self.collect_outlives_from_predicate_list(
-            move |ty| ty == identity_proj,
-            traits::elaborate_predicates(tcx, trait_predicates).map(|o| o.predicate),
-        )
-        .map(|b| b.1)
+        let predicates = tcx.projection_predicates(assoc_item_def_id);
+        predicates
+            .into_iter()
+            .filter_map(|p| p.to_opt_type_outlives())
+            .filter_map(|p| p.no_bound_vars())
+            .map(|b| b.1)
     }
 
     /// Searches through a predicate list for a predicate `T: 'a`.
diff --git a/src/librustc_infer/traits/mod.rs b/src/librustc_infer/traits/mod.rs
index 47555aca9f3..8cd1eb9957b 100644
--- a/src/librustc_infer/traits/mod.rs
+++ b/src/librustc_infer/traits/mod.rs
@@ -25,8 +25,6 @@ pub use self::project::{
     Normalized, NormalizedTy, ProjectionCache, ProjectionCacheEntry, ProjectionCacheKey,
     ProjectionCacheStorage, Reveal,
 };
-crate use self::util::elaborate_predicates;
-
 pub use rustc_middle::traits::*;
 
 /// An `Obligation` represents some trait reference (e.g., `i32: Eq`) for
diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index d92c1131ff9..a19c9a35579 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -895,22 +895,33 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
     }
 
     fn check_for_opaque_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool {
-        struct ProhibitOpaqueTypes<'tcx> {
+        struct ProhibitOpaqueTypes<'a, 'tcx> {
+            cx: &'a LateContext<'a, 'tcx>,
             ty: Option<Ty<'tcx>>,
         };
 
-        impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueTypes<'tcx> {
+        impl<'a, 'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueTypes<'a, 'tcx> {
             fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
-                if let ty::Opaque(..) = ty.kind {
-                    self.ty = Some(ty);
-                    true
-                } else {
-                    ty.super_visit_with(self)
+                match ty.kind {
+                    ty::Opaque(..) => {
+                        self.ty = Some(ty);
+                        true
+                    }
+                    // Consider opaque types within projections FFI-safe if they do not normalize
+                    // to more opaque types.
+                    ty::Projection(..) => {
+                        let ty = self.cx.tcx.normalize_erasing_regions(self.cx.param_env, ty);
+
+                        // If `ty` is a opaque type directly then `super_visit_with` won't invoke
+                        // this function again.
+                        if ty.has_opaque_types() { self.visit_ty(ty) } else { false }
+                    }
+                    _ => ty.super_visit_with(self),
                 }
             }
         }
 
-        let mut visitor = ProhibitOpaqueTypes { ty: None };
+        let mut visitor = ProhibitOpaqueTypes { cx: self.cx, ty: None };
         ty.visit_with(&mut visitor);
         if let Some(ty) = visitor.ty {
             self.emit_ffi_unsafe_type_lint(ty, sp, "opaque types have no C equivalent", None);
diff --git a/src/librustc_middle/hir/map/collector.rs b/src/librustc_middle/hir/map/collector.rs
index 2906da437ab..dce06a5f7ee 100644
--- a/src/librustc_middle/hir/map/collector.rs
+++ b/src/librustc_middle/hir/map/collector.rs
@@ -117,6 +117,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
                 body_ids: _,
                 modules: _,
                 proc_macros: _,
+                trait_map: _,
             } = *krate;
 
             hash_body(&mut hcx, root_mod_def_path_hash, item, &mut hir_body_nodes)
@@ -241,11 +242,8 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
         // Make sure that the DepNode of some node coincides with the HirId
         // owner of that node.
         if cfg!(debug_assertions) {
-            let node_id = self.definitions.hir_id_to_node_id(hir_id);
-            assert_eq!(self.definitions.node_id_to_hir_id(node_id), hir_id);
-
             if hir_id.owner != self.current_dep_node_owner {
-                let node_str = match self.definitions.opt_local_def_id(node_id) {
+                let node_str = match self.definitions.opt_hir_id_to_local_def_id(hir_id) {
                     Some(def_id) => self.definitions.def_path(def_id).to_string_no_crate(),
                     None => format!("{:?}", node),
                 };
@@ -335,9 +333,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
         debug!("visit_item: {:?}", i);
         debug_assert_eq!(
             i.hir_id.owner,
-            self.definitions
-                .opt_local_def_id(self.definitions.hir_id_to_node_id(i.hir_id))
-                .unwrap()
+            self.definitions.opt_hir_id_to_local_def_id(i.hir_id).unwrap()
         );
         self.with_dep_node_owner(i.hir_id.owner, i, |this, hash| {
             this.insert_with_hash(i.span, i.hir_id, Node::Item(i), hash);
@@ -369,9 +365,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
     fn visit_trait_item(&mut self, ti: &'hir TraitItem<'hir>) {
         debug_assert_eq!(
             ti.hir_id.owner,
-            self.definitions
-                .opt_local_def_id(self.definitions.hir_id_to_node_id(ti.hir_id))
-                .unwrap()
+            self.definitions.opt_hir_id_to_local_def_id(ti.hir_id).unwrap()
         );
         self.with_dep_node_owner(ti.hir_id.owner, ti, |this, hash| {
             this.insert_with_hash(ti.span, ti.hir_id, Node::TraitItem(ti), hash);
@@ -385,9 +379,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
     fn visit_impl_item(&mut self, ii: &'hir ImplItem<'hir>) {
         debug_assert_eq!(
             ii.hir_id.owner,
-            self.definitions
-                .opt_local_def_id(self.definitions.hir_id_to_node_id(ii.hir_id))
-                .unwrap()
+            self.definitions.opt_hir_id_to_local_def_id(ii.hir_id).unwrap()
         );
         self.with_dep_node_owner(ii.hir_id.owner, ii, |this, hash| {
             this.insert_with_hash(ii.span, ii.hir_id, Node::ImplItem(ii), hash);
diff --git a/src/librustc_middle/lib.rs b/src/librustc_middle/lib.rs
index 8025246f3d6..82dff60a26d 100644
--- a/src/librustc_middle/lib.rs
+++ b/src/librustc_middle/lib.rs
@@ -36,7 +36,6 @@
 #![feature(drain_filter)]
 #![feature(never_type)]
 #![feature(exhaustive_patterns)]
-#![feature(marker_trait_attr)]
 #![feature(extern_types)]
 #![feature(nll)]
 #![feature(option_expect_none)]
diff --git a/src/librustc_middle/query/mod.rs b/src/librustc_middle/query/mod.rs
index b3751beede2..ca51d5b949c 100644
--- a/src/librustc_middle/query/mod.rs
+++ b/src/librustc_middle/query/mod.rs
@@ -133,6 +133,23 @@ rustc_queries! {
             cache_on_disk_if { key.is_local() }
         }
 
+        /// Returns the list of predicates that can be used for
+        /// `SelectionCandidate::ProjectionCandidate` and
+        /// `ProjectionTyCandidate::TraitDef`.
+        /// Specifically this is the bounds (equivalent to) those
+        /// written on the trait's type definition, or those
+        /// after the `impl` keyword
+        ///
+        /// type X: Bound + 'lt
+        ///         ^^^^^^^^^^^
+        /// impl Debug + Display
+        ///      ^^^^^^^^^^^^^^^
+        ///
+        /// `key` is the `DefId` of the associated type or opaque type.
+        query projection_predicates(key: DefId) -> &'tcx ty::List<ty::Predicate<'tcx>> {
+            desc { |tcx| "finding projection predicates for `{}`", tcx.def_path_str(key) }
+        }
+
         query native_libraries(_: CrateNum) -> Lrc<Vec<NativeLib>> {
             desc { "looking up the native libraries of a linked crate" }
         }
diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs
index 6380f8be98d..5b44ffe8caf 100644
--- a/src/librustc_middle/ty/context.rs
+++ b/src/librustc_middle/ty/context.rs
@@ -1101,9 +1101,9 @@ impl<'tcx> TyCtxt<'tcx> {
         };
 
         let mut trait_map: FxHashMap<_, FxHashMap<_, _>> = FxHashMap::default();
-        for (hir_id, v) in resolutions.trait_map.into_iter() {
+        for (hir_id, v) in krate.trait_map.iter() {
             let map = trait_map.entry(hir_id.owner).or_default();
-            map.insert(hir_id.local_id, StableVec::new(v));
+            map.insert(hir_id.local_id, StableVec::new(v.to_vec()));
         }
 
         GlobalCtxt {
diff --git a/src/librustc_middle/ty/flags.rs b/src/librustc_middle/ty/flags.rs
index bee42be8a53..d13be4f4285 100644
--- a/src/librustc_middle/ty/flags.rs
+++ b/src/librustc_middle/ty/flags.rs
@@ -93,7 +93,6 @@ impl FlagComputation {
 
             &ty::Bound(debruijn, _) => {
                 self.add_binder(debruijn);
-                self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
             }
 
             &ty::Placeholder(..) => {
@@ -216,7 +215,6 @@ impl FlagComputation {
             }
             ty::ConstKind::Bound(debruijn, _) => {
                 self.add_binder(debruijn);
-                self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
             }
             ty::ConstKind::Param(_) => {
                 self.add_flags(TypeFlags::HAS_CT_PARAM);
diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs
index ca0a1ac71c6..56fb3b58d3f 100644
--- a/src/librustc_middle/ty/mod.rs
+++ b/src/librustc_middle/ty/mod.rs
@@ -121,7 +121,6 @@ pub struct ResolverOutputs {
     pub definitions: rustc_hir::definitions::Definitions,
     pub cstore: Box<CrateStoreDyn>,
     pub extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
-    pub trait_map: FxHashMap<hir::HirId, Vec<hir::TraitCandidate>>,
     pub maybe_unused_trait_imports: FxHashSet<LocalDefId>,
     pub maybe_unused_extern_crates: Vec<(LocalDefId, Span)>,
     pub export_map: ExportMap<LocalDefId>,
diff --git a/src/librustc_middle/ty/sty.rs b/src/librustc_middle/ty/sty.rs
index b0addcb2bb6..1d680c35636 100644
--- a/src/librustc_middle/ty/sty.rs
+++ b/src/librustc_middle/ty/sty.rs
@@ -1589,19 +1589,16 @@ impl RegionKind {
                 flags = flags | TypeFlags::HAS_FREE_REGIONS;
                 flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS;
                 flags = flags | TypeFlags::HAS_RE_INFER;
-                flags = flags | TypeFlags::STILL_FURTHER_SPECIALIZABLE;
             }
             ty::RePlaceholder(..) => {
                 flags = flags | TypeFlags::HAS_FREE_REGIONS;
                 flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS;
                 flags = flags | TypeFlags::HAS_RE_PLACEHOLDER;
-                flags = flags | TypeFlags::STILL_FURTHER_SPECIALIZABLE;
             }
             ty::ReEarlyBound(..) => {
                 flags = flags | TypeFlags::HAS_FREE_REGIONS;
                 flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS;
                 flags = flags | TypeFlags::HAS_RE_PARAM;
-                flags = flags | TypeFlags::STILL_FURTHER_SPECIALIZABLE;
             }
             ty::ReFree { .. } => {
                 flags = flags | TypeFlags::HAS_FREE_REGIONS;
diff --git a/src/librustc_middle/ty/subst.rs b/src/librustc_middle/ty/subst.rs
index 3b4254a18ea..fd31adae499 100644
--- a/src/librustc_middle/ty/subst.rs
+++ b/src/librustc_middle/ty/subst.rs
@@ -333,6 +333,17 @@ impl<'a, 'tcx> InternalSubsts<'tcx> {
     /// in a different item, with `target_substs` as the base for
     /// the target impl/trait, with the source child-specific
     /// parameters (e.g., method parameters) on top of that base.
+    ///
+    /// For example given:
+    ///
+    /// trait X<S> { fn f<T>(); }
+    /// impl<U> X<U> for U { fn f<V>() {} }
+    ///
+    /// * If `self` is `[Self, S, T]`: the identity substs of `f` in the trait.
+    /// * If `source_ancestor` is the def_id of the trait.
+    /// * If `target_substs` is `[U]`, the substs for the impl.
+    /// * Then we will return `[U, T]`, the subst for `f` in the impl that
+    ///   are needed for it to match the trait.
     pub fn rebase_onto(
         &self,
         tcx: TyCtxt<'tcx>,
diff --git a/src/librustc_resolve/late/lifetimes.rs b/src/librustc_resolve/late/lifetimes.rs
index 5bbf8703f0b..903eee672cf 100644
--- a/src/librustc_resolve/late/lifetimes.rs
+++ b/src/librustc_resolve/late/lifetimes.rs
@@ -883,7 +883,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                         })
                         .collect();
                     if !lifetimes.is_empty() {
-                        self.trait_ref_hack = true;
                         let next_early_index = self.next_early_index();
                         let scope = Scope::Binder {
                             lifetimes,
@@ -895,9 +894,10 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                         let result = self.with(scope, |old_scope, this| {
                             this.check_lifetime_params(old_scope, &bound_generic_params);
                             this.visit_ty(&bounded_ty);
+                            this.trait_ref_hack = true;
                             walk_list!(this, visit_param_bound, bounds);
+                            this.trait_ref_hack = false;
                         });
-                        self.trait_ref_hack = false;
                         result
                     } else {
                         self.visit_ty(&bounded_ty);
@@ -932,13 +932,15 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
         debug!("visit_poly_trait_ref(trait_ref={:?})", trait_ref);
 
         let should_pop_missing_lt = self.is_trait_ref_fn_scope(trait_ref);
-        if !self.trait_ref_hack
+
+        let trait_ref_hack = take(&mut self.trait_ref_hack);
+        if !trait_ref_hack
             || trait_ref.bound_generic_params.iter().any(|param| match param.kind {
                 GenericParamKind::Lifetime { .. } => true,
                 _ => false,
             })
         {
-            if self.trait_ref_hack {
+            if trait_ref_hack {
                 struct_span_err!(
                     self.tcx.sess,
                     trait_ref.span,
@@ -968,10 +970,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                 this.check_lifetime_params(old_scope, &trait_ref.bound_generic_params);
                 walk_list!(this, visit_generic_param, trait_ref.bound_generic_params);
                 this.visit_trait_ref(&trait_ref.trait_ref);
-            })
+            });
         } else {
             self.visit_trait_ref(&trait_ref.trait_ref);
         }
+        self.trait_ref_hack = trait_ref_hack;
         if should_pop_missing_lt {
             self.missing_named_lifetime_spots.pop();
         }
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 66e5612b627..91bd1556141 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -1109,6 +1109,10 @@ impl rustc_ast_lowering::Resolver for Resolver<'_> {
     fn next_node_id(&mut self) -> NodeId {
         self.next_node_id()
     }
+
+    fn trait_map(&self) -> &NodeMap<Vec<TraitCandidate>> {
+        &self.trait_map
+    }
 }
 
 impl<'a> Resolver<'a> {
@@ -1284,11 +1288,6 @@ impl<'a> Resolver<'a> {
         let definitions = self.definitions;
         let extern_crate_map = self.extern_crate_map;
         let export_map = self.export_map;
-        let trait_map = self
-            .trait_map
-            .into_iter()
-            .map(|(k, v)| (definitions.node_id_to_hir_id(k), v))
-            .collect();
         let maybe_unused_trait_imports = self.maybe_unused_trait_imports;
         let maybe_unused_extern_crates = self.maybe_unused_extern_crates;
         let glob_map = self.glob_map;
@@ -1297,7 +1296,6 @@ impl<'a> Resolver<'a> {
             cstore: Box::new(self.crate_loader.into_cstore()),
             extern_crate_map,
             export_map,
-            trait_map,
             glob_map,
             maybe_unused_trait_imports,
             maybe_unused_extern_crates,
@@ -1315,11 +1313,6 @@ impl<'a> Resolver<'a> {
             cstore: Box::new(self.cstore().clone()),
             extern_crate_map: self.extern_crate_map.clone(),
             export_map: self.export_map.clone(),
-            trait_map: self
-                .trait_map
-                .iter()
-                .map(|(&k, v)| (self.definitions.node_id_to_hir_id(k), v.clone()))
-                .collect(),
             glob_map: self.glob_map.clone(),
             maybe_unused_trait_imports: self.maybe_unused_trait_imports.clone(),
             maybe_unused_extern_crates: self.maybe_unused_extern_crates.clone(),
diff --git a/src/librustc_trait_selection/autoderef.rs b/src/librustc_trait_selection/autoderef.rs
new file mode 100644
index 00000000000..d542e16d83f
--- /dev/null
+++ b/src/librustc_trait_selection/autoderef.rs
@@ -0,0 +1,229 @@
+use crate::traits::query::evaluate_obligation::InferCtxtExt;
+use crate::traits::{self, TraitEngine};
+use rustc_errors::struct_span_err;
+use rustc_hir as hir;
+use rustc_infer::infer::InferCtxt;
+use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt, WithConstness};
+use rustc_middle::ty::{ToPredicate, TypeFoldable};
+use rustc_session::DiagnosticMessageId;
+use rustc_span::symbol::Ident;
+use rustc_span::Span;
+
+#[derive(Copy, Clone, Debug)]
+pub enum AutoderefKind {
+    Builtin,
+    Overloaded,
+}
+
+struct AutoderefSnapshot<'tcx> {
+    at_start: bool,
+    reached_recursion_limit: bool,
+    steps: Vec<(Ty<'tcx>, AutoderefKind)>,
+    cur_ty: Ty<'tcx>,
+    obligations: Vec<traits::PredicateObligation<'tcx>>,
+}
+
+pub struct Autoderef<'a, 'tcx> {
+    // Meta infos:
+    infcx: &'a InferCtxt<'a, 'tcx>,
+    span: Span,
+    body_id: hir::HirId,
+    param_env: ty::ParamEnv<'tcx>,
+
+    // Current state:
+    state: AutoderefSnapshot<'tcx>,
+
+    // Configurations:
+    include_raw_pointers: bool,
+    silence_errors: bool,
+}
+
+impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> {
+    type Item = (Ty<'tcx>, usize);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        let tcx = self.infcx.tcx;
+
+        debug!("autoderef: steps={:?}, cur_ty={:?}", self.state.steps, self.state.cur_ty);
+        if self.state.at_start {
+            self.state.at_start = false;
+            debug!("autoderef stage #0 is {:?}", self.state.cur_ty);
+            return Some((self.state.cur_ty, 0));
+        }
+
+        // If we have reached the recursion limit, error gracefully.
+        if !tcx.sess.recursion_limit().value_within_limit(self.state.steps.len()) {
+            if !self.silence_errors {
+                report_autoderef_recursion_limit_error(tcx, self.span, self.state.cur_ty);
+            }
+            self.state.reached_recursion_limit = true;
+            return None;
+        }
+
+        if self.state.cur_ty.is_ty_var() {
+            return None;
+        }
+
+        // Otherwise, deref if type is derefable:
+        let (kind, new_ty) =
+            if let Some(mt) = self.state.cur_ty.builtin_deref(self.include_raw_pointers) {
+                (AutoderefKind::Builtin, mt.ty)
+            } else if let Some(ty) = self.overloaded_deref_ty(self.state.cur_ty) {
+                (AutoderefKind::Overloaded, ty)
+            } else {
+                return None;
+            };
+
+        if new_ty.references_error() {
+            return None;
+        }
+
+        self.state.steps.push((self.state.cur_ty, kind));
+        debug!(
+            "autoderef stage #{:?} is {:?} from {:?}",
+            self.step_count(),
+            new_ty,
+            (self.state.cur_ty, kind)
+        );
+        self.state.cur_ty = new_ty;
+
+        Some((self.state.cur_ty, self.step_count()))
+    }
+}
+
+impl<'a, 'tcx> Autoderef<'a, 'tcx> {
+    pub fn new(
+        infcx: &'a InferCtxt<'a, 'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+        body_id: hir::HirId,
+        span: Span,
+        base_ty: Ty<'tcx>,
+    ) -> Autoderef<'a, 'tcx> {
+        Autoderef {
+            infcx,
+            span,
+            body_id,
+            param_env,
+            state: AutoderefSnapshot {
+                steps: vec![],
+                cur_ty: infcx.resolve_vars_if_possible(&base_ty),
+                obligations: vec![],
+                at_start: true,
+                reached_recursion_limit: false,
+            },
+            include_raw_pointers: false,
+            silence_errors: false,
+        }
+    }
+
+    fn overloaded_deref_ty(&mut self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
+        debug!("overloaded_deref_ty({:?})", ty);
+
+        let tcx = self.infcx.tcx;
+
+        // <ty as Deref>
+        let trait_ref = TraitRef {
+            def_id: tcx.lang_items().deref_trait()?,
+            substs: tcx.mk_substs_trait(ty, &[]),
+        };
+
+        let cause = traits::ObligationCause::misc(self.span, self.body_id);
+
+        let obligation = traits::Obligation::new(
+            cause.clone(),
+            self.param_env,
+            trait_ref.without_const().to_predicate(tcx),
+        );
+        if !self.infcx.predicate_may_hold(&obligation) {
+            debug!("overloaded_deref_ty: cannot match obligation");
+            return None;
+        }
+
+        let mut fulfillcx = traits::FulfillmentContext::new_in_snapshot();
+        let normalized_ty = fulfillcx.normalize_projection_type(
+            &self.infcx,
+            self.param_env,
+            ty::ProjectionTy::from_ref_and_name(tcx, trait_ref, Ident::from_str("Target")),
+            cause,
+        );
+        if let Err(e) = fulfillcx.select_where_possible(&self.infcx) {
+            // This shouldn't happen, except for evaluate/fulfill mismatches,
+            // but that's not a reason for an ICE (`predicate_may_hold` is conservative
+            // by design).
+            debug!("overloaded_deref_ty: encountered errors {:?} while fulfilling", e);
+            return None;
+        }
+        let obligations = fulfillcx.pending_obligations();
+        debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", ty, normalized_ty, obligations);
+        self.state.obligations.extend(obligations);
+
+        Some(self.infcx.resolve_vars_if_possible(&normalized_ty))
+    }
+
+    /// Returns the final type we ended up with, which may be an inference
+    /// variable (we will resolve it first, if we want).
+    pub fn final_ty(&self, resolve: bool) -> Ty<'tcx> {
+        if resolve {
+            self.infcx.resolve_vars_if_possible(&self.state.cur_ty)
+        } else {
+            self.state.cur_ty
+        }
+    }
+
+    pub fn step_count(&self) -> usize {
+        self.state.steps.len()
+    }
+
+    pub fn into_obligations(self) -> Vec<traits::PredicateObligation<'tcx>> {
+        self.state.obligations
+    }
+
+    pub fn steps(&self) -> &[(Ty<'tcx>, AutoderefKind)] {
+        &self.state.steps
+    }
+
+    pub fn span(&self) -> Span {
+        self.span.clone()
+    }
+
+    pub fn reached_recursion_limit(&self) -> bool {
+        self.state.reached_recursion_limit
+    }
+
+    /// also dereference through raw pointer types
+    /// e.g., assuming ptr_to_Foo is the type `*const Foo`
+    /// fcx.autoderef(span, ptr_to_Foo)  => [*const Foo]
+    /// fcx.autoderef(span, ptr_to_Foo).include_raw_ptrs() => [*const Foo, Foo]
+    pub fn include_raw_pointers(mut self) -> Self {
+        self.include_raw_pointers = true;
+        self
+    }
+
+    pub fn silence_errors(mut self) -> Self {
+        self.silence_errors = true;
+        self
+    }
+}
+
+pub fn report_autoderef_recursion_limit_error<'tcx>(tcx: TyCtxt<'tcx>, span: Span, ty: Ty<'tcx>) {
+    // We've reached the recursion limit, error gracefully.
+    let suggested_limit = tcx.sess.recursion_limit() * 2;
+    let msg = format!("reached the recursion limit while auto-dereferencing `{:?}`", ty);
+    let error_id = (DiagnosticMessageId::ErrorId(55), Some(span), msg);
+    let fresh = tcx.sess.one_time_diagnostics.borrow_mut().insert(error_id);
+    if fresh {
+        struct_span_err!(
+            tcx.sess,
+            span,
+            E0055,
+            "reached the recursion limit while auto-dereferencing `{:?}`",
+            ty
+        )
+        .span_label(span, "deref recursion limit reached")
+        .help(&format!(
+            "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)",
+            suggested_limit, tcx.crate_name,
+        ))
+        .emit();
+    }
+}
diff --git a/src/librustc_trait_selection/lib.rs b/src/librustc_trait_selection/lib.rs
index ea886cd1f9e..4692fa04ed5 100644
--- a/src/librustc_trait_selection/lib.rs
+++ b/src/librustc_trait_selection/lib.rs
@@ -28,6 +28,7 @@ extern crate log;
 #[macro_use]
 extern crate rustc_middle;
 
+pub mod autoderef;
 pub mod infer;
 pub mod opaque_types;
 pub mod traits;
diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs
index 060877f80ad..fd0c1a54d27 100644
--- a/src/librustc_trait_selection/traits/error_reporting/mod.rs
+++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs
@@ -402,6 +402,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                             err.span_label(enclosing_scope_span, s.as_str());
                         }
 
+                        self.suggest_dereferences(&obligation, &mut err, &trait_ref, points_at_arg);
                         self.suggest_borrow_on_unsized_slice(&obligation.cause.code, &mut err);
                         self.suggest_fn_call(&obligation, &mut err, &trait_ref, points_at_arg);
                         self.suggest_remove_reference(&obligation, &mut err, &trait_ref);
diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs
index dfd7dac72d8..176bd90303d 100644
--- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs
+++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs
@@ -3,6 +3,7 @@ use super::{
     SelectionContext,
 };
 
+use crate::autoderef::Autoderef;
 use crate::infer::InferCtxt;
 use crate::traits::normalize_projection_type;
 
@@ -13,11 +14,11 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::lang_items;
 use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node};
-use rustc_middle::ty::TypeckTables;
 use rustc_middle::ty::{
     self, suggest_constraining_type_param, AdtKind, DefIdTree, Infer, InferTy, ToPredicate, Ty,
     TyCtxt, TypeFoldable, WithConstness,
 };
+use rustc_middle::ty::{TypeAndMut, TypeckTables};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{MultiSpan, Span, DUMMY_SP};
 use std::fmt;
@@ -48,6 +49,14 @@ pub trait InferCtxtExt<'tcx> {
         err: &mut DiagnosticBuilder<'_>,
     );
 
+    fn suggest_dereferences(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+        err: &mut DiagnosticBuilder<'tcx>,
+        trait_ref: &ty::PolyTraitRef<'tcx>,
+        points_at_arg: bool,
+    );
+
     fn get_closure_name(
         &self,
         def_id: DefId,
@@ -450,6 +459,62 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         }
     }
 
+    /// When after several dereferencing, the reference satisfies the trait
+    /// binding. This function provides dereference suggestion for this
+    /// specific situation.
+    fn suggest_dereferences(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+        err: &mut DiagnosticBuilder<'tcx>,
+        trait_ref: &ty::PolyTraitRef<'tcx>,
+        points_at_arg: bool,
+    ) {
+        // It only make sense when suggesting dereferences for arguments
+        if !points_at_arg {
+            return;
+        }
+        let param_env = obligation.param_env;
+        let body_id = obligation.cause.body_id;
+        let span = obligation.cause.span;
+        let real_trait_ref = match &obligation.cause.code {
+            ObligationCauseCode::ImplDerivedObligation(cause)
+            | ObligationCauseCode::DerivedObligation(cause)
+            | ObligationCauseCode::BuiltinDerivedObligation(cause) => &cause.parent_trait_ref,
+            _ => trait_ref,
+        };
+        let real_ty = match real_trait_ref.self_ty().no_bound_vars() {
+            Some(ty) => ty,
+            None => return,
+        };
+
+        if let ty::Ref(region, base_ty, mutbl) = real_ty.kind {
+            let mut autoderef = Autoderef::new(self, param_env, body_id, span, base_ty);
+            if let Some(steps) = autoderef.find_map(|(ty, steps)| {
+                // Re-add the `&`
+                let ty = self.tcx.mk_ref(region, TypeAndMut { ty, mutbl });
+                let obligation =
+                    self.mk_trait_obligation_with_new_self_ty(param_env, real_trait_ref, ty);
+                Some(steps).filter(|_| self.predicate_may_hold(&obligation))
+            }) {
+                if steps > 0 {
+                    if let Ok(src) = self.tcx.sess.source_map().span_to_snippet(span) {
+                        // Don't care about `&mut` because `DerefMut` is used less
+                        // often and user will not expect autoderef happens.
+                        if src.starts_with("&") && !src.starts_with("&mut ") {
+                            let derefs = "*".repeat(steps);
+                            err.span_suggestion(
+                                span,
+                                "consider adding dereference here",
+                                format!("&{}{}", derefs, &src[1..]),
+                                Applicability::MachineApplicable,
+                            );
+                        }
+                    }
+                }
+            }
+        }
+    }
+
     /// When encountering an assignment of an unsized trait, like `let x = ""[..];`, provide a
     /// suggestion to borrow the initializer in order to use have a slice instead.
     fn suggest_borrow_on_unsized_slice(
diff --git a/src/librustc_trait_selection/traits/project.rs b/src/librustc_trait_selection/traits/project.rs
index 19640542547..574d50a4fcc 100644
--- a/src/librustc_trait_selection/traits/project.rs
+++ b/src/librustc_trait_selection/traits/project.rs
@@ -896,9 +896,12 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>(
 
     let tcx = selcx.tcx();
     // Check whether the self-type is itself a projection.
-    let (def_id, substs) = match obligation_trait_ref.self_ty().kind {
-        ty::Projection(ref data) => (data.trait_ref(tcx).def_id, data.substs),
-        ty::Opaque(def_id, substs) => (def_id, substs),
+    // If so, extract what we know from the trait and try to come up with a good answer.
+    let bounds = match obligation_trait_ref.self_ty().kind {
+        ty::Projection(ref data) => {
+            tcx.projection_predicates(data.item_def_id).subst(tcx, data.substs)
+        }
+        ty::Opaque(def_id, substs) => tcx.projection_predicates(def_id).subst(tcx, substs),
         ty::Infer(ty::TyVar(_)) => {
             // If the self-type is an inference variable, then it MAY wind up
             // being a projected type, so induce an ambiguity.
@@ -908,17 +911,13 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>(
         _ => return,
     };
 
-    // If so, extract what we know from the trait and try to come up with a good answer.
-    let trait_predicates = tcx.predicates_of(def_id);
-    let bounds = trait_predicates.instantiate(tcx, substs);
-    let bounds = elaborate_predicates(tcx, bounds.predicates.into_iter()).map(|o| o.predicate);
     assemble_candidates_from_predicates(
         selcx,
         obligation,
         obligation_trait_ref,
         candidate_set,
         ProjectionTyCandidate::TraitDef,
-        bounds,
+        bounds.iter(),
     )
 }
 
@@ -1484,6 +1483,12 @@ fn confirm_impl_candidate<'cx, 'tcx>(
         );
         return Progress { ty: tcx.ty_error(), obligations: nested };
     }
+    // If we're trying to normalize `<Vec<u32> as X>::A<S>` using
+    //`impl<T> X for Vec<T> { type A<Y> = Box<Y>; }`, then:
+    //
+    // * `obligation.predicate.substs` is `[Vec<u32>, S]`
+    // * `substs` is `[u32]`
+    // * `substs` ends up as `[u32, S]`
     let substs = obligation.predicate.substs.rebase_onto(tcx, trait_def_id, substs);
     let substs =
         translate_substs(selcx.infcx(), param_env, impl_def_id, substs, assoc_ty.defining_node);
diff --git a/src/librustc_trait_selection/traits/select/mod.rs b/src/librustc_trait_selection/traits/select/mod.rs
index 7dc8c2cf4cd..076bdad423a 100644
--- a/src/librustc_trait_selection/traits/select/mod.rs
+++ b/src/librustc_trait_selection/traits/select/mod.rs
@@ -1273,9 +1273,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             placeholder_trait_predicate,
         );
 
-        let (def_id, substs) = match placeholder_trait_predicate.trait_ref.self_ty().kind {
-            ty::Projection(ref data) => (data.trait_ref(self.tcx()).def_id, data.substs),
-            ty::Opaque(def_id, substs) => (def_id, substs),
+        let tcx = self.infcx.tcx;
+        let predicates = match placeholder_trait_predicate.trait_ref.self_ty().kind {
+            ty::Projection(ref data) => {
+                tcx.projection_predicates(data.item_def_id).subst(tcx, data.substs)
+            }
+            ty::Opaque(def_id, substs) => tcx.projection_predicates(def_id).subst(tcx, substs),
             _ => {
                 span_bug!(
                     obligation.cause.span,
@@ -1285,32 +1288,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 );
             }
         };
-        debug!(
-            "match_projection_obligation_against_definition_bounds: \
-             def_id={:?}, substs={:?}",
-            def_id, substs
-        );
 
-        let predicates_of = self.tcx().predicates_of(def_id);
-        let bounds = predicates_of.instantiate(self.tcx(), substs);
-        debug!(
-            "match_projection_obligation_against_definition_bounds: \
-             bounds={:?}",
-            bounds
-        );
-
-        let elaborated_predicates =
-            util::elaborate_predicates(self.tcx(), bounds.predicates.into_iter());
-        let matching_bound = elaborated_predicates.filter_to_traits().find(|bound| {
-            self.infcx.probe(|_| {
-                self.match_projection(
-                    obligation,
-                    *bound,
-                    placeholder_trait_predicate.trait_ref,
-                    &placeholder_map,
-                    snapshot,
-                )
-            })
+        let matching_bound = predicates.iter().find_map(|bound| {
+            if let ty::PredicateKind::Trait(bound, _) = bound.kind() {
+                let bound = bound.to_poly_trait_ref();
+                if self.infcx.probe(|_| {
+                    self.match_projection(
+                        obligation,
+                        bound,
+                        placeholder_trait_predicate.trait_ref,
+                        &placeholder_map,
+                        snapshot,
+                    )
+                }) {
+                    return Some(bound);
+                }
+            }
+            None
         });
 
         debug!(
diff --git a/src/librustc_ty/ty.rs b/src/librustc_ty/ty.rs
index cf70a845af0..595992d01dd 100644
--- a/src/librustc_ty/ty.rs
+++ b/src/librustc_ty/ty.rs
@@ -1,8 +1,10 @@
 use rustc_data_structures::svh::Svh;
 use rustc_hir as hir;
+use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
+use rustc_infer::traits::util;
 use rustc_middle::hir::map as hir_map;
-use rustc_middle::ty::subst::Subst;
+use rustc_middle::ty::subst::{InternalSubsts, Subst};
 use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness};
 use rustc_session::CrateDisambiguator;
 use rustc_span::symbol::Symbol;
@@ -365,6 +367,133 @@ fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync {
     fn_like.asyncness()
 }
 
+/// For associated types we allow bounds written on the associated type
+/// (`type X: Trait`) to be used as candidates. We also allow the same bounds
+/// when desugared as bounds on the trait `where Self::X: Trait`.
+///
+/// Note that this filtering is done with the items identity substs to
+/// simplify checking that these bounds are met in impls. This means that
+/// a bound such as `for<'b> <Self as X<'b>>::U: Clone` can't be used, as in
+/// `hr-associated-type-bound-1.rs`.
+fn associated_type_projection_predicates(
+    tcx: TyCtxt<'_>,
+    assoc_item_def_id: DefId,
+) -> &'_ ty::List<ty::Predicate<'_>> {
+    let generic_trait_bounds = tcx.predicates_of(assoc_item_def_id);
+    // We include predicates from the trait as well to handle
+    // `where Self::X: Trait`.
+    let item_bounds = generic_trait_bounds.instantiate_identity(tcx);
+    let item_predicates = util::elaborate_predicates(tcx, item_bounds.predicates.into_iter());
+
+    let assoc_item_ty = ty::ProjectionTy {
+        item_def_id: assoc_item_def_id,
+        substs: InternalSubsts::identity_for_item(tcx, assoc_item_def_id),
+    };
+
+    let predicates = item_predicates.filter_map(|obligation| {
+        let pred = obligation.predicate;
+        match pred.kind() {
+            ty::PredicateKind::Trait(tr, _) => {
+                if let ty::Projection(p) = tr.skip_binder().self_ty().kind {
+                    if p == assoc_item_ty {
+                        return Some(pred);
+                    }
+                }
+            }
+            ty::PredicateKind::Projection(proj) => {
+                if let ty::Projection(p) = proj.skip_binder().projection_ty.self_ty().kind {
+                    if p == assoc_item_ty {
+                        return Some(pred);
+                    }
+                }
+            }
+            ty::PredicateKind::TypeOutlives(outlives) => {
+                if let ty::Projection(p) = outlives.skip_binder().0.kind {
+                    if p == assoc_item_ty {
+                        return Some(pred);
+                    }
+                }
+            }
+            _ => {}
+        }
+        None
+    });
+
+    let result = tcx.mk_predicates(predicates);
+    debug!(
+        "associated_type_projection_predicates({}) = {:?}",
+        tcx.def_path_str(assoc_item_def_id),
+        result
+    );
+    result
+}
+
+/// Opaque types don't have the same issues as associated types: the only
+/// predicates on an opaque type (excluding those it inherits from its parent
+/// item) should be of the form we're expecting.
+fn opaque_type_projection_predicates(
+    tcx: TyCtxt<'_>,
+    def_id: DefId,
+) -> &'_ ty::List<ty::Predicate<'_>> {
+    let substs = InternalSubsts::identity_for_item(tcx, def_id);
+
+    let bounds = tcx.predicates_of(def_id);
+    let predicates =
+        util::elaborate_predicates(tcx, bounds.predicates.into_iter().map(|&(pred, _)| pred));
+
+    let filtered_predicates = predicates.filter_map(|obligation| {
+        let pred = obligation.predicate;
+        match pred.kind() {
+            ty::PredicateKind::Trait(tr, _) => {
+                if let ty::Opaque(opaque_def_id, opaque_substs) = tr.skip_binder().self_ty().kind {
+                    if opaque_def_id == def_id && opaque_substs == substs {
+                        return Some(pred);
+                    }
+                }
+            }
+            ty::PredicateKind::Projection(proj) => {
+                if let ty::Opaque(opaque_def_id, opaque_substs) =
+                    proj.skip_binder().projection_ty.self_ty().kind
+                {
+                    if opaque_def_id == def_id && opaque_substs == substs {
+                        return Some(pred);
+                    }
+                }
+            }
+            ty::PredicateKind::TypeOutlives(outlives) => {
+                if let ty::Opaque(opaque_def_id, opaque_substs) = outlives.skip_binder().0.kind {
+                    if opaque_def_id == def_id && opaque_substs == substs {
+                        return Some(pred);
+                    }
+                } else {
+                    // These can come from elaborating other predicates
+                    return None;
+                }
+            }
+            // These can come from elaborating other predicates
+            ty::PredicateKind::RegionOutlives(_) => return None,
+            _ => {}
+        }
+        tcx.sess.delay_span_bug(
+            obligation.cause.span(tcx),
+            &format!("unexpected predicate {:?} on opaque type", pred),
+        );
+        None
+    });
+
+    let result = tcx.mk_predicates(filtered_predicates);
+    debug!("opaque_type_projection_predicates({}) = {:?}", tcx.def_path_str(def_id), result);
+    result
+}
+
+fn projection_predicates(tcx: TyCtxt<'_>, def_id: DefId) -> &'_ ty::List<ty::Predicate<'_>> {
+    match tcx.def_kind(def_id) {
+        DefKind::AssocTy => associated_type_projection_predicates(tcx, def_id),
+        DefKind::OpaqueTy => opaque_type_projection_predicates(tcx, def_id),
+        k => bug!("projection_predicates called on {}", k.descr(def_id)),
+    }
+}
+
 pub fn provide(providers: &mut ty::query::Providers<'_>) {
     *providers = ty::query::Providers {
         asyncness,
@@ -381,6 +510,7 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
         instance_def_size_estimate,
         issue33140_self_ty,
         impl_defaultness,
+        projection_predicates,
         ..*providers
     };
 }
diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs
index 2570025959c..97d2b3e5a8e 100644
--- a/src/librustc_typeck/check/autoderef.rs
+++ b/src/librustc_typeck/check/autoderef.rs
@@ -1,191 +1,46 @@
+//! Some helper functions for `AutoDeref`
 use super::method::MethodCallee;
 use super::{FnCtxt, PlaceOp};
 
-use rustc_errors::struct_span_err;
-use rustc_hir as hir;
-use rustc_infer::infer::{InferCtxt, InferOk};
+use rustc_infer::infer::InferOk;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref};
-use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt, WithConstness};
-use rustc_middle::ty::{ToPredicate, TypeFoldable};
-use rustc_session::DiagnosticMessageId;
-use rustc_span::symbol::Ident;
+use rustc_middle::ty::{self, Ty};
 use rustc_span::Span;
-use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
-use rustc_trait_selection::traits::{self, TraitEngine};
+use rustc_trait_selection::autoderef::{Autoderef, AutoderefKind};
 
 use std::iter;
 
-#[derive(Copy, Clone, Debug)]
-enum AutoderefKind {
-    Builtin,
-    Overloaded,
-}
-
-pub struct Autoderef<'a, 'tcx> {
-    infcx: &'a InferCtxt<'a, 'tcx>,
-    body_id: hir::HirId,
-    param_env: ty::ParamEnv<'tcx>,
-    steps: Vec<(Ty<'tcx>, AutoderefKind)>,
-    cur_ty: Ty<'tcx>,
-    obligations: Vec<traits::PredicateObligation<'tcx>>,
-    at_start: bool,
-    include_raw_pointers: bool,
-    span: Span,
-    silence_errors: bool,
-    reached_recursion_limit: bool,
-}
-
-impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> {
-    type Item = (Ty<'tcx>, usize);
-
-    fn next(&mut self) -> Option<Self::Item> {
-        let tcx = self.infcx.tcx;
-
-        debug!("autoderef: steps={:?}, cur_ty={:?}", self.steps, self.cur_ty);
-        if self.at_start {
-            self.at_start = false;
-            debug!("autoderef stage #0 is {:?}", self.cur_ty);
-            return Some((self.cur_ty, 0));
-        }
-
-        if !tcx.sess.recursion_limit().value_within_limit(self.steps.len()) {
-            if !self.silence_errors {
-                report_autoderef_recursion_limit_error(tcx, self.span, self.cur_ty);
-            }
-            self.reached_recursion_limit = true;
-            return None;
-        }
-
-        if self.cur_ty.is_ty_var() {
-            return None;
-        }
-
-        // Otherwise, deref if type is derefable:
-        let (kind, new_ty) = if let Some(mt) = self.cur_ty.builtin_deref(self.include_raw_pointers)
-        {
-            (AutoderefKind::Builtin, mt.ty)
-        } else {
-            let ty = self.overloaded_deref_ty(self.cur_ty)?;
-            (AutoderefKind::Overloaded, ty)
-        };
-
-        if new_ty.references_error() {
-            return None;
-        }
-
-        self.steps.push((self.cur_ty, kind));
-        debug!(
-            "autoderef stage #{:?} is {:?} from {:?}",
-            self.steps.len(),
-            new_ty,
-            (self.cur_ty, kind)
-        );
-        self.cur_ty = new_ty;
-
-        Some((self.cur_ty, self.steps.len()))
+impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+    pub fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'tcx> {
+        Autoderef::new(self, self.param_env, self.body_id, span, base_ty)
     }
-}
 
-impl<'a, 'tcx> Autoderef<'a, 'tcx> {
-    pub fn new(
-        infcx: &'a InferCtxt<'a, 'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-        body_id: hir::HirId,
+    pub fn try_overloaded_deref(
+        &self,
         span: Span,
         base_ty: Ty<'tcx>,
-    ) -> Autoderef<'a, 'tcx> {
-        Autoderef {
-            infcx,
-            body_id,
-            param_env,
-            steps: vec![],
-            cur_ty: infcx.resolve_vars_if_possible(&base_ty),
-            obligations: vec![],
-            at_start: true,
-            include_raw_pointers: false,
-            silence_errors: false,
-            reached_recursion_limit: false,
-            span,
-        }
-    }
-
-    fn overloaded_deref_ty(&mut self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
-        debug!("overloaded_deref_ty({:?})", ty);
-
-        let tcx = self.infcx.tcx;
-
-        // <ty as Deref>
-        let trait_ref = TraitRef {
-            def_id: tcx.lang_items().deref_trait()?,
-            substs: tcx.mk_substs_trait(ty, &[]),
-        };
-
-        let cause = traits::ObligationCause::misc(self.span, self.body_id);
-
-        let obligation = traits::Obligation::new(
-            cause.clone(),
-            self.param_env,
-            trait_ref.without_const().to_predicate(tcx),
-        );
-        if !self.infcx.predicate_may_hold(&obligation) {
-            debug!("overloaded_deref_ty: cannot match obligation");
-            return None;
-        }
-
-        let mut fulfillcx = traits::FulfillmentContext::new_in_snapshot();
-        let normalized_ty = fulfillcx.normalize_projection_type(
-            &self.infcx,
-            self.param_env,
-            ty::ProjectionTy::from_ref_and_name(tcx, trait_ref, Ident::from_str("Target")),
-            cause,
-        );
-        if let Err(e) = fulfillcx.select_where_possible(&self.infcx) {
-            // This shouldn't happen, except for evaluate/fulfill mismatches,
-            // but that's not a reason for an ICE (`predicate_may_hold` is conservative
-            // by design).
-            debug!("overloaded_deref_ty: encountered errors {:?} while fulfilling", e);
-            return None;
-        }
-        let obligations = fulfillcx.pending_obligations();
-        debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", ty, normalized_ty, obligations);
-        self.obligations.extend(obligations);
-
-        Some(self.infcx.resolve_vars_if_possible(&normalized_ty))
-    }
-
-    /// Returns the final type, generating an error if it is an
-    /// unresolved inference variable.
-    pub fn unambiguous_final_ty(&self, fcx: &FnCtxt<'a, 'tcx>) -> Ty<'tcx> {
-        fcx.structurally_resolved_type(self.span, self.cur_ty)
-    }
-
-    /// Returns the final type we ended up with, which may well be an
-    /// inference variable (we will resolve it first, if possible).
-    pub fn maybe_ambiguous_final_ty(&self) -> Ty<'tcx> {
-        self.infcx.resolve_vars_if_possible(&self.cur_ty)
-    }
-
-    pub fn step_count(&self) -> usize {
-        self.steps.len()
+    ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
+        self.try_overloaded_place_op(span, base_ty, &[], PlaceOp::Deref)
     }
 
     /// Returns the adjustment steps.
-    pub fn adjust_steps(&self, fcx: &FnCtxt<'a, 'tcx>) -> Vec<Adjustment<'tcx>> {
-        fcx.register_infer_ok_obligations(self.adjust_steps_as_infer_ok(fcx))
+    pub fn adjust_steps(&self, autoderef: &Autoderef<'a, 'tcx>) -> Vec<Adjustment<'tcx>> {
+        self.register_infer_ok_obligations(self.adjust_steps_as_infer_ok(autoderef))
     }
 
     pub fn adjust_steps_as_infer_ok(
         &self,
-        fcx: &FnCtxt<'a, 'tcx>,
+        autoderef: &Autoderef<'a, 'tcx>,
     ) -> InferOk<'tcx, Vec<Adjustment<'tcx>>> {
         let mut obligations = vec![];
-        let targets = self.steps.iter().skip(1).map(|&(ty, _)| ty).chain(iter::once(self.cur_ty));
-        let steps: Vec<_> = self
-            .steps
+        let steps = autoderef.steps();
+        let targets =
+            steps.iter().skip(1).map(|&(ty, _)| ty).chain(iter::once(autoderef.final_ty(false)));
+        let steps: Vec<_> = steps
             .iter()
             .map(|&(source, kind)| {
                 if let AutoderefKind::Overloaded = kind {
-                    fcx.try_overloaded_deref(self.span, source).and_then(
+                    self.try_overloaded_deref(autoderef.span(), source).and_then(
                         |InferOk { value: method, obligations: o }| {
                             obligations.extend(o);
                             if let ty::Ref(region, _, mutbl) = method.sig.output().kind {
@@ -205,67 +60,4 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
 
         InferOk { obligations, value: steps }
     }
-
-    /// also dereference through raw pointer types
-    /// e.g., assuming ptr_to_Foo is the type `*const Foo`
-    /// fcx.autoderef(span, ptr_to_Foo)  => [*const Foo]
-    /// fcx.autoderef(span, ptr_to_Foo).include_raw_ptrs() => [*const Foo, Foo]
-    pub fn include_raw_pointers(mut self) -> Self {
-        self.include_raw_pointers = true;
-        self
-    }
-
-    pub fn silence_errors(mut self) -> Self {
-        self.silence_errors = true;
-        self
-    }
-
-    pub fn reached_recursion_limit(&self) -> bool {
-        self.reached_recursion_limit
-    }
-
-    pub fn finalize(self, fcx: &FnCtxt<'a, 'tcx>) {
-        fcx.register_predicates(self.into_obligations());
-    }
-
-    pub fn into_obligations(self) -> Vec<traits::PredicateObligation<'tcx>> {
-        self.obligations
-    }
-}
-
-pub fn report_autoderef_recursion_limit_error<'tcx>(tcx: TyCtxt<'tcx>, span: Span, ty: Ty<'tcx>) {
-    // We've reached the recursion limit, error gracefully.
-    let suggested_limit = tcx.sess.recursion_limit() * 2;
-    let msg = format!("reached the recursion limit while auto-dereferencing `{:?}`", ty);
-    let error_id = (DiagnosticMessageId::ErrorId(55), Some(span), msg);
-    let fresh = tcx.sess.one_time_diagnostics.borrow_mut().insert(error_id);
-    if fresh {
-        struct_span_err!(
-            tcx.sess,
-            span,
-            E0055,
-            "reached the recursion limit while auto-dereferencing `{:?}`",
-            ty
-        )
-        .span_label(span, "deref recursion limit reached")
-        .help(&format!(
-            "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)",
-            suggested_limit, tcx.crate_name,
-        ))
-        .emit();
-    }
-}
-
-impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
-    pub fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'tcx> {
-        Autoderef::new(self, self.param_env, self.body_id, span, base_ty)
-    }
-
-    pub fn try_overloaded_deref(
-        &self,
-        span: Span,
-        base_ty: Ty<'tcx>,
-    ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
-        self.try_overloaded_place_op(span, base_ty, &[], PlaceOp::Deref)
-    }
 }
diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs
index fe200a0ad2a..308ed5d8402 100644
--- a/src/librustc_typeck/check/callee.rs
+++ b/src/librustc_typeck/check/callee.rs
@@ -1,4 +1,3 @@
-use super::autoderef::Autoderef;
 use super::method::MethodCallee;
 use super::{Expectation, FnCtxt, TupleArgumentsFlag};
 use crate::type_error_struct;
@@ -17,6 +16,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
 use rustc_span::symbol::Ident;
 use rustc_span::Span;
 use rustc_target::spec::abi;
+use rustc_trait_selection::autoderef::Autoderef;
 
 /// Checks that it is legal to call methods of the trait corresponding
 /// to `trait_id` (this only cares about the trait, not the specific
@@ -72,7 +72,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         while result.is_none() && autoderef.next().is_some() {
             result = self.try_overloaded_call_step(call_expr, callee_expr, arg_exprs, &autoderef);
         }
-        autoderef.finalize(self);
+        self.register_predicates(autoderef.into_obligations());
 
         let output = match result {
             None => {
@@ -106,7 +106,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         arg_exprs: &'tcx [hir::Expr<'tcx>],
         autoderef: &Autoderef<'a, 'tcx>,
     ) -> Option<CallStep<'tcx>> {
-        let adjusted_ty = autoderef.unambiguous_final_ty(self);
+        let adjusted_ty =
+            self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false));
         debug!(
             "try_overloaded_call_step(call_expr={:?}, adjusted_ty={:?})",
             call_expr, adjusted_ty
@@ -115,7 +116,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // If the callee is a bare function or a closure, then we're all set.
         match adjusted_ty.kind {
             ty::FnDef(..) | ty::FnPtr(_) => {
-                let adjustments = autoderef.adjust_steps(self);
+                let adjustments = self.adjust_steps(autoderef);
                 self.apply_adjustments(callee_expr, adjustments);
                 return Some(CallStep::Builtin(adjusted_ty));
             }
@@ -135,7 +136,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             &closure_sig,
                         )
                         .0;
-                    let adjustments = autoderef.adjust_steps(self);
+                    let adjustments = self.adjust_steps(autoderef);
                     self.record_deferred_call_resolution(
                         def_id,
                         DeferredCallResolution {
@@ -176,7 +177,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         self.try_overloaded_call_traits(call_expr, adjusted_ty, Some(arg_exprs))
             .or_else(|| self.try_overloaded_call_traits(call_expr, adjusted_ty, None))
             .map(|(autoref, method)| {
-                let mut adjustments = autoderef.adjust_steps(self);
+                let mut adjustments = self.adjust_steps(autoderef);
                 adjustments.extend(autoref);
                 self.apply_adjustments(callee_expr, adjustments);
                 CallStep::Overloaded(method)
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index 15d210b89b6..dec53c369bb 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -409,7 +409,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
         }
 
         let InferOk { value: mut adjustments, obligations: o } =
-            autoderef.adjust_steps_as_infer_ok(self);
+            self.adjust_steps_as_infer_ok(&autoderef);
         obligations.extend(o);
         obligations.extend(autoderef.into_obligations());
 
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index 1d47e64630c..4e97ba41dcb 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -4,15 +4,17 @@ use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit;
 use rustc_hir::{GenericParamKind, ImplItemKind, TraitItemKind};
 use rustc_infer::infer::{self, InferOk, TyCtxtInferExt};
+use rustc_middle::ty;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
-use rustc_middle::ty::subst::{InternalSubsts, Subst};
+use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
 use rustc_middle::ty::util::ExplicitSelf;
-use rustc_middle::ty::{self, GenericParamDefKind, TyCtxt};
+use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt, WithConstness};
 use rustc_span::Span;
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
 use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, Reveal};
 
 use super::{potentially_plural_count, FnCtxt, Inherited};
+use std::iter;
 
 /// Checks that a method from an impl conforms to the signature of
 /// the same method as declared in the trait.
@@ -1057,13 +1059,15 @@ crate fn compare_ty_impl<'tcx>(
     let _: Result<(), ErrorReported> = (|| {
         compare_number_of_generics(tcx, impl_ty, impl_ty_span, trait_ty, trait_item_span)?;
 
-        compare_type_predicate_entailment(tcx, impl_ty, impl_ty_span, trait_ty, impl_trait_ref)
+        compare_type_predicate_entailment(tcx, impl_ty, impl_ty_span, trait_ty, impl_trait_ref)?;
+
+        compare_projection_bounds(tcx, trait_ty, impl_ty, impl_ty_span, impl_trait_ref)
     })();
 }
 
 /// The equivalent of [compare_predicate_entailment], but for associated types
 /// instead of associated functions.
-fn compare_type_predicate_entailment(
+fn compare_type_predicate_entailment<'tcx>(
     tcx: TyCtxt<'tcx>,
     impl_ty: &ty::AssocItem,
     impl_ty_span: Span,
@@ -1165,6 +1169,145 @@ fn compare_type_predicate_entailment(
     })
 }
 
+/// Validate that `ProjectionCandidate`s created for this associated type will
+/// be valid.
+///
+/// Usually given
+///
+/// trait X { type Y: Copy } impl X for T { type Y = S; }
+///
+/// We are able to normalize `<T as X>::U` to `S`, and so when we check the
+/// impl is well-formed we have to prove `S: Copy`.
+///
+/// For default associated types the normalization is not possible (the value
+/// from the impl could be overridden). We also can't normalize generic
+/// associated types (yet) because they contain bound parameters.
+fn compare_projection_bounds<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    trait_ty: &ty::AssocItem,
+    impl_ty: &ty::AssocItem,
+    impl_ty_span: Span,
+    impl_trait_ref: ty::TraitRef<'tcx>,
+) -> Result<(), ErrorReported> {
+    let have_gats = tcx.features().generic_associated_types;
+    if impl_ty.defaultness.is_final() && !have_gats {
+        // For "final", non-generic associate type implementations, we
+        // don't need this as described above.
+        return Ok(());
+    }
+
+    let param_env = tcx.param_env(impl_ty.def_id);
+
+    // Given
+    //
+    // impl<A, B> Foo<u32> for (A, B) {
+    //     type Bar<C> =...
+    // }
+    //
+    // - `impl_substs` would be `[A, B, C]`
+    // - `rebased_substs` would be `[(A, B), u32, C]`, combining the substs from
+    //    the *trait* with the generic associated type parameters.
+    let impl_ty_substs = InternalSubsts::identity_for_item(tcx, impl_ty.def_id);
+    let rebased_substs =
+        impl_ty_substs.rebase_onto(tcx, impl_ty.container.id(), impl_trait_ref.substs);
+    let impl_ty_value = tcx.type_of(impl_ty.def_id);
+
+    // Map the predicate from the trait to the corresponding one for the impl.
+    // For example:
+    //
+    // trait X<A> { type Y<'a>: PartialEq<A> } impl X for T { type Y<'a> = &'a S; }
+    // impl<'x> X<&'x u32> for () { type Y<'c> = &'c u32; }
+    //
+    // For the `for<'a> <<Self as X<A>>::Y<'a>: PartialEq<A>` bound, this
+    // function would translate and partially normalize
+    // `[<Self as X<A>>::Y<'a>, A]` to `[&'a u32, &'x u32]`.
+    let translate_predicate_substs = move |predicate_substs: SubstsRef<'tcx>| {
+        tcx.mk_substs(
+            iter::once(impl_ty_value.into())
+                .chain(predicate_substs[1..].iter().map(|s| s.subst(tcx, rebased_substs))),
+        )
+    };
+
+    tcx.infer_ctxt().enter(move |infcx| {
+        let inh = Inherited::new(infcx, impl_ty.def_id.expect_local());
+        let infcx = &inh.infcx;
+        let mut selcx = traits::SelectionContext::new(&infcx);
+
+        let impl_ty_hir_id = tcx.hir().as_local_hir_id(impl_ty.def_id.expect_local());
+        let normalize_cause = traits::ObligationCause::misc(impl_ty_span, impl_ty_hir_id);
+        let cause = ObligationCause::new(
+            impl_ty_span,
+            impl_ty_hir_id,
+            ObligationCauseCode::ItemObligation(trait_ty.def_id),
+        );
+
+        let predicates = tcx.projection_predicates(trait_ty.def_id);
+
+        debug!("compare_projection_bounds: projection_predicates={:?}", predicates);
+
+        for predicate in predicates {
+            let concrete_ty_predicate = match predicate.kind() {
+                ty::PredicateKind::Trait(poly_tr, c) => poly_tr
+                    .map_bound(|tr| {
+                        let trait_substs = translate_predicate_substs(tr.trait_ref.substs);
+                        ty::TraitRef { def_id: tr.def_id(), substs: trait_substs }
+                    })
+                    .with_constness(*c)
+                    .to_predicate(tcx),
+                ty::PredicateKind::Projection(poly_projection) => poly_projection
+                    .map_bound(|projection| {
+                        let projection_substs =
+                            translate_predicate_substs(projection.projection_ty.substs);
+                        ty::ProjectionPredicate {
+                            projection_ty: ty::ProjectionTy {
+                                substs: projection_substs,
+                                item_def_id: projection.projection_ty.item_def_id,
+                            },
+                            ty: projection.ty.subst(tcx, rebased_substs),
+                        }
+                    })
+                    .to_predicate(tcx),
+                ty::PredicateKind::TypeOutlives(poly_outlives) => poly_outlives
+                    .map_bound(|outlives| {
+                        ty::OutlivesPredicate(impl_ty_value, outlives.1.subst(tcx, rebased_substs))
+                    })
+                    .to_predicate(tcx),
+                _ => bug!("unexepected projection predicate kind: `{:?}`", predicate),
+            };
+
+            let traits::Normalized { value: normalized_predicate, obligations } = traits::normalize(
+                &mut selcx,
+                param_env,
+                normalize_cause.clone(),
+                &concrete_ty_predicate,
+            );
+
+            debug!("compare_projection_bounds: normalized predicate = {:?}", normalized_predicate);
+
+            inh.register_predicates(obligations);
+            inh.register_predicate(traits::Obligation::new(
+                cause.clone(),
+                param_env,
+                normalized_predicate,
+            ));
+        }
+
+        // Check that all obligations are satisfied by the implementation's
+        // version.
+        if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
+            infcx.report_fulfillment_errors(errors, None, false);
+            return Err(ErrorReported);
+        }
+
+        // Finally, resolve all regions. This catches wily misuses of
+        // lifetime parameters.
+        let fcx = FnCtxt::new(&inh, param_env, impl_ty_hir_id);
+        fcx.regionck_item(impl_ty_hir_id, impl_ty_span, &[]);
+
+        Ok(())
+    })
+}
+
 fn assoc_item_kind_str(impl_item: &ty::AssocItem) -> &'static str {
     match impl_item.kind {
         ty::AssocKind::Const => "const",
diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs
index 6a006676371..1eaa5a6c31e 100644
--- a/src/librustc_typeck/check/expr.rs
+++ b/src/librustc_typeck/check/expr.rs
@@ -1447,9 +1447,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         // of error recovery.
                         self.write_field_index(expr.hir_id, index);
                         if field.vis.is_accessible_from(def_scope, self.tcx) {
-                            let adjustments = autoderef.adjust_steps(self);
+                            let adjustments = self.adjust_steps(&autoderef);
                             self.apply_adjustments(base, adjustments);
-                            autoderef.finalize(self);
+                            self.register_predicates(autoderef.into_obligations());
 
                             self.tcx.check_stability(field.did, Some(expr.hir_id), expr.span);
                             return field_ty;
@@ -1462,9 +1462,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     if let Ok(index) = fstr.parse::<usize>() {
                         if fstr == index.to_string() {
                             if let Some(field_ty) = tys.get(index) {
-                                let adjustments = autoderef.adjust_steps(self);
+                                let adjustments = self.adjust_steps(&autoderef);
                                 self.apply_adjustments(base, adjustments);
-                                autoderef.finalize(self);
+                                self.register_predicates(autoderef.into_obligations());
 
                                 self.write_field_index(expr.hir_id, index);
                                 return field_ty.expect_ty();
@@ -1475,7 +1475,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 _ => {}
             }
         }
-        autoderef.unambiguous_final_ty(self);
+        self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false));
 
         if let Some((did, field_ty)) = private_candidate {
             self.ban_private_field_access(expr, expr_t, field, did);
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index 6844c9416af..1c3d23a3a24 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -144,9 +144,10 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
         };
         assert_eq!(n, pick.autoderefs);
 
-        let mut adjustments = autoderef.adjust_steps(self);
+        let mut adjustments = self.adjust_steps(&autoderef);
 
-        let mut target = autoderef.unambiguous_final_ty(self);
+        let mut target =
+            self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false));
 
         if let Some(mutbl) = pick.autoref {
             let region = self.next_region_var(infer::Autoref(self.span));
@@ -176,7 +177,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
             assert!(pick.unsize.is_none());
         }
 
-        autoderef.finalize(self);
+        self.register_predicates(autoderef.into_obligations());
 
         // Write out the final adjustments.
         self.apply_adjustments(self.self_expr, adjustments);
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index efd23894d02..a3e34815d31 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -3,7 +3,6 @@ use super::MethodError;
 use super::NoMatchData;
 use super::{CandidateSource, ImplSource, TraitSource};
 
-use crate::check::autoderef::{self, Autoderef};
 use crate::check::FnCtxt;
 use crate::hir::def::DefKind;
 use crate::hir::def_id::DefId;
@@ -30,6 +29,7 @@ use rustc_session::config::nightly_options;
 use rustc_session::lint;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::{symbol::Ident, Span, Symbol, DUMMY_SP};
+use rustc_trait_selection::autoderef::{self, Autoderef};
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
 use rustc_trait_selection::traits::query::method_autoderef::MethodAutoderefBadTy;
 use rustc_trait_selection::traits::query::method_autoderef::{
@@ -477,7 +477,7 @@ fn method_autoderef_steps<'tcx>(
             })
             .collect();
 
-        let final_ty = autoderef.maybe_ambiguous_final_ty();
+        let final_ty = autoderef.final_ty(true);
         let opt_bad_ty = match final_ty.kind {
             ty::Infer(ty::TyVar(_)) | ty::Error(_) => Some(MethodAutoderefBadTy {
                 reached_raw_pointer,
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 775441cb746..1594d65e9bd 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -2281,7 +2281,7 @@ fn check_impl_items_against_trait<'tcx>(
                             &ty_trait_item,
                             impl_trait_ref,
                             opt_trait_span,
-                        )
+                        );
                     } else {
                         let mut err = struct_span_err!(
                             tcx.sess,
diff --git a/src/librustc_typeck/check/place_op.rs b/src/librustc_typeck/check/place_op.rs
index d1c22cd1ac0..b7c8f310a14 100644
--- a/src/librustc_typeck/check/place_op.rs
+++ b/src/librustc_typeck/check/place_op.rs
@@ -1,4 +1,3 @@
-use crate::check::autoderef::Autoderef;
 use crate::check::method::MethodCallee;
 use crate::check::{FnCtxt, PlaceOp};
 use rustc_hir as hir;
@@ -9,6 +8,7 @@ use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutabili
 use rustc_middle::ty::{self, Ty};
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
+use rustc_trait_selection::autoderef::Autoderef;
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// Type-check `*oprnd_expr` with `oprnd_expr` type-checked already.
@@ -57,7 +57,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         while result.is_none() && autoderef.next().is_some() {
             result = self.try_index_step(expr, base_expr, &autoderef, idx_ty);
         }
-        autoderef.finalize(self);
+        self.register_predicates(autoderef.into_obligations());
         result
     }
 
@@ -73,7 +73,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         autoderef: &Autoderef<'a, 'tcx>,
         index_ty: Ty<'tcx>,
     ) -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> {
-        let adjusted_ty = autoderef.unambiguous_final_ty(self);
+        let adjusted_ty =
+            self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false));
         debug!(
             "try_index_step(expr={:?}, base_expr={:?}, adjusted_ty={:?}, \
              index_ty={:?})",
@@ -105,7 +106,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 debug!("try_index_step: success, using overloaded indexing");
                 let method = self.register_infer_ok_obligations(ok);
 
-                let mut adjustments = autoderef.adjust_steps(self);
+                let mut adjustments = self.adjust_steps(autoderef);
                 if let ty::Ref(region, _, hir::Mutability::Not) = method.sig.inputs()[0].kind {
                     adjustments.push(Adjustment {
                         kind: Adjust::Borrow(AutoBorrow::Ref(region, AutoBorrowMutability::Not)),
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index f3297ed6743..d1a86a7ee89 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -1118,7 +1118,7 @@ fn receiver_is_valid<'fcx, 'tcx>(
             );
 
             if can_eq_self(potential_self_ty) {
-                autoderef.finalize(fcx);
+                fcx.register_predicates(autoderef.into_obligations());
 
                 if let Some(mut err) =
                     fcx.demand_eqtype_with_origin(&cause, self_ty, potential_self_ty)
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 91266eeb9ba..054165f2b09 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -35,7 +35,7 @@ use rustc_middle::hir::map::Map;
 use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
 use rustc_middle::mir::mono::Linkage;
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::subst::{InternalSubsts, Subst};
+use rustc_middle::ty::subst::InternalSubsts;
 use rustc_middle::ty::util::Discr;
 use rustc_middle::ty::util::IntTypeExt;
 use rustc_middle::ty::{self, AdtKind, Const, ToPolyTraitRef, Ty, TyCtxt};
@@ -1692,6 +1692,7 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat
 
     let mut is_trait = None;
     let mut is_default_impl_trait = None;
+    let mut is_trait_associated_type = None;
 
     let icx = ItemCtxt::new(tcx, def_id);
     let constness = icx.default_constness_for_trait_bounds();
@@ -1701,7 +1702,12 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat
     let mut predicates = UniquePredicates::new();
 
     let ast_generics = match node {
-        Node::TraitItem(item) => &item.generics,
+        Node::TraitItem(item) => {
+            if let hir::TraitItemKind::Type(bounds, _) = item.kind {
+                is_trait_associated_type = Some((bounds, item.span));
+            }
+            &item.generics
+        }
 
         Node::ImplItem(item) => &item.generics,
 
@@ -1925,10 +1931,21 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat
         }
     }
 
-    // Add predicates from associated type bounds.
-    if let Some((self_trait_ref, trait_items)) = is_trait {
+    // Add predicates from associated type bounds (`type X: Bound`)
+    if tcx.features().generic_associated_types {
+        // New behavior: bounds declared on associate type are predicates of that
+        // associated type. Not the default because it needs more testing.
+        if let Some((bounds, span)) = is_trait_associated_type {
+            let projection_ty =
+                tcx.mk_projection(def_id, InternalSubsts::identity_for_item(tcx, def_id));
+
+            predicates.extend(associated_item_bounds(tcx, def_id, bounds, projection_ty, span))
+        }
+    } else if let Some((self_trait_ref, trait_items)) = is_trait {
+        // Current behavior: bounds declared on associate type are predicates
+        // of its parent trait.
         predicates.extend(trait_items.iter().flat_map(|trait_item_ref| {
-            associated_item_predicates(tcx, def_id, self_trait_ref, trait_item_ref)
+            trait_associated_item_predicates(tcx, def_id, self_trait_ref, trait_item_ref)
         }))
     }
 
@@ -1958,7 +1975,7 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat
     result
 }
 
-fn associated_item_predicates(
+fn trait_associated_item_predicates(
     tcx: TyCtxt<'tcx>,
     def_id: DefId,
     self_trait_ref: ty::TraitRef<'tcx>,
@@ -1971,92 +1988,40 @@ fn associated_item_predicates(
         _ => return Vec::new(),
     };
 
-    let is_gat = !tcx.generics_of(item_def_id).params.is_empty();
-
-    let mut had_error = false;
-
-    let mut unimplemented_error = |arg_kind: &str| {
-        if !had_error {
-            tcx.sess
-                .struct_span_err(
-                    trait_item.span,
-                    &format!("{}-generic associated types are not yet implemented", arg_kind),
-                )
-                .note(
-                    "for more information, see issue #44265 \
-                     <https://github.com/rust-lang/rust/issues/44265> for more information",
-                )
-                .emit();
-            had_error = true;
-        }
-    };
-
-    let mk_bound_param = |param: &ty::GenericParamDef, _: &_| {
-        match param.kind {
-            ty::GenericParamDefKind::Lifetime => tcx
-                .mk_region(ty::RegionKind::ReLateBound(
-                    ty::INNERMOST,
-                    ty::BoundRegion::BrNamed(param.def_id, param.name),
-                ))
-                .into(),
-            // FIXME(generic_associated_types): Use bound types and constants
-            // once they are handled by the trait system.
-            ty::GenericParamDefKind::Type { .. } => {
-                unimplemented_error("type");
-                tcx.ty_error().into()
-            }
-            ty::GenericParamDefKind::Const => {
-                unimplemented_error("const");
-                tcx.const_error(tcx.type_of(param.def_id)).into()
-            }
-        }
-    };
+    if !tcx.generics_of(item_def_id).params.is_empty() {
+        // For GATs the substs provided to the mk_projection call below are
+        // wrong. We should emit a feature gate error if we get here so skip
+        // this type.
+        tcx.sess.delay_span_bug(trait_item.span, "gats used without feature gate");
+        return Vec::new();
+    }
 
-    let bound_substs = if is_gat {
-        // Given:
-        //
-        // trait X<'a, B, const C: usize> {
-        //     type T<'d, E, const F: usize>: Default;
-        // }
-        //
-        // We need to create predicates on the trait:
-        //
-        // for<'d, E, const F: usize>
-        // <Self as X<'a, B, const C: usize>>::T<'d, E, const F: usize>: Sized + Default
-        //
-        // We substitute escaping bound parameters for the generic
-        // arguments to the associated type which are then bound by
-        // the `Binder` around the the predicate.
-        //
-        // FIXME(generic_associated_types): Currently only lifetimes are handled.
-        self_trait_ref.substs.extend_to(tcx, item_def_id.to_def_id(), mk_bound_param)
-    } else {
-        self_trait_ref.substs
-    };
+    let assoc_ty = tcx.mk_projection(
+        tcx.hir().local_def_id(trait_item.hir_id).to_def_id(),
+        self_trait_ref.substs,
+    );
 
-    let assoc_ty =
-        tcx.mk_projection(tcx.hir().local_def_id(trait_item.hir_id).to_def_id(), bound_substs);
+    associated_item_bounds(tcx, def_id, bounds, assoc_ty, trait_item.span)
+}
 
+fn associated_item_bounds(
+    tcx: TyCtxt<'tcx>,
+    def_id: DefId,
+    bounds: &'tcx [hir::GenericBound<'tcx>],
+    projection_ty: Ty<'tcx>,
+    span: Span,
+) -> Vec<(ty::Predicate<'tcx>, Span)> {
     let bounds = AstConv::compute_bounds(
         &ItemCtxt::new(tcx, def_id),
-        assoc_ty,
+        projection_ty,
         bounds,
         SizedByDefault::Yes,
-        trait_item.span,
+        span,
     );
 
-    let predicates = bounds.predicates(tcx, assoc_ty);
+    let predicates = bounds.predicates(tcx, projection_ty);
 
-    if is_gat {
-        // We use shifts to get the regions that we're substituting to
-        // be bound by the binders in the `Predicate`s rather that
-        // escaping.
-        let shifted_in = ty::fold::shift_vars(tcx, &predicates, 1);
-        let substituted = shifted_in.subst(tcx, bound_substs);
-        ty::fold::shift_out_vars(tcx, &substituted, 1)
-    } else {
-        predicates
-    }
+    predicates
 }
 
 /// Converts a specific `GenericBound` from the AST into a set of
diff --git a/src/stage0.txt b/src/stage0.txt
index 5e840b9db19..769ec669bdc 100644
--- a/src/stage0.txt
+++ b/src/stage0.txt
@@ -12,7 +12,7 @@
 # source tarball for a stable release you'll likely see `1.x.0` for rustc and
 # `0.(x+1).0` for Cargo where they were released on `date`.
 
-date: 2020-06-03
+date: 2020-06-16
 rustc: beta
 cargo: beta
 
diff --git a/src/test/codegen/asm-multiple-options.rs b/src/test/codegen/asm-multiple-options.rs
new file mode 100644
index 00000000000..c702742bf1a
--- /dev/null
+++ b/src/test/codegen/asm-multiple-options.rs
@@ -0,0 +1,53 @@
+// compile-flags: -O
+// only-x86_64
+
+#![crate_type = "rlib"]
+#![feature(asm)]
+
+// CHECK-LABEL: @pure
+// CHECK-NOT: asm
+// CHECK: ret void
+#[no_mangle]
+pub unsafe fn pure(x: i32) {
+    let y: i32;
+    asm!("", out("ax") y, in("bx") x, options(pure), options(nomem));
+}
+
+pub static mut VAR: i32 = 0;
+pub static mut DUMMY_OUTPUT: i32 = 0;
+
+// CHECK-LABEL: @readonly
+// CHECK: call i32 asm
+// CHECK: ret i32 1
+#[no_mangle]
+pub unsafe fn readonly() -> i32 {
+    VAR = 1;
+    asm!("", out("ax") DUMMY_OUTPUT, options(pure), options(readonly));
+    VAR
+}
+
+// CHECK-LABEL: @nomem
+// CHECK-NOT: store
+// CHECK: call i32 asm
+// CHECK: store
+// CHECK: ret i32 2
+#[no_mangle]
+pub unsafe fn nomem() -> i32 {
+    VAR = 1;
+    asm!("", out("ax") DUMMY_OUTPUT, options(pure), options(nomem));
+    VAR = 2;
+    VAR
+}
+
+// CHECK-LABEL: @not_nomem
+// CHECK: store
+// CHECK: call i32 asm
+// CHECK: store
+// CHECK: ret i32 2
+#[no_mangle]
+pub unsafe fn not_nomem() -> i32 {
+    VAR = 1;
+    asm!("", out("ax") DUMMY_OUTPUT, options(pure), options(readonly));
+    VAR = 2;
+    VAR
+}
diff --git a/src/test/ui/asm/duplicate-options.fixed b/src/test/ui/asm/duplicate-options.fixed
new file mode 100644
index 00000000000..f4672a50fd0
--- /dev/null
+++ b/src/test/ui/asm/duplicate-options.fixed
@@ -0,0 +1,26 @@
+// only-x86_64
+// run-rustfix
+
+#![feature(asm)]
+
+fn main() {
+    unsafe {
+        asm!("", options(nomem, ));
+        //~^ ERROR the `nomem` option was already provided
+        asm!("", options(att_syntax, ));
+        //~^ ERROR the `att_syntax` option was already provided
+        asm!("", options(nostack, att_syntax), options());
+        //~^ ERROR the `nostack` option was already provided
+        asm!("", options(nostack, ), options(), options());
+        //~^ ERROR the `nostack` option was already provided
+        //~| ERROR the `nostack` option was already provided
+        //~| ERROR the `nostack` option was already provided
+        asm!(
+            "",
+            options(nomem, noreturn),
+            options(att_syntax, ), //~ ERROR the `noreturn` option was already provided
+            options( nostack), //~ ERROR the `nomem` option was already provided
+            options(), //~ ERROR the `noreturn` option was already provided
+        );
+    }
+}
diff --git a/src/test/ui/asm/duplicate-options.rs b/src/test/ui/asm/duplicate-options.rs
new file mode 100644
index 00000000000..80292d7521a
--- /dev/null
+++ b/src/test/ui/asm/duplicate-options.rs
@@ -0,0 +1,26 @@
+// only-x86_64
+// run-rustfix
+
+#![feature(asm)]
+
+fn main() {
+    unsafe {
+        asm!("", options(nomem, nomem));
+        //~^ ERROR the `nomem` option was already provided
+        asm!("", options(att_syntax, att_syntax));
+        //~^ ERROR the `att_syntax` option was already provided
+        asm!("", options(nostack, att_syntax), options(nostack));
+        //~^ ERROR the `nostack` option was already provided
+        asm!("", options(nostack, nostack), options(nostack), options(nostack));
+        //~^ ERROR the `nostack` option was already provided
+        //~| ERROR the `nostack` option was already provided
+        //~| ERROR the `nostack` option was already provided
+        asm!(
+            "",
+            options(nomem, noreturn),
+            options(att_syntax, noreturn), //~ ERROR the `noreturn` option was already provided
+            options(nomem, nostack), //~ ERROR the `nomem` option was already provided
+            options(noreturn), //~ ERROR the `noreturn` option was already provided
+        );
+    }
+}
diff --git a/src/test/ui/asm/duplicate-options.stderr b/src/test/ui/asm/duplicate-options.stderr
new file mode 100644
index 00000000000..cd8d743e031
--- /dev/null
+++ b/src/test/ui/asm/duplicate-options.stderr
@@ -0,0 +1,56 @@
+error: the `nomem` option was already provided
+  --> $DIR/duplicate-options.rs:8:33
+   |
+LL |         asm!("", options(nomem, nomem));
+   |                                 ^^^^^ this option was already provided
+
+error: the `att_syntax` option was already provided
+  --> $DIR/duplicate-options.rs:10:38
+   |
+LL |         asm!("", options(att_syntax, att_syntax));
+   |                                      ^^^^^^^^^^ this option was already provided
+
+error: the `nostack` option was already provided
+  --> $DIR/duplicate-options.rs:12:56
+   |
+LL |         asm!("", options(nostack, att_syntax), options(nostack));
+   |                                                        ^^^^^^^ this option was already provided
+
+error: the `nostack` option was already provided
+  --> $DIR/duplicate-options.rs:14:35
+   |
+LL |         asm!("", options(nostack, nostack), options(nostack), options(nostack));
+   |                                   ^^^^^^^ this option was already provided
+
+error: the `nostack` option was already provided
+  --> $DIR/duplicate-options.rs:14:53
+   |
+LL |         asm!("", options(nostack, nostack), options(nostack), options(nostack));
+   |                                                     ^^^^^^^ this option was already provided
+
+error: the `nostack` option was already provided
+  --> $DIR/duplicate-options.rs:14:71
+   |
+LL |         asm!("", options(nostack, nostack), options(nostack), options(nostack));
+   |                                                                       ^^^^^^^ this option was already provided
+
+error: the `noreturn` option was already provided
+  --> $DIR/duplicate-options.rs:21:33
+   |
+LL |             options(att_syntax, noreturn),
+   |                                 ^^^^^^^^ this option was already provided
+
+error: the `nomem` option was already provided
+  --> $DIR/duplicate-options.rs:22:21
+   |
+LL |             options(nomem, nostack),
+   |                     ^^^^^ this option was already provided
+
+error: the `noreturn` option was already provided
+  --> $DIR/duplicate-options.rs:23:21
+   |
+LL |             options(noreturn),
+   |                     ^^^^^^^^ this option was already provided
+
+error: aborting due to 9 previous errors
+
diff --git a/src/test/ui/asm/parse-error.rs b/src/test/ui/asm/parse-error.rs
index fbf399d8b07..538a3fde8fd 100644
--- a/src/test/ui/asm/parse-error.rs
+++ b/src/test/ui/asm/parse-error.rs
@@ -34,11 +34,6 @@ fn main() {
         //~^ ERROR expected one of
         asm!("", options(nomem, foo));
         //~^ ERROR expected one of
-        asm!("", options(), options());
-        //~^ ERROR asm options cannot be specified multiple times
-        asm!("", options(), options(), options());
-        //~^ ERROR asm options cannot be specified multiple times
-        //~^^ ERROR asm options cannot be specified multiple times
         asm!("{}", options(), const foo);
         //~^ ERROR arguments are not allowed after options
         asm!("{a}", a = const foo, a = const bar);
diff --git a/src/test/ui/asm/parse-error.stderr b/src/test/ui/asm/parse-error.stderr
index ba7e8f7a03c..dfbfc0abe34 100644
--- a/src/test/ui/asm/parse-error.stderr
+++ b/src/test/ui/asm/parse-error.stderr
@@ -82,32 +82,8 @@ error: expected one of `)`, `att_syntax`, `nomem`, `noreturn`, `nostack`, `prese
 LL |         asm!("", options(nomem, foo));
    |                                 ^^^ expected one of 8 possible tokens
 
-error: asm options cannot be specified multiple times
-  --> $DIR/parse-error.rs:37:29
-   |
-LL |         asm!("", options(), options());
-   |                  ---------  ^^^^^^^^^ duplicate options
-   |                  |
-   |                  previously here
-
-error: asm options cannot be specified multiple times
-  --> $DIR/parse-error.rs:39:29
-   |
-LL |         asm!("", options(), options(), options());
-   |                  ---------  ^^^^^^^^^ duplicate options
-   |                  |
-   |                  previously here
-
-error: asm options cannot be specified multiple times
-  --> $DIR/parse-error.rs:39:40
-   |
-LL |         asm!("", options(), options(), options());
-   |                  ---------             ^^^^^^^^^ duplicate options
-   |                  |
-   |                  previously here
-
 error: arguments are not allowed after options
-  --> $DIR/parse-error.rs:42:31
+  --> $DIR/parse-error.rs:37:31
    |
 LL |         asm!("{}", options(), const foo);
    |                    ---------  ^^^^^^^^^ argument
@@ -115,7 +91,7 @@ LL |         asm!("{}", options(), const foo);
    |                    previous options
 
 error: duplicate argument named `a`
-  --> $DIR/parse-error.rs:44:36
+  --> $DIR/parse-error.rs:39:36
    |
 LL |         asm!("{a}", a = const foo, a = const bar);
    |                     -------------  ^^^^^^^^^^^^^ duplicate argument
@@ -123,7 +99,7 @@ LL |         asm!("{a}", a = const foo, a = const bar);
    |                     previously here
 
 error: argument never used
-  --> $DIR/parse-error.rs:44:36
+  --> $DIR/parse-error.rs:39:36
    |
 LL |         asm!("{a}", a = const foo, a = const bar);
    |                                    ^^^^^^^^^^^^^ argument never used
@@ -131,13 +107,13 @@ LL |         asm!("{a}", a = const foo, a = const bar);
    = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"`
 
 error: explicit register arguments cannot have names
-  --> $DIR/parse-error.rs:47:18
+  --> $DIR/parse-error.rs:42:18
    |
 LL |         asm!("", a = in("eax") foo);
    |                  ^^^^^^^^^^^^^^^^^
 
 error: named arguments cannot follow explicit register arguments
-  --> $DIR/parse-error.rs:49:36
+  --> $DIR/parse-error.rs:44:36
    |
 LL |         asm!("{a}", in("eax") foo, a = const bar);
    |                     -------------  ^^^^^^^^^^^^^ named argument
@@ -145,7 +121,7 @@ LL |         asm!("{a}", in("eax") foo, a = const bar);
    |                     explicit register argument
 
 error: named arguments cannot follow explicit register arguments
-  --> $DIR/parse-error.rs:51:36
+  --> $DIR/parse-error.rs:46:36
    |
 LL |         asm!("{a}", in("eax") foo, a = const bar);
    |                     -------------  ^^^^^^^^^^^^^ named argument
@@ -153,7 +129,7 @@ LL |         asm!("{a}", in("eax") foo, a = const bar);
    |                     explicit register argument
 
 error: positional arguments cannot follow named arguments or explicit register arguments
-  --> $DIR/parse-error.rs:53:36
+  --> $DIR/parse-error.rs:48:36
    |
 LL |         asm!("{1}", in("eax") foo, const bar);
    |                     -------------  ^^^^^^^^^ positional argument
@@ -161,19 +137,19 @@ LL |         asm!("{1}", in("eax") foo, const bar);
    |                     explicit register argument
 
 error: expected one of `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `""`
-  --> $DIR/parse-error.rs:55:29
+  --> $DIR/parse-error.rs:50:29
    |
 LL |         asm!("", options(), "");
    |                             ^^ expected one of 8 possible tokens
 
 error: expected one of `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `"{}"`
-  --> $DIR/parse-error.rs:57:33
+  --> $DIR/parse-error.rs:52:33
    |
 LL |         asm!("{}", in(reg) foo, "{}", out(reg) foo);
    |                                 ^^^^ expected one of 8 possible tokens
 
 error: asm template must be a string literal
-  --> $DIR/parse-error.rs:59:14
+  --> $DIR/parse-error.rs:54:14
    |
 LL |         asm!(format!("{{{}}}", 0), in(reg) foo);
    |              ^^^^^^^^^^^^^^^^^^^^
@@ -181,12 +157,12 @@ LL |         asm!(format!("{{{}}}", 0), in(reg) foo);
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: asm template must be a string literal
-  --> $DIR/parse-error.rs:61:21
+  --> $DIR/parse-error.rs:56:21
    |
 LL |         asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar);
    |                     ^^^^^^^^^^^^^^^^^^^^
    |
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 28 previous errors
+error: aborting due to 25 previous errors
 
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-1.rs b/src/test/ui/associated-types/hr-associated-type-bound-1.rs
new file mode 100644
index 00000000000..497b86eeab8
--- /dev/null
+++ b/src/test/ui/associated-types/hr-associated-type-bound-1.rs
@@ -0,0 +1,18 @@
+trait X<'a>
+where
+    for<'b> <Self as X<'b>>::U: Clone,
+{
+    type U: ?Sized;
+    fn f(&self, x: &Self::U) {
+        <Self::U>::clone(x);
+    }
+}
+
+impl X<'_> for i32 {
+    type U = str;
+    //~^ ERROR the trait bound `for<'b> <i32 as X<'b>>::U: std::clone::Clone`
+}
+
+fn main() {
+    1i32.f("abc");
+}
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-1.stderr b/src/test/ui/associated-types/hr-associated-type-bound-1.stderr
new file mode 100644
index 00000000000..7ef2faef9c6
--- /dev/null
+++ b/src/test/ui/associated-types/hr-associated-type-bound-1.stderr
@@ -0,0 +1,19 @@
+error[E0277]: the trait bound `for<'b> <i32 as X<'b>>::U: std::clone::Clone` is not satisfied
+  --> $DIR/hr-associated-type-bound-1.rs:12:14
+   |
+LL | trait X<'a>
+   |       - required by a bound in this
+LL | where
+LL |     for<'b> <Self as X<'b>>::U: Clone,
+   |                                 ----- required by this bound in `X`
+...
+LL |     type U = str;
+   |              ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `<i32 as X<'b>>::U`
+   |
+   = help: the following implementations were found:
+             <&T as std::clone::Clone>
+             <&mut T as std::clone::Clone>
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-2.rs b/src/test/ui/associated-types/hr-associated-type-bound-2.rs
new file mode 100644
index 00000000000..7ff0fede28c
--- /dev/null
+++ b/src/test/ui/associated-types/hr-associated-type-bound-2.rs
@@ -0,0 +1,21 @@
+trait X<'a>
+where
+    for<'b> <Self as X<'b>>::U: Clone,
+{
+    type U: ?Sized;
+    fn f(&self, x: &Self::U) {
+        <Self::U>::clone(x);
+    }
+}
+
+impl X<'_> for u32
+where
+    for<'b> <Self as X<'b>>::U: Clone,
+{
+    type U = str;
+}
+
+fn main() {
+    1u32.f("abc");
+    //~^ ERROR no method named `f` found for type `u32` in the current scope
+}
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-2.stderr b/src/test/ui/associated-types/hr-associated-type-bound-2.stderr
new file mode 100644
index 00000000000..2a364d349d7
--- /dev/null
+++ b/src/test/ui/associated-types/hr-associated-type-bound-2.stderr
@@ -0,0 +1,13 @@
+error[E0599]: no method named `f` found for type `u32` in the current scope
+  --> $DIR/hr-associated-type-bound-2.rs:19:10
+   |
+LL |     1u32.f("abc");
+   |          ^ method not found in `u32`
+   |
+   = note: the method `f` exists but the following trait bounds were not satisfied:
+           `<u32 as X<'b>>::U: std::clone::Clone`
+           which is required by `u32: X`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-object.rs b/src/test/ui/associated-types/hr-associated-type-bound-object.rs
new file mode 100644
index 00000000000..7c64ae38caf
--- /dev/null
+++ b/src/test/ui/associated-types/hr-associated-type-bound-object.rs
@@ -0,0 +1,14 @@
+trait X<'a>
+where
+    for<'b> <Self as X<'b>>::U: Clone,
+{
+    type U: ?Sized;
+}
+fn f<'a, T: X<'a> + ?Sized>(x: &<T as X<'a>>::U) {
+    //~^ ERROR the trait bound `for<'b> <T as X<'b>>::U: std::clone::Clone` is not satisfied
+    <<T as X<'_>>::U>::clone(x);
+}
+
+pub fn main() {
+    f::<dyn X<'_, U = str>>("abc");
+}
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-object.stderr b/src/test/ui/associated-types/hr-associated-type-bound-object.stderr
new file mode 100644
index 00000000000..db966875c70
--- /dev/null
+++ b/src/test/ui/associated-types/hr-associated-type-bound-object.stderr
@@ -0,0 +1,19 @@
+error[E0277]: the trait bound `for<'b> <T as X<'b>>::U: std::clone::Clone` is not satisfied
+  --> $DIR/hr-associated-type-bound-object.rs:7:13
+   |
+LL | trait X<'a>
+   |       - required by a bound in this
+LL | where
+LL |     for<'b> <Self as X<'b>>::U: Clone,
+   |                                 ----- required by this bound in `X`
+...
+LL | fn f<'a, T: X<'a> + ?Sized>(x: &<T as X<'a>>::U) {
+   |             ^^^^^ the trait `for<'b> std::clone::Clone` is not implemented for `<T as X<'b>>::U`
+   |
+   = help: the following implementations were found:
+             <&T as std::clone::Clone>
+             <&mut T as std::clone::Clone>
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-1.rs b/src/test/ui/associated-types/hr-associated-type-bound-param-1.rs
new file mode 100644
index 00000000000..a65f8a8c498
--- /dev/null
+++ b/src/test/ui/associated-types/hr-associated-type-bound-param-1.rs
@@ -0,0 +1,20 @@
+trait Y<'a, T: ?Sized>
+where
+    T: Y<'a, Self>,
+    for<'b> <Self as Y<'b, T>>::V: Clone,
+    for<'b> <T as Y<'b, Self>>::V: Clone,
+{
+    type V: ?Sized;
+    fn g(&self, x: &Self::V) {
+        <Self::V>::clone(x);
+    }
+}
+
+impl<'a> Y<'a, u8> for u8 {
+    type V = str;
+    //~^ ERROR the trait bound `for<'b> <u8 as Y<'b, u8>>::V: std::clone::Clone` is not satisfied
+}
+
+fn main() {
+    1u8.g("abc");
+}
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-1.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-1.stderr
new file mode 100644
index 00000000000..347a5818dce
--- /dev/null
+++ b/src/test/ui/associated-types/hr-associated-type-bound-param-1.stderr
@@ -0,0 +1,19 @@
+error[E0277]: the trait bound `for<'b> <u8 as Y<'b, u8>>::V: std::clone::Clone` is not satisfied
+  --> $DIR/hr-associated-type-bound-param-1.rs:14:14
+   |
+LL | trait Y<'a, T: ?Sized>
+   |       - required by a bound in this
+...
+LL |     for<'b> <Self as Y<'b, T>>::V: Clone,
+   |                                    ----- required by this bound in `Y`
+...
+LL |     type V = str;
+   |              ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `<u8 as Y<'b, u8>>::V`
+   |
+   = help: the following implementations were found:
+             <&T as std::clone::Clone>
+             <&mut T as std::clone::Clone>
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-2.rs b/src/test/ui/associated-types/hr-associated-type-bound-param-2.rs
new file mode 100644
index 00000000000..9f849b03276
--- /dev/null
+++ b/src/test/ui/associated-types/hr-associated-type-bound-param-2.rs
@@ -0,0 +1,21 @@
+trait Z<'a, T: ?Sized>
+where
+    T: Z<'a, u16>,
+    //~^ the trait bound `for<'b> <u16 as Z<'b, u16>>::W: std::clone::Clone` is not satisfied
+    //~| the trait bound `for<'b> <u16 as Z<'b, u16>>::W: std::clone::Clone` is not satisfied
+    for<'b> <T as Z<'b, u16>>::W: Clone,
+{
+    type W: ?Sized;
+    fn h(&self, x: &T::W) {
+        <T::W>::clone(x);
+    }
+}
+
+impl<'a> Z<'a, u16> for u16 {
+    type W = str;
+    //~^ ERROR the trait bound `for<'b> <u16 as Z<'b, u16>>::W: std::clone::Clone
+}
+
+fn main() {
+    1u16.h("abc");
+}
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr
new file mode 100644
index 00000000000..e06777e36a8
--- /dev/null
+++ b/src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr
@@ -0,0 +1,51 @@
+error[E0277]: the trait bound `for<'b> <u16 as Z<'b, u16>>::W: std::clone::Clone` is not satisfied
+  --> $DIR/hr-associated-type-bound-param-2.rs:3:8
+   |
+LL | trait Z<'a, T: ?Sized>
+   |       - required by a bound in this
+LL | where
+LL |     T: Z<'a, u16>,
+   |        ^^^^^^^^^^ the trait `for<'b> std::clone::Clone` is not implemented for `<u16 as Z<'b, u16>>::W`
+...
+LL |     for<'b> <T as Z<'b, u16>>::W: Clone,
+   |                                   ----- required by this bound in `Z`
+   |
+   = help: the following implementations were found:
+             <&T as std::clone::Clone>
+             <&mut T as std::clone::Clone>
+
+error[E0277]: the trait bound `for<'b> <u16 as Z<'b, u16>>::W: std::clone::Clone` is not satisfied
+  --> $DIR/hr-associated-type-bound-param-2.rs:15:14
+   |
+LL | trait Z<'a, T: ?Sized>
+   |       - required by a bound in this
+...
+LL |     for<'b> <T as Z<'b, u16>>::W: Clone,
+   |                                   ----- required by this bound in `Z`
+...
+LL |     type W = str;
+   |              ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `<u16 as Z<'b, u16>>::W`
+   |
+   = help: the following implementations were found:
+             <&T as std::clone::Clone>
+             <&mut T as std::clone::Clone>
+
+error[E0277]: the trait bound `for<'b> <u16 as Z<'b, u16>>::W: std::clone::Clone` is not satisfied
+  --> $DIR/hr-associated-type-bound-param-2.rs:3:8
+   |
+LL | trait Z<'a, T: ?Sized>
+   |       - required by a bound in this
+LL | where
+LL |     T: Z<'a, u16>,
+   |        ^^^^^^^^^^ the trait `for<'b> std::clone::Clone` is not implemented for `<u16 as Z<'b, u16>>::W`
+...
+LL |     for<'b> <T as Z<'b, u16>>::W: Clone,
+   |                                   ----- required by this bound in `Z`
+   |
+   = help: the following implementations were found:
+             <&T as std::clone::Clone>
+             <&mut T as std::clone::Clone>
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-3.rs b/src/test/ui/associated-types/hr-associated-type-bound-param-3.rs
new file mode 100644
index 00000000000..9aca59f8ce6
--- /dev/null
+++ b/src/test/ui/associated-types/hr-associated-type-bound-param-3.rs
@@ -0,0 +1,21 @@
+// ignore-tidy-linelength
+
+trait X<'a, T>
+where
+    for<'b> T: X<'b, T>,
+    for<'b> <T as X<'b, T>>::U: Clone,
+{
+    type U: ?Sized;
+    fn f(x: &<T as X<'_, T>>::U) {
+        <<T as X<'_, T>>::U>::clone(x);
+    }
+}
+
+impl<S, T> X<'_, (T,)> for (S,) {
+    type U = str;
+    //~^ ERROR the trait bound `for<'b> <(T,) as X<'b, (T,)>>::U: std::clone::Clone` is not satisfied
+}
+
+pub fn main() {
+    <(i32,) as X<(i32,)>>::f("abc");
+}
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-3.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-3.stderr
new file mode 100644
index 00000000000..ff56f60e4c9
--- /dev/null
+++ b/src/test/ui/associated-types/hr-associated-type-bound-param-3.stderr
@@ -0,0 +1,19 @@
+error[E0277]: the trait bound `for<'b> <(T,) as X<'b, (T,)>>::U: std::clone::Clone` is not satisfied
+  --> $DIR/hr-associated-type-bound-param-3.rs:15:14
+   |
+LL | trait X<'a, T>
+   |       - required by a bound in this
+...
+LL |     for<'b> <T as X<'b, T>>::U: Clone,
+   |                                 ----- required by this bound in `X`
+...
+LL |     type U = str;
+   |              ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `<(T,) as X<'b, (T,)>>::U`
+   |
+   = help: the following implementations were found:
+             <&T as std::clone::Clone>
+             <&mut T as std::clone::Clone>
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-4.rs b/src/test/ui/associated-types/hr-associated-type-bound-param-4.rs
new file mode 100644
index 00000000000..ffe43c674c3
--- /dev/null
+++ b/src/test/ui/associated-types/hr-associated-type-bound-param-4.rs
@@ -0,0 +1,19 @@
+trait X<'a, T>
+where
+    for<'b> (T,): X<'b, T>,
+    for<'b> <(T,) as X<'b, T>>::U: Clone,
+{
+    type U: ?Sized;
+    fn f(x: &<(T,) as X<'_, T>>::U) {
+        <<(T,) as X<'_, T>>::U>::clone(x);
+    }
+}
+
+impl<S, T> X<'_, T> for (S,) {
+    type U = str;
+    //~^ ERROR the trait bound `for<'b> <(T,) as X<'b, T>>::U: std::clone::Clone` is not satisfied
+}
+
+pub fn main() {
+    <(i32,) as X<i32>>::f("abc");
+}
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-4.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-4.stderr
new file mode 100644
index 00000000000..c41efb8b6e1
--- /dev/null
+++ b/src/test/ui/associated-types/hr-associated-type-bound-param-4.stderr
@@ -0,0 +1,19 @@
+error[E0277]: the trait bound `for<'b> <(T,) as X<'b, T>>::U: std::clone::Clone` is not satisfied
+  --> $DIR/hr-associated-type-bound-param-4.rs:13:14
+   |
+LL | trait X<'a, T>
+   |       - required by a bound in this
+...
+LL |     for<'b> <(T,) as X<'b, T>>::U: Clone,
+   |                                    ----- required by this bound in `X`
+...
+LL |     type U = str;
+   |              ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `<(T,) as X<'b, T>>::U`
+   |
+   = help: the following implementations were found:
+             <&T as std::clone::Clone>
+             <&mut T as std::clone::Clone>
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-5.rs b/src/test/ui/associated-types/hr-associated-type-bound-param-5.rs
new file mode 100644
index 00000000000..dcca0b3ce92
--- /dev/null
+++ b/src/test/ui/associated-types/hr-associated-type-bound-param-5.rs
@@ -0,0 +1,41 @@
+// ignore-tidy-linelength
+
+trait Cycle: Sized {
+    type Next: Cycle<Next = Self>;
+}
+
+impl<T> Cycle for Box<T> {
+    type Next = Vec<T>;
+}
+
+impl<T> Cycle for Vec<T> {
+    type Next = Box<T>;
+}
+
+trait X<'a, T: Cycle + for<'b> X<'b, T>>
+where
+    for<'b> <T as X<'b, T>>::U: Clone,
+    for<'b> T::Next: X<'b, T::Next>,
+    for<'b> <T::Next as X<'b, T::Next>>::U: Clone,
+{
+    type U: ?Sized;
+    fn f(x: &<T as X<'_, T>>::U) {
+        <<T as X<'_, T>>::U>::clone(x);
+    }
+}
+
+impl<S, T> X<'_, Vec<T>> for S {
+    type U = str;
+    //~^ ERROR the trait bound `for<'b> <std::boxed::Box<T> as X<'b, std::boxed::Box<T>>>::U: std::clone::Clone` is not satisfied
+    //~| ERROR the trait bound `for<'b> <std::vec::Vec<T> as X<'b, std::vec::Vec<T>>>::U: std::clone::Clone` is not satisfied
+}
+
+impl<S, T> X<'_, Box<T>> for S {
+    type U = str;
+    //~^ ERROR the trait bound `for<'b> <std::boxed::Box<T> as X<'b, std::boxed::Box<T>>>::U: std::clone::Clone` is not satisfied
+    //~| ERROR the trait bound `for<'b> <std::vec::Vec<T> as X<'b, std::vec::Vec<T>>>::U: std::clone::Clone` is not satisfied
+}
+
+pub fn main() {
+    <i32 as X<Box<i32>>>::f("abc");
+}
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr
new file mode 100644
index 00000000000..39c191e9747
--- /dev/null
+++ b/src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr
@@ -0,0 +1,67 @@
+error[E0277]: the trait bound `for<'b> <std::boxed::Box<T> as X<'b, std::boxed::Box<T>>>::U: std::clone::Clone` is not satisfied
+  --> $DIR/hr-associated-type-bound-param-5.rs:28:14
+   |
+LL | trait X<'a, T: Cycle + for<'b> X<'b, T>>
+   |       - required by a bound in this
+...
+LL |     for<'b> <T::Next as X<'b, T::Next>>::U: Clone,
+   |                                             ----- required by this bound in `X`
+...
+LL |     type U = str;
+   |              ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `<std::boxed::Box<T> as X<'b, std::boxed::Box<T>>>::U`
+   |
+   = help: the following implementations were found:
+             <&T as std::clone::Clone>
+             <&mut T as std::clone::Clone>
+
+error[E0277]: the trait bound `for<'b> <std::vec::Vec<T> as X<'b, std::vec::Vec<T>>>::U: std::clone::Clone` is not satisfied
+  --> $DIR/hr-associated-type-bound-param-5.rs:28:14
+   |
+LL | trait X<'a, T: Cycle + for<'b> X<'b, T>>
+   |       - required by a bound in this
+LL | where
+LL |     for<'b> <T as X<'b, T>>::U: Clone,
+   |                                 ----- required by this bound in `X`
+...
+LL |     type U = str;
+   |              ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `<std::vec::Vec<T> as X<'b, std::vec::Vec<T>>>::U`
+   |
+   = help: the following implementations were found:
+             <&T as std::clone::Clone>
+             <&mut T as std::clone::Clone>
+
+error[E0277]: the trait bound `for<'b> <std::vec::Vec<T> as X<'b, std::vec::Vec<T>>>::U: std::clone::Clone` is not satisfied
+  --> $DIR/hr-associated-type-bound-param-5.rs:34:14
+   |
+LL | trait X<'a, T: Cycle + for<'b> X<'b, T>>
+   |       - required by a bound in this
+...
+LL |     for<'b> <T::Next as X<'b, T::Next>>::U: Clone,
+   |                                             ----- required by this bound in `X`
+...
+LL |     type U = str;
+   |              ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `<std::vec::Vec<T> as X<'b, std::vec::Vec<T>>>::U`
+   |
+   = help: the following implementations were found:
+             <&T as std::clone::Clone>
+             <&mut T as std::clone::Clone>
+
+error[E0277]: the trait bound `for<'b> <std::boxed::Box<T> as X<'b, std::boxed::Box<T>>>::U: std::clone::Clone` is not satisfied
+  --> $DIR/hr-associated-type-bound-param-5.rs:34:14
+   |
+LL | trait X<'a, T: Cycle + for<'b> X<'b, T>>
+   |       - required by a bound in this
+LL | where
+LL |     for<'b> <T as X<'b, T>>::U: Clone,
+   |                                 ----- required by this bound in `X`
+...
+LL |     type U = str;
+   |              ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `<std::boxed::Box<T> as X<'b, std::boxed::Box<T>>>::U`
+   |
+   = help: the following implementations were found:
+             <&T as std::clone::Clone>
+             <&mut T as std::clone::Clone>
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-6.rs b/src/test/ui/associated-types/hr-associated-type-bound-param-6.rs
new file mode 100644
index 00000000000..4b8018cb430
--- /dev/null
+++ b/src/test/ui/associated-types/hr-associated-type-bound-param-6.rs
@@ -0,0 +1,20 @@
+trait X<'a, T>
+where
+    for<'b> T: X<'b, T>,
+    for<'b> <T as X<'b, T>>::U: Clone,
+{
+    type U: ?Sized;
+    fn f(x: &<T as X<'_, T>>::U) {
+        <<T as X<'_, T>>::U>::clone(x);
+    }
+}
+
+impl<S, T> X<'_, T> for (S,) {
+    //~^ ERROR the trait bound `for<'b> T: X<'b, T>` is not satisfied
+    type U = str;
+    //~^ ERROR the trait bound `for<'b> <T as X<'b, T>>::U: std::clone::Clone` is not satisfied
+}
+
+pub fn main() {
+    <(i32,) as X<i32>>::f("abc");
+}
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-6.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-6.stderr
new file mode 100644
index 00000000000..83845d3a941
--- /dev/null
+++ b/src/test/ui/associated-types/hr-associated-type-bound-param-6.stderr
@@ -0,0 +1,36 @@
+error[E0277]: the trait bound `for<'b> <T as X<'b, T>>::U: std::clone::Clone` is not satisfied
+  --> $DIR/hr-associated-type-bound-param-6.rs:14:14
+   |
+LL | trait X<'a, T>
+   |       - required by a bound in this
+...
+LL |     for<'b> <T as X<'b, T>>::U: Clone,
+   |                                 ----- required by this bound in `X`
+...
+LL |     type U = str;
+   |              ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `<T as X<'b, T>>::U`
+   |
+   = help: the following implementations were found:
+             <&T as std::clone::Clone>
+             <&mut T as std::clone::Clone>
+
+error[E0277]: the trait bound `for<'b> T: X<'b, T>` is not satisfied
+  --> $DIR/hr-associated-type-bound-param-6.rs:12:12
+   |
+LL | trait X<'a, T>
+   |       - required by a bound in this
+LL | where
+LL |     for<'b> T: X<'b, T>,
+   |                -------- required by this bound in `X`
+...
+LL | impl<S, T> X<'_, T> for (S,) {
+   |            ^^^^^^^^ the trait `for<'b> X<'b, T>` is not implemented for `T`
+   |
+help: consider restricting type parameter `T`
+   |
+LL | impl<S, T: for<'b> X<'b, T>> X<'_, T> for (S,) {
+   |          ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/associated-types/hr-associated-type-projection-1.rs b/src/test/ui/associated-types/hr-associated-type-projection-1.rs
new file mode 100644
index 00000000000..0d4567a55fc
--- /dev/null
+++ b/src/test/ui/associated-types/hr-associated-type-projection-1.rs
@@ -0,0 +1,21 @@
+trait UnsafeCopy<'a, T: Copy>
+where
+    for<'b> <Self as UnsafeCopy<'b, T>>::Item: std::ops::Deref<Target = T>,
+{
+    type Item;
+
+    fn bug(item: &Self::Item) -> () {
+        let x: T = **item;
+        &x as *const _;
+    }
+}
+
+impl<T: Copy + std::ops::Deref> UnsafeCopy<'_, T> for T {
+    //~^ ERROR the trait bound `<T as UnsafeCopy<'b, T>>::Item: std::ops::Deref` is not satisfied
+    type Item = T;
+    //~^ ERROR the trait bound `for<'b> <T as UnsafeCopy<'b, T>>::Item: std::ops::Deref
+}
+
+pub fn main() {
+    <&'static str>::bug(&"");
+}
diff --git a/src/test/ui/associated-types/hr-associated-type-projection-1.stderr b/src/test/ui/associated-types/hr-associated-type-projection-1.stderr
new file mode 100644
index 00000000000..5ab57410c44
--- /dev/null
+++ b/src/test/ui/associated-types/hr-associated-type-projection-1.stderr
@@ -0,0 +1,30 @@
+error[E0277]: the trait bound `for<'b> <T as UnsafeCopy<'b, T>>::Item: std::ops::Deref` is not satisfied
+  --> $DIR/hr-associated-type-projection-1.rs:15:17
+   |
+LL | trait UnsafeCopy<'a, T: Copy>
+   |       ---------- required by a bound in this
+LL | where
+LL |     for<'b> <Self as UnsafeCopy<'b, T>>::Item: std::ops::Deref<Target = T>,
+   |                                                --------------------------- required by this bound in `UnsafeCopy`
+...
+LL |     type Item = T;
+   |                 ^ the trait `for<'b> std::ops::Deref` is not implemented for `<T as UnsafeCopy<'b, T>>::Item`
+   |
+   = help: the following implementations were found:
+             <&T as std::ops::Deref>
+             <&mut T as std::ops::Deref>
+
+error[E0277]: the trait bound `<T as UnsafeCopy<'b, T>>::Item: std::ops::Deref` is not satisfied
+  --> $DIR/hr-associated-type-projection-1.rs:13:33
+   |
+LL | impl<T: Copy + std::ops::Deref> UnsafeCopy<'_, T> for T {
+   |                                 ^^^^^^^^^^^^^^^^^ the trait `std::ops::Deref` is not implemented for `<T as UnsafeCopy<'b, T>>::Item`
+   |
+help: consider further restricting the associated type
+   |
+LL | impl<T: Copy + std::ops::Deref> UnsafeCopy<'_, T> for T where <T as UnsafeCopy<'b, T>>::Item: std::ops::Deref {
+   |                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/feature-gates/feature-gate-generic_associated_types.rs b/src/test/ui/feature-gates/feature-gate-generic_associated_types.rs
index 7ff348aca7c..17548d7b9e8 100644
--- a/src/test/ui/feature-gates/feature-gate-generic_associated_types.rs
+++ b/src/test/ui/feature-gates/feature-gate-generic_associated_types.rs
@@ -3,11 +3,9 @@ use std::ops::Deref;
 trait PointerFamily<U> {
     type Pointer<T>: Deref<Target = T>;
     //~^ ERROR generic associated types are unstable
-    //~| ERROR type-generic associated types are not yet implemented
     type Pointer2<T>: Deref<Target = T> where T: Clone, U: Clone;
     //~^ ERROR generic associated types are unstable
     //~| ERROR where clauses on associated types are unstable
-    //~| ERROR type-generic associated types are not yet implemented
 }
 
 struct Foo;
diff --git a/src/test/ui/feature-gates/feature-gate-generic_associated_types.stderr b/src/test/ui/feature-gates/feature-gate-generic_associated_types.stderr
index a0e06cb2b67..8499b1ab70f 100644
--- a/src/test/ui/feature-gates/feature-gate-generic_associated_types.stderr
+++ b/src/test/ui/feature-gates/feature-gate-generic_associated_types.stderr
@@ -8,7 +8,7 @@ LL |     type Pointer<T>: Deref<Target = T>;
    = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable
 
 error[E0658]: generic associated types are unstable
-  --> $DIR/feature-gate-generic_associated_types.rs:7:5
+  --> $DIR/feature-gate-generic_associated_types.rs:6:5
    |
 LL |     type Pointer2<T>: Deref<Target = T> where T: Clone, U: Clone;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -17,7 +17,7 @@ LL |     type Pointer2<T>: Deref<Target = T> where T: Clone, U: Clone;
    = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable
 
 error[E0658]: where clauses on associated types are unstable
-  --> $DIR/feature-gate-generic_associated_types.rs:7:5
+  --> $DIR/feature-gate-generic_associated_types.rs:6:5
    |
 LL |     type Pointer2<T>: Deref<Target = T> where T: Clone, U: Clone;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -26,7 +26,7 @@ LL |     type Pointer2<T>: Deref<Target = T> where T: Clone, U: Clone;
    = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable
 
 error[E0658]: generic associated types are unstable
-  --> $DIR/feature-gate-generic_associated_types.rs:16:5
+  --> $DIR/feature-gate-generic_associated_types.rs:14:5
    |
 LL |     type Pointer<Usize> = Box<Usize>;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -35,7 +35,7 @@ LL |     type Pointer<Usize> = Box<Usize>;
    = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable
 
 error[E0658]: generic associated types are unstable
-  --> $DIR/feature-gate-generic_associated_types.rs:18:5
+  --> $DIR/feature-gate-generic_associated_types.rs:16:5
    |
 LL |     type Pointer2<U32> = Box<U32>;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -44,7 +44,7 @@ LL |     type Pointer2<U32> = Box<U32>;
    = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable
 
 error[E0658]: where clauses on associated types are unstable
-  --> $DIR/feature-gate-generic_associated_types.rs:23:5
+  --> $DIR/feature-gate-generic_associated_types.rs:21:5
    |
 LL |     type Assoc where Self: Sized;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -53,7 +53,7 @@ LL |     type Assoc where Self: Sized;
    = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable
 
 error[E0658]: where clauses on associated types are unstable
-  --> $DIR/feature-gate-generic_associated_types.rs:28:5
+  --> $DIR/feature-gate-generic_associated_types.rs:26:5
    |
 LL |     type Assoc where Self: Sized = Foo;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -61,22 +61,6 @@ LL |     type Assoc where Self: Sized = Foo;
    = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
    = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable
 
-error: type-generic associated types are not yet implemented
-  --> $DIR/feature-gate-generic_associated_types.rs:4:5
-   |
-LL |     type Pointer<T>: Deref<Target = T>;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
-
-error: type-generic associated types are not yet implemented
-  --> $DIR/feature-gate-generic_associated_types.rs:7:5
-   |
-LL |     type Pointer2<T>: Deref<Target = T> where T: Clone, U: Clone;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
-
-error: aborting due to 9 previous errors
+error: aborting due to 7 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/generic-associated-types/collections-project-default.rs b/src/test/ui/generic-associated-types/collections-project-default.rs
new file mode 100644
index 00000000000..5fbae02573c
--- /dev/null
+++ b/src/test/ui/generic-associated-types/collections-project-default.rs
@@ -0,0 +1,72 @@
+#![allow(incomplete_features)]
+#![feature(generic_associated_types)]
+#![feature(associated_type_defaults)]
+
+// A Collection trait and collection families. Based on
+// http://smallcultfollowing.com/babysteps/blog/2016/11/03/
+// associated-type-constructors-part-2-family-traits/
+
+// check that we don't normalize with trait defaults.
+
+trait Collection<T> {
+    type Iter<'iter>: Iterator<Item=&'iter T> where T: 'iter;
+    type Family: CollectionFamily;
+    // Test associated type defaults with parameters
+    type Sibling<U>: Collection<U> =
+        <<Self as Collection<T>>::Family as CollectionFamily>::Member<U>;
+
+    fn empty() -> Self;
+
+    fn add(&mut self, value: T);
+
+    fn iterate<'iter>(&'iter self) -> Self::Iter<'iter>;
+}
+
+trait CollectionFamily {
+    type Member<T>: Collection<T, Family = Self>;
+}
+
+struct VecFamily;
+
+impl CollectionFamily for VecFamily {
+    type Member<T> = Vec<T>;
+}
+
+impl<T> Collection<T> for Vec<T> {
+    type Iter<'iter> where T: 'iter = std::slice::Iter<'iter, T>;
+    type Family = VecFamily;
+
+    fn empty() -> Self {
+        Vec::new()
+    }
+
+    fn add(&mut self, value: T) {
+        self.push(value)
+    }
+
+    fn iterate<'iter>(&'iter self) -> Self::Iter<'iter> {
+        self.iter()
+    }
+}
+
+fn floatify_sibling<C>(ints: &C) -> <C as Collection<i32>>::Sibling<f32>
+where
+    C: Collection<i32>,
+{
+    let mut res = <C::Family as CollectionFamily>::Member::<f32>::empty();
+    for &v in ints.iterate() {
+        res.add(v as f32);
+    }
+    res
+    //~^ ERROR mismatched types
+}
+
+fn use_floatify() {
+    let a = vec![1i32, 2, 3];
+    let c = floatify_sibling(&a);
+    assert_eq!(Some(&1.0), c.iterate().next());
+}
+
+fn main() {
+    use_floatify();
+}
diff --git a/src/test/ui/generic-associated-types/collections-project-default.stderr b/src/test/ui/generic-associated-types/collections-project-default.stderr
new file mode 100644
index 00000000000..ca02b2603ba
--- /dev/null
+++ b/src/test/ui/generic-associated-types/collections-project-default.stderr
@@ -0,0 +1,15 @@
+error[E0308]: mismatched types
+  --> $DIR/collections-project-default.rs:60:5
+   |
+LL | fn floatify_sibling<C>(ints: &C) -> <C as Collection<i32>>::Sibling<f32>
+   |                                     ------------------------------------ expected `<C as Collection<i32>>::Sibling<f32>` because of return type
+...
+LL |     res
+   |     ^^^ expected Collection::Sibling, found CollectionFamily::Member
+   |
+   = note: expected associated type `<C as Collection<i32>>::Sibling<f32>`
+              found associated type `<<C as Collection<i32>>::Family as CollectionFamily>::Member<f32>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/generic-associated-types/collections.rs b/src/test/ui/generic-associated-types/collections.rs
index 6f018f04018..1b5b9c181fb 100644
--- a/src/test/ui/generic-associated-types/collections.rs
+++ b/src/test/ui/generic-associated-types/collections.rs
@@ -6,13 +6,14 @@
 // http://smallcultfollowing.com/babysteps/blog/2016/11/03/
 // associated-type-constructors-part-2-family-traits/
 
+// run-pass
+
 trait Collection<T> {
-    type Iter<'iter>: Iterator<Item=&'iter T>;
+    type Iter<'iter>: Iterator<Item=&'iter T> where T: 'iter;
     type Family: CollectionFamily;
     // Test associated type defaults with parameters
     type Sibling<U>: Collection<U> =
         <<Self as Collection<T>>::Family as CollectionFamily>::Member<U>;
-    //~^^ ERROR type-generic associated types are not yet implemented
 
     fn empty() -> Self;
 
@@ -23,7 +24,6 @@ trait Collection<T> {
 
 trait CollectionFamily {
     type Member<T>: Collection<T, Family = Self>;
-    //~^ ERROR type-generic associated types are not yet implemented
 }
 
 struct VecFamily;
@@ -33,7 +33,7 @@ impl CollectionFamily for VecFamily {
 }
 
 impl<T> Collection<T> for Vec<T> {
-    type Iter<'iter> = std::slice::Iter<'iter, T>;
+    type Iter<'iter> where T: 'iter = std::slice::Iter<'iter, T>;
     type Family = VecFamily;
 
     fn empty() -> Self {
@@ -53,18 +53,7 @@ fn floatify<C>(ints: &C) -> <<C as Collection<i32>>::Family as CollectionFamily>
 where
     C: Collection<i32>,
 {
-    let mut res = C::Family::Member::<f32>::empty();
-    for &v in ints.iterate() {
-        res.add(v as f32);
-    }
-    res
-}
-
-fn floatify_sibling<C>(ints: &C) -> <C as Collection<i32>>::Sibling<f32>
-where
-    C: Collection<i32>,
-{
-    let mut res = C::Family::Member::<f32>::empty();
+    let mut res = <C::Family as CollectionFamily>::Member::<f32>::empty();
     for &v in ints.iterate() {
         res.add(v as f32);
     }
@@ -72,11 +61,11 @@ where
 }
 
 fn use_floatify() {
-    let a = vec![1i32, 2, 3];
-    let b = floatify(a);
-    println!("{}", b.iterate().next());
-    let c = floatify_sibling(a);
-    println!("{}", c.iterate().next());
+    let a = vec![1, 2, 3];
+    let b = floatify(&a);
+    assert_eq!(Some(&1.0), b.iterate().next());
 }
 
-fn main() {}
+fn main() {
+    use_floatify();
+}
diff --git a/src/test/ui/generic-associated-types/collections.stderr b/src/test/ui/generic-associated-types/collections.stderr
deleted file mode 100644
index fb06d5e49a3..00000000000
--- a/src/test/ui/generic-associated-types/collections.stderr
+++ /dev/null
@@ -1,19 +0,0 @@
-error: type-generic associated types are not yet implemented
-  --> $DIR/collections.rs:13:5
-   |
-LL | /     type Sibling<U>: Collection<U> =
-LL | |         <<Self as Collection<T>>::Family as CollectionFamily>::Member<U>;
-   | |_________________________________________________________________________^
-   |
-   = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
-
-error: type-generic associated types are not yet implemented
-  --> $DIR/collections.rs:25:5
-   |
-LL |     type Member<T>: Collection<T, Family = Self>;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
-
-error: aborting due to 2 previous errors
-
diff --git a/src/test/ui/generic-associated-types/construct_with_other_type.rs b/src/test/ui/generic-associated-types/construct_with_other_type.rs
index 2198b99db25..ff9d61658f4 100644
--- a/src/test/ui/generic-associated-types/construct_with_other_type.rs
+++ b/src/test/ui/generic-associated-types/construct_with_other_type.rs
@@ -1,7 +1,7 @@
 #![allow(incomplete_features)]
 #![feature(generic_associated_types)]
 
-// FIXME(#30472) normalize enough to handle this.
+// check-pass
 
 use std::ops::Deref;
 
@@ -17,7 +17,6 @@ trait Baz {
 }
 
 impl<T> Baz for T where T: Foo {
-//~^ ERROR type mismatch resolving
     type Quux<'a> where T: 'a = T;
 
     type Baa<'a> where T: 'a = &'a <T as Foo>::Bar<'a, 'static>;
diff --git a/src/test/ui/generic-associated-types/construct_with_other_type.stderr b/src/test/ui/generic-associated-types/construct_with_other_type.stderr
deleted file mode 100644
index b9468b3330b..00000000000
--- a/src/test/ui/generic-associated-types/construct_with_other_type.stderr
+++ /dev/null
@@ -1,18 +0,0 @@
-error[E0271]: type mismatch resolving `for<'a> <<T as Baz>::Baa<'a> as std::ops::Deref>::Target == <<T as Baz>::Quux<'a> as Foo>::Bar<'a, 'static>`
-  --> $DIR/construct_with_other_type.rs:19:9
-   |
-LL | impl<T> Baz for T where T: Foo {
-   |      -  ^^^ expected type parameter `T`, found associated type
-   |      |
-   |      this type parameter
-   |
-   = note: expected associated type `<T as Foo>::Bar<'_, 'static>`
-              found associated type `<<T as Baz>::Quux<'_> as Foo>::Bar<'_, 'static>`
-help: consider further restricting this bound
-   |
-LL | impl<T> Baz for T where T: Foo + Baz<Quux = T> {
-   |                                ^^^^^^^^^^^^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0271`.
diff --git a/src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature-2.rs b/src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature-2.rs
index f88df6a608a..c1d68812e93 100644
--- a/src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature-2.rs
+++ b/src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature-2.rs
@@ -6,7 +6,6 @@ struct Foo;
 trait MyTrait {
     type Item<T>;
     //~^ ERROR generic associated types are unstable [E0658]
-    //~| ERROR type-generic associated types are not yet implemented
 }
 
 impl MyTrait for Foo {
diff --git a/src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature-2.stderr b/src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature-2.stderr
index f3da27775ad..34f536dbe8f 100644
--- a/src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature-2.stderr
+++ b/src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature-2.stderr
@@ -8,7 +8,7 @@ LL |     type Item<T>;
    = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable
 
 error[E0658]: generic associated types are unstable
-  --> $DIR/gat-dont-ice-on-absent-feature-2.rs:13:5
+  --> $DIR/gat-dont-ice-on-absent-feature-2.rs:12:5
    |
 LL |     type Item<T> = T;
    |     ^^^^^^^^^^^^^^^^^
@@ -16,14 +16,6 @@ LL |     type Item<T> = T;
    = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
    = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable
 
-error: type-generic associated types are not yet implemented
-  --> $DIR/gat-dont-ice-on-absent-feature-2.rs:7:5
-   |
-LL |     type Item<T>;
-   |     ^^^^^^^^^^^^^
-   |
-   = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/generic-associated-types/generic-associated-types-where.rs b/src/test/ui/generic-associated-types/generic-associated-types-where.rs
index 589024e1621..1a94796535c 100644
--- a/src/test/ui/generic-associated-types/generic-associated-types-where.rs
+++ b/src/test/ui/generic-associated-types/generic-associated-types-where.rs
@@ -9,11 +9,8 @@ use std::fmt::{Display, Debug};
 trait Foo {
     type Assoc where Self: Sized;
     type Assoc2<T> where T: Display;
-    //~^ ERROR type-generic associated types are not yet implemented
     type Assoc3<T>;
-    //~^ ERROR type-generic associated types are not yet implemented
-    type WithDefault<'a, T: Debug + 'a> = dyn Iterator<Item=T>;
-    //~^ ERROR type-generic associated types are not yet implemented
+    type WithDefault<'a, T: Debug + 'a>: ?Sized = dyn Iterator<Item=T>;
     type NoGenerics;
 }
 
@@ -23,6 +20,7 @@ impl Foo for Bar {
     type Assoc = usize;
     type Assoc2<T> = Vec<T>;
     type Assoc3<T> where T: Iterator = Vec<T>;
+    //~^ impl has stricter requirements than trait
     type WithDefault<'a, T: Debug + 'a> = &'a dyn Iterator<Item=T>;
     type NoGenerics = ::std::cell::Cell<i32>;
 }
diff --git a/src/test/ui/generic-associated-types/generic-associated-types-where.stderr b/src/test/ui/generic-associated-types/generic-associated-types-where.stderr
index fb29b377a16..4d02f2c46a6 100644
--- a/src/test/ui/generic-associated-types/generic-associated-types-where.stderr
+++ b/src/test/ui/generic-associated-types/generic-associated-types-where.stderr
@@ -1,26 +1,12 @@
-error: type-generic associated types are not yet implemented
-  --> $DIR/generic-associated-types-where.rs:11:5
-   |
-LL |     type Assoc2<T> where T: Display;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
-
-error: type-generic associated types are not yet implemented
-  --> $DIR/generic-associated-types-where.rs:13:5
+error[E0276]: impl has stricter requirements than trait
+  --> $DIR/generic-associated-types-where.rs:22:5
    |
 LL |     type Assoc3<T>;
-   |     ^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
-
-error: type-generic associated types are not yet implemented
-  --> $DIR/generic-associated-types-where.rs:15:5
-   |
-LL |     type WithDefault<'a, T: Debug + 'a> = dyn Iterator<Item=T>;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+   |     --------------- definition of `Assoc3` from trait
+...
+LL |     type Assoc3<T> where T: Iterator = Vec<T>;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: std::iter::Iterator`
 
-error: aborting due to 3 previous errors
+error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0276`.
diff --git a/src/test/ui/generic-associated-types/issue-47206-where-clause.rs b/src/test/ui/generic-associated-types/issue-47206-where-clause.rs
index 53e350aacf8..de2b978460f 100644
--- a/src/test/ui/generic-associated-types/issue-47206-where-clause.rs
+++ b/src/test/ui/generic-associated-types/issue-47206-where-clause.rs
@@ -5,13 +5,13 @@
 
 trait Foo {
     type Assoc3<T>;
-    //~^ type-generic associated types are not yet implemented
 }
 
 struct Bar;
 
 impl Foo for Bar {
     type Assoc3<T> where T: Iterator = Vec<T>;
+    //~^ ERROR impl has stricter requirements than trait
 }
 
 fn main() {}
diff --git a/src/test/ui/generic-associated-types/issue-47206-where-clause.stderr b/src/test/ui/generic-associated-types/issue-47206-where-clause.stderr
index c9c1a4753b0..bc5c40ff029 100644
--- a/src/test/ui/generic-associated-types/issue-47206-where-clause.stderr
+++ b/src/test/ui/generic-associated-types/issue-47206-where-clause.stderr
@@ -1,10 +1,12 @@
-error: type-generic associated types are not yet implemented
-  --> $DIR/issue-47206-where-clause.rs:7:5
+error[E0276]: impl has stricter requirements than trait
+  --> $DIR/issue-47206-where-clause.rs:13:5
    |
 LL |     type Assoc3<T>;
-   |     ^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+   |     --------------- definition of `Assoc3` from trait
+...
+LL |     type Assoc3<T> where T: Iterator = Vec<T>;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: std::iter::Iterator`
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0276`.
diff --git a/src/test/ui/generic-associated-types/issue-62326-parameter-out-of-range.rs b/src/test/ui/generic-associated-types/issue-62326-parameter-out-of-range.rs
index 1a79dbf2279..404be59a36d 100644
--- a/src/test/ui/generic-associated-types/issue-62326-parameter-out-of-range.rs
+++ b/src/test/ui/generic-associated-types/issue-62326-parameter-out-of-range.rs
@@ -1,11 +1,14 @@
 #![allow(incomplete_features)]
 #![feature(generic_associated_types)]
 
-// FIXME(generic-associated-types) Investigate why this doesn't compile.
+// check-pass
 
 trait Iterator {
     type Item<'a>: 'a;
-    //~^ ERROR the requirement `for<'a> <Self as Iterator>::Item<'a>: 'a` is not satisfied
+}
+
+impl Iterator for () {
+    type Item<'a> = &'a ();
 }
 
 fn main() {}
diff --git a/src/test/ui/generic-associated-types/issue-62326-parameter-out-of-range.stderr b/src/test/ui/generic-associated-types/issue-62326-parameter-out-of-range.stderr
deleted file mode 100644
index 4b06baa09ff..00000000000
--- a/src/test/ui/generic-associated-types/issue-62326-parameter-out-of-range.stderr
+++ /dev/null
@@ -1,10 +0,0 @@
-error[E0280]: the requirement `for<'a> <Self as Iterator>::Item<'a>: 'a` is not satisfied
-  --> $DIR/issue-62326-parameter-out-of-range.rs:7:20
-   |
-LL | trait Iterator {
-   |       -------- required by a bound in this
-LL |     type Item<'a>: 'a;
-   |                    ^^ required by this bound in `Iterator`
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/generic-associated-types/issue-67424.rs b/src/test/ui/generic-associated-types/issue-67424.rs
index 9b616b8abc2..fa35a3e8b04 100644
--- a/src/test/ui/generic-associated-types/issue-67424.rs
+++ b/src/test/ui/generic-associated-types/issue-67424.rs
@@ -7,7 +7,6 @@ trait Trait1 {
 trait Trait2 {
     type Type1<B>: Trait1<A=B>;
     //~^ ERROR: generic associated types are unstable
-    //~| ERROR: type-generic associated types are not yet implemented
 }
 
 fn main() {}
diff --git a/src/test/ui/generic-associated-types/issue-67424.stderr b/src/test/ui/generic-associated-types/issue-67424.stderr
index 8b08c71759b..bbb7d56f592 100644
--- a/src/test/ui/generic-associated-types/issue-67424.stderr
+++ b/src/test/ui/generic-associated-types/issue-67424.stderr
@@ -7,14 +7,6 @@ LL |     type Type1<B>: Trait1<A=B>;
    = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
    = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable
 
-error: type-generic associated types are not yet implemented
-  --> $DIR/issue-67424.rs:8:5
-   |
-LL |     type Type1<B>: Trait1<A=B>;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.rs b/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.rs
new file mode 100644
index 00000000000..71f9b2967dc
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.rs
@@ -0,0 +1,32 @@
+// Regression test for #68641
+
+#![feature(generic_associated_types)]
+//~^ WARNING the feature `generic_associated_types` is incomplete and may not
+
+trait UnsafeCopy {
+    type Item<'a>: Copy;
+
+    fn copy<'a>(item: &Self::Item<'a>) -> Self::Item<'a> {
+        *item
+    }
+}
+
+impl<T> UnsafeCopy for T {
+    type Item<'a> = T;
+    //~^ ERROR the trait bound `T: std::marker::Copy` is not satisfied
+}
+
+fn main() {
+    let mut s = String::from("Hello world!");
+
+    let copy = String::copy(&s);
+
+    // Do we indeed point to the samme memory?
+    assert!(s.as_ptr() == copy.as_ptr());
+
+    // Any use of `copy` is certeinly UB after this
+    drop(s);
+
+    // UB UB UB UB UB!!
+    println!("{}", copy);
+}
diff --git a/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr b/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr
new file mode 100644
index 00000000000..834bc3b7878
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr
@@ -0,0 +1,26 @@
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-68641-check-gat-bounds.rs:3:12
+   |
+LL | #![feature(generic_associated_types)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
+  --> $DIR/issue-68641-check-gat-bounds.rs:15:5
+   |
+LL |     type Item<'a>: Copy;
+   |     -------------------- required by `UnsafeCopy::Item`
+...
+LL |     type Item<'a> = T;
+   |     ^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
+   |
+help: consider restricting type parameter `T`
+   |
+LL | impl<T: std::marker::Copy> UnsafeCopy for T {
+   |       ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.rs b/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.rs
new file mode 100644
index 00000000000..c99073c1328
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.rs
@@ -0,0 +1,21 @@
+// Regression test for #68642
+
+#![feature(generic_associated_types)]
+//~^ WARNING the feature `generic_associated_types` is incomplete and may not
+
+trait Fun {
+    type F<'a>: Fn() -> u32;
+
+    fn callme<'a>(f: Self::F<'a>) -> u32 {
+        f()
+    }
+}
+
+impl<T> Fun for T {
+    type F<'a> = Self;
+    //~^ ERROR expected a `std::ops::Fn<()>` closure, found `T`
+}
+
+fn main() {
+    <fn() -> usize>::callme(|| 1);
+}
diff --git a/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr b/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr
new file mode 100644
index 00000000000..89cc5dfd060
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr
@@ -0,0 +1,28 @@
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-68642-broken-llvm-ir.rs:3:12
+   |
+LL | #![feature(generic_associated_types)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+error[E0277]: expected a `std::ops::Fn<()>` closure, found `T`
+  --> $DIR/issue-68642-broken-llvm-ir.rs:15:5
+   |
+LL |     type F<'a>: Fn() -> u32;
+   |     ------------------------ required by `Fun::F`
+...
+LL |     type F<'a> = Self;
+   |     ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T`
+   |
+   = help: the trait `std::ops::Fn<()>` is not implemented for `T`
+   = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }
+help: consider restricting type parameter `T`
+   |
+LL | impl<T: std::ops::Fn<()>> Fun for T {
+   |       ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/generic-associated-types/issue-68643-broken-mir.rs b/src/test/ui/generic-associated-types/issue-68643-broken-mir.rs
new file mode 100644
index 00000000000..24133e75ccc
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-68643-broken-mir.rs
@@ -0,0 +1,21 @@
+// Regression test for #68643
+
+#![feature(generic_associated_types)]
+//~^ WARNING the feature `generic_associated_types` is incomplete and may not
+
+trait Fun {
+    type F<'a>: Fn() -> u32;
+
+    fn callme<'a>(f: Self::F<'a>) -> u32 {
+        f()
+    }
+}
+
+impl<T> Fun for T {
+    type F<'a> = Self;
+    //~^ ERROR expected a `std::ops::Fn<()>` closure, found `T`
+}
+
+pub fn main() {
+    <fn()>::callme(|| {});
+}
diff --git a/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr b/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr
new file mode 100644
index 00000000000..efd3287853f
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr
@@ -0,0 +1,28 @@
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-68643-broken-mir.rs:3:12
+   |
+LL | #![feature(generic_associated_types)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+error[E0277]: expected a `std::ops::Fn<()>` closure, found `T`
+  --> $DIR/issue-68643-broken-mir.rs:15:5
+   |
+LL |     type F<'a>: Fn() -> u32;
+   |     ------------------------ required by `Fun::F`
+...
+LL |     type F<'a> = Self;
+   |     ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T`
+   |
+   = help: the trait `std::ops::Fn<()>` is not implemented for `T`
+   = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }
+help: consider restricting type parameter `T`
+   |
+LL | impl<T: std::ops::Fn<()>> Fun for T {
+   |       ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/generic-associated-types/issue-68644-codegen-selection.rs b/src/test/ui/generic-associated-types/issue-68644-codegen-selection.rs
new file mode 100644
index 00000000000..22620c61b83
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-68644-codegen-selection.rs
@@ -0,0 +1,21 @@
+// Regression test for #68644
+
+#![feature(generic_associated_types)]
+//~^ WARNING the feature `generic_associated_types` is incomplete and may not
+
+trait Fun {
+    type F<'a>: Fn() -> u32;
+
+    fn callme<'a>(f: Self::F<'a>) -> u32 {
+        f()
+    }
+}
+
+impl<T> Fun for T {
+    type F<'a> = Self;
+    //~^ ERROR expected a `std::ops::Fn<()>` closure, found `T`
+}
+
+fn main() {
+    <u8>::callme(0);
+}
diff --git a/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr b/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr
new file mode 100644
index 00000000000..5da924a512f
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr
@@ -0,0 +1,28 @@
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-68644-codegen-selection.rs:3:12
+   |
+LL | #![feature(generic_associated_types)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+error[E0277]: expected a `std::ops::Fn<()>` closure, found `T`
+  --> $DIR/issue-68644-codegen-selection.rs:15:5
+   |
+LL |     type F<'a>: Fn() -> u32;
+   |     ------------------------ required by `Fun::F`
+...
+LL |     type F<'a> = Self;
+   |     ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T`
+   |
+   = help: the trait `std::ops::Fn<()>` is not implemented for `T`
+   = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }
+help: consider restricting type parameter `T`
+   |
+LL | impl<T: std::ops::Fn<()>> Fun for T {
+   |       ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.rs b/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.rs
new file mode 100644
index 00000000000..423b80e8476
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.rs
@@ -0,0 +1,21 @@
+// Regression test for #68645
+
+#![feature(generic_associated_types)]
+//~^ WARNING the feature `generic_associated_types` is incomplete and may not
+
+trait Fun {
+    type F<'a>: Fn() -> u32;
+
+    fn callme<'a>(f: Self::F<'a>) -> u32 {
+        f()
+    }
+}
+
+impl<T> Fun for T {
+    type F<'a> = Self;
+    //~^ ERROR expected a `std::ops::Fn<()>` closure, found `T`
+}
+
+fn main() {
+    <&dyn Iterator<Item = u8>>::callme(&std::iter::once(1));
+}
diff --git a/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr b/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr
new file mode 100644
index 00000000000..12d84ab6a36
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr
@@ -0,0 +1,28 @@
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-68645-codegen-fulfillment.rs:3:12
+   |
+LL | #![feature(generic_associated_types)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+error[E0277]: expected a `std::ops::Fn<()>` closure, found `T`
+  --> $DIR/issue-68645-codegen-fulfillment.rs:15:5
+   |
+LL |     type F<'a>: Fn() -> u32;
+   |     ------------------------ required by `Fun::F`
+...
+LL |     type F<'a> = Self;
+   |     ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T`
+   |
+   = help: the trait `std::ops::Fn<()>` is not implemented for `T`
+   = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }
+help: consider restricting type parameter `T`
+   |
+LL | impl<T: std::ops::Fn<()>> Fun for T {
+   |       ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/generic-associated-types/issue-68656-unsized-values.rs b/src/test/ui/generic-associated-types/issue-68656-unsized-values.rs
new file mode 100644
index 00000000000..4ccd42ba643
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-68656-unsized-values.rs
@@ -0,0 +1,22 @@
+// Regression test for #68656
+
+#![feature(generic_associated_types)]
+//~^ WARNING the feature `generic_associated_types` is incomplete and may not
+
+trait UnsafeCopy<T: Copy> {
+    type Item<'a>: std::ops::Deref<Target = T>;
+
+    fn bug<'a>(item: &Self::Item<'a>) -> () {
+        let x: T = **item;
+        &x as *const _;
+    }
+}
+
+impl<T: Copy + std::ops::Deref> UnsafeCopy<T> for T {
+    type Item<'a> = T;
+    //~^ ERROR type mismatch resolving `<T as std::ops::Deref>::Target == T`
+}
+
+fn main() {
+    <&'static str>::bug(&"");
+}
diff --git a/src/test/ui/generic-associated-types/issue-68656-unsized-values.stderr b/src/test/ui/generic-associated-types/issue-68656-unsized-values.stderr
new file mode 100644
index 00000000000..e1ceeac3196
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-68656-unsized-values.stderr
@@ -0,0 +1,30 @@
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-68656-unsized-values.rs:3:12
+   |
+LL | #![feature(generic_associated_types)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+error[E0271]: type mismatch resolving `<T as std::ops::Deref>::Target == T`
+  --> $DIR/issue-68656-unsized-values.rs:16:5
+   |
+LL |     type Item<'a>: std::ops::Deref<Target = T>;
+   |     ------------------------------------------- required by `UnsafeCopy::Item`
+...
+LL | impl<T: Copy + std::ops::Deref> UnsafeCopy<T> for T {
+   |      - this type parameter
+LL |     type Item<'a> = T;
+   |     ^^^^^^^^^^^^^^^^^^ expected type parameter `T`, found associated type
+   |
+   = note: expected type parameter `T`
+             found associated type `<T as std::ops::Deref>::Target`
+help: consider further restricting this bound
+   |
+LL | impl<T: Copy + std::ops::Deref + std::ops::Deref<Target = T>> UnsafeCopy<T> for T {
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0271`.
diff --git a/src/test/ui/generic-associated-types/iterable.rs b/src/test/ui/generic-associated-types/iterable.rs
index 105ab4a8adc..600a69006c1 100644
--- a/src/test/ui/generic-associated-types/iterable.rs
+++ b/src/test/ui/generic-associated-types/iterable.rs
@@ -1,7 +1,7 @@
 #![allow(incomplete_features)]
 #![feature(generic_associated_types)]
 
-// FIXME(#30472) normalize enough to handle this.
+// run-pass
 
 trait Iterable {
     type Item<'a> where Self: 'a;
@@ -13,39 +13,35 @@ trait Iterable {
 // Impl for struct type
 impl<T> Iterable for Vec<T> {
     type Item<'a> where T: 'a = <std::slice::Iter<'a, T> as Iterator>::Item;
-    //~^ ERROR type mismatch resolving
     type Iter<'a> where T: 'a = std::slice::Iter<'a, T>;
 
     fn iter<'a>(&'a self) -> Self::Iter<'a> {
-    //~^ ERROR type mismatch resolving
-        self.iter()
+        self[..].iter()
     }
 }
 
 // Impl for a primitive type
 impl<T> Iterable for [T] {
     type Item<'a> where T: 'a = <std::slice::Iter<'a, T> as Iterator>::Item;
-    //~^ ERROR type mismatch resolving
     type Iter<'a> where T: 'a = std::slice::Iter<'a, T>;
 
     fn iter<'a>(&'a self) -> Self::Iter<'a> {
-    //~^ ERROR type mismatch resolving
         self.iter()
     }
 }
 
-fn make_iter<'a, I: Iterable>(it: &'a I) -> I::Iter<'a> {
+fn make_iter<'a, I: Iterable + ?Sized>(it: &'a I) -> I::Iter<'a> {
     it.iter()
 }
 
-fn get_first<'a, I: Iterable>(it: &'a I) -> Option<I::Item<'a>> {
+fn get_first<'a, I: Iterable + ?Sized>(it: &'a I) -> Option<I::Item<'a>> {
     it.iter().next()
 }
 
 fn main() {
     let v = vec![1, 2, 3];
-    assert_eq!(v, make_iter(&v).copied().collect());
-    assert_eq!(v, make_iter(&*v).copied().collect());
-    assert_eq!(1, get_first(&v));
-    assert_eq!(1, get_first(&*v));
+    assert_eq!(v, make_iter(&v).copied().collect::<Vec<_>>());
+    assert_eq!(v, make_iter(&*v).copied().collect::<Vec<_>>());
+    assert_eq!(Some(&1), get_first(&v));
+    assert_eq!(Some(&1), get_first(&*v));
 }
diff --git a/src/test/ui/generic-associated-types/iterable.stderr b/src/test/ui/generic-associated-types/iterable.stderr
deleted file mode 100644
index 6e754621225..00000000000
--- a/src/test/ui/generic-associated-types/iterable.stderr
+++ /dev/null
@@ -1,59 +0,0 @@
-error[E0271]: type mismatch resolving `for<'a> <<std::vec::Vec<T> as Iterable>::Iter<'a> as std::iter::Iterator>::Item == <std::vec::Vec<T> as Iterable>::Item<'a>`
-  --> $DIR/iterable.rs:15:33
-   |
-LL |     type Item<'a> where T: 'a = <std::slice::Iter<'a, T> as Iterator>::Item;
-   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected reference, found associated type
-   |
-   = note:    expected reference `&T`
-           found associated type `<std::vec::Vec<T> as Iterable>::Item<'_>`
-   = help: consider constraining the associated type `<std::vec::Vec<T> as Iterable>::Item<'_>` to `&_`
-   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
-
-error[E0271]: type mismatch resolving `for<'a> <<[T] as Iterable>::Iter<'a> as std::iter::Iterator>::Item == <[T] as Iterable>::Item<'a>`
-  --> $DIR/iterable.rs:27:33
-   |
-LL |     type Item<'a> where T: 'a = <std::slice::Iter<'a, T> as Iterator>::Item;
-   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected reference, found associated type
-   |
-   = note:    expected reference `&T`
-           found associated type `<[T] as Iterable>::Item<'_>`
-   = help: consider constraining the associated type `<[T] as Iterable>::Item<'_>` to `&_`
-   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
-
-error[E0271]: type mismatch resolving `for<'a> <<std::vec::Vec<T> as Iterable>::Iter<'a> as std::iter::Iterator>::Item == <std::vec::Vec<T> as Iterable>::Item<'a>`
-  --> $DIR/iterable.rs:19:30
-   |
-LL | trait Iterable {
-   |       -------- required by a bound in this
-LL |     type Item<'a> where Self: 'a;
-LL |     type Iter<'a>: Iterator<Item = Self::Item<'a>> where Self: 'a;
-   |                             --------------------- required by this bound in `Iterable`
-...
-LL |     fn iter<'a>(&'a self) -> Self::Iter<'a> {
-   |                              ^^^^^^^^^^^^^^ expected associated type, found reference
-   |
-   = note: expected associated type `<std::vec::Vec<T> as Iterable>::Item<'_>`
-                    found reference `&T`
-   = help: consider constraining the associated type `<std::vec::Vec<T> as Iterable>::Item<'_>` to `&_` or calling a method that returns `<std::vec::Vec<T> as Iterable>::Item<'_>`
-   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
-
-error[E0271]: type mismatch resolving `for<'a> <<[T] as Iterable>::Iter<'a> as std::iter::Iterator>::Item == <[T] as Iterable>::Item<'a>`
-  --> $DIR/iterable.rs:31:30
-   |
-LL | trait Iterable {
-   |       -------- required by a bound in this
-LL |     type Item<'a> where Self: 'a;
-LL |     type Iter<'a>: Iterator<Item = Self::Item<'a>> where Self: 'a;
-   |                             --------------------- required by this bound in `Iterable`
-...
-LL |     fn iter<'a>(&'a self) -> Self::Iter<'a> {
-   |                              ^^^^^^^^^^^^^^ expected associated type, found reference
-   |
-   = note: expected associated type `<[T] as Iterable>::Item<'_>`
-                    found reference `&T`
-   = help: consider constraining the associated type `<[T] as Iterable>::Item<'_>` to `&_` or calling a method that returns `<[T] as Iterable>::Item<'_>`
-   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
-
-error: aborting due to 4 previous errors
-
-For more information about this error, try `rustc --explain E0271`.
diff --git a/src/test/ui/generic-associated-types/missing-bounds.fixed b/src/test/ui/generic-associated-types/missing-bounds.fixed
index 364d2388741..3ba7d043d07 100644
--- a/src/test/ui/generic-associated-types/missing-bounds.fixed
+++ b/src/test/ui/generic-associated-types/missing-bounds.fixed
@@ -34,12 +34,11 @@ impl<B: std::ops::Add<Output = B>> Add for D<B> {
 
 struct E<B>(B);
 
-impl<B: Add> Add for E<B> where B: Add<Output = B>, B: std::ops::Add<Output = B> {
-    //~^ ERROR equality constraints are not yet supported in `where` clauses
+impl<B: Add> Add for E<B> where B: Add<Output = B> {
     type Output = Self;
 
     fn add(self, rhs: Self) -> Self {
-        Self(self.0 + rhs.0) //~ ERROR mismatched types
+        Self(self.0 + rhs.0)
     }
 }
 
diff --git a/src/test/ui/generic-associated-types/missing-bounds.rs b/src/test/ui/generic-associated-types/missing-bounds.rs
index ffafff5e9f5..962d2db9476 100644
--- a/src/test/ui/generic-associated-types/missing-bounds.rs
+++ b/src/test/ui/generic-associated-types/missing-bounds.rs
@@ -34,12 +34,11 @@ impl<B> Add for D<B> {
 
 struct E<B>(B);
 
-impl<B: Add> Add for E<B> where <B as Add>::Output = B {
-    //~^ ERROR equality constraints are not yet supported in `where` clauses
+impl<B: Add> Add for E<B> where B: Add<Output = B> {
     type Output = Self;
 
     fn add(self, rhs: Self) -> Self {
-        Self(self.0 + rhs.0) //~ ERROR mismatched types
+        Self(self.0 + rhs.0)
     }
 }
 
diff --git a/src/test/ui/generic-associated-types/missing-bounds.stderr b/src/test/ui/generic-associated-types/missing-bounds.stderr
index 50536fdaca9..630ceac093e 100644
--- a/src/test/ui/generic-associated-types/missing-bounds.stderr
+++ b/src/test/ui/generic-associated-types/missing-bounds.stderr
@@ -1,15 +1,3 @@
-error: equality constraints are not yet supported in `where` clauses
-  --> $DIR/missing-bounds.rs:37:33
-   |
-LL | impl<B: Add> Add for E<B> where <B as Add>::Output = B {
-   |                                 ^^^^^^^^^^^^^^^^^^^^^^ not supported
-   |
-   = note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
-help: if `Output` is an associated type you're trying to set, use the associated type binding syntax
-   |
-LL | impl<B: Add> Add for E<B> where B: Add<Output = B> {
-   |                                 ^^^^^^^^^^^^^^^^^^
-
 error[E0308]: mismatched types
   --> $DIR/missing-bounds.rs:11:11
    |
@@ -55,23 +43,7 @@ help: consider restricting type parameter `B`
 LL | impl<B: std::ops::Add<Output = B>> Add for D<B> {
    |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0308]: mismatched types
-  --> $DIR/missing-bounds.rs:42:14
-   |
-LL | impl<B: Add> Add for E<B> where <B as Add>::Output = B {
-   |      - this type parameter
-...
-LL |         Self(self.0 + rhs.0)
-   |              ^^^^^^^^^^^^^^ expected type parameter `B`, found associated type
-   |
-   = note: expected type parameter `B`
-             found associated type `<B as std::ops::Add>::Output`
-help: consider further restricting type parameter `B`
-   |
-LL | impl<B: Add> Add for E<B> where <B as Add>::Output = B, B: std::ops::Add<Output = B> {
-   |                                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 5 previous errors
+error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0308, E0369.
 For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/generic-associated-types/parameter_number_and_kind.rs b/src/test/ui/generic-associated-types/parameter_number_and_kind.rs
index 0edc5c48c01..f4d09fc1539 100644
--- a/src/test/ui/generic-associated-types/parameter_number_and_kind.rs
+++ b/src/test/ui/generic-associated-types/parameter_number_and_kind.rs
@@ -7,18 +7,14 @@ trait Foo {
     type B<'a, 'b>;
     type C;
     type D<T>;
-    //~^ ERROR type-generic associated types are not yet implemented
     type E<'a, T>;
-    //~^ ERROR type-generic associated types are not yet implemented
     // Test parameters in default values
     type FOk<T> = Self::E<'static, T>;
-    //~^ ERROR type-generic associated types are not yet implemented
     type FErr1 = Self::E<'static, 'static>;
     //~^ ERROR wrong number of lifetime arguments: expected 1, found 2
     //~| ERROR wrong number of type arguments: expected 1, found 0
     type FErr2<T> = Self::E<'static, T, u32>;
-    //~^ ERROR type-generic associated types are not yet implemented
-    //~| ERROR wrong number of type arguments: expected 1, found 2
+    //~^ ERROR wrong number of type arguments: expected 1, found 2
 }
 
 fn main() {}
diff --git a/src/test/ui/generic-associated-types/parameter_number_and_kind.stderr b/src/test/ui/generic-associated-types/parameter_number_and_kind.stderr
index 028ab72f488..ed090e302ce 100644
--- a/src/test/ui/generic-associated-types/parameter_number_and_kind.stderr
+++ b/src/test/ui/generic-associated-types/parameter_number_and_kind.stderr
@@ -1,53 +1,21 @@
-error: type-generic associated types are not yet implemented
-  --> $DIR/parameter_number_and_kind.rs:9:5
-   |
-LL |     type D<T>;
-   |     ^^^^^^^^^^
-   |
-   = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
-
-error: type-generic associated types are not yet implemented
-  --> $DIR/parameter_number_and_kind.rs:11:5
-   |
-LL |     type E<'a, T>;
-   |     ^^^^^^^^^^^^^^
-   |
-   = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
-
-error: type-generic associated types are not yet implemented
-  --> $DIR/parameter_number_and_kind.rs:14:5
-   |
-LL |     type FOk<T> = Self::E<'static, T>;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
-
-error: type-generic associated types are not yet implemented
-  --> $DIR/parameter_number_and_kind.rs:19:5
-   |
-LL |     type FErr2<T> = Self::E<'static, T, u32>;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
-
 error[E0107]: wrong number of lifetime arguments: expected 1, found 2
-  --> $DIR/parameter_number_and_kind.rs:16:35
+  --> $DIR/parameter_number_and_kind.rs:13:35
    |
 LL |     type FErr1 = Self::E<'static, 'static>;
    |                                   ^^^^^^^ unexpected lifetime argument
 
 error[E0107]: wrong number of type arguments: expected 1, found 0
-  --> $DIR/parameter_number_and_kind.rs:16:18
+  --> $DIR/parameter_number_and_kind.rs:13:18
    |
 LL |     type FErr1 = Self::E<'static, 'static>;
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 type argument
 
 error[E0107]: wrong number of type arguments: expected 1, found 2
-  --> $DIR/parameter_number_and_kind.rs:19:41
+  --> $DIR/parameter_number_and_kind.rs:16:41
    |
 LL |     type FErr2<T> = Self::E<'static, T, u32>;
    |                                         ^^^ unexpected type argument
 
-error: aborting due to 7 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0107`.
diff --git a/src/test/ui/generic-associated-types/pointer_family.rs b/src/test/ui/generic-associated-types/pointer_family.rs
index 1668759b4e3..b322b752a15 100644
--- a/src/test/ui/generic-associated-types/pointer_family.rs
+++ b/src/test/ui/generic-associated-types/pointer_family.rs
@@ -1,7 +1,7 @@
 #![allow(incomplete_features)]
 #![feature(generic_associated_types)]
 
-// FIXME(#44265): allow type-generic associated types.
+// check-pass
 
 use std::rc::Rc;
 use std::sync::Arc;
@@ -9,7 +9,6 @@ use std::ops::Deref;
 
 trait PointerFamily {
     type Pointer<T>: Deref<Target = T>;
-    //~^ ERROR type-generic associated types are not yet implemented
     fn new<T>(value: T) -> Self::Pointer<T>;
 }
 
diff --git a/src/test/ui/generic-associated-types/pointer_family.stderr b/src/test/ui/generic-associated-types/pointer_family.stderr
deleted file mode 100644
index 83fe992fcb5..00000000000
--- a/src/test/ui/generic-associated-types/pointer_family.stderr
+++ /dev/null
@@ -1,10 +0,0 @@
-error: type-generic associated types are not yet implemented
-  --> $DIR/pointer_family.rs:11:5
-   |
-LL |     type Pointer<T>: Deref<Target = T>;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/generic-associated-types/shadowing.rs b/src/test/ui/generic-associated-types/shadowing.rs
index 5c308948bd3..44528ca1da3 100644
--- a/src/test/ui/generic-associated-types/shadowing.rs
+++ b/src/test/ui/generic-associated-types/shadowing.rs
@@ -18,12 +18,10 @@ impl<'a> NoShadow<'a> for &'a u32 {
 trait ShadowT<T> {
     type Bar<T>;
     //~^ ERROR the name `T` is already used
-    //~| ERROR type-generic associated types are not yet implemented
 }
 
 trait NoShadowT<T> {
     type Bar<U>; // OK
-    //~^ ERROR type-generic associated types are not yet implemented
 }
 
 impl<T> NoShadowT<T> for Option<T> {
diff --git a/src/test/ui/generic-associated-types/shadowing.stderr b/src/test/ui/generic-associated-types/shadowing.stderr
index 2d9a0d6fceb..d51c29080a0 100644
--- a/src/test/ui/generic-associated-types/shadowing.stderr
+++ b/src/test/ui/generic-associated-types/shadowing.stderr
@@ -7,7 +7,7 @@ LL |     type Bar<T>;
    |              ^ already used
 
 error[E0403]: the name `T` is already used for a generic parameter in this item's generic parameters
-  --> $DIR/shadowing.rs:30:14
+  --> $DIR/shadowing.rs:28:14
    |
 LL | impl<T> NoShadowT<T> for Option<T> {
    |      - first use of `T`
@@ -30,23 +30,7 @@ LL | impl<'a> NoShadow<'a> for &'a u32 {
 LL |     type Bar<'a> = i32;
    |              ^^ lifetime 'a already in scope
 
-error: type-generic associated types are not yet implemented
-  --> $DIR/shadowing.rs:19:5
-   |
-LL |     type Bar<T>;
-   |     ^^^^^^^^^^^^
-   |
-   = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
-
-error: type-generic associated types are not yet implemented
-  --> $DIR/shadowing.rs:25:5
-   |
-LL |     type Bar<U>; // OK
-   |     ^^^^^^^^^^^^
-   |
-   = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
-
-error: aborting due to 6 previous errors
+error: aborting due to 4 previous errors
 
 Some errors have detailed explanations: E0403, E0496.
 For more information about an error, try `rustc --explain E0403`.
diff --git a/src/test/ui/generic-associated-types/unsatisfied-outlives-bound.rs b/src/test/ui/generic-associated-types/unsatisfied-outlives-bound.rs
new file mode 100644
index 00000000000..7510c58d574
--- /dev/null
+++ b/src/test/ui/generic-associated-types/unsatisfied-outlives-bound.rs
@@ -0,0 +1,22 @@
+#![allow(incomplete_features)]
+#![feature(generic_associated_types)]
+
+trait ATy {
+    type Item<'a>: 'a;
+}
+
+impl<'b> ATy for &'b () {
+    type Item<'a> = &'b ();
+    //~^ ERROR does not fulfill the required lifetime
+}
+
+trait StaticTy {
+    type Item<'a>: 'static;
+}
+
+impl StaticTy for () {
+    type Item<'a> = &'a ();
+    //~^ ERROR does not fulfill the required lifetime
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/unsatisfied-outlives-bound.stderr b/src/test/ui/generic-associated-types/unsatisfied-outlives-bound.stderr
new file mode 100644
index 00000000000..5d612284a21
--- /dev/null
+++ b/src/test/ui/generic-associated-types/unsatisfied-outlives-bound.stderr
@@ -0,0 +1,23 @@
+error[E0477]: the type `&'b ()` does not fulfill the required lifetime
+  --> $DIR/unsatisfied-outlives-bound.rs:9:5
+   |
+LL |     type Item<'a> = &'b ();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: type must outlive the lifetime `'a` as defined on the associated item at 9:15
+  --> $DIR/unsatisfied-outlives-bound.rs:9:15
+   |
+LL |     type Item<'a> = &'b ();
+   |               ^^
+
+error[E0477]: the type `&'a ()` does not fulfill the required lifetime
+  --> $DIR/unsatisfied-outlives-bound.rs:18:5
+   |
+LL |     type Item<'a> = &'a ();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: type must satisfy the static lifetime
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0477`.
diff --git a/src/test/ui/issues/issue-38091.rs b/src/test/ui/issues/issue-38091.rs
index c1262430502..a84391b94d1 100644
--- a/src/test/ui/issues/issue-38091.rs
+++ b/src/test/ui/issues/issue-38091.rs
@@ -1,4 +1,3 @@
-// run-pass
 #![feature(specialization)]
 //~^ WARN the feature `specialization` is incomplete
 
@@ -8,6 +7,7 @@ trait Iterate<'a> {
 }
 impl<'a, T> Iterate<'a> for T where T: Check {
     default type Ty = ();
+    //~^ ERROR the trait bound `(): Valid` is not satisfied
     default fn iterate(self) {}
 }
 
diff --git a/src/test/ui/issues/issue-38091.stderr b/src/test/ui/issues/issue-38091.stderr
index a9855445f66..81beec80263 100644
--- a/src/test/ui/issues/issue-38091.stderr
+++ b/src/test/ui/issues/issue-38091.stderr
@@ -1,5 +1,5 @@
 warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/issue-38091.rs:2:12
+  --> $DIR/issue-38091.rs:1:12
    |
 LL | #![feature(specialization)]
    |            ^^^^^^^^^^^^^^
@@ -7,5 +7,15 @@ LL | #![feature(specialization)]
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
 
-warning: 1 warning emitted
+error[E0277]: the trait bound `(): Valid` is not satisfied
+  --> $DIR/issue-38091.rs:9:5
+   |
+LL |     type Ty: Valid;
+   |     --------------- required by `Iterate::Ty`
+...
+LL |     default type Ty = ();
+   |     ^^^^^^^^^^^^^^^^^^^^^ the trait `Valid` is not implemented for `()`
+
+error: aborting due to previous error; 1 warning emitted
 
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/lint/lint-ctypes-73251-1.rs b/src/test/ui/lint/lint-ctypes-73251-1.rs
new file mode 100644
index 00000000000..2ce80982f5c
--- /dev/null
+++ b/src/test/ui/lint/lint-ctypes-73251-1.rs
@@ -0,0 +1,24 @@
+#![feature(type_alias_impl_trait)]
+#![deny(improper_ctypes)]
+
+pub trait Baz { }
+
+impl Baz for u32 { }
+
+type Qux = impl Baz;
+
+pub trait Foo {
+    type Assoc;
+}
+
+impl Foo for u32 {
+    type Assoc = Qux;
+}
+
+fn assign() -> Qux { 1 }
+
+extern "C" {
+    pub fn lint_me() -> <u32 as Foo>::Assoc; //~ ERROR: uses type `impl Baz`
+}
+
+fn main() {}
diff --git a/src/test/ui/lint/lint-ctypes-73251-1.stderr b/src/test/ui/lint/lint-ctypes-73251-1.stderr
new file mode 100644
index 00000000000..0b4237bb96f
--- /dev/null
+++ b/src/test/ui/lint/lint-ctypes-73251-1.stderr
@@ -0,0 +1,15 @@
+error: `extern` block uses type `impl Baz`, which is not FFI-safe
+  --> $DIR/lint-ctypes-73251-1.rs:21:25
+   |
+LL |     pub fn lint_me() -> <u32 as Foo>::Assoc;
+   |                         ^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+note: the lint level is defined here
+  --> $DIR/lint-ctypes-73251-1.rs:2:9
+   |
+LL | #![deny(improper_ctypes)]
+   |         ^^^^^^^^^^^^^^^
+   = note: opaque types have no C equivalent
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lint/lint-ctypes-73251-2.rs b/src/test/ui/lint/lint-ctypes-73251-2.rs
new file mode 100644
index 00000000000..3427c657b42
--- /dev/null
+++ b/src/test/ui/lint/lint-ctypes-73251-2.rs
@@ -0,0 +1,32 @@
+#![feature(type_alias_impl_trait)]
+#![deny(improper_ctypes)]
+
+pub trait TraitA {
+    type Assoc;
+}
+
+impl TraitA for u32 {
+    type Assoc = u32;
+}
+
+pub trait TraitB {
+    type Assoc;
+}
+
+impl<T> TraitB for T where T: TraitA {
+    type Assoc = <T as TraitA>::Assoc;
+}
+
+type AliasA = impl TraitA<Assoc = u32>;
+
+type AliasB = impl TraitB<Assoc = AliasA>;
+
+fn use_of_a() -> AliasA { 3 }
+
+fn use_of_b() -> AliasB { 3 }
+
+extern "C" {
+    pub fn lint_me() -> <AliasB as TraitB>::Assoc; //~ ERROR: uses type `impl TraitA`
+}
+
+fn main() {}
diff --git a/src/test/ui/lint/lint-ctypes-73251-2.stderr b/src/test/ui/lint/lint-ctypes-73251-2.stderr
new file mode 100644
index 00000000000..43f7629b043
--- /dev/null
+++ b/src/test/ui/lint/lint-ctypes-73251-2.stderr
@@ -0,0 +1,15 @@
+error: `extern` block uses type `impl TraitA`, which is not FFI-safe
+  --> $DIR/lint-ctypes-73251-2.rs:29:25
+   |
+LL |     pub fn lint_me() -> <AliasB as TraitB>::Assoc;
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+note: the lint level is defined here
+  --> $DIR/lint-ctypes-73251-2.rs:2:9
+   |
+LL | #![deny(improper_ctypes)]
+   |         ^^^^^^^^^^^^^^^
+   = note: opaque types have no C equivalent
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lint/lint-ctypes-73251.rs b/src/test/ui/lint/lint-ctypes-73251.rs
new file mode 100644
index 00000000000..ebc2ca77b67
--- /dev/null
+++ b/src/test/ui/lint/lint-ctypes-73251.rs
@@ -0,0 +1,22 @@
+// check-pass
+
+#![feature(type_alias_impl_trait)]
+#![deny(improper_ctypes)]
+
+pub trait Foo {
+    type Assoc;
+}
+
+impl Foo for () {
+    type Assoc = u32;
+}
+
+type Bar = impl Foo<Assoc = u32>;
+
+fn assign() -> Bar {}
+
+extern "C" {
+    pub fn lint_me() -> <Bar as Foo>::Assoc;
+}
+
+fn main() {}
diff --git a/src/test/ui/specialization/deafult-associated-type-bound-1.rs b/src/test/ui/specialization/deafult-associated-type-bound-1.rs
new file mode 100644
index 00000000000..272a5e3fe10
--- /dev/null
+++ b/src/test/ui/specialization/deafult-associated-type-bound-1.rs
@@ -0,0 +1,24 @@
+// Check that we check that default associated types satisfy the required
+// bounds on them.
+
+#![feature(specialization)]
+//~^ WARNING `specialization` is incomplete
+
+trait X {
+    type U: Clone;
+    fn unsafe_clone(&self, x: Option<&Self::U>) {
+        x.cloned();
+    }
+}
+
+// We cannot normalize `<T as X>::U` to `str` here, because the default could
+// be overridden. The error here must therefore be found by a method other than
+// normalization.
+impl<T> X for T {
+    default type U = str;
+    //~^ ERROR the trait bound `str: std::clone::Clone` is not satisfied
+}
+
+pub fn main() {
+    1.unsafe_clone(None);
+}
diff --git a/src/test/ui/specialization/deafult-associated-type-bound-1.stderr b/src/test/ui/specialization/deafult-associated-type-bound-1.stderr
new file mode 100644
index 00000000000..90ad5d4c155
--- /dev/null
+++ b/src/test/ui/specialization/deafult-associated-type-bound-1.stderr
@@ -0,0 +1,21 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/deafult-associated-type-bound-1.rs:4:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+error[E0277]: the trait bound `str: std::clone::Clone` is not satisfied
+  --> $DIR/deafult-associated-type-bound-1.rs:18:5
+   |
+LL |     type U: Clone;
+   |     -------------- required by `X::U`
+...
+LL |     default type U = str;
+   |     ^^^^^^^^^^^^^^^^^^^^^ the trait `std::clone::Clone` is not implemented for `str`
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/specialization/deafult-associated-type-bound-2.rs b/src/test/ui/specialization/deafult-associated-type-bound-2.rs
new file mode 100644
index 00000000000..0a21b1f0910
--- /dev/null
+++ b/src/test/ui/specialization/deafult-associated-type-bound-2.rs
@@ -0,0 +1,22 @@
+// Check that generic predicates are also checked for default associated types.
+#![feature(specialization)]
+//~^ WARNING `specialization` is incomplete
+
+trait X<T> {
+    type U: PartialEq<T>;
+    fn unsafe_compare(x: Option<Self::U>, y: Option<T>) {
+        match (x, y) {
+            (Some(a), Some(b)) => a == b,
+            _ => false,
+        };
+    }
+}
+
+impl<B: 'static, T> X<B> for T {
+    default type U = &'static B;
+    //~^ ERROR can't compare `&'static B` with `B`
+}
+
+pub fn main() {
+    <i32 as X<i32>>::unsafe_compare(None, None);
+}
diff --git a/src/test/ui/specialization/deafult-associated-type-bound-2.stderr b/src/test/ui/specialization/deafult-associated-type-bound-2.stderr
new file mode 100644
index 00000000000..ea40f846e36
--- /dev/null
+++ b/src/test/ui/specialization/deafult-associated-type-bound-2.stderr
@@ -0,0 +1,23 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/deafult-associated-type-bound-2.rs:2:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+error[E0277]: can't compare `&'static B` with `B`
+  --> $DIR/deafult-associated-type-bound-2.rs:16:5
+   |
+LL |     type U: PartialEq<T>;
+   |     --------------------- required by `X::U`
+...
+LL |     default type U = &'static B;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `&'static B == B`
+   |
+   = help: the trait `std::cmp::PartialEq<B>` is not implemented for `&'static B`
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/specialization/deafult-generic-associated-type-bound.rs b/src/test/ui/specialization/deafult-generic-associated-type-bound.rs
new file mode 100644
index 00000000000..8a94ea658d2
--- /dev/null
+++ b/src/test/ui/specialization/deafult-generic-associated-type-bound.rs
@@ -0,0 +1,27 @@
+// Check that default generics associated types are validated.
+
+#![feature(specialization)]
+#![feature(generic_associated_types)]
+//~^^ WARNING `specialization` is incomplete
+//~^^ WARNING the feature `generic_associated_types` is incomplete
+
+trait X {
+    type U<'a>: PartialEq<&'a Self>;
+    fn unsafe_compare<'b>(x: Option<Self::U<'b>>, y: Option<&'b Self>) {
+        match (x, y) {
+            (Some(a), Some(b)) => a == b,
+            _ => false,
+        };
+    }
+}
+
+impl<T: 'static> X for T {
+    default type U<'a> = &'a T;
+    //~^ ERROR can't compare `T` with `T`
+}
+
+struct NotComparable;
+
+pub fn main() {
+    <NotComparable as X>::unsafe_compare(None, None);
+}
diff --git a/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr b/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr
new file mode 100644
index 00000000000..7f3c49e753f
--- /dev/null
+++ b/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr
@@ -0,0 +1,36 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/deafult-generic-associated-type-bound.rs:3:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/deafult-generic-associated-type-bound.rs:4:12
+   |
+LL | #![feature(generic_associated_types)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+error[E0277]: can't compare `T` with `T`
+  --> $DIR/deafult-generic-associated-type-bound.rs:19:5
+   |
+LL |     type U<'a>: PartialEq<&'a Self>;
+   |     -------------------------------- required by `X::U`
+...
+LL |     default type U<'a> = &'a T;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `T == T`
+   |
+   = help: the trait `std::cmp::PartialEq` is not implemented for `T`
+   = note: required because of the requirements on the impl of `std::cmp::PartialEq` for `&'a T`
+help: consider further restricting this bound
+   |
+LL | impl<T: 'static + std::cmp::PartialEq> X for T {
+   |                 ^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error; 2 warnings emitted
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/traits/trait-suggest-deferences-issue-39029.fixed b/src/test/ui/traits/trait-suggest-deferences-issue-39029.fixed
new file mode 100644
index 00000000000..2bb34b0ebee
--- /dev/null
+++ b/src/test/ui/traits/trait-suggest-deferences-issue-39029.fixed
@@ -0,0 +1,18 @@
+// run-rustfix
+use std::net::TcpListener;
+
+struct NoToSocketAddrs(String);
+
+impl std::ops::Deref for NoToSocketAddrs {
+    type Target = String;
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+fn main() {
+    let _works = TcpListener::bind("some string");
+    let bad = NoToSocketAddrs("bad".to_owned());
+    let _errors = TcpListener::bind(&*bad);
+    //~^ ERROR the trait bound `NoToSocketAddrs: std::net::ToSocketAddrs` is not satisfied
+}
diff --git a/src/test/ui/traits/trait-suggest-deferences-issue-39029.rs b/src/test/ui/traits/trait-suggest-deferences-issue-39029.rs
new file mode 100644
index 00000000000..33d524608a0
--- /dev/null
+++ b/src/test/ui/traits/trait-suggest-deferences-issue-39029.rs
@@ -0,0 +1,18 @@
+// run-rustfix
+use std::net::TcpListener;
+
+struct NoToSocketAddrs(String);
+
+impl std::ops::Deref for NoToSocketAddrs {
+    type Target = String;
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+fn main() {
+    let _works = TcpListener::bind("some string");
+    let bad = NoToSocketAddrs("bad".to_owned());
+    let _errors = TcpListener::bind(&bad);
+    //~^ ERROR the trait bound `NoToSocketAddrs: std::net::ToSocketAddrs` is not satisfied
+}
diff --git a/src/test/ui/traits/trait-suggest-deferences-issue-39029.stderr b/src/test/ui/traits/trait-suggest-deferences-issue-39029.stderr
new file mode 100644
index 00000000000..0bf9794a744
--- /dev/null
+++ b/src/test/ui/traits/trait-suggest-deferences-issue-39029.stderr
@@ -0,0 +1,19 @@
+error[E0277]: the trait bound `NoToSocketAddrs: std::net::ToSocketAddrs` is not satisfied
+  --> $DIR/trait-suggest-deferences-issue-39029.rs:16:37
+   |
+LL |     let _errors = TcpListener::bind(&bad);
+   |                                     ^^^^
+   |                                     |
+   |                                     the trait `std::net::ToSocketAddrs` is not implemented for `NoToSocketAddrs`
+   |                                     help: consider adding dereference here: `&*bad`
+   | 
+  ::: $SRC_DIR/libstd/net/tcp.rs:LL:COL
+   |
+LL |     pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<TcpListener> {
+   |                    ------------- required by this bound in `std::net::TcpListener::bind`
+   |
+   = note: required because of the requirements on the impl of `std::net::ToSocketAddrs` for `&NoToSocketAddrs`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/traits/trait-suggest-deferences-issue-62530.fixed b/src/test/ui/traits/trait-suggest-deferences-issue-62530.fixed
new file mode 100644
index 00000000000..fa7b9167d8d
--- /dev/null
+++ b/src/test/ui/traits/trait-suggest-deferences-issue-62530.fixed
@@ -0,0 +1,15 @@
+// run-rustfix
+fn takes_str(_x: &str) {}
+
+fn takes_type_parameter<T>(_x: T) where T: SomeTrait {}
+
+trait SomeTrait {}
+impl SomeTrait for &'_ str {}
+impl SomeTrait for char {}
+
+fn main() {
+    let string = String::new();
+    takes_str(&string);             // Ok
+    takes_type_parameter(&*string);  // Error
+    //~^ ERROR the trait bound `&std::string::String: SomeTrait` is not satisfied
+}
diff --git a/src/test/ui/traits/trait-suggest-deferences-issue-62530.rs b/src/test/ui/traits/trait-suggest-deferences-issue-62530.rs
new file mode 100644
index 00000000000..e785f012177
--- /dev/null
+++ b/src/test/ui/traits/trait-suggest-deferences-issue-62530.rs
@@ -0,0 +1,15 @@
+// run-rustfix
+fn takes_str(_x: &str) {}
+
+fn takes_type_parameter<T>(_x: T) where T: SomeTrait {}
+
+trait SomeTrait {}
+impl SomeTrait for &'_ str {}
+impl SomeTrait for char {}
+
+fn main() {
+    let string = String::new();
+    takes_str(&string);             // Ok
+    takes_type_parameter(&string);  // Error
+    //~^ ERROR the trait bound `&std::string::String: SomeTrait` is not satisfied
+}
diff --git a/src/test/ui/traits/trait-suggest-deferences-issue-62530.stderr b/src/test/ui/traits/trait-suggest-deferences-issue-62530.stderr
new file mode 100644
index 00000000000..9c2a582638e
--- /dev/null
+++ b/src/test/ui/traits/trait-suggest-deferences-issue-62530.stderr
@@ -0,0 +1,15 @@
+error[E0277]: the trait bound `&std::string::String: SomeTrait` is not satisfied
+  --> $DIR/trait-suggest-deferences-issue-62530.rs:13:26
+   |
+LL | fn takes_type_parameter<T>(_x: T) where T: SomeTrait {}
+   |                                            --------- required by this bound in `takes_type_parameter`
+...
+LL |     takes_type_parameter(&string);  // Error
+   |                          ^^^^^^^
+   |                          |
+   |                          the trait `SomeTrait` is not implemented for `&std::string::String`
+   |                          help: consider adding dereference here: `&*string`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/traits/trait-suggest-deferences-multiple-0.fixed b/src/test/ui/traits/trait-suggest-deferences-multiple-0.fixed
new file mode 100644
index 00000000000..b7160b75c60
--- /dev/null
+++ b/src/test/ui/traits/trait-suggest-deferences-multiple-0.fixed
@@ -0,0 +1,36 @@
+// run-rustfix
+use std::ops::Deref;
+
+trait Happy {}
+struct LDM;
+impl Happy for &LDM {}
+
+struct Foo(LDM);
+struct Bar(Foo);
+struct Baz(Bar);
+impl Deref for Foo {
+    type Target = LDM;
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+impl Deref for Bar {
+    type Target = Foo;
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+impl Deref for Baz {
+    type Target = Bar;
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+fn foo<T>(_: T) where T: Happy {}
+
+fn main() {
+    let baz = Baz(Bar(Foo(LDM)));
+    foo(&***baz);
+    //~^ ERROR the trait bound `&Baz: Happy` is not satisfied
+}
diff --git a/src/test/ui/traits/trait-suggest-deferences-multiple-0.rs b/src/test/ui/traits/trait-suggest-deferences-multiple-0.rs
new file mode 100644
index 00000000000..9ac55177ffa
--- /dev/null
+++ b/src/test/ui/traits/trait-suggest-deferences-multiple-0.rs
@@ -0,0 +1,36 @@
+// run-rustfix
+use std::ops::Deref;
+
+trait Happy {}
+struct LDM;
+impl Happy for &LDM {}
+
+struct Foo(LDM);
+struct Bar(Foo);
+struct Baz(Bar);
+impl Deref for Foo {
+    type Target = LDM;
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+impl Deref for Bar {
+    type Target = Foo;
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+impl Deref for Baz {
+    type Target = Bar;
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+fn foo<T>(_: T) where T: Happy {}
+
+fn main() {
+    let baz = Baz(Bar(Foo(LDM)));
+    foo(&baz);
+    //~^ ERROR the trait bound `&Baz: Happy` is not satisfied
+}
diff --git a/src/test/ui/traits/trait-suggest-deferences-multiple-0.stderr b/src/test/ui/traits/trait-suggest-deferences-multiple-0.stderr
new file mode 100644
index 00000000000..add34a553bc
--- /dev/null
+++ b/src/test/ui/traits/trait-suggest-deferences-multiple-0.stderr
@@ -0,0 +1,15 @@
+error[E0277]: the trait bound `&Baz: Happy` is not satisfied
+  --> $DIR/trait-suggest-deferences-multiple-0.rs:34:9
+   |
+LL | fn foo<T>(_: T) where T: Happy {}
+   |                          ----- required by this bound in `foo`
+...
+LL |     foo(&baz);
+   |         ^^^^
+   |         |
+   |         the trait `Happy` is not implemented for `&Baz`
+   |         help: consider adding dereference here: `&***baz`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/traits/trait-suggest-deferences-multiple-1.rs b/src/test/ui/traits/trait-suggest-deferences-multiple-1.rs
new file mode 100644
index 00000000000..91c6c7924a4
--- /dev/null
+++ b/src/test/ui/traits/trait-suggest-deferences-multiple-1.rs
@@ -0,0 +1,54 @@
+use std::ops::{Deref, DerefMut};
+
+trait Happy {}
+struct LDM;
+impl Happy for &mut LDM {}
+
+struct Foo(LDM);
+struct Bar(Foo);
+struct Baz(Bar);
+impl Deref for Foo {
+    type Target = LDM;
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+impl Deref for Bar {
+    type Target = Foo;
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+impl Deref for Baz {
+    type Target = Bar;
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+impl DerefMut for Foo {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
+    }
+}
+impl DerefMut for Bar {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
+    }
+}
+impl DerefMut for Baz {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
+    }
+}
+
+
+fn foo<T>(_: T) where T: Happy {}
+
+fn main() {
+    // Currently the compiler doesn't try to suggest dereferences for situations
+    // where DerefMut involves. So this test is meant to ensure compiler doesn't
+    // generate incorrect help message.
+    let mut baz = Baz(Bar(Foo(LDM)));
+    foo(&mut baz);
+    //~^ ERROR the trait bound `&mut Baz: Happy` is not satisfied
+}
diff --git a/src/test/ui/traits/trait-suggest-deferences-multiple-1.stderr b/src/test/ui/traits/trait-suggest-deferences-multiple-1.stderr
new file mode 100644
index 00000000000..e90278fa16f
--- /dev/null
+++ b/src/test/ui/traits/trait-suggest-deferences-multiple-1.stderr
@@ -0,0 +1,12 @@
+error[E0277]: the trait bound `&mut Baz: Happy` is not satisfied
+  --> $DIR/trait-suggest-deferences-multiple-1.rs:52:9
+   |
+LL | fn foo<T>(_: T) where T: Happy {}
+   |                          ----- required by this bound in `foo`
+...
+LL |     foo(&mut baz);
+   |         ^^^^^^^^ the trait `Happy` is not implemented for `&mut Baz`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/where-clauses/where-lifetime-resolution.rs b/src/test/ui/where-clauses/where-lifetime-resolution.rs
index 0d426386768..d8677ee959a 100644
--- a/src/test/ui/where-clauses/where-lifetime-resolution.rs
+++ b/src/test/ui/where-clauses/where-lifetime-resolution.rs
@@ -7,7 +7,6 @@ fn f() where
     //~^ ERROR use of undeclared lifetime name `'a`
     for<'a> dyn for<'b> Trait2<'a, 'b>: Trait2<'a, 'b>,
     //~^ ERROR use of undeclared lifetime name `'b`
-    //~| ERROR nested quantification of lifetimes
 {}
 
 fn main() {}
diff --git a/src/test/ui/where-clauses/where-lifetime-resolution.stderr b/src/test/ui/where-clauses/where-lifetime-resolution.stderr
index 49799a93017..6c52664154b 100644
--- a/src/test/ui/where-clauses/where-lifetime-resolution.stderr
+++ b/src/test/ui/where-clauses/where-lifetime-resolution.stderr
@@ -7,12 +7,6 @@ LL |     for<'a> dyn Trait1<'a>: Trait1<'a>, // OK
 LL |     (dyn for<'a> Trait1<'a>): Trait1<'a>,
    |                                      ^^ undeclared lifetime
 
-error[E0316]: nested quantification of lifetimes
-  --> $DIR/where-lifetime-resolution.rs:8:17
-   |
-LL |     for<'a> dyn for<'b> Trait2<'a, 'b>: Trait2<'a, 'b>,
-   |                 ^^^^^^^^^^^^^^^^^^^^^^
-
 error[E0261]: use of undeclared lifetime name `'b`
   --> $DIR/where-lifetime-resolution.rs:8:52
    |
@@ -22,6 +16,6 @@ LL | fn f() where
 LL |     for<'a> dyn for<'b> Trait2<'a, 'b>: Trait2<'a, 'b>,
    |                                                    ^^ undeclared lifetime
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0261`.