]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #61095 - ehuss:update-cargo, r=alexcrichton
authorMazdak Farrokhzad <twingoow@gmail.com>
Sat, 25 May 2019 02:55:29 +0000 (04:55 +0200)
committerGitHub <noreply@github.com>
Sat, 25 May 2019 02:55:29 +0000 (04:55 +0200)
Update cargo

Update cargo

14 commits in c4fcfb725b4be00c72eb9cf30c7d8b095577c280..545f354259be4e9745ea00a524c0e4c51df01aa6
2019-05-15 19:48:47 +0000 to 2019-05-23 17:45:30 +0000
- Bump to 0.38.0 (rust-lang/cargo#6979)
- cargo package: detect new empty directories (rust-lang/cargo#6973)
- Add message caching. (rust-lang/cargo#6933)
- Fix typo (rust-lang/cargo#6974)
- Set `Finished` line correctly for debug=0. (rust-lang/cargo#6971)
- Clippy fixes (rust-lang/cargo#6970)
- Remove rustdoc `can_add_color_process`. (rust-lang/cargo#6968)
- Document new `doctest` field. (rust-lang/cargo#6965)
- Update some man pages that missed --offline. (rust-lang/cargo#6964)
- add public & private prop tests. (rust-lang/cargo#6962)
- zsh completion: Pull list of commands from cargo --list (rust-lang/cargo#6956)
- Change docs "inequality" for semver requirement. (rust-lang/cargo#6963)
- Update im-rc requirement from 12.1.0 to 13.0.0 (rust-lang/cargo#6959)
- Add `doctest` field into metadata (rust-lang/cargo#6953)

130 files changed:
.azure-pipelines/auto.yml [new file with mode: 0644]
.azure-pipelines/master.yml [new file with mode: 0644]
.azure-pipelines/pr.yml [new file with mode: 0644]
.azure-pipelines/steps/install-clang.yml [new file with mode: 0644]
.azure-pipelines/steps/install-sccache.yml [new file with mode: 0644]
.azure-pipelines/steps/install-windows-build-deps.yml [new file with mode: 0644]
.azure-pipelines/steps/run.yml [new file with mode: 0644]
.azure-pipelines/try.yml [new file with mode: 0644]
Cargo.lock
appveyor.yml
config.toml.example
src/bootstrap/bin/rustc.rs
src/bootstrap/builder.rs
src/bootstrap/compile.rs
src/bootstrap/config.rs
src/bootstrap/configure.py
src/bootstrap/mk/Makefile.in
src/bootstrap/test.rs
src/bootstrap/tool.rs
src/bootstrap/util.rs
src/ci/docker/dist-various-2/Dockerfile
src/ci/docker/run.sh
src/ci/run.sh
src/ci/shared.sh
src/liballoc/boxed.rs
src/liballoc/tests/vec.rs
src/liballoc/vec.rs
src/libarena/lib.rs
src/librustc/arena.rs
src/librustc/hir/lowering.rs
src/librustc/lint/mod.rs
src/librustc/middle/cstore.rs
src/librustc/middle/resolve_lifetime.rs
src/librustc/middle/stability.rs
src/librustc/mir/mod.rs
src/librustc/query/mod.rs
src/librustc/traits/on_unimplemented.rs
src/librustc/ty/context.rs
src/librustc/ty/mod.rs
src/librustc/ty/print/pretty.rs
src/librustc/ty/query/values.rs
src/librustc_borrowck/borrowck/mod.rs
src/librustc_codegen_llvm/attributes.rs
src/librustc_codegen_ssa/back/symbol_export.rs
src/librustc_codegen_ssa/base.rs
src/librustc_metadata/Cargo.toml
src/librustc_metadata/cstore_impl.rs
src/librustc_metadata/decoder.rs
src/librustc_metadata/encoder.rs
src/librustc_mir/borrow_check/conflict_errors.rs [new file with mode: 0644]
src/librustc_mir/borrow_check/error_reporting.rs
src/librustc_mir/borrow_check/mod.rs
src/librustc_mir/borrow_check/mutability_errors.rs
src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs
src/librustc_passes/ast_validation.rs
src/librustc_privacy/lib.rs
src/librustc_save_analysis/lib.rs
src/librustc_typeck/astconv.rs
src/librustc_typeck/check/demand.rs
src/librustc_typeck/check/method/suggest.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/coherence/inherent_impls.rs
src/librustc_typeck/collect.rs
src/librustc_typeck/outlives/mod.rs
src/librustc_typeck/variance/mod.rs
src/librustdoc/clean/auto_trait.rs
src/librustdoc/clean/mod.rs
src/libsyntax/ast.rs
src/libsyntax/attr/mod.rs
src/libsyntax/ext/base.rs
src/libsyntax/ext/tt/macro_parser.rs
src/libsyntax/ext/tt/macro_rules.rs
src/libsyntax/feature_gate.rs
src/libsyntax/lib.rs
src/libsyntax/mut_visit.rs
src/libsyntax/parse/diagnostics.rs
src/libsyntax/parse/mod.rs
src/libsyntax/parse/parser.rs
src/libsyntax/print/pprust.rs
src/libsyntax/util/parser.rs
src/libsyntax/visit.rs
src/libsyntax_ext/asm.rs
src/libsyntax_ext/deriving/custom.rs
src/test/debuginfo/issue-13213.rs
src/test/debuginfo/pretty-std.rs
src/test/debuginfo/should-fail.rs
src/test/incremental/cyclic-trait-hierarchy.rs
src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs
src/test/ui/cycle-projection-based-on-where-clause.rs
src/test/ui/cycle-projection-based-on-where-clause.stderr
src/test/ui/issues/issue-20772.rs
src/test/ui/issues/issue-20772.stderr
src/test/ui/issues/issue-21177.rs
src/test/ui/issues/issue-21177.stderr
src/test/ui/issues/issue-23302-3.rs
src/test/ui/issues/issue-23302-3.stderr
src/test/ui/lint/deny-overflowing-literals.rs
src/test/ui/lint/deny-overflowing-literals.stderr
src/test/ui/macros/format-parse-errors.stderr
src/test/ui/malformed/malformed-derive-entry.rs
src/test/ui/malformed/malformed-derive-entry.stderr
src/test/ui/malformed/malformed-special-attrs.rs
src/test/ui/malformed/malformed-special-attrs.stderr
src/test/ui/nll/dont-print-desugared-async.rs [new file with mode: 0644]
src/test/ui/nll/dont-print-desugared-async.stderr [new file with mode: 0644]
src/test/ui/nll/dont-print-desugared.rs [new file with mode: 0644]
src/test/ui/nll/dont-print-desugared.stderr [new file with mode: 0644]
src/test/ui/obsolete-in-place/bad.bad.stderr
src/test/ui/obsolete-in-place/bad.rs
src/test/ui/obsolete-in-place/bad.stderr [new file with mode: 0644]
src/test/ui/parser/if-in-in.stderr
src/test/ui/parser/issue-17383.rs
src/test/ui/parser/issue-17383.stderr
src/test/ui/parser/macro/bad-macro-argument.rs [new file with mode: 0644]
src/test/ui/parser/macro/bad-macro-argument.stderr [new file with mode: 0644]
src/test/ui/parser/tag-variant-disr-non-nullary.rs
src/test/ui/parser/tag-variant-disr-non-nullary.stderr
src/test/ui/placement-syntax.rs
src/test/ui/placement-syntax.stderr
src/test/ui/proc-macro/attr-invalid-exprs.rs
src/test/ui/proc-macro/attr-invalid-exprs.stderr
src/test/ui/suggestions/mut-ref-reassignment.rs [new file with mode: 0644]
src/test/ui/suggestions/mut-ref-reassignment.stderr [new file with mode: 0644]
src/test/ui/unreachable/unreachable-loop-patterns.rs
src/test/ui/unreachable/unreachable-loop-patterns.stderr
src/tools/cargotest/main.rs
src/tools/compiletest/src/common.rs
src/tools/compiletest/src/header.rs
src/tools/compiletest/src/main.rs
src/tools/compiletest/src/runtest.rs

diff --git a/.azure-pipelines/auto.yml b/.azure-pipelines/auto.yml
new file mode 100644 (file)
index 0000000..7bb38a4
--- /dev/null
@@ -0,0 +1,350 @@
+#
+# Azure Pipelines "auto" branch build for Rust on Linux, macOS, and Windows.
+#
+
+pr: none
+trigger:
+  - auto
+
+variables:
+- group: prod-credentials
+
+jobs:
+- job: Linux
+  pool:
+    vmImage: ubuntu-16.04
+  steps:
+  - template: steps/run.yml
+  strategy:
+    matrix:
+      x86_64-gnu-llvm-6.0:
+        IMAGE: x86_64-gnu-llvm-6.0
+        RUST_BACKTRACE: 1
+
+      dist-x86_64-linux:
+        IMAGE: dist-x86_64-linux
+        DEPLOY: 1
+
+      # "alternate" deployments, these are "nightlies" but have LLVM assertions
+      # turned on, they're deployed to a different location primarily for
+      # additional testing.
+      dist-x86_64-linux-alt:
+        IMAGE: dist-x86_64-linux
+        DEPLOY_ALT: 1
+
+      # Linux builders, remaining docker images
+      arm-android:
+        IMAGE: arm-android
+
+      armhf-gnu:
+        IMAGE: armhf-gnu
+
+      dist-various-1:
+        IMAGE: dist-various-1
+        DEPLOY: 1
+
+      dist-various-2:
+        IMAGE: dist-various-2
+        DEPLOY: 1
+
+      dist-aarch64-linux:
+        IMAGE: dist-aarch64-linux
+        DEPLOY: 1
+
+      dist-android:
+        IMAGE: dist-android
+        DEPLOY: 1
+
+      dist-arm-linux:
+        IMAGE: dist-arm-linux
+        DEPLOY: 1
+
+      dist-armhf-linux:
+        IMAGE: dist-armhf-linux
+        DEPLOY: 1
+
+      dist-armv7-linux:
+        IMAGE: dist-armv7-linux
+        DEPLOY: 1
+
+      dist-i586-gnu-i586-i686-musl:
+        IMAGE: dist-i586-gnu-i586-i686-musl
+        DEPLOY: 1
+
+      dist-i686-freebsd:
+        IMAGE: dist-i686-freebsd
+        DEPLOY: 1
+
+      dist-i686-linux:
+        IMAGE: dist-i686-linux
+        DEPLOY: 1
+
+      dist-mips-linux:
+        IMAGE: dist-mips-linux
+        DEPLOY: 1
+
+      dist-mips64-linux:
+        IMAGE: dist-mips64-linux
+        DEPLOY: 1
+
+      dist-mips64el-linux:
+        IMAGE: dist-mips64el-linux
+        DEPLOY: 1
+
+      dist-mipsel-linux:
+        IMAGE: dist-mipsel-linux
+        DEPLOY: 1
+
+      dist-powerpc-linux:
+        IMAGE: dist-powerpc-linux
+        DEPLOY: 1
+
+      dist-powerpc64-linux:
+        IMAGE: dist-powerpc64-linux
+        DEPLOY: 1
+
+      dist-powerpc64le-linux:
+        IMAGE: dist-powerpc64le-linux
+        DEPLOY: 1
+
+      dist-s390x-linux:
+        IMAGE: dist-s390x-linux
+        DEPLOY: 1
+
+      dist-x86_64-freebsd:
+        IMAGE: dist-x86_64-freebsd
+        DEPLOY: 1
+
+      dist-x86_64-musl:
+        IMAGE: dist-x86_64-musl
+        DEPLOY: 1
+
+      dist-x86_64-netbsd:
+        IMAGE: dist-x86_64-netbsd
+        DEPLOY: 1
+
+      asmjs:
+        IMAGE: asmjs
+      i686-gnu:
+        IMAGE: i686-gnu
+      i686-gnu-nopt:
+        IMAGE: i686-gnu-nopt
+      test-various:
+        IMAGE: test-various
+      x86_64-gnu:
+        IMAGE: x86_64-gnu
+      x86_64-gnu-full-bootstrap:
+        IMAGE: x86_64-gnu-full-bootstrap
+      x86_64-gnu-aux:
+        IMAGE: x86_64-gnu-aux
+      x86_64-gnu-tools:
+        IMAGE: x86_64-gnu-tools
+      # FIXME if: branch = auto OR (type = pull_request AND commit_message =~ /(?i:^update.*\b(rls|rustfmt|clippy|miri|cargo)\b)/)
+      x86_64-gnu-debug:
+        IMAGE: x86_64-gnu-debug
+      x86_64-gnu-nopt:
+        IMAGE: x86_64-gnu-nopt
+      x86_64-gnu-distcheck:
+        IMAGE: x86_64-gnu-distcheck
+      mingw-check:
+        IMAGE: mingw-check
+
+- job: macOS
+  pool:
+    vmImage: macos-10.13
+  steps:
+  - checkout: self
+    fetchDepth: 2
+  - template: steps/run.yml
+  strategy:
+    matrix:
+      # OSX builders running tests, these run the full test suite.
+      # NO_DEBUG_ASSERTIONS=1 to make them go faster, but also do have some
+      # runners that run `//ignore-debug` tests.
+      #
+      # Note that the compiler is compiled to target 10.8 here because the Xcode
+      # version that we're using, 8.2, cannot compile LLVM for OSX 10.7.
+      x86_64-apple:
+        RUST_CHECK_TARGET: check
+        RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc
+        RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+        MACOSX_DEPLOYMENT_TARGET: 10.8
+        MACOSX_STD_DEPLOYMENT_TARGET: 10.7
+        NO_LLVM_ASSERTIONS: 1
+        NO_DEBUG_ASSERTIONS: 1
+
+      dist-x86_64-apple:
+        RUST_CHECK_TARGET: dist
+        RUST_CONFIGURE_ARGS: --target=aarch64-apple-ios,armv7-apple-ios,armv7s-apple-ios,i386-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --enable-lldb --set rust.jemalloc
+        DEPLOY: 1
+        RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+        MACOSX_DEPLOYMENT_TARGET: 10.7
+        NO_LLVM_ASSERTIONS: 1
+        NO_DEBUG_ASSERTIONS: 1
+        DIST_REQUIRE_ALL_TOOLS: 1
+
+      dist-x86_64-apple-alt:
+        RUST_CHECK_TARGET: dist
+        RUST_CONFIGURE_ARGS: --enable-extended --enable-profiler --enable-lldb --set rust.jemalloc
+        DEPLOY_ALT: 1
+        RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+        MACOSX_DEPLOYMENT_TARGET: 10.7
+        NO_LLVM_ASSERTIONS: 1
+        NO_DEBUG_ASSERTIONS: 1
+
+      i686-apple:
+        RUST_CHECK_TARGET: check
+        RUST_CONFIGURE_ARGS: --build=i686-apple-darwin --set rust.jemalloc
+        RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+        MACOSX_DEPLOYMENT_TARGET: 10.8
+        MACOSX_STD_DEPLOYMENT_TARGET: 10.7
+        NO_LLVM_ASSERTIONS: 1
+        NO_DEBUG_ASSERTIONS: 1
+
+      dist-i686-apple:
+        RUST_CHECK_TARGET: dist
+        RUST_CONFIGURE_ARGS: --build=i686-apple-darwin --enable-full-tools --enable-profiler --enable-lldb --set rust.jemalloc
+        DEPLOY: 1
+        RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+        MACOSX_DEPLOYMENT_TARGET: 10.7
+        NO_LLVM_ASSERTIONS: 1
+        NO_DEBUG_ASSERTIONS: 1
+        DIST_REQUIRE_ALL_TOOLS: 1
+
+
+
+- job: Windows
+  pool:
+    vmImage: 'vs2017-win2016'
+  steps:
+  - template: steps/run.yml
+  strategy:
+    matrix:
+      # 32/64 bit MSVC tests
+      x86_64-msvc-1:
+        MSYS_BITS: 64
+        RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-profiler
+        SCRIPT: make ci-subset-1
+        # FIXME(#59637)
+        NO_DEBUG_ASSERTIONS: 1
+        NO_LLVM_ASSERTIONS: 1
+      x86_64-msvc-2:
+        MSYS_BITS: 64
+        RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-profiler
+        SCRIPT: make ci-subset-2
+      i686-msvc-1:
+        MSYS_BITS: 32
+        RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc
+        SCRIPT: make ci-subset-1
+      i686-msvc-2:
+        MSYS_BITS: 32
+        RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc
+        SCRIPT: make ci-subset-2
+      # MSVC aux tests
+      x86_64-msvc-aux:
+        MSYS_BITS: 64
+        RUST_CHECK_TARGET: check-aux EXCLUDE_CARGO=1
+        RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc
+      x86_64-msvc-cargo:
+        MSYS_BITS: 64
+        SCRIPT: python x.py test src/tools/cargotest src/tools/cargo
+        RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc
+        VCVARS_BAT: vcvars64.bat
+      # MSVC tools tests
+      x86_64-msvc-tools:
+        MSYS_BITS: 64
+        SCRIPT: src/ci/docker/x86_64-gnu-tools/checktools.sh x.py /tmp/toolstates.json windows
+        RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --save-toolstates=/tmp/toolstates.json --enable-test-miri
+
+      # 32/64-bit MinGW builds.
+      #
+      # We are using MinGW with posix threads since LLVM does not compile with
+      # the win32 threads version due to missing support for C++'s std::thread.
+      #
+      # Instead of relying on the MinGW version installed on appveryor we download
+      # and install one ourselves so we won't be surprised by changes to appveyor's
+      # build image.
+      #
+      # Finally, note that the downloads below are all in the `rust-lang-ci` S3
+      # bucket, but they cleraly didn't originate there! The downloads originally
+      # came from the mingw-w64 SourceForge download site. Unfortunately
+      # SourceForge is notoriously flaky, so we mirror it on our own infrastructure.
+      i686-mingw-1:
+        MSYS_BITS: 32
+        RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu
+        SCRIPT: make ci-subset-1
+        MINGW_URL: https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror
+        MINGW_ARCHIVE: i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z
+        MINGW_DIR: mingw32
+        # FIXME(#59637)
+        NO_DEBUG_ASSERTIONS: 1
+        NO_LLVM_ASSERTIONS: 1
+      i686-mingw-2:
+        MSYS_BITS: 32
+        RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu
+        SCRIPT: make ci-subset-2
+        MINGW_URL: https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror
+        MINGW_ARCHIVE: i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z
+        MINGW_DIR: mingw32
+      x86_64-mingw-1:
+        MSYS_BITS: 64
+        SCRIPT: make ci-subset-1
+        RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu
+        MINGW_URL: https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror
+        MINGW_ARCHIVE: x86_64-6.3.0-release-posix-seh-rt_v5-rev2.7z
+        MINGW_DIR: mingw64
+        # FIXME(#59637)
+        NO_DEBUG_ASSERTIONS: 1
+        NO_LLVM_ASSERTIONS: 1
+      x86_64-mingw-2:
+        MSYS_BITS: 64
+        SCRIPT: make ci-subset-2
+        RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu
+        MINGW_URL: https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror
+        MINGW_ARCHIVE: x86_64-6.3.0-release-posix-seh-rt_v5-rev2.7z
+        MINGW_DIR: mingw64
+
+      # 32/64 bit MSVC and GNU deployment
+      dist-x86_64-msvc:
+        RUST_CONFIGURE_ARGS: >
+          --build=x86_64-pc-windows-msvc
+          --target=x86_64-pc-windows-msvc,aarch64-pc-windows-msvc
+          --enable-full-tools
+          --enable-profiler
+        SCRIPT: python x.py dist
+        DIST_REQUIRE_ALL_TOOLS: 1
+        DEPLOY: 1
+      dist-i686-msvc:
+        RUST_CONFIGURE_ARGS: >
+          --build=i686-pc-windows-msvc
+          --target=i586-pc-windows-msvc
+          --enable-full-tools
+          --enable-profiler
+        SCRIPT: python x.py dist
+        DIST_REQUIRE_ALL_TOOLS: 1
+        DEPLOY: 1
+      dist-i686-mingw:
+        MSYS_BITS: 32
+        RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-full-tools
+        SCRIPT: python x.py dist
+        MINGW_URL: https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror
+        MINGW_ARCHIVE: i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z
+        MINGW_DIR: mingw32
+        DIST_REQUIRE_ALL_TOOLS: 1
+        DEPLOY: 1
+      dist-x86_64-mingw:
+        MSYS_BITS: 64
+        SCRIPT: python x.py dist
+        RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-full-tools
+        MINGW_URL: https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror
+        MINGW_ARCHIVE: x86_64-6.3.0-release-posix-seh-rt_v5-rev2.7z
+        MINGW_DIR: mingw64
+        DIST_REQUIRE_ALL_TOOLS: 1
+        DEPLOY: 1
+
+      # "alternate" deployment, see .travis.yml for more info
+      dist-x86_64-msvc-alt:
+        MSYS_BITS: 64
+        RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-extended --enable-profiler
+        SCRIPT: python x.py dist
+        DEPLOY_ALT: 1
diff --git a/.azure-pipelines/master.yml b/.azure-pipelines/master.yml
new file mode 100644 (file)
index 0000000..3f3025a
--- /dev/null
@@ -0,0 +1,24 @@
+#
+# Azure Pipelines job to publish toolstate. Only triggers on pushes to master.
+#
+
+pr: none
+trigger:
+  - master
+
+pool:
+  vmImage: ubuntu-16.04
+
+steps:
+- checkout: self
+  fetchDepth: 2
+
+- script: |
+    export MESSAGE_FILE=$(mktemp -t msg.XXXXXX)
+    . src/ci/docker/x86_64-gnu-tools/repo.sh
+    # FIXME(pietro): committing is disabled until we switch to Azure Pipelines
+    # as the source of truth, or until we setup a separate test repo.
+    #commit_toolstate_change "$MESSAGE_FILE" "$BUILD_SOURCESDIRECTORY/src/tools/publish_toolstate.py" "$(git rev-parse HEAD)" "$(git log --format=%s -n1 HEAD)" "$MESSAGE_FILE" "$TOOLSTATE_REPO_ACCESS_TOKEN"
+  displayName: Publish toolstate
+  env:
+    TOOLSTATE_REPO_ACCESS_TOKEN: $(TOOLSTATE_REPO_ACCESS_TOKEN_SECRET)
diff --git a/.azure-pipelines/pr.yml b/.azure-pipelines/pr.yml
new file mode 100644 (file)
index 0000000..84c9454
--- /dev/null
@@ -0,0 +1,22 @@
+#
+# Azure Pipelines pull request build for Rust
+#
+
+trigger: none
+pr:
+- master # FIXME: really just want any branch, but want an explicit "pr" property set so it's clear
+
+jobs:
+- job: Linux
+  pool:
+    vmImage: ubuntu-16.04
+  steps:
+    - template: steps/run.yml
+  strategy:
+    matrix:
+      x86_64-gnu-llvm-6.0:
+        RUST_BACKTRACE: 1
+
+#      x86_64-gnu-tools: {}
+#      # if: branch = auto OR (type = pull_request AND commit_message =~ /(?i:^update.*\b(rls|rustfmt|clippy|miri|cargo)\b)/)
+#      mingw-check: {}
diff --git a/.azure-pipelines/steps/install-clang.yml b/.azure-pipelines/steps/install-clang.yml
new file mode 100644 (file)
index 0000000..26a2232
--- /dev/null
@@ -0,0 +1,40 @@
+steps:
+
+- bash: |
+    set -e
+    curl -f http://releases.llvm.org/7.0.0/clang+llvm-7.0.0-x86_64-apple-darwin.tar.xz | tar xJf -
+
+    export CC=`pwd`/clang+llvm-7.0.0-x86_64-apple-darwin/bin/clang
+    echo "##vso[task.setvariable variable=CC]$CC"
+
+    export CXX=`pwd`/clang+llvm-7.0.0-x86_64-apple-darwin/bin/clang++
+    echo "##vso[task.setvariable variable=CXX]$CXX"
+
+    # Configure `AR` specifically so rustbuild doesn't try to infer it as
+    # `clang-ar` by accident.
+    echo "##vso[task.setvariable variable=AR]ar"
+  displayName: Install clang (OSX)
+  condition: and(succeeded(), eq(variables['Agent.OS'], 'Darwin'))
+
+# If we're compiling for MSVC then we, like most other distribution builders,
+# switch to clang as the compiler. This'll allow us eventually to enable LTO
+# amongst LLVM and rustc. Note that we only do this on MSVC as I don't think
+# clang has an output mode compatible with MinGW that we need. If it does we
+# should switch to clang for MinGW as well!
+#
+# Note that the LLVM installer is an NSIS installer
+#
+# Original downloaded here came from
+# http://releases.llvm.org/7.0.0/LLVM-7.0.0-win64.exe
+- script: |
+    powershell -Command "iwr -outf %TEMP%\LLVM-7.0.0-win64.exe https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/LLVM-7.0.0-win64.exe"
+    set CLANG_DIR=%CD%\citools\clang-rust
+    %TEMP%\LLVM-7.0.0-win64.exe /S /NCRC /D=%CLANG_DIR%
+    set RUST_CONFIGURE_ARGS=%RUST_CONFIGURE_ARGS% --set llvm.clang-cl=%CLANG_DIR%\bin\clang-cl.exe
+    echo ##vso[task.setvariable variable=RUST_CONFIGURE_ARGS]%RUST_CONFIGURE_ARGS%
+  condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'), eq(variables['MINGW_URL'],''))
+  displayName: Install clang (Windows)
+
+# Note that we don't install clang on Linux since its compiler story is just so
+# different. Each container has its own toolchain configured appropriately
+# already.
diff --git a/.azure-pipelines/steps/install-sccache.yml b/.azure-pipelines/steps/install-sccache.yml
new file mode 100644 (file)
index 0000000..39f5800
--- /dev/null
@@ -0,0 +1,21 @@
+steps:
+
+- bash: |
+    set -e
+    curl -fo /usr/local/bin/sccache https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/2018-04-02-sccache-x86_64-apple-darwin
+    chmod +x /usr/local/bin/sccache
+  displayName: Install sccache (OSX)
+  condition: and(succeeded(), eq(variables['Agent.OS'], 'Darwin'))
+
+- script: |
+    md sccache
+    powershell -Command "iwr -outf sccache\sccache.exe https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/2018-04-26-sccache-x86_64-pc-windows-msvc"
+    echo ##vso[task.prependpath]%CD%\sccache
+  displayName: Install sccache (Windows)
+  condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
+
+# Note that we don't install sccache on Linux since it's installed elsewhere
+# through all the containers.
+#
+# FIXME: we should probably install sccache outside the containers and then
+# mount it inside the containers so we can centralize all installation here.
diff --git a/.azure-pipelines/steps/install-windows-build-deps.yml b/.azure-pipelines/steps/install-windows-build-deps.yml
new file mode 100644 (file)
index 0000000..037c8da
--- /dev/null
@@ -0,0 +1,91 @@
+steps:
+# We've had issues with the default drive in use running out of space during a
+# build, and it looks like the `C:` drive has more space than the default `D:`
+# drive. We should probably confirm this with the azure pipelines team at some
+# point, but this seems to fix our "disk space full" problems.
+- script: |
+    mkdir c:\MORE_SPACE
+    mklink /J build c:\MORE_SPACE
+  displayName: "Ensure build happens on C:/ instead of D:/"
+  condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
+
+# Download and install MSYS2, needed primarily for the test suite (run-make) but
+# also used by the MinGW toolchain for assembling things.
+#
+# FIXME: we should probe the default azure image and see if we can use the MSYS2
+# toolchain there. (if there's even one there). For now though this gets the job
+# done.
+- script: |
+    set MSYS_PATH=%CD%\citools\msys64
+    choco install msys2 --params="/InstallDir:%MSYS_PATH% /NoPath" -y
+    set PATH=%MSYS_PATH%\usr\bin;%PATH%
+    pacman -S --noconfirm --needed base-devel ca-certificates make diffutils tar
+    IF "%MINGW_URL%"=="" (
+      IF "%MSYS_BITS%"=="32" pacman -S --noconfirm --needed mingw-w64-i686-toolchain mingw-w64-i686-cmake mingw-w64-i686-gcc mingw-w64-i686-python2
+      IF "%MSYS_BITS%"=="64" pacman -S --noconfirm --needed mingw-w64-x86_64-toolchain mingw-w64-x86_64-cmake mingw-w64-x86_64-gcc mingw-w64-x86_64-python2
+    )
+    where rev
+    rev --help
+    where make
+
+    echo ##vso[task.setvariable variable=MSYS_PATH]%MSYS_PATH%
+    echo ##vso[task.prependpath]%MSYS_PATH%\usr\bin
+  displayName: Install msys2
+  condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
+
+# If we need to download a custom MinGW, do so here and set the path
+# appropriately.
+#
+# Here we also do a pretty heinous thing which is to mangle the MinGW
+# installation we just downloaded. Currently, as of this writing, we're using
+# MinGW-w64 builds of gcc, and that's currently at 6.3.0. We use 6.3.0 as it
+# appears to be the first version which contains a fix for #40546, builds
+# randomly failing during LLVM due to ar.exe/ranlib.exe failures.
+#
+# Unfortunately, though, 6.3.0 *also* is the first version of MinGW-w64 builds
+# to contain a regression in gdb (#40184). As a result if we were to use the
+# gdb provided (7.11.1) then we would fail all debuginfo tests.
+#
+# In order to fix spurious failures (pretty high priority) we use 6.3.0. To
+# avoid disabling gdb tests we download an *old* version of gdb, specifically
+# that found inside the 6.2.0 distribution. We then overwrite the 6.3.0 gdb
+# with the 6.2.0 gdb to get tests passing.
+#
+# Note that we don't literally overwrite the gdb.exe binary because it appears
+# to just use gdborig.exe, so that's the binary we deal with instead.
+- script: |
+    powershell -Command "iwr -outf %MINGW_ARCHIVE% %MINGW_URL%/%MINGW_ARCHIVE%"
+    7z x -y %MINGW_ARCHIVE% > nul
+    powershell -Command "iwr -outf 2017-04-20-%MSYS_BITS%bit-gdborig.exe %MINGW_URL%/2017-04-20-%MSYS_BITS%bit-gdborig.exe"
+    mv 2017-04-20-%MSYS_BITS%bit-gdborig.exe %MINGW_DIR%\bin\gdborig.exe
+    echo ##vso[task.prependpath]%CD%\%MINGW_DIR%\bin
+  condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'), ne(variables['MINGW_URL'],''))
+  displayName: Download custom MinGW
+
+# Otherwise pull in the MinGW installed on appveyor
+- script: |
+    echo ##vso[task.prependpath]%MSYS_PATH%\mingw%MSYS_BITS%\bin
+  condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'), eq(variables['MINGW_URL'],''))
+  displayName: Add MinGW to path
+
+# Make sure we use the native python interpreter instead of some msys equivalent
+# one way or another. The msys interpreters seem to have weird path conversions
+# baked in which break LLVM's build system one way or another, so let's use the
+# native version which keeps everything as native as possible.
+- script: |
+    copy C:\Python27amd64\python.exe C:\Python27amd64\python2.7.exe
+    echo ##vso[task.prependpath]C:\Python27amd64
+  displayName: Prefer the "native" Python as LLVM has trouble building with MSYS sometimes
+  condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
+
+# Note that this is originally from the github releases patch of Ninja
+- script: |
+    md ninja
+    powershell -Command "iwr -outf 2017-03-15-ninja-win.zip https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/2017-03-15-ninja-win.zip"
+    7z x -oninja 2017-03-15-ninja-win.zip
+    del 2017-03-15-ninja-win.zip
+    set RUST_CONFIGURE_ARGS=%RUST_CONFIGURE_ARGS% --enable-ninja
+    echo ##vso[task.setvariable variable=RUST_CONFIGURE_ARGS]%RUST_CONFIGURE_ARGS%
+    echo ##vso[task.prependpath]%CD%\ninja
+  displayName: Download and install ninja
+  condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
diff --git a/.azure-pipelines/steps/run.yml b/.azure-pipelines/steps/run.yml
new file mode 100644 (file)
index 0000000..47a4c18
--- /dev/null
@@ -0,0 +1,137 @@
+# FIXME(linux): need to configure core dumps, enable them, and then dump
+# backtraces on failure from all core dumps:
+#
+# - bash: sudo apt install gdb
+# - bash: sudo sh -c 'echo "/checkout/obj/cores/core.%p.%E" > /proc/sys/kernel/core_pattern'
+#
+# Check travis config for `gdb --batch` command to print all crash logs
+
+steps:
+
+- checkout: self
+  fetchDepth: 2
+
+- bash: printenv | sort
+  displayName: Show environment variables
+
+- bash: |
+    set -e
+    df -h
+    du . | sort -nr | head -n100
+  displayName: Show disk usage
+  # FIXME: this hasn't been tested, but maybe it works on Windows? Should test!
+  condition: and(succeeded(), ne(variables['Agent.OS'], 'Windows_NT'))
+
+- template: install-sccache.yml
+- template: install-clang.yml
+
+# Install some dependencies needed to build LLDB/Clang, currently only needed
+# during the `dist` target
+- bash: |
+    set -e
+    brew update
+    brew install xz
+    brew install swig
+  displayName: Install build dependencies (OSX)
+  condition: and(succeeded(), eq(variables['Agent.OS'], 'Darwin'), eq(variables['RUST_CHECK_TARGET'],'dist'))
+
+# Switch to XCode 9.3 on OSX since it seems to be the last version that supports
+# i686-apple-darwin. We'll eventually want to upgrade this and it will probably
+# force us to drop i686-apple-darwin, but let's keep the wheels turning for now.
+- bash: |
+    set -e
+    sudo xcode-select --switch /Applications/Xcode_9.3.app
+  displayName: Switch to Xcode 9.3 (OSX)
+  condition: and(succeeded(), eq(variables['Agent.OS'], 'Darwin'))
+
+- template: install-windows-build-deps.yml
+
+# Looks like docker containers have IPv6 disabled by default, so let's turn it
+# on since libstd tests require it
+- bash: |
+    set -e
+    echo '{"ipv6":true,"fixed-cidr-v6":"fd9a:8454:6789:13f7::/64"}' | sudo tee /etc/docker/daemon.json
+    sudo service docker restart
+  displayName: Enable IPv6
+  condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux'))
+
+# Check out all our submodules, but more quickly than using git by using one of
+# our custom scripts
+- bash: |
+    set -e
+    mkdir -p $HOME/rustsrc
+    $BUILD_SOURCESDIRECTORY/src/ci/init_repo.sh . $HOME/rustsrc
+  condition: and(succeeded(), ne(variables['Agent.OS'], 'Windows_NT'))
+  displayName: Check out submodules (Unix)
+- script: |
+    if not exist D:\cache\rustsrc\NUL mkdir D:\cache\rustsrc
+    sh src/ci/init_repo.sh . /d/cache/rustsrc
+  condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
+  displayName: Check out submodules (Windows)
+
+# Ensure the `aws` CLI is installed so we can deploy later on, cache docker
+# images, etc.
+- bash: |
+    set -e
+    sudo apt-get install -y python3-setuptools
+    pip3 install awscli --upgrade --user
+    echo "##vso[task.prependpath]$HOME/.local/bin"
+  displayName: Install awscli (Linux)
+  condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux'))
+- script: pip install awscli
+  displayName: Install awscli (non-Linux)
+  condition: and(succeeded(), ne(variables['Agent.OS'], 'Linux'))
+
+# Configure our CI_JOB_NAME variable which log analyzers can use for the main
+# step to see what's going on.
+- bash: echo "##vso[task.setvariable variable=CI_JOB_NAME]$SYSTEM_JOBNAME"
+  displayName: Configure Job Name
+
+# As a quick smoke check on the otherwise very fast mingw-check linux builder
+# check our own internal scripts.
+- bash: |
+    set -e
+    git clone --depth=1 https://github.com/rust-lang-nursery/rust-toolstate.git
+    cd rust-toolstate
+    python2.7 "$BUILD_SOURCESDIRECTORY/src/tools/publish_toolstate.py" "$(git rev-parse HEAD)" "$(git log --format=%s -n1 HEAD)" "" ""
+    cd ..
+    rm -rf rust-toolstate
+  condition: and(succeeded(), eq(variables['IMAGE'], 'mingw-check'))
+  displayName: Verify the publish_toolstate script works
+
+- bash: |
+    set -e
+    if [ "$IMAGE" = "" ]; then
+      src/ci/run.sh
+    else
+      src/ci/docker/run.sh $IMAGE
+    fi
+  #timeoutInMinutes: 180
+  timeoutInMinutes: 600
+  env:
+    CI: true
+    SRC: .
+    AWS_SECRET_ACCESS_KEY: $(AWS_SECRET_ACCESS_KEY)
+  displayName: Run build
+
+# If we're a deploy builder, use the `aws` command to publish everything to our
+# bucket.
+- bash: |
+    set -e
+    if [ "$AGENT_OS" = "Linux" ]; then
+        rm -rf obj/build/dist/doc
+        upload_dir=obj/build/dist
+    else
+        rm -rf build/dist/doc
+        upload_dir=build/dist
+    fi
+    ls -la $upload_dir
+    deploy_dir=rustc-builds
+    if [ "$DEPLOY_ALT" == "1" ]; then
+        deploy_dir=rustc-builds-alt
+    fi
+    aws s3 cp --no-progress --recursive --acl public-read ./$upload_dir s3://$DEPLOY_BUCKET/$deploy_dir/$BUILD_SOURCEVERSION
+  env:
+    AWS_SECRET_ACCESS_KEY: $(AWS_SECRET_ACCESS_KEY)
+  condition: and(succeeded(), or(eq(variables.DEPLOY, '1'), eq(variables.DEPLOY_ALT, '1')))
+  displayName: Upload artifacts
diff --git a/.azure-pipelines/try.yml b/.azure-pipelines/try.yml
new file mode 100644 (file)
index 0000000..f37bb7d
--- /dev/null
@@ -0,0 +1,78 @@
+#
+# Azure Pipelines "auto" branch build for Rust on Linux, macOS, and Windows.
+#
+
+pr: none
+trigger:
+- try
+
+variables:
+- group: prod-credentials
+
+jobs:
+- job: Linux
+  timeoutInMinutes: 600
+  pool:
+    vmImage: ubuntu-16.04
+  steps:
+  - template: steps/run.yml
+  strategy:
+    matrix:
+      dist-x86_64-linux:
+        IMAGE: dist-x86_64-linux
+        DEPLOY: 1
+
+      dist-x86_64-linux-alt:
+        IMAGE: dist-x86_64-linux
+        DEPLOY_ALT: 1
+
+- job: macOS
+  timeoutInMinutes: 600
+  pool:
+    vmImage: macos-10.13
+  steps:
+  - template: steps/run.yml
+  strategy:
+    matrix:
+      dist-x86_64-apple:
+        RUST_CHECK_TARGET: dist
+        RUST_CONFIGURE_ARGS: --target=aarch64-apple-ios,armv7-apple-ios,armv7s-apple-ios,i386-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --enable-lldb --set rust.jemalloc
+        DEPLOY: 1
+        RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+        MACOSX_DEPLOYMENT_TARGET: 10.7
+        NO_LLVM_ASSERTIONS: 1
+        NO_DEBUG_ASSERTIONS: 1
+        DIST_REQUIRE_ALL_TOOLS: 1
+
+      dist-x86_64-apple-alt:
+        RUST_CHECK_TARGET: dist
+        RUST_CONFIGURE_ARGS: --enable-extended --enable-profiler --enable-lldb --set rust.jemalloc
+        DEPLOY_ALT: 1
+        RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+        MACOSX_DEPLOYMENT_TARGET: 10.7
+        NO_LLVM_ASSERTIONS: 1
+        NO_DEBUG_ASSERTIONS: 1
+
+- job: Windows
+  timeoutInMinutes: 600
+  pool:
+    vmImage: 'vs2017-win2016'
+  steps:
+  - template: steps/run.yml
+  strategy:
+    matrix:
+      dist-x86_64-msvc:
+        RUST_CONFIGURE_ARGS: >
+          --build=x86_64-pc-windows-msvc
+          --target=x86_64-pc-windows-msvc,aarch64-pc-windows-msvc
+          --enable-full-tools
+          --enable-profiler
+        SCRIPT: python x.py dist
+        DIST_REQUIRE_ALL_TOOLS: 1
+        DEPLOY: 1
+
+      dist-x86_64-msvc-alt:
+        MSYS_BITS: 64
+        RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-extended --enable-profiler
+        SCRIPT: python x.py dist
+        DEPLOY_ALT: 1
index a4d0180b1e40698848f899473fca324c84078c6e..39ea2fbdf279e2fd342d8e34e5705f7a20e9bf2a 100644 (file)
@@ -2879,6 +2879,7 @@ dependencies = [
  "rustc_errors 0.0.0",
  "rustc_target 0.0.0",
  "serialize 0.0.0",
+ "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "stable_deref_trait 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "syntax 0.0.0",
  "syntax_ext 0.0.0",
index dffd79c56e48a70ac26addf789d553601069eed2..c35da8927ce93520f4f94520660c5c0f9f470eee 100644 (file)
@@ -20,11 +20,11 @@ environment:
   - CI_JOB_NAME: i686-msvc-1
     MSYS_BITS: 32
     RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc
-    SCRIPT: make appveyor-subset-1
+    SCRIPT: make ci-subset-1
   - CI_JOB_NAME: i686-msvc-2
     MSYS_BITS: 32
     RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc
-    SCRIPT: make appveyor-subset-2
+    SCRIPT: make ci-subset-2
 
   # MSVC aux tests
   - CI_JOB_NAME: x86_64-msvc-aux
@@ -58,7 +58,7 @@ environment:
   - CI_JOB_NAME: i686-mingw-1
     MSYS_BITS: 32
     RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu
-    SCRIPT: make appveyor-subset-1
+    SCRIPT: make ci-subset-1
     MINGW_URL: https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror
     MINGW_ARCHIVE: i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z
     MINGW_DIR: mingw32
@@ -68,7 +68,7 @@ environment:
   - CI_JOB_NAME: i686-mingw-2
     MSYS_BITS: 32
     RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu
-    SCRIPT: make appveyor-subset-2
+    SCRIPT: make ci-subset-2
     MINGW_URL: https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror
     MINGW_ARCHIVE: i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z
     MINGW_DIR: mingw32
index 556625b531d1c96b397062fd4360446978cf0069..c14adf8ce33c7f276332bc9d0b8685c7fdf219b8 100644 (file)
 # library.
 #debug-assertions = false
 
-# Whether or not debuginfo is emitted
-#debuginfo = false
+# Debuginfo level for most of Rust code, corresponds to the `-C debuginfo=N` option of `rustc`.
+# `0` - no debug info
+# `1` - line tables only
+# `2` - full debug info with variable and type information
+# Can be overriden for specific subsets of Rust code (rustc, std or tools).
+# Debuginfo for tests run with compiletest is not controlled by this option
+# and needs to be enabled separately with `debuginfo-level-tests`.
+#debuginfo-level = if debug { 2 } else { 0 }
 
-# Whether or not line number debug information is emitted
-#debuginfo-lines = false
+# Debuginfo level for the compiler.
+#debuginfo-level-rustc = debuginfo-level
 
-# Whether or not to only build debuginfo for the standard library if enabled.
-# If enabled, this will not compile the compiler with debuginfo, just the
-# standard library.
-#debuginfo-only-std = false
+# Debuginfo level for the standard library.
+#debuginfo-level-std = debuginfo-level
 
-# Enable debuginfo for the extended tools: cargo, rls, rustfmt
-# Adding debuginfo makes them several times larger.
-#debuginfo-tools = false
+# Debuginfo level for the tools.
+#debuginfo-level-tools = debuginfo-level
+
+# Debuginfo level for the test suites run with compiletest.
+# FIXME(#61117): Some tests fail when this option is enabled.
+#debuginfo-level-tests = 0
 
 # Whether or not `panic!`s generate backtraces (RUST_BACKTRACE)
 #backtrace = true
 # harness are debuggable just from logfiles.
 #verbose-tests = false
 
-# Flag indicating whether tests are compiled with optimizations (the -O flag) or
-# with debuginfo (the -g flag)
+# Flag indicating whether tests are compiled with optimizations (the -O flag).
 #optimize-tests = true
-#debuginfo-tests = true
 
 # Flag indicating whether codegen tests will be run or not. If you get an error
 # saying that the FileCheck executable is missing, you may want to disable this.
index 821c37dc235969eaded9f4505287e86cfb9307b5..d51961c65b7aed63b32833e273e2afc4e4b69cf6 100644 (file)
@@ -102,6 +102,10 @@ fn main() {
 
     cmd.env("RUSTC_BREAK_ON_ICE", "1");
 
+    if let Ok(debuginfo_level) = env::var("RUSTC_DEBUGINFO_LEVEL") {
+        cmd.arg(format!("-Cdebuginfo={}", debuginfo_level));
+    }
+
     if let Some(target) = target {
         // The stage0 compiler has a special sysroot distinct from what we
         // actually downloaded, so we just always pass the `--sysroot` option.
@@ -169,11 +173,6 @@ fn main() {
 
         // Set various options from config.toml to configure how we're building
         // code.
-        if env::var("RUSTC_DEBUGINFO") == Ok("true".to_string()) {
-            cmd.arg("-g");
-        } else if env::var("RUSTC_DEBUGINFO_LINES") == Ok("true".to_string()) {
-            cmd.arg("-Cdebuginfo=1");
-        }
         let debug_assertions = match env::var("RUSTC_DEBUG_ASSERTIONS") {
             Ok(s) => if s == "true" { "y" } else { "n" },
             Err(..) => "n",
index 51663e93169822fb1e15b6eb3f3e35338b00075a..e616b2647a9f4ea16806d902391b5387b984a7b6 100644 (file)
@@ -970,22 +970,15 @@ pub fn cargo(
             cargo.env("RUSTDOC_LIBDIR", self.rustc_libdir(compiler));
         }
 
-        if mode.is_tool() {
-            // Tools like cargo and rls don't get debuginfo by default right now, but this can be
-            // enabled in the config.  Adding debuginfo makes them several times larger.
-            if self.config.rust_debuginfo_tools {
-                cargo.env("RUSTC_DEBUGINFO", self.config.rust_debuginfo.to_string());
-                cargo.env(
-                    "RUSTC_DEBUGINFO_LINES",
-                    self.config.rust_debuginfo_lines.to_string(),
-                );
-            }
-        } else {
-            cargo.env("RUSTC_DEBUGINFO", self.config.rust_debuginfo.to_string());
-            cargo.env(
-                "RUSTC_DEBUGINFO_LINES",
-                self.config.rust_debuginfo_lines.to_string(),
-            );
+        let debuginfo_level = match mode {
+            Mode::Rustc | Mode::Codegen => self.config.rust_debuginfo_level_rustc,
+            Mode::Std | Mode::Test => self.config.rust_debuginfo_level_std,
+            Mode::ToolBootstrap | Mode::ToolStd |
+            Mode::ToolTest | Mode::ToolRustc => self.config.rust_debuginfo_level_tools,
+        };
+        cargo.env("RUSTC_DEBUGINFO_LEVEL", debuginfo_level.to_string());
+
+        if !mode.is_tool() {
             cargo.env("RUSTC_FORCE_UNSTABLE", "1");
 
             // Currently the compiler depends on crates from crates.io, and
index 2da5e1c5902c11deadf028842a0b1d3d34c59b8e..6c81b6ada2b9fdc066589dde545b87c68a7b9903 100644 (file)
@@ -586,13 +586,6 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Command) {
     let libdir_relative = builder.config.libdir_relative().unwrap_or(Path::new("lib"));
     cargo.env("CFG_LIBDIR_RELATIVE", libdir_relative);
 
-    // If we're not building a compiler with debugging information then remove
-    // these two env vars which would be set otherwise.
-    if builder.config.rust_debuginfo_only_std {
-        cargo.env_remove("RUSTC_DEBUGINFO");
-        cargo.env_remove("RUSTC_DEBUGINFO_LINES");
-    }
-
     if let Some(ref ver_date) = builder.rust_info.commit_date() {
         cargo.env("CFG_VER_DATE", ver_date);
     }
index b1d009a674066974415de9c2782f08351a4a8e9c..d618654b129af844b3a3a1ca6097da7ae6e39d3d 100644 (file)
@@ -96,15 +96,14 @@ pub struct Config {
     pub rust_codegen_units: Option<u32>,
     pub rust_codegen_units_std: Option<u32>,
     pub rust_debug_assertions: bool,
-    pub rust_debuginfo: bool,
-    pub rust_debuginfo_lines: bool,
-    pub rust_debuginfo_only_std: bool,
-    pub rust_debuginfo_tools: bool,
+    pub rust_debuginfo_level_rustc: u32,
+    pub rust_debuginfo_level_std: u32,
+    pub rust_debuginfo_level_tools: u32,
+    pub rust_debuginfo_level_tests: u32,
     pub rust_rpath: bool,
     pub rustc_parallel: bool,
     pub rustc_default_linker: Option<String>,
     pub rust_optimize_tests: bool,
-    pub rust_debuginfo_tests: bool,
     pub rust_dist_src: bool,
     pub rust_codegen_backends: Vec<Interned<String>>,
     pub rust_codegen_backends_dir: String,
@@ -300,10 +299,11 @@ struct Rust {
     codegen_units: Option<u32>,
     codegen_units_std: Option<u32>,
     debug_assertions: Option<bool>,
-    debuginfo: Option<bool>,
-    debuginfo_lines: Option<bool>,
-    debuginfo_only_std: Option<bool>,
-    debuginfo_tools: Option<bool>,
+    debuginfo_level: Option<u32>,
+    debuginfo_level_rustc: Option<u32>,
+    debuginfo_level_std: Option<u32>,
+    debuginfo_level_tools: Option<u32>,
+    debuginfo_level_tests: Option<u32>,
     parallel_compiler: Option<bool>,
     backtrace: Option<bool>,
     default_linker: Option<String>,
@@ -311,7 +311,6 @@ struct Rust {
     musl_root: Option<String>,
     rpath: Option<bool>,
     optimize_tests: Option<bool>,
-    debuginfo_tests: Option<bool>,
     codegen_tests: Option<bool>,
     ignore_git: Option<bool>,
     debug: Option<bool>,
@@ -495,12 +494,13 @@ pub fn parse(args: &[String]) -> Config {
         // Store off these values as options because if they're not provided
         // we'll infer default values for them later
         let mut llvm_assertions = None;
-        let mut debuginfo_lines = None;
-        let mut debuginfo_only_std = None;
-        let mut debuginfo_tools = None;
         let mut debug = None;
-        let mut debuginfo = None;
         let mut debug_assertions = None;
+        let mut debuginfo_level = None;
+        let mut debuginfo_level_rustc = None;
+        let mut debuginfo_level_std = None;
+        let mut debuginfo_level_tools = None;
+        let mut debuginfo_level_tests = None;
         let mut optimize = None;
         let mut ignore_git = None;
 
@@ -540,14 +540,14 @@ pub fn parse(args: &[String]) -> Config {
         if let Some(ref rust) = toml.rust {
             debug = rust.debug;
             debug_assertions = rust.debug_assertions;
-            debuginfo = rust.debuginfo;
-            debuginfo_lines = rust.debuginfo_lines;
-            debuginfo_only_std = rust.debuginfo_only_std;
-            debuginfo_tools = rust.debuginfo_tools;
+            debuginfo_level = rust.debuginfo_level;
+            debuginfo_level_rustc = rust.debuginfo_level_rustc;
+            debuginfo_level_std = rust.debuginfo_level_std;
+            debuginfo_level_tools = rust.debuginfo_level_tools;
+            debuginfo_level_tests = rust.debuginfo_level_tests;
             optimize = rust.optimize;
             ignore_git = rust.ignore_git;
             set(&mut config.rust_optimize_tests, rust.optimize_tests);
-            set(&mut config.rust_debuginfo_tests, rust.debuginfo_tests);
             set(&mut config.codegen_tests, rust.codegen_tests);
             set(&mut config.rust_rpath, rust.rpath);
             set(&mut config.jemalloc, rust.jemalloc);
@@ -639,18 +639,19 @@ pub fn parse(args: &[String]) -> Config {
         let default = true;
         config.rust_optimize = optimize.unwrap_or(default);
 
-        let default = match &config.channel[..] {
-            "stable" | "beta" | "nightly" => true,
-            _ => false,
-        };
-        config.rust_debuginfo_lines = debuginfo_lines.unwrap_or(default);
-        config.rust_debuginfo_only_std = debuginfo_only_std.unwrap_or(default);
-        config.rust_debuginfo_tools = debuginfo_tools.unwrap_or(false);
-
         let default = debug == Some(true);
-        config.rust_debuginfo = debuginfo.unwrap_or(default);
         config.rust_debug_assertions = debug_assertions.unwrap_or(default);
 
+        let with_defaults = |debuginfo_level_specific: Option<u32>| {
+            debuginfo_level_specific
+                .or(debuginfo_level)
+                .unwrap_or(if debug == Some(true) { 2 } else { 0 })
+        };
+        config.rust_debuginfo_level_rustc = with_defaults(debuginfo_level_rustc);
+        config.rust_debuginfo_level_std = with_defaults(debuginfo_level_std);
+        config.rust_debuginfo_level_tools = with_defaults(debuginfo_level_tools);
+        config.rust_debuginfo_level_tests = debuginfo_level_tests.unwrap_or(0);
+
         let default = config.channel == "dev";
         config.ignore_git = ignore_git.unwrap_or(default);
 
index ade8afee7c10930942660bdf2cf70814c2cb21e7..53d3dbf60d1d7c74a094fead7f66471c133c07ae 100755 (executable)
@@ -37,7 +37,6 @@ o("compiler-docs", "build.compiler-docs", "build compiler documentation")
 o("optimize-tests", "rust.optimize-tests", "build tests with optimizations")
 o("parallel-compiler", "rust.parallel-compiler", "build a multi-threaded rustc")
 o("test-miri", "rust.test-miri", "run miri's test suite")
-o("debuginfo-tests", "rust.debuginfo-tests", "build tests with debugger metadata")
 o("verbose-tests", "rust.verbose-tests", "enable verbose output when running tests")
 o("ccache", "llvm.ccache", "invoke gcc/clang via ccache to reuse object files between builds")
 o("sccache", None, "invoke gcc/clang via sccache to reuse object files between builds")
@@ -77,10 +76,11 @@ o("optimize-llvm", "llvm.optimize", "build optimized LLVM")
 o("llvm-assertions", "llvm.assertions", "build LLVM with assertions")
 o("debug-assertions", "rust.debug-assertions", "build with debugging assertions")
 o("llvm-release-debuginfo", "llvm.release-debuginfo", "build LLVM with debugger metadata")
-o("debuginfo", "rust.debuginfo", "build with debugger metadata")
-o("debuginfo-lines", "rust.debuginfo-lines", "build with line number debugger metadata")
-o("debuginfo-only-std", "rust.debuginfo-only-std", "build only libstd with debugging information")
-o("debuginfo-tools", "rust.debuginfo-tools", "build extended tools with debugging information")
+o("debuginfo-level", "rust.debuginfo-level", "debuginfo level for Rust code")
+o("debuginfo-level-rustc", "rust.debuginfo-level-rustc", "debuginfo level for the compiler")
+o("debuginfo-level-std", "rust.debuginfo-level-std", "debuginfo level for the standard library")
+o("debuginfo-level-tools", "rust.debuginfo-level-tools", "debuginfo level for the tools")
+o("debuginfo-level-tests", "rust.debuginfo-level-tests", "debuginfo level for the test suites run with compiletest")
 v("save-toolstates", "rust.save-toolstates", "save build and test status of external tools into this file")
 
 v("prefix", "install.prefix", "set installation prefix")
index 07be27c2f5a0238a24a2523989a836139b87a434..ea05b30eceff9f1c0e3525a45367028fa5e1c3ad 100644 (file)
@@ -80,9 +80,9 @@ TESTS_IN_2 := \
        src/test/run-pass-fulldeps \
        src/tools/linkchecker
 
-appveyor-subset-1:
+ci-subset-1:
        $(Q)$(BOOTSTRAP) test $(TESTS_IN_2:%=--exclude %)
-appveyor-subset-2:
+ci-subset-2:
        $(Q)$(BOOTSTRAP) test $(TESTS_IN_2)
 
 
index be0af8be7b272bc615aab84985faa07db286c449..05b3ce6bc896464c0c127ca6a0a9444219ded7e1 100644 (file)
@@ -976,14 +976,10 @@ fn run(self, builder: &Builder<'_>) {
         }
 
         if suite == "debuginfo" {
-            // Skip debuginfo tests on MSVC
-            if builder.config.build.contains("msvc") {
-                return;
-            }
-
+            let msvc = builder.config.build.contains("msvc");
             if mode == "debuginfo" {
                 return builder.ensure(Compiletest {
-                    mode: "debuginfo-both",
+                    mode: if msvc { "debuginfo-cdb" } else { "debuginfo-gdb+lldb" },
                     ..self
                 });
             }
@@ -1082,10 +1078,8 @@ fn run(self, builder: &Builder<'_>) {
             if builder.config.rust_optimize_tests {
                 flags.push("-O".to_string());
             }
-            if builder.config.rust_debuginfo_tests {
-                flags.push("-g".to_string());
-            }
         }
+        flags.push(format!("-Cdebuginfo={}", builder.config.rust_debuginfo_level_tests));
         flags.push("-Zunstable-options".to_string());
         flags.push(builder.config.cmd.rustc_args().join(" "));
 
index edcd68d010e8451a44cdbd5259b221715608ba6f..d723f286fa8890a7b5936474d2e1116333d3be50 100644 (file)
@@ -485,10 +485,6 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
             &[],
         );
 
-        // Most tools don't get debuginfo, but rustdoc should.
-        cargo.env("RUSTC_DEBUGINFO", builder.config.rust_debuginfo.to_string())
-             .env("RUSTC_DEBUGINFO_LINES", builder.config.rust_debuginfo_lines.to_string());
-
         let _folder = builder.fold_output(|| format!("stage{}-rustdoc", target_compiler.stage));
         builder.info(&format!("Building rustdoc for stage{} ({})",
             target_compiler.stage, target_compiler.host));
index a162c65672f8251771ffe2bf2a0c80a570a7dd95..f22f0559265b11ef6d0f5bbb526b722e5359c91d 100644 (file)
@@ -326,6 +326,8 @@ pub enum CiEnv {
     Travis,
     /// The AppVeyor environment, for Windows builds.
     AppVeyor,
+    /// The Azure Pipelines environment, for Linux (including Docker), Windows, and macOS builds.
+    AzurePipelines,
 }
 
 impl CiEnv {
@@ -335,6 +337,8 @@ pub fn current() -> CiEnv {
             CiEnv::Travis
         } else if env::var("APPVEYOR").ok().map_or(false, |e| &*e == "True") {
             CiEnv::AppVeyor
+        } else if env::var("TF_BUILD").ok().map_or(false, |e| &*e == "True") {
+            CiEnv::AzurePipelines
         } else {
             CiEnv::None
         }
index e7d6f201b444ec757ec0775e644252999459f45c..bf449c83f12f1fe04559184626d007803d0a35bf 100644 (file)
@@ -32,9 +32,10 @@ COPY dist-various-2/build-cloudabi-toolchain.sh /tmp/
 RUN /tmp/build-cloudabi-toolchain.sh x86_64-unknown-cloudabi
 COPY dist-various-2/build-fuchsia-toolchain.sh /tmp/
 RUN /tmp/build-fuchsia-toolchain.sh
-COPY dist-various-2/build-solaris-toolchain.sh /tmp/
-RUN /tmp/build-solaris-toolchain.sh x86_64  amd64   solaris-i386
-RUN /tmp/build-solaris-toolchain.sh sparcv9 sparcv9 solaris-sparc
+# FIXME(#61022) - reenable solaris
+# COPY dist-various-2/build-solaris-toolchain.sh /tmp/
+# RUN /tmp/build-solaris-toolchain.sh x86_64  amd64   solaris-i386
+# RUN /tmp/build-solaris-toolchain.sh sparcv9 sparcv9 solaris-sparc
 COPY dist-various-2/build-x86_64-fortanix-unknown-sgx-toolchain.sh /tmp/
 # We pass the commit id of the port of LLVM's libunwind to the build script.
 # Any update to the commit id here, should cause the container image to be re-built from this point on.
@@ -73,10 +74,11 @@ ENV CARGO_TARGET_AARCH64_FUCHSIA_RUSTFLAGS \
 
 ENV TARGETS=x86_64-fuchsia
 ENV TARGETS=$TARGETS,aarch64-fuchsia
-ENV TARGETS=$TARGETS,sparcv9-sun-solaris
 ENV TARGETS=$TARGETS,wasm32-unknown-unknown
 ENV TARGETS=$TARGETS,wasm32-wasi
-ENV TARGETS=$TARGETS,x86_64-sun-solaris
+# FIXME(#61022) - reenable solaris
+# ENV TARGETS=$TARGETS,sparcv9-sun-solaris
+# ENV TARGETS=$TARGETS,x86_64-sun-solaris
 ENV TARGETS=$TARGETS,x86_64-unknown-linux-gnux32
 ENV TARGETS=$TARGETS,x86_64-unknown-cloudabi
 ENV TARGETS=$TARGETS,x86_64-fortanix-unknown-sgx
index 98a765e1cec9557c815dca50507ebeb5fe2def60..c9642dbf60c66b52745527813a1a98c4cb217e0d 100755 (executable)
@@ -40,9 +40,12 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then
       docker --version >> $hash_key
       cksum=$(sha512sum $hash_key | \
         awk '{print $1}')
+
       s3url="s3://$SCCACHE_BUCKET/docker/$cksum"
-      url="https://s3-us-west-1.amazonaws.com/$SCCACHE_BUCKET/docker/$cksum"
-      echo "Attempting to download $s3url"
+      url="https://$SCCACHE_BUCKET.s3.amazonaws.com/docker/$cksum"
+      upload="aws s3 cp - $s3url"
+
+      echo "Attempting to download $url"
       rm -f /tmp/rustci_docker_cache
       set +e
       retry curl -y 30 -Y 10 --connect-timeout 30 -f -L -C - -o /tmp/rustci_docker_cache "$url"
@@ -65,17 +68,17 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then
       -f "$dockerfile" \
       "$context"
 
-    if [ "$s3url" != "" ]; then
+    if [ "$upload" != "" ]; then
       digest=$(docker inspect rust-ci --format '{{.Id}}')
       echo "Built container $digest"
       if ! grep -q "$digest" <(echo "$loaded_images"); then
-        echo "Uploading finished image to $s3url"
+        echo "Uploading finished image to $url"
         set +e
         docker history -q rust-ci | \
           grep -v missing | \
           xargs docker save | \
           gzip | \
-          aws s3 cp - $s3url
+          $upload
         set -e
       else
         echo "Looks like docker image is the same as before, not uploading"
@@ -87,8 +90,8 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then
       echo "$digest" >>"$info"
     fi
 elif [ -f "$docker_dir/disabled/$image/Dockerfile" ]; then
-    if [ -n "$TRAVIS_OS_NAME" ]; then
-        echo Cannot run disabled images on travis!
+    if isCI; then
+        echo Cannot run disabled images on CI!
         exit 1
     fi
     # retry messes with the pipe from tar to docker. Not needed on non-travis
@@ -140,8 +143,11 @@ exec docker \
   --env DEPLOY \
   --env DEPLOY_ALT \
   --env LOCAL_USER_ID=`id -u` \
+  --env CI \
   --env TRAVIS \
   --env TRAVIS_BRANCH \
+  --env TF_BUILD \
+  --env BUILD_SOURCEBRANCHNAME \
   --env TOOLSTATE_REPO_ACCESS_TOKEN \
   --env CI_JOB_NAME="${CI_JOB_NAME-$IMAGE}" \
   --volume "$HOME/.cargo:/cargo" \
index 42d0d7db5964ca59a2e444e1aed0dc80ab43f795..8ead6e0e4bd6b7c8ff73e137d0a9c2a6faab1db5 100755 (executable)
@@ -23,7 +23,9 @@ fi
 ci_dir=`cd $(dirname $0) && pwd`
 source "$ci_dir/shared.sh"
 
-if [ "$TRAVIS" != "true" ] || [ "$TRAVIS_BRANCH" == "auto" ]; then
+branch_name=$(getCIBranch)
+
+if [ ! isCI ] || [ "$branch_name" = "auto" ]; then
     RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set build.print-step-timings --enable-verbose-tests"
 fi
 
@@ -44,10 +46,11 @@ fi
 # FIXME: need a scheme for changing this `nightly` value to `beta` and `stable`
 #        either automatically or manually.
 export RUST_RELEASE_CHANNEL=nightly
-if [ "$DEPLOY$DEPLOY_ALT" != "" ]; then
+if [ "$DEPLOY$DEPLOY_ALT" = "1" ]; then
   RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --release-channel=$RUST_RELEASE_CHANNEL"
   RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-llvm-static-stdcpp"
   RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.remap-debuginfo"
+  RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.debuginfo-level-std=1"
 
   if [ "$NO_LLVM_ASSERTIONS" = "1" ]; then
     RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-llvm-assertions"
@@ -109,7 +112,7 @@ travis_time_finish
 # Display the CPU and memory information. This helps us know why the CI timing
 # is fluctuating.
 travis_fold start log-system-info
-if [ "$TRAVIS_OS_NAME" = "osx" ]; then
+if isOSX; then
     system_profiler SPHardwareDataType || true
     sysctl hw || true
     ncpus=$(sysctl -n hw.ncpu)
@@ -138,3 +141,5 @@ else
   do_make all
   do_make "$RUST_CHECK_TARGET"
 fi
+
+sccache --show-stats || true
index 3ba64ad412064e48b5eb3a91d84793fa891323bb..1e667fca5875afd8b57213211c3cdb63bd1207af 100644 (file)
@@ -24,6 +24,22 @@ function retry {
   done
 }
 
+function isCI {
+  [ "$CI" = "true" ] || [ "$TRAVIS" = "true" ] || [ "$TF_BUILD" = "True" ]
+}
+
+function isOSX {
+  [ "$TRAVIS_OS_NAME" = "osx" ] || [ "$AGENT_OS" = "Darwin" ]
+}
+
+function getCIBranch {
+  if [ "$TRAVIS" = "true" ]; then
+    echo "$TRAVIS_BRANCH"
+  else
+    echo "$BUILD_SOURCEBRANCHNAME"
+  fi;
+}
+
 if ! declare -F travis_fold; then
   if [ "${TRAVIS-false}" = 'true' ]; then
     # This is a trimmed down copy of
index 024594517d9884bfa636789086d6e570c44d4611..97c2d8e7a8e796010dc0f5126c599b52c386de57 100644 (file)
@@ -253,15 +253,16 @@ pub fn into_raw_non_null(b: Box<T>) -> NonNull<T> {
     #[unstable(feature = "ptr_internals", issue = "0", reason = "use into_raw_non_null instead")]
     #[inline]
     #[doc(hidden)]
-    pub fn into_unique(mut b: Box<T>) -> Unique<T> {
+    pub fn into_unique(b: Box<T>) -> Unique<T> {
+        let mut unique = b.0;
+        mem::forget(b);
         // Box is kind-of a library type, but recognized as a "unique pointer" by
         // Stacked Borrows.  This function here corresponds to "reborrowing to
         // a raw pointer", but there is no actual reborrow here -- so
         // without some care, the pointer we are returning here still carries
-        // the `Uniq` tag.  We round-trip through a mutable reference to avoid that.
-        let unique = unsafe { b.0.as_mut() as *mut T };
-        mem::forget(b);
-        unsafe { Unique::new_unchecked(unique) }
+        // the tag of `b`, with `Unique` permission.
+        // We round-trip through a mutable reference to avoid that.
+        unsafe { Unique::new_unchecked(unique.as_mut() as *mut T) }
     }
 
     /// Consumes and leaks the `Box`, returning a mutable reference,
index 545332bcd6a2f3985c5243bcb08b7f3417e7ce7f..3307bdf94f98590a04463d631cdce47c6dca2da1 100644 (file)
@@ -1,5 +1,3 @@
-#![cfg(not(miri))]
-
 use std::borrow::Cow;
 use std::mem::size_of;
 use std::{usize, isize};
@@ -763,6 +761,7 @@ fn from_into_inner() {
     it.next().unwrap();
     let vec = it.collect::<Vec<_>>();
     assert_eq!(vec, [2, 3]);
+    #[cfg(not(miri))] // Miri does not support comparing dangling pointers
     assert!(ptr != vec.as_ptr());
 }
 
@@ -971,6 +970,7 @@ fn test_reserve_exact() {
 }
 
 #[test]
+#[cfg(not(miri))] // Miri does not support signalling OOM
 fn test_try_reserve() {
 
     // These are the interesting cases:
@@ -1073,6 +1073,7 @@ fn test_try_reserve() {
 }
 
 #[test]
+#[cfg(not(miri))] // Miri does not support signalling OOM
 fn test_try_reserve_exact() {
 
     // This is exactly the same as test_try_reserve with the method changed.
index 073d3ab5937035a148053e8e6243a8c300903ab2..dc661a267e2a621f84682065b3276ecd45008d56 100644 (file)
@@ -1094,7 +1094,7 @@ unsafe fn append_elements(&mut self, other: *const [T]) {
         let count = (*other).len();
         self.reserve(count);
         let len = self.len();
-        ptr::copy_nonoverlapping(other as *const T, self.get_unchecked_mut(len), count);
+        ptr::copy_nonoverlapping(other as *const T, self.as_mut_ptr().add(len), count);
         self.len += count;
     }
 
index ce5e5f23a94b81e0745d9acaae662bea75adf719..d6bec816e4ee60fcea0fb79e277a4ccd27d99990 100644 (file)
@@ -486,9 +486,31 @@ pub fn alloc_slice<T>(&self, slice: &[T]) -> &mut [T]
         }
     }
 
+    #[inline]
+    unsafe fn write_from_iter<T, I: Iterator<Item = T>>(
+        &self,
+        mut iter: I,
+        len: usize,
+        mem: *mut T,
+    ) -> &mut [T] {
+        let mut i = 0;
+        // Use a manual loop since LLVM manages to optimize it better for
+        // slice iterators
+        loop {
+            let value = iter.next();
+            if i >= len || value.is_none() {
+                // We only return as many items as the iterator gave us, even
+                // though it was supposed to give us `len`
+                return slice::from_raw_parts_mut(mem, i);
+            }
+            ptr::write(mem.offset(i as isize), value.unwrap());
+            i += 1;
+        }
+    }
+
     #[inline]
     pub fn alloc_from_iter<T, I: IntoIterator<Item = T>>(&self, iter: I) -> &mut [T] {
-        let mut iter = iter.into_iter();
+        let iter = iter.into_iter();
         assert!(mem::size_of::<T>() != 0);
         assert!(!mem::needs_drop::<T>());
 
@@ -505,10 +527,7 @@ pub fn alloc_from_iter<T, I: IntoIterator<Item = T>>(&self, iter: I) -> &mut [T]
                 let size = len.checked_mul(mem::size_of::<T>()).unwrap();
                 let mem = self.alloc_raw(size, mem::align_of::<T>()) as *mut _ as *mut T;
                 unsafe {
-                    for i in 0..len {
-                        ptr::write(mem.offset(i as isize), iter.next().unwrap())
-                    }
-                    slice::from_raw_parts_mut(mem, len)
+                    self.write_from_iter(iter, len, mem)
                 }
             }
             (_, _) => {
index b48d81f2ef8f4731623fb7ffe50747ab64954529..c179b05683d1c91258bf53b335f9cc94d8e305c5 100644 (file)
@@ -6,6 +6,15 @@
 use std::marker::PhantomData;
 use smallvec::SmallVec;
 
+/// This declares a list of types which can be allocated by `Arena`.
+///
+/// The `few` modifier will cause allocation to use the shared arena and recording the destructor.
+/// This is faster and more memory efficient if there's only a few allocations of the type.
+/// Leaving `few` out will cause the type to get its own dedicated `TypedArena` which is
+/// faster and more memory efficient if there is lots of allocations.
+///
+/// Specifying the `decode` modifier will add decode impls for &T and &[T] where T is the type
+/// listed. These impls will appear in the implement_ty_decoder! macro.
 #[macro_export]
 macro_rules! arena_types {
     ($macro:path, $args:tt, $tcx:lifetime) => (
@@ -14,7 +23,7 @@ macro_rules! arena_types {
                 rustc::hir::def_id::DefId,
                 rustc::ty::subst::SubstsRef<$tcx>
             )>,
-            [few] mir_keys: rustc::util::nodemap::DefIdSet,
+            [few, decode] mir_keys: rustc::util::nodemap::DefIdSet,
             [decode] specialization_graph: rustc::traits::specialization_graph::Graph,
             [] region_scope_tree: rustc::middle::region::ScopeTree,
             [] item_local_set: rustc::util::nodemap::ItemLocalSet,
@@ -58,6 +67,40 @@ macro_rules! arena_types {
                 rustc::infer::canonical::Canonical<'tcx,
                     rustc::infer::canonical::QueryResponse<'tcx, rustc::ty::Ty<'tcx>>
                 >,
+            [few] crate_inherent_impls: rustc::ty::CrateInherentImpls,
+            [decode] borrowck: rustc::middle::borrowck::BorrowCheckResult,
+            [few] upstream_monomorphizations:
+                rustc::util::nodemap::DefIdMap<
+                    rustc_data_structures::fx::FxHashMap<
+                        rustc::ty::subst::SubstsRef<'tcx>,
+                        rustc::hir::def_id::CrateNum
+                    >
+                >,
+            [few] resolve_lifetimes: rustc::middle::resolve_lifetime::ResolveLifetimes,
+            [decode] generic_predicates: rustc::ty::GenericPredicates<'tcx>,
+            [few] lint_levels: rustc::lint::LintLevelMap,
+            [few] stability_index: rustc::middle::stability::Index<'tcx>,
+            [few] features: syntax::feature_gate::Features,
+            [few] all_traits: Vec<rustc::hir::def_id::DefId>,
+            [few] privacy_access_levels: rustc::middle::privacy::AccessLevels,
+            [few] target_features_whitelist: rustc_data_structures::fx::FxHashMap<
+                String,
+                Option<syntax::symbol::Symbol>
+            >,
+            [few] wasm_import_module_map: rustc_data_structures::fx::FxHashMap<
+                rustc::hir::def_id::DefId,
+                String
+            >,
+            [few] get_lib_features: rustc::middle::lib_features::LibFeatures,
+            [few] defined_lib_features: rustc::middle::lang_items::LanguageItems,
+            [few] visible_parent_map: rustc::util::nodemap::DefIdMap<rustc::hir::def_id::DefId>,
+            [few] foreign_module: rustc::middle::cstore::ForeignModule,
+            [few] foreign_modules: Vec<rustc::middle::cstore::ForeignModule>,
+            [few] reachable_non_generics: rustc::util::nodemap::DefIdMap<
+                rustc::middle::exported_symbols::SymbolExportLevel
+            >,
+            [few] crate_variances: rustc::ty::CrateVariancesMap<'tcx>,
+            [few] inferred_outlives_crate: rustc::ty::CratePredicatesMap<'tcx>,
         ], $tcx);
     )
 }
@@ -119,7 +162,7 @@ pub trait ArenaAllocatable {}
 
 impl<T: Copy> ArenaAllocatable for T {}
 
-pub unsafe trait ArenaField<'tcx>: Sized {
+unsafe trait ArenaField<'tcx>: Sized {
     /// 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 TypedArena<Self>>;
index 6b82548f6dcde11e7ee9ce2ea6f397647c7e0935..3d83918bd0a661989ef1d7a78eac2504ae75e42a 100644 (file)
@@ -4062,10 +4062,6 @@ fn lower_anon_const(&mut self, c: &AnonConst) -> hir::AnonConst {
     fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
         let kind = match e.node {
             ExprKind::Box(ref inner) => hir::ExprKind::Box(P(self.lower_expr(inner))),
-            ExprKind::ObsoleteInPlace(..) => {
-                self.sess.abort_if_errors();
-                span_bug!(e.span, "encountered ObsoleteInPlace expr during lowering");
-            }
             ExprKind::Array(ref exprs) => {
                 hir::ExprKind::Array(exprs.iter().map(|x| self.lower_expr(x)).collect())
             }
index 512e4d434434ce892a52f9050036e9ba0ac8359e..c3afca35303c93e8272d1a5681317f48af448eb2 100644 (file)
@@ -21,7 +21,7 @@
 pub use self::Level::*;
 pub use self::LintSource::*;
 
-use rustc_data_structures::sync::{self, Lrc};
+use rustc_data_structures::sync;
 
 use crate::hir::def_id::{CrateNum, LOCAL_CRATE};
 use crate::hir::intravisit;
@@ -35,7 +35,7 @@
 use errors::{DiagnosticBuilder, DiagnosticId};
 use std::{hash, ptr};
 use syntax::ast;
-use syntax::source_map::{MultiSpan, ExpnFormat};
+use syntax::source_map::{MultiSpan, ExpnFormat, CompilerDesugaringKind};
 use syntax::early_buffered_lints::BufferedEarlyLintId;
 use syntax::edition::Edition;
 use syntax::symbol::{Symbol, sym};
@@ -767,7 +767,7 @@ pub fn maybe_lint_level_root(tcx: TyCtxt<'_, '_, '_>, id: hir::HirId) -> bool {
 }
 
 fn lint_levels<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, cnum: CrateNum)
-    -> Lrc<LintLevelMap>
+    -> &'tcx LintLevelMap
 {
     assert_eq!(cnum, LOCAL_CRATE);
     let mut builder = LintLevelMapBuilder {
@@ -784,7 +784,7 @@ fn lint_levels<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, cnum: CrateNum)
     intravisit::walk_crate(&mut builder, krate);
     builder.levels.pop(push);
 
-    Lrc::new(builder.levels.build_map())
+    tcx.arena.alloc(builder.levels.build_map())
 }
 
 struct LintLevelMapBuilder<'a, 'tcx: 'a> {
@@ -887,21 +887,22 @@ pub fn in_external_macro(sess: &Session, span: Span) -> bool {
     };
 
     match info.format {
-        ExpnFormat::MacroAttribute(..) => return true, // definitely a plugin
-        ExpnFormat::CompilerDesugaring(_) => return true, // well, it's "external"
-        ExpnFormat::MacroBang(..) => {} // check below
-    }
-
-    let def_site = match info.def_site {
-        Some(span) => span,
-        // no span for the def_site means it's an external macro
-        None => return true,
-    };
+        ExpnFormat::MacroAttribute(..) => true, // definitely a plugin
+        ExpnFormat::CompilerDesugaring(CompilerDesugaringKind::ForLoop) => false,
+        ExpnFormat::CompilerDesugaring(_) => true, // well, it's "external"
+        ExpnFormat::MacroBang(..) => {
+            let def_site = match info.def_site {
+                Some(span) => span,
+                // no span for the def_site means it's an external macro
+                None => return true,
+            };
 
-    match sess.source_map().span_to_snippet(def_site) {
-        Ok(code) => !code.starts_with("macro_rules"),
-        // no snippet = external macro or compiler-builtin expansion
-        Err(_) => true,
+            match sess.source_map().span_to_snippet(def_site) {
+                Ok(code) => !code.starts_with("macro_rules"),
+                // no snippet = external macro or compiler-builtin expansion
+                Err(_) => true,
+            }
+        }
     }
 }
 
index d22de6c6476996ea85f254427de7fbb933b75784..6f9abcd624f9921abca3606fa11e73172449c2f1 100644 (file)
@@ -256,8 +256,8 @@ pub fn used_crates(tcx: TyCtxt<'_, '_, '_>, prefer: LinkagePreference)
             Some((cnum, path))
         })
         .collect::<Vec<_>>();
-    let mut ordering = tcx.postorder_cnums(LOCAL_CRATE);
-    Lrc::make_mut(&mut ordering).reverse();
+    let mut ordering = tcx.postorder_cnums(LOCAL_CRATE).to_owned();
+    ordering.reverse();
     libs.sort_by_cached_key(|&(a, _)| {
         ordering.iter().position(|x| *x == a)
     });
index 419cc5936862cb250f1da8d09b7eaa05269594e8..775da1de313fa0956286240569006e739022d4d9 100644 (file)
@@ -15,7 +15,6 @@
 use crate::session::Session;
 use crate::util::nodemap::{DefIdMap, FxHashMap, FxHashSet, HirIdMap, HirIdSet};
 use errors::{Applicability, DiagnosticBuilder};
-use rustc_data_structures::sync::Lrc;
 use rustc_macros::HashStable;
 use std::borrow::Cow;
 use std::cell::Cell;
@@ -211,10 +210,10 @@ struct NamedRegionMap {
 /// See [`NamedRegionMap`].
 #[derive(Default)]
 pub struct ResolveLifetimes {
-    defs: FxHashMap<LocalDefId, Lrc<FxHashMap<ItemLocalId, Region>>>,
-    late_bound: FxHashMap<LocalDefId, Lrc<FxHashSet<ItemLocalId>>>,
+    defs: FxHashMap<LocalDefId, FxHashMap<ItemLocalId, Region>>,
+    late_bound: FxHashMap<LocalDefId, FxHashSet<ItemLocalId>>,
     object_lifetime_defaults:
-        FxHashMap<LocalDefId, Lrc<FxHashMap<ItemLocalId, Lrc<Vec<ObjectLifetimeDefault>>>>>,
+        FxHashMap<LocalDefId, FxHashMap<ItemLocalId, Vec<ObjectLifetimeDefault>>>,
 }
 
 impl_stable_hash_for!(struct crate::middle::resolve_lifetime::ResolveLifetimes {
@@ -347,7 +346,7 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
 
         named_region_map: |tcx, id| {
             let id = LocalDefId::from_def_id(DefId::local(id)); // (*)
-            tcx.resolve_lifetimes(LOCAL_CRATE).defs.get(&id).cloned()
+            tcx.resolve_lifetimes(LOCAL_CRATE).defs.get(&id)
         },
 
         is_late_bound_map: |tcx, id| {
@@ -355,7 +354,6 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
             tcx.resolve_lifetimes(LOCAL_CRATE)
                 .late_bound
                 .get(&id)
-                .cloned()
         },
 
         object_lifetime_defaults_map: |tcx, id| {
@@ -363,7 +361,6 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
             tcx.resolve_lifetimes(LOCAL_CRATE)
                 .object_lifetime_defaults
                 .get(&id)
-                .cloned()
         },
 
         ..*providers
@@ -379,7 +376,7 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
 fn resolve_lifetimes<'tcx>(
     tcx: TyCtxt<'_, 'tcx, 'tcx>,
     for_krate: CrateNum,
-) -> Lrc<ResolveLifetimes> {
+) -> &'tcx ResolveLifetimes {
     assert_eq!(for_krate, LOCAL_CRATE);
 
     let named_region_map = krate(tcx);
@@ -388,24 +385,22 @@ fn resolve_lifetimes<'tcx>(
 
     for (hir_id, v) in named_region_map.defs {
         let map = rl.defs.entry(hir_id.owner_local_def_id()).or_default();
-        Lrc::get_mut(map).unwrap().insert(hir_id.local_id, v);
+        map.insert(hir_id.local_id, v);
     }
     for hir_id in named_region_map.late_bound {
         let map = rl.late_bound
             .entry(hir_id.owner_local_def_id())
             .or_default();
-        Lrc::get_mut(map).unwrap().insert(hir_id.local_id);
+        map.insert(hir_id.local_id);
     }
     for (hir_id, v) in named_region_map.object_lifetime_defaults {
         let map = rl.object_lifetime_defaults
             .entry(hir_id.owner_local_def_id())
             .or_default();
-        Lrc::get_mut(map)
-            .unwrap()
-            .insert(hir_id.local_id, Lrc::new(v));
+        map.insert(hir_id.local_id, v);
     }
 
-    Lrc::new(rl)
+    tcx.arena.alloc(rl)
 }
 
 fn krate<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>) -> NamedRegionMap {
index abcf164cda6d46f783eec9251c3311f79a9c73be..ac0e99137cbc3ea68f76f7affc21f4d991347ffe 100644 (file)
@@ -883,7 +883,7 @@ pub fn check_unused_or_stable_features<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     remaining_lib_features.remove(&Symbol::intern("test"));
 
     let check_features =
-        |remaining_lib_features: &mut FxHashMap<_, _>, defined_features: &Vec<_>| {
+        |remaining_lib_features: &mut FxHashMap<_, _>, defined_features: &[_]| {
             for &(feature, since) in defined_features {
                 if let Some(since) = since {
                     if let Some(span) = remaining_lib_features.get(&feature) {
@@ -908,7 +908,7 @@ pub fn check_unused_or_stable_features<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
             if remaining_lib_features.is_empty() {
                 break;
             }
-            check_features(&mut remaining_lib_features, &tcx.defined_lib_features(cnum));
+            check_features(&mut remaining_lib_features, tcx.defined_lib_features(cnum));
         }
     }
 
index dd43cb2f18ece8d3c09ec480dc786b12f97c2295..aab9d5e3a02bee2bca2d9a0eb535b99af37ec824 100644 (file)
@@ -915,6 +915,13 @@ pub fn is_nonref_binding(&self) -> bool {
         }
     }
 
+    /// Returns `true` is the local is from a compiler desugaring, e.g.,
+    /// `__next` from a `for` loop.
+    #[inline]
+    pub fn from_compiler_desugaring(&self) -> bool {
+        self.source_info.span.compiler_desugaring_kind().is_some()
+    }
+
     /// Creates a new `LocalDecl` for a temporary.
     #[inline]
     pub fn new_temp(ty: Ty<'tcx>, span: Span) -> Self {
index 8825c94cdb81cb27c3abaef0002ffb80caaccc1c..c03cd7e268ef5ceed3e20e678624516bf12ed3fc 100644 (file)
         /// predicate gets in the way of some checks, which are intended
         /// to operate over only the actual where-clauses written by the
         /// user.)
-        query predicates_of(_: DefId) -> Lrc<ty::GenericPredicates<'tcx>> {}
+        query predicates_of(_: DefId) -> &'tcx ty::GenericPredicates<'tcx> {}
 
         query native_libraries(_: CrateNum) -> Lrc<Vec<NativeLibrary>> {
             desc { "looking up the native libraries of a linked crate" }
         }
 
-        query lint_levels(_: CrateNum) -> Lrc<lint::LintLevelMap> {
+        query lint_levels(_: CrateNum) -> &'tcx lint::LintLevelMap {
             eval_always
             desc { "computing the lint levels for items in this crate" }
         }
     }
 
     Linking {
-        query wasm_import_module_map(_: CrateNum) -> Lrc<FxHashMap<DefId, String>> {
+        query wasm_import_module_map(_: CrateNum) -> &'tcx FxHashMap<DefId, String> {
             desc { "wasm import module map" }
         }
     }
         /// equal to the `explicit_predicates_of` predicates plus the
         /// `inferred_outlives_of` predicates.
         query predicates_defined_on(_: DefId)
-            -> Lrc<ty::GenericPredicates<'tcx>> {}
+            -> &'tcx ty::GenericPredicates<'tcx> {}
 
         /// Returns the predicates written explicitly by the user.
         query explicit_predicates_of(_: DefId)
-            -> Lrc<ty::GenericPredicates<'tcx>> {}
+            -> &'tcx ty::GenericPredicates<'tcx> {}
 
         /// Returns the inferred outlives predicates (e.g., for `struct
         /// Foo<'a, T> { x: &'a T }`, this would return `T: 'a`).
         /// evaluate them even during type conversion, often before the
         /// full predicates are available (note that supertraits have
         /// additional acyclicity requirements).
-        query super_predicates_of(key: DefId) -> Lrc<ty::GenericPredicates<'tcx>> {
+        query super_predicates_of(key: DefId) -> &'tcx ty::GenericPredicates<'tcx> {
             desc { |tcx| "computing the supertraits of `{}`", tcx.def_path_str(key) }
         }
 
         /// To avoid cycles within the predicates of a single item we compute
         /// per-type-parameter predicates for resolving `T::AssocTy`.
         query type_param_predicates(key: (DefId, DefId))
-            -> Lrc<ty::GenericPredicates<'tcx>> {
+            -> &'tcx ty::GenericPredicates<'tcx> {
             no_force
             desc { |tcx| "computing the bounds for type parameter `{}`", {
                 let id = tcx.hir().as_local_hir_id(key.1).unwrap();
         query static_mutability(_: DefId) -> Option<hir::Mutability> {}
 
         /// Gets a map with the variance of every item; use `item_variance` instead.
-        query crate_variances(_: CrateNum) -> Lrc<ty::CrateVariancesMap<'tcx>> {
+        query crate_variances(_: CrateNum) -> &'tcx ty::CrateVariancesMap<'tcx> {
             desc { "computing the variances for items in this crate" }
         }
 
     TypeChecking {
         /// Maps from thee `DefId` of a type to its (inferred) outlives.
         query inferred_outlives_crate(_: CrateNum)
-            -> Lrc<ty::CratePredicatesMap<'tcx>> {
+            -> &'tcx ty::CratePredicatesMap<'tcx> {
             desc { "computing the inferred outlives predicates for items in this crate" }
         }
     }
 
     Other {
         /// Maps from an impl/trait `DefId to a list of the `DefId`s of its items.
-        query associated_item_def_ids(_: DefId) -> Lrc<Vec<DefId>> {}
+        query associated_item_def_ids(_: DefId) -> &'tcx [DefId] {}
 
         /// Maps from a trait item to the trait item "descriptor".
         query associated_item(_: DefId) -> ty::AssociatedItem {}
         /// Maps a `DefId` of a type to a list of its inherent impls.
         /// Contains implementations of methods that are inherent to a type.
         /// Methods in these implementations don't need to be exported.
-        query inherent_impls(_: DefId) -> Lrc<Vec<DefId>> {
+        query inherent_impls(_: DefId) -> &'tcx [DefId] {
             eval_always
         }
     }
     }
 
     Other {
-        query used_trait_imports(_: DefId) -> Lrc<DefIdSet> {}
+        query used_trait_imports(_: DefId) -> &'tcx DefIdSet {}
     }
 
     TypeChecking {
     }
 
     BorrowChecking {
-        query borrowck(_: DefId) -> Lrc<BorrowCheckResult> {}
+        query borrowck(_: DefId) -> &'tcx BorrowCheckResult {}
 
         /// Borrow-checks the function body. If this is a closure, returns
         /// additional requirements that the closure's creator must verify.
         /// Not meant to be used directly outside of coherence.
         /// (Defined only for `LOCAL_CRATE`.)
         query crate_inherent_impls(k: CrateNum)
-            -> Lrc<CrateInherentImpls> {
+            -> &'tcx CrateInherentImpls {
             eval_always
             desc { "all inherent impls defined in crate `{:?}`", k }
         }
         query check_match(_: DefId) -> () {}
 
         /// Performs part of the privacy check and computes "access levels".
-        query privacy_access_levels(_: CrateNum) -> Lrc<AccessLevels> {
+        query privacy_access_levels(_: CrateNum) -> &'tcx AccessLevels {
             eval_always
             desc { "privacy access levels" }
         }
 
     Other {
         query dylib_dependency_formats(_: CrateNum)
-                                        -> Lrc<Vec<(CrateNum, LinkagePreference)>> {
+                                        -> &'tcx [(CrateNum, LinkagePreference)] {
             desc { "dylib dependency formats of crate" }
         }
     }
             desc { "test whether a crate has #![no_builtins]" }
         }
 
-        query extern_crate(_: DefId) -> Lrc<Option<ExternCrate>> {
+        query extern_crate(_: DefId) -> Option<&'tcx ExternCrate> {
             eval_always
             desc { "getting crate's ExternCrateData" }
         }
             desc { "computing whether impls specialize one another" }
         }
         query in_scope_traits_map(_: DefIndex)
-            -> Option<Lrc<FxHashMap<ItemLocalId, Lrc<StableVec<TraitCandidate>>>>> {
+            -> Option<&'tcx FxHashMap<ItemLocalId, StableVec<TraitCandidate>>> {
             eval_always
             desc { "traits in scope at a block" }
         }
     }
 
     Other {
-        query module_exports(_: DefId) -> Option<Lrc<Vec<Export<hir::HirId>>>> {
+        query module_exports(_: DefId) -> Option<&'tcx [Export<hir::HirId>]> {
             eval_always
         }
     }
         // Does not include external symbols that don't have a corresponding DefId,
         // like the compiler-generated `main` function and so on.
         query reachable_non_generics(_: CrateNum)
-            -> Lrc<DefIdMap<SymbolExportLevel>> {
+            -> &'tcx DefIdMap<SymbolExportLevel> {
             desc { "looking up the exported symbols of a crate" }
         }
         query is_reachable_non_generic(_: DefId) -> bool {}
     Codegen {
         query upstream_monomorphizations(
             k: CrateNum
-        ) -> Lrc<DefIdMap<Lrc<FxHashMap<SubstsRef<'tcx>, CrateNum>>>> {
+        ) -> &'tcx DefIdMap<FxHashMap<SubstsRef<'tcx>, CrateNum>> {
             desc { "collecting available upstream monomorphizations `{:?}`", k }
         }
         query upstream_monomorphizations_for(_: DefId)
-            -> Option<Lrc<FxHashMap<SubstsRef<'tcx>, CrateNum>>> {}
+            -> Option<&'tcx FxHashMap<SubstsRef<'tcx>, CrateNum>> {}
     }
 
     Other {
-        query foreign_modules(_: CrateNum) -> Lrc<Vec<ForeignModule>> {
+        query foreign_modules(_: CrateNum) -> &'tcx [ForeignModule] {
             desc { "looking up the foreign modules of a linked crate" }
         }
 
 
     TypeChecking {
         query implementations_of_trait(_: (CrateNum, DefId))
-            -> Lrc<Vec<DefId>> {
+            -> &'tcx [DefId] {
             no_force
             desc { "looking up implementations of a trait in a crate" }
         }
         query all_trait_implementations(_: CrateNum)
-            -> Lrc<Vec<DefId>> {
+            -> &'tcx [DefId] {
             desc { "looking up all (?) trait implementations" }
         }
     }
 
     Other {
         query dllimport_foreign_items(_: CrateNum)
-            -> Lrc<FxHashSet<DefId>> {
+            -> &'tcx FxHashSet<DefId> {
             desc { "dllimport_foreign_items" }
         }
         query is_dllimport_foreign_item(_: DefId) -> bool {}
 
     BorrowChecking {
         // Lifetime resolution. See `middle::resolve_lifetimes`.
-        query resolve_lifetimes(_: CrateNum) -> Lrc<ResolveLifetimes> {
+        query resolve_lifetimes(_: CrateNum) -> &'tcx ResolveLifetimes {
             desc { "resolving lifetimes" }
         }
         query named_region_map(_: DefIndex) ->
-            Option<Lrc<FxHashMap<ItemLocalId, Region>>> {
+            Option<&'tcx FxHashMap<ItemLocalId, Region>> {
             desc { "looking up a named region" }
         }
         query is_late_bound_map(_: DefIndex) ->
-            Option<Lrc<FxHashSet<ItemLocalId>>> {
+            Option<&'tcx FxHashSet<ItemLocalId>> {
             desc { "testing if a region is late bound" }
         }
         query object_lifetime_defaults_map(_: DefIndex)
-            -> Option<Lrc<FxHashMap<ItemLocalId, Lrc<Vec<ObjectLifetimeDefault>>>>> {
+            -> Option<&'tcx FxHashMap<ItemLocalId, Vec<ObjectLifetimeDefault>>> {
             desc { "looking up lifetime defaults for a region" }
         }
     }
             eval_always
             desc { "fetching what a crate is named" }
         }
-        query item_children(_: DefId) -> Lrc<Vec<Export<hir::HirId>>> {}
+        query item_children(_: DefId) -> &'tcx [Export<hir::HirId>] {}
         query extern_mod_stmt_cnum(_: DefId) -> Option<CrateNum> {}
 
-        query get_lib_features(_: CrateNum) -> Lrc<LibFeatures> {
+        query get_lib_features(_: CrateNum) -> &'tcx LibFeatures {
             eval_always
             desc { "calculating the lib features map" }
         }
         query defined_lib_features(_: CrateNum)
-            -> Lrc<Vec<(Symbol, Option<Symbol>)>> {
+            -> &'tcx [(Symbol, Option<Symbol>)] {
             desc { "calculating the lib features defined in a crate" }
         }
-        query get_lang_items(_: CrateNum) -> Lrc<LanguageItems> {
+        query get_lang_items(_: CrateNum) -> &'tcx LanguageItems {
             eval_always
             desc { "calculating the lang items map" }
         }
-        query defined_lang_items(_: CrateNum) -> Lrc<Vec<(DefId, usize)>> {
+        query defined_lang_items(_: CrateNum) -> &'tcx [(DefId, usize)] {
             desc { "calculating the lang items defined in a crate" }
         }
-        query missing_lang_items(_: CrateNum) -> Lrc<Vec<LangItem>> {
+        query missing_lang_items(_: CrateNum) -> &'tcx [LangItem] {
             desc { "calculating the missing lang items in a crate" }
         }
         query visible_parent_map(_: CrateNum)
-            -> Lrc<DefIdMap<DefId>> {
+            -> &'tcx DefIdMap<DefId> {
             desc { "calculating the visible parent map" }
         }
         query missing_extern_crate_item(_: CrateNum) -> bool {
             eval_always
             desc { "looking at the source for a crate" }
         }
-        query postorder_cnums(_: CrateNum) -> Lrc<Vec<CrateNum>> {
+        query postorder_cnums(_: CrateNum) -> &'tcx [CrateNum] {
             eval_always
             desc { "generating a postorder list of CrateNums" }
         }
 
-        query upvars(_: DefId) -> Option<Lrc<Vec<hir::Upvar>>> {
+        query upvars(_: DefId) -> Option<&'tcx [hir::Upvar]> {
             eval_always
         }
         query maybe_unused_trait_import(_: DefId) -> bool {
             eval_always
         }
         query maybe_unused_extern_crates(_: CrateNum)
-            -> Lrc<Vec<(DefId, Span)>> {
+            -> &'tcx [(DefId, Span)] {
             eval_always
             desc { "looking up all possibly unused extern crates" }
         }
             eval_always
         }
 
-        query stability_index(_: CrateNum) -> Lrc<stability::Index<'tcx>> {
+        query stability_index(_: CrateNum) -> &'tcx stability::Index<'tcx> {
             eval_always
             desc { "calculating the stability index for the local crate" }
         }
-        query all_crate_nums(_: CrateNum) -> Lrc<Vec<CrateNum>> {
+        query all_crate_nums(_: CrateNum) -> &'tcx [CrateNum] {
             eval_always
             desc { "fetching all foreign CrateNum instances" }
         }
         /// A vector of every trait accessible in the whole crate
         /// (i.e., including those from subcrates). This is used only for
         /// error reporting.
-        query all_traits(_: CrateNum) -> Lrc<Vec<DefId>> {
+        query all_traits(_: CrateNum) -> &'tcx [DefId] {
             desc { "fetching all foreign and local traits" }
         }
     }
     }
 
     Other {
-        query target_features_whitelist(_: CrateNum) -> Lrc<FxHashMap<String, Option<Symbol>>> {
+        query target_features_whitelist(_: CrateNum) -> &'tcx FxHashMap<String, Option<Symbol>> {
             eval_always
             desc { "looking up the whitelist of target features" }
         }
             desc { |tcx| "estimating size for `{}`", tcx.def_path_str(def.def_id()) }
         }
 
-        query features_query(_: CrateNum) -> Lrc<feature_gate::Features> {
+        query features_query(_: CrateNum) -> &'tcx feature_gate::Features {
             eval_always
             desc { "looking up enabled feature gates" }
         }
index f9ceeb5bfc01b373e22b615a6056481c0dfa729f..1c17ace90c2fbbc458f1ea4e8dab464da5e67ed7 100644 (file)
@@ -226,12 +226,12 @@ pub fn try_parse(tcx: TyCtxt<'a, 'gcx, 'tcx>,
         Ok(result)
     }
 
-    fn verify(&self,
-              tcx: TyCtxt<'a, 'gcx, 'tcx>,
-              trait_def_id: DefId,
-              span: Span)
-              -> Result<(), ErrorReported>
-    {
+    fn verify(
+        &self,
+        tcx: TyCtxt<'a, 'gcx, 'tcx>,
+        trait_def_id: DefId,
+        span: Span,
+    ) -> Result<(), ErrorReported> {
         let name = tcx.item_name(trait_def_id);
         let generics = tcx.generics_of(trait_def_id);
         let parser = Parser::new(&self.0, None, vec![], false);
@@ -272,12 +272,12 @@ fn verify(&self,
         result
     }
 
-    pub fn format(&self,
-                  tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                  trait_ref: ty::TraitRef<'tcx>,
-                  options: &FxHashMap<String, String>)
-                  -> String
-    {
+    pub fn format(
+        &self,
+        tcx: TyCtxt<'a, 'gcx, 'tcx>,
+        trait_ref: ty::TraitRef<'tcx>,
+        options: &FxHashMap<String, String>,
+    ) -> String {
         let name = tcx.item_name(trait_ref.def_id);
         let trait_str = tcx.def_path_str(trait_ref.def_id);
         let generics = tcx.generics_of(trait_ref.def_id);
index b5a17684c0ff24a1d124a64fb04e172f43546a6f..d83b2ce842a88057df2322e1d550ad88e7d1882e 100644 (file)
@@ -201,6 +201,10 @@ fn intern_ty(
     }
 }
 
+pub struct Common<'tcx> {
+    pub empty_predicates: ty::GenericPredicates<'tcx>,
+}
+
 pub struct CommonTypes<'tcx> {
     pub unit: Ty<'tcx>,
     pub bool: Ty<'tcx>,
@@ -1045,6 +1049,9 @@ pub struct GlobalCtxt<'tcx> {
 
     pub dep_graph: DepGraph,
 
+    /// Common objects.
+    pub common: Common<'tcx>,
+
     /// Common types, pre-interned for your convenience.
     pub types: CommonTypes<'tcx>,
 
@@ -1057,11 +1064,11 @@ pub struct GlobalCtxt<'tcx> {
     /// Map indicating what traits are in scope for places where this
     /// is relevant; generated by resolve.
     trait_map: FxHashMap<DefIndex,
-                         Lrc<FxHashMap<ItemLocalId,
-                                       Lrc<StableVec<TraitCandidate>>>>>,
+                         FxHashMap<ItemLocalId,
+                                   StableVec<TraitCandidate>>>,
 
     /// Export map produced by name resolution.
-    export_map: FxHashMap<DefId, Lrc<Vec<Export<hir::HirId>>>>,
+    export_map: FxHashMap<DefId, Vec<Export<hir::HirId>>>,
 
     hir_map: hir_map::Map<'tcx>,
 
@@ -1074,7 +1081,7 @@ pub struct GlobalCtxt<'tcx> {
     // Records the captured variables referenced by every closure
     // expression. Do not track deps for this, just recompute it from
     // scratch every time.
-    upvars: FxHashMap<DefId, Lrc<Vec<hir::Upvar>>>,
+    upvars: FxHashMap<DefId, Vec<hir::Upvar>>,
 
     maybe_unused_trait_imports: FxHashSet<DefId>,
     maybe_unused_extern_crates: Vec<(DefId, Span)>,
@@ -1252,6 +1259,12 @@ pub fn create_global_ctxt(
             s.fatal(&err);
         });
         let interners = CtxtInterners::new(&arenas.interner);
+        let common = Common {
+            empty_predicates: ty::GenericPredicates {
+                parent: None,
+                predicates: vec![],
+            },
+        };
         let common_types = CommonTypes::new(&interners);
         let common_lifetimes = CommonLifetimes::new(&interners);
         let common_consts = CommonConsts::new(&interners, &common_types);
@@ -1292,13 +1305,11 @@ pub fn create_global_ctxt(
             None
         };
 
-        let mut trait_map: FxHashMap<_, Lrc<FxHashMap<_, _>>> = FxHashMap::default();
+        let mut trait_map: FxHashMap<_, FxHashMap<_, _>> = FxHashMap::default();
         for (k, v) in resolutions.trait_map {
             let hir_id = hir.node_to_hir_id(k);
             let map = trait_map.entry(hir_id.owner).or_default();
-            Lrc::get_mut(map).unwrap()
-                             .insert(hir_id.local_id,
-                                     Lrc::new(StableVec::new(v)));
+            map.insert(hir_id.local_id, StableVec::new(v));
         }
 
         GlobalCtxt {
@@ -1308,6 +1319,7 @@ pub fn create_global_ctxt(
             global_arenas: &arenas.global,
             global_interners: interners,
             dep_graph,
+            common,
             types: common_types,
             lifetimes: common_lifetimes,
             consts: common_consts,
@@ -1316,13 +1328,13 @@ pub fn create_global_ctxt(
                 let exports: Vec<_> = v.into_iter().map(|e| {
                     e.map_id(|id| hir.node_to_hir_id(id))
                 }).collect();
-                (k, Lrc::new(exports))
+                (k, exports)
             }).collect(),
             upvars: resolutions.upvars.into_iter().map(|(k, v)| {
                 let vars: Vec<_> = v.into_iter().map(|e| {
                     e.map_id(|id| hir.node_to_hir_id(id))
                 }).collect();
-                (hir.local_def_id(k), Lrc::new(vars))
+                (hir.local_def_id(k), vars)
             }).collect(),
             maybe_unused_trait_imports:
                 resolutions.maybe_unused_trait_imports
@@ -1364,11 +1376,11 @@ pub fn consider_optimizing<T: Fn() -> String>(&self, msg: T) -> bool {
         self.sess.consider_optimizing(&cname, msg)
     }
 
-    pub fn lib_features(self) -> Lrc<middle::lib_features::LibFeatures> {
+    pub fn lib_features(self) -> &'gcx middle::lib_features::LibFeatures {
         self.get_lib_features(LOCAL_CRATE)
     }
 
-    pub fn lang_items(self) -> Lrc<middle::lang_items::LanguageItems> {
+    pub fn lang_items(self) -> &'gcx middle::lang_items::LanguageItems {
         self.get_lang_items(LOCAL_CRATE)
     }
 
@@ -1406,15 +1418,15 @@ pub fn is_binop_lang_item(&self, def_id: DefId) -> Option<(mir::BinOp, bool)> {
         else { None }
     }
 
-    pub fn stability(self) -> Lrc<stability::Index<'tcx>> {
+    pub fn stability(self) -> &'gcx stability::Index<'gcx> {
         self.stability_index(LOCAL_CRATE)
     }
 
-    pub fn crates(self) -> Lrc<Vec<CrateNum>> {
+    pub fn crates(self) -> &'gcx [CrateNum] {
         self.all_crate_nums(LOCAL_CRATE)
     }
 
-    pub fn features(self) -> Lrc<feature_gate::Features> {
+    pub fn features(self) -> &'gcx feature_gate::Features {
         self.features_query(LOCAL_CRATE)
     }
 
@@ -2965,9 +2977,9 @@ pub fn struct_lint_node(self, lint: &'static Lint, id: HirId, msg: &str)
         lint::struct_lint_level(self.sess, lint, level, src, None, msg)
     }
 
-    pub fn in_scope_traits(self, id: HirId) -> Option<Lrc<StableVec<TraitCandidate>>> {
+    pub fn in_scope_traits(self, id: HirId) -> Option<&'gcx StableVec<TraitCandidate>> {
         self.in_scope_traits_map(id.owner)
-            .and_then(|map| map.get(&id.local_id).cloned())
+            .and_then(|map| map.get(&id.local_id))
     }
 
     pub fn named_region(self, id: HirId) -> Option<resolve_lifetime::Region> {
@@ -2982,10 +2994,10 @@ pub fn is_late_bound(self, id: HirId) -> bool {
     }
 
     pub fn object_lifetime_defaults(self, id: HirId)
-        -> Option<Lrc<Vec<ObjectLifetimeDefault>>>
+        -> Option<&'gcx [ObjectLifetimeDefault]>
     {
         self.object_lifetime_defaults_map(id.owner)
-            .and_then(|map| map.get(&id.local_id).cloned())
+            .and_then(|map| map.get(&id.local_id).map(|v| &**v))
     }
 }
 
@@ -3040,27 +3052,27 @@ fn ptr_eq<T, U>(t: *const T, u: *const U) -> bool {
 }
 
 pub fn provide(providers: &mut ty::query::Providers<'_>) {
-    providers.in_scope_traits_map = |tcx, id| tcx.gcx.trait_map.get(&id).cloned();
-    providers.module_exports = |tcx, id| tcx.gcx.export_map.get(&id).cloned();
+    providers.in_scope_traits_map = |tcx, id| tcx.gcx.trait_map.get(&id);
+    providers.module_exports = |tcx, id| tcx.gcx.export_map.get(&id).map(|v| &v[..]);
     providers.crate_name = |tcx, id| {
         assert_eq!(id, LOCAL_CRATE);
         tcx.crate_name
     };
     providers.get_lib_features = |tcx, id| {
         assert_eq!(id, LOCAL_CRATE);
-        Lrc::new(middle::lib_features::collect(tcx))
+        tcx.arena.alloc(middle::lib_features::collect(tcx))
     };
     providers.get_lang_items = |tcx, id| {
         assert_eq!(id, LOCAL_CRATE);
-        Lrc::new(middle::lang_items::collect(tcx))
+        tcx.arena.alloc(middle::lang_items::collect(tcx))
     };
-    providers.upvars = |tcx, id| tcx.gcx.upvars.get(&id).cloned();
+    providers.upvars = |tcx, id| tcx.gcx.upvars.get(&id).map(|v| &v[..]);
     providers.maybe_unused_trait_import = |tcx, id| {
         tcx.maybe_unused_trait_imports.contains(&id)
     };
     providers.maybe_unused_extern_crates = |tcx, cnum| {
         assert_eq!(cnum, LOCAL_CRATE);
-        Lrc::new(tcx.maybe_unused_extern_crates.clone())
+        &tcx.maybe_unused_extern_crates[..]
     };
     providers.names_imported_by_glob_use = |tcx, id| {
         assert_eq!(id.krate, LOCAL_CRATE);
@@ -3069,7 +3081,7 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
 
     providers.stability_index = |tcx, cnum| {
         assert_eq!(cnum, LOCAL_CRATE);
-        Lrc::new(stability::Index::new(tcx))
+        tcx.arena.alloc(stability::Index::new(tcx))
     };
     providers.lookup_stability = |tcx, id| {
         assert_eq!(id.krate, LOCAL_CRATE);
@@ -3087,11 +3099,11 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
     };
     providers.all_crate_nums = |tcx, cnum| {
         assert_eq!(cnum, LOCAL_CRATE);
-        Lrc::new(tcx.cstore.crates_untracked())
+        tcx.arena.alloc_slice(&tcx.cstore.crates_untracked())
     };
     providers.postorder_cnums = |tcx, cnum| {
         assert_eq!(cnum, LOCAL_CRATE);
-        Lrc::new(tcx.cstore.postorder_cnums_untracked())
+        tcx.arena.alloc_slice(&tcx.cstore.postorder_cnums_untracked())
     };
     providers.output_filenames = |tcx, cnum| {
         assert_eq!(cnum, LOCAL_CRATE);
@@ -3099,7 +3111,7 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
     };
     providers.features_query = |tcx, cnum| {
         assert_eq!(cnum, LOCAL_CRATE);
-        Lrc::new(tcx.sess.features_untracked().clone())
+        tcx.arena.alloc(tcx.sess.features_untracked().clone())
     };
     providers.is_panic_runtime = |tcx, cnum| {
         assert_eq!(cnum, LOCAL_CRATE);
index a2c89489b95dcee2162a8bd0d6894a47c0425a6c..99c3293168754dd9a15cb2073996fa08088c0970 100644 (file)
@@ -2298,7 +2298,7 @@ pub fn non_enum_variant(&self) -> &VariantDef {
     }
 
     #[inline]
-    pub fn predicates(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Lrc<GenericPredicates<'gcx>> {
+    pub fn predicates(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> &'tcx GenericPredicates<'gcx> {
         tcx.predicates_of(self.did)
     }
 
@@ -3106,7 +3106,7 @@ pub fn adjust_ident(self, mut ident: Ident, scope: DefId, block: hir::HirId) ->
 
 pub struct AssociatedItemsIterator<'a, 'gcx: 'tcx, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'gcx, 'tcx>,
-    def_ids: Lrc<Vec<DefId>>,
+    def_ids: &'gcx [DefId],
     next_index: usize,
 }
 
@@ -3183,26 +3183,27 @@ fn adt_sized_constraint<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
 fn associated_item_def_ids<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                      def_id: DefId)
-                                     -> Lrc<Vec<DefId>> {
+                                     -> &'tcx [DefId] {
     let id = tcx.hir().as_local_hir_id(def_id).unwrap();
     let item = tcx.hir().expect_item_by_hir_id(id);
-    let vec: Vec<_> = match item.node {
+    match item.node {
         hir::ItemKind::Trait(.., ref trait_item_refs) => {
-            trait_item_refs.iter()
-                           .map(|trait_item_ref| trait_item_ref.id)
-                           .map(|id| tcx.hir().local_def_id_from_hir_id(id.hir_id))
-                           .collect()
+            tcx.arena.alloc_from_iter(
+                trait_item_refs.iter()
+                               .map(|trait_item_ref| trait_item_ref.id)
+                               .map(|id| tcx.hir().local_def_id_from_hir_id(id.hir_id))
+            )
         }
         hir::ItemKind::Impl(.., ref impl_item_refs) => {
-            impl_item_refs.iter()
-                          .map(|impl_item_ref| impl_item_ref.id)
-                          .map(|id| tcx.hir().local_def_id_from_hir_id(id.hir_id))
-                          .collect()
+            tcx.arena.alloc_from_iter(
+                impl_item_refs.iter()
+                              .map(|impl_item_ref| impl_item_ref.id)
+                              .map(|id| tcx.hir().local_def_id_from_hir_id(id.hir_id))
+            )
         }
-        hir::ItemKind::TraitAlias(..) => vec![],
+        hir::ItemKind::TraitAlias(..) => &[],
         _ => span_bug!(item.span, "associated_item_def_ids: not impl or trait")
-    };
-    Lrc::new(vec)
+    }
 }
 
 fn def_span<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Span {
@@ -3388,7 +3389,7 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
 /// (constructing this map requires touching the entire crate).
 #[derive(Clone, Debug, Default, HashStable)]
 pub struct CrateInherentImpls {
-    pub inherent_impls: DefIdMap<Lrc<Vec<DefId>>>,
+    pub inherent_impls: DefIdMap<Vec<DefId>>,
 }
 
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable)]
index 7a8d5d3bb9a67f62371634229a26fe85c0f6f4ac..06db4b9b65bcaf545ebad92ab6f816d3b2015ab7 100644 (file)
@@ -253,8 +253,8 @@ fn try_print_visible_def_path(
             // 2. for an extern inferred from a path or an indirect crate,
             //    where there is no explicit `extern crate`, we just prepend
             //    the crate name.
-            match *self.tcx().extern_crate(def_id) {
-                Some(ExternCrate {
+            match self.tcx().extern_crate(def_id) {
+                Some(&ExternCrate {
                     src: ExternCrateSource::Extern(def_id),
                     direct: true,
                     span,
index 2fb318a47befd80f6919cd0b22c9eb56bbe3f8f4..01d431b0ef0e7a04fb8c50f51dfe72c6ea4e5653 100644 (file)
@@ -14,12 +14,6 @@ impl<'tcx, T> Value<'tcx> for T {
     }
 }
 
-impl<'tcx, T: Default> Value<'tcx> for T {
-    default fn from_cycle_error<'a>(_: TyCtxt<'a, 'tcx, 'tcx>) -> T {
-        T::default()
-    }
-}
-
 impl<'tcx> Value<'tcx> for Ty<'tcx> {
     fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> {
         tcx.types.err
index 65a550b1b8914a821534615834e3eaa9b1febcae..7dca47485bb928d8f531083ef6b7d4affa8a3214 100644 (file)
@@ -32,7 +32,6 @@
 use std::cell::{Cell, RefCell};
 use std::fmt;
 use std::rc::Rc;
-use rustc_data_structures::sync::Lrc;
 use std::hash::{Hash, Hasher};
 use syntax::source_map::CompilerDesugaringKind;
 use syntax_pos::{MultiSpan, Span};
@@ -75,7 +74,7 @@ pub struct AnalysisData<'a, 'tcx: 'a> {
 }
 
 fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId)
-    -> Lrc<BorrowCheckResult>
+    -> &'tcx BorrowCheckResult
 {
     assert!(tcx.use_ast_borrowck() || tcx.migrate_borrowck());
 
@@ -89,7 +88,7 @@ fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId)
             // those things (notably the synthesized constructors from
             // tuple structs/variants) do not have an associated body
             // and do not need borrowchecking.
-            return Lrc::new(BorrowCheckResult {
+            return tcx.arena.alloc(BorrowCheckResult {
                 used_mut_nodes: Default::default(),
                 signalled_any_error: SignalledError::NoErrorsSeen,
             })
@@ -136,7 +135,7 @@ fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId)
         check_loans::check_loans(&mut bccx, &loan_dfcx, &flowed_moves, &all_loans, body);
     }
 
-    Lrc::new(BorrowCheckResult {
+    tcx.arena.alloc(BorrowCheckResult {
         used_mut_nodes: bccx.used_mut_nodes.into_inner(),
         signalled_any_error: bccx.signalled_any_error.into_inner(),
     })
index f26684d9ef04ae4a46c4ee87f1884a1f33af350b..9d0e7dde34d131eb590afb5d7fc3a065944498e5 100644 (file)
@@ -10,7 +10,6 @@
 use rustc::ty::layout::HasTyCtxt;
 use rustc::ty::query::Providers;
 use rustc_data_structures::small_c_str::SmallCStr;
-use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_target::spec::PanicStrategy;
 use rustc_codegen_ssa::traits::*;
@@ -320,11 +319,11 @@ pub fn provide(providers: &mut Providers<'_>) {
         if tcx.sess.opts.actually_rustdoc {
             // rustdoc needs to be able to document functions that use all the features, so
             // whitelist them all
-            Lrc::new(llvm_util::all_known_features()
+            tcx.arena.alloc(llvm_util::all_known_features()
                 .map(|(a, b)| (a.to_string(), b))
                 .collect())
         } else {
-            Lrc::new(llvm_util::target_feature_whitelist(tcx.sess)
+            tcx.arena.alloc(llvm_util::target_feature_whitelist(tcx.sess)
                 .iter()
                 .map(|&(a, b)| (a.to_string(), b))
                 .collect())
@@ -364,7 +363,7 @@ pub fn provide_extern(providers: &mut Providers<'_>) {
             }));
         }
 
-        Lrc::new(ret)
+        tcx.arena.alloc(ret)
     };
 }
 
index a55f783df43a372b43294353c813199b5e1f1dcb..fb7ef87646296b4fbe1711f5eaf7ad7f6d1cc1f1 100644 (file)
@@ -1,4 +1,3 @@
-use rustc_data_structures::sync::Lrc;
 use std::sync::Arc;
 
 use rustc::ty::Instance;
@@ -49,12 +48,12 @@ pub fn crates_export_threshold(crate_types: &[config::CrateType]) -> SymbolExpor
 
 fn reachable_non_generics_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                              cnum: CrateNum)
-                                             -> Lrc<DefIdMap<SymbolExportLevel>>
+                                             -> &'tcx DefIdMap<SymbolExportLevel>
 {
     assert_eq!(cnum, LOCAL_CRATE);
 
     if !tcx.sess.opts.output_types.should_codegen() {
-        return Default::default();
+        return tcx.arena.alloc(Default::default());
     }
 
     // Check to see if this crate is a "special runtime crate". These
@@ -155,7 +154,7 @@ fn reachable_non_generics_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         reachable_non_generics.insert(id, SymbolExportLevel::C);
     }
 
-    Lrc::new(reachable_non_generics)
+    tcx.arena.alloc(reachable_non_generics)
 }
 
 fn is_reachable_non_generic_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
@@ -282,7 +281,7 @@ fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 fn upstream_monomorphizations_provider<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     cnum: CrateNum)
-    -> Lrc<DefIdMap<Lrc<FxHashMap<SubstsRef<'tcx>, CrateNum>>>>
+    -> &'tcx DefIdMap<FxHashMap<SubstsRef<'tcx>, CrateNum>>
 {
     debug_assert!(cnum == LOCAL_CRATE);
 
@@ -326,20 +325,16 @@ fn upstream_monomorphizations_provider<'a, 'tcx>(
         }
     }
 
-    Lrc::new(instances.into_iter()
-                      .map(|(key, value)| (key, Lrc::new(value)))
-                      .collect())
+    tcx.arena.alloc(instances)
 }
 
 fn upstream_monomorphizations_for_provider<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     def_id: DefId)
-    -> Option<Lrc<FxHashMap<SubstsRef<'tcx>, CrateNum>>>
+    -> Option<&'tcx FxHashMap<SubstsRef<'tcx>, CrateNum>>
 {
     debug_assert!(!def_id.is_local());
-    tcx.upstream_monomorphizations(LOCAL_CRATE)
-       .get(&def_id)
-       .cloned()
+    tcx.upstream_monomorphizations(LOCAL_CRATE).get(&def_id)
 }
 
 fn is_unreachable_local_definition_provider(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) -> bool {
index 3cd47dfbb29fb7cf6387cecc36406e59999565b0..0b037f872475decc13b8adb23623f665d4c9b25f 100644 (file)
@@ -33,7 +33,6 @@
 use rustc_mir::monomorphize::partitioning::{CodegenUnit, CodegenUnitExt};
 use rustc::util::nodemap::FxHashMap;
 use rustc_data_structures::indexed_vec::Idx;
-use rustc_data_structures::sync::Lrc;
 use rustc_codegen_utils::{symbol_names_test, check_for_rustc_errors_attr};
 use rustc::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA};
 use crate::mir::place::PlaceRef;
@@ -916,7 +915,7 @@ pub fn provide_both(providers: &mut Providers<'_>) {
             .map(|id| &module_map[&id])
             .flat_map(|module| module.foreign_items.iter().cloned())
             .collect();
-        Lrc::new(dllimports)
+        tcx.arena.alloc(dllimports)
     };
 
     providers.is_dllimport_foreign_item = |tcx, def_id| {
index e234f4f88070382f99d9c9a85dcb9d8f2018f8bd..76aba33b6a404ddcb5cc6243106fb353701a9bb4 100644 (file)
@@ -13,6 +13,7 @@ crate-type = ["dylib"]
 flate2 = "1.0"
 log = "0.4"
 memmap = "0.6"
+smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }
 rustc = { path = "../librustc" }
 rustc_data_structures = { path = "../librustc_data_structures" }
 errors = { path = "../librustc_errors", package = "rustc_errors" }
index 49f93c4014dc06ad40724f724d9372bb346820dc..fae4c244d6e1404a5e765c22255fa62b5e9386ff 100644 (file)
@@ -21,6 +21,7 @@
 use rustc::util::nodemap::DefIdMap;
 use rustc_data_structures::svh::Svh;
 
+use smallvec::SmallVec;
 use std::any::Any;
 use rustc_data_structures::sync::Lrc;
 use std::sync::Arc;
@@ -95,9 +96,11 @@ fn into_args(self) -> (DefId, DefId) { (self.0.as_def_id(), self.1) }
     generics_of => {
         tcx.alloc_generics(cdata.get_generics(def_id.index, tcx.sess))
     }
-    predicates_of => { Lrc::new(cdata.get_predicates(def_id.index, tcx)) }
-    predicates_defined_on => { Lrc::new(cdata.get_predicates_defined_on(def_id.index, tcx)) }
-    super_predicates_of => { Lrc::new(cdata.get_super_predicates(def_id.index, tcx)) }
+    predicates_of => { tcx.arena.alloc(cdata.get_predicates(def_id.index, tcx)) }
+    predicates_defined_on => {
+        tcx.arena.alloc(cdata.get_predicates_defined_on(def_id.index, tcx))
+    }
+    super_predicates_of => { tcx.arena.alloc(cdata.get_super_predicates(def_id.index, tcx)) }
     trait_def => {
         tcx.alloc_trait_def(cdata.get_trait_def(def_id.index, tcx.sess))
     }
@@ -108,10 +111,10 @@ fn into_args(self) -> (DefId, DefId) { (self.0.as_def_id(), self.1) }
     }
     variances_of => { tcx.arena.alloc_from_iter(cdata.get_item_variances(def_id.index)) }
     associated_item_def_ids => {
-        let mut result = vec![];
+        let mut result = SmallVec::<[_; 8]>::new();
         cdata.each_child_of_item(def_id.index,
           |child| result.push(child.res.def_id()), tcx.sess);
-        Lrc::new(result)
+        tcx.arena.alloc_slice(&result)
     }
     associated_item => { cdata.get_associated_item(def_id.index) }
     impl_trait_ref => { cdata.get_impl_trait(def_id.index, tcx) }
@@ -134,7 +137,7 @@ fn into_args(self) -> (DefId, DefId) { (self.0.as_def_id(), self.1) }
         (cdata.mir_const_qualif(def_id.index), tcx.arena.alloc(BitSet::new_empty(0)))
     }
     fn_sig => { cdata.fn_sig(def_id.index, tcx) }
-    inherent_impls => { Lrc::new(cdata.get_inherent_implementations_for_type(def_id.index)) }
+    inherent_impls => { cdata.get_inherent_implementations_for_type(tcx, def_id.index) }
     is_const_fn_raw => { cdata.is_const_fn_raw(def_id.index) }
     is_foreign_item => { cdata.is_foreign_item(def_id.index) }
     static_mutability => { cdata.static_mutability(def_id.index) }
@@ -160,7 +163,7 @@ fn into_args(self) -> (DefId, DefId) { (self.0.as_def_id(), self.1) }
     }
     is_mir_available => { cdata.is_item_mir_available(def_id.index) }
 
-    dylib_dependency_formats => { Lrc::new(cdata.get_dylib_dependency_formats()) }
+    dylib_dependency_formats => { cdata.get_dylib_dependency_formats(tcx) }
     is_panic_runtime => { cdata.root.panic_runtime }
     is_compiler_builtins => { cdata.root.compiler_builtins }
     has_global_allocator => { cdata.root.has_global_allocator }
@@ -169,8 +172,8 @@ fn into_args(self) -> (DefId, DefId) { (self.0.as_def_id(), self.1) }
     is_profiler_runtime => { cdata.root.profiler_runtime }
     panic_strategy => { cdata.root.panic_strategy }
     extern_crate => {
-        let r = Lrc::new(*cdata.extern_crate.lock());
-        r
+        let r = *cdata.extern_crate.lock();
+        r.map(|c| &*tcx.arena.alloc(c))
     }
     is_no_builtins => { cdata.root.no_builtins }
     impl_defaultness => { cdata.get_impl_defaultness(def_id.index) }
@@ -187,10 +190,10 @@ fn into_args(self) -> (DefId, DefId) { (self.0.as_def_id(), self.1) }
             })
             .collect();
 
-        Lrc::new(reachable_non_generics)
+        tcx.arena.alloc(reachable_non_generics)
     }
     native_libraries => { Lrc::new(cdata.get_native_libraries(tcx.sess)) }
-    foreign_modules => { Lrc::new(cdata.get_foreign_modules(tcx.sess)) }
+    foreign_modules => { cdata.get_foreign_modules(tcx) }
     plugin_registrar_fn => {
         cdata.root.plugin_registrar_fn.map(|index| {
             DefId { krate: def_id.krate, index }
@@ -207,18 +210,12 @@ fn into_args(self) -> (DefId, DefId) { (self.0.as_def_id(), self.1) }
 
     extra_filename => { cdata.root.extra_filename.clone() }
 
-
     implementations_of_trait => {
-        let mut result = vec![];
-        let filter = Some(other);
-        cdata.get_implementations_for_trait(filter, &mut result);
-        Lrc::new(result)
+        cdata.get_implementations_for_trait(tcx, Some(other))
     }
 
     all_trait_implementations => {
-        let mut result = vec![];
-        cdata.get_implementations_for_trait(None, &mut result);
-        Lrc::new(result)
+        cdata.get_implementations_for_trait(tcx, None)
     }
 
     visibility => { cdata.get_visibility(def_id.index) }
@@ -228,13 +225,13 @@ fn into_args(self) -> (DefId, DefId) { (self.0.as_def_id(), self.1) }
     }
     crate_name => { cdata.name }
     item_children => {
-        let mut result = vec![];
+        let mut result = SmallVec::<[_; 8]>::new();
         cdata.each_child_of_item(def_id.index, |child| result.push(child), tcx.sess);
-        Lrc::new(result)
+        tcx.arena.alloc_slice(&result)
     }
-    defined_lib_features => { Lrc::new(cdata.get_lib_features()) }
-    defined_lang_items => { Lrc::new(cdata.get_lang_items()) }
-    missing_lang_items => { Lrc::new(cdata.get_missing_lang_items()) }
+    defined_lib_features => { cdata.get_lib_features(tcx) }
+    defined_lang_items => { cdata.get_lang_items(tcx) }
+    missing_lang_items => { cdata.get_missing_lang_items(tcx) }
 
     missing_extern_crate_item => {
         let r = match *cdata.extern_crate.borrow() {
@@ -288,7 +285,7 @@ pub fn provide<'tcx>(providers: &mut Providers<'tcx>) {
         },
         foreign_modules: |tcx, cnum| {
             assert_eq!(cnum, LOCAL_CRATE);
-            Lrc::new(foreign_modules::collect(tcx))
+            &tcx.arena.alloc(foreign_modules::collect(tcx))[..]
         },
         link_args: |tcx, cnum| {
             assert_eq!(cnum, LOCAL_CRATE);
@@ -325,7 +322,7 @@ pub fn provide<'tcx>(providers: &mut Providers<'tcx>) {
             // which is to say, its not deterministic in general. But
             // we believe that libstd is consistently assigned crate
             // num 1, so it should be enough to resolve #46112.
-            let mut crates: Vec<CrateNum> = (*tcx.crates()).clone();
+            let mut crates: Vec<CrateNum> = (*tcx.crates()).to_owned();
             crates.sort();
 
             for &cnum in crates.iter() {
@@ -374,7 +371,7 @@ pub fn provide<'tcx>(providers: &mut Providers<'tcx>) {
                 }
             }
 
-            Lrc::new(visible_parent_map)
+            tcx.arena.alloc(visible_parent_map)
         },
 
         ..*providers
index a89cfe42eaaf45f96a604c2a48107ee35eae6b88..958c81989ffd6707328578b888c95146a20c0923 100644 (file)
@@ -708,26 +708,30 @@ pub fn get_impl_trait(&self,
     }
 
     /// Iterates over all the stability attributes in the given crate.
-    pub fn get_lib_features(&self) -> Vec<(ast::Name, Option<ast::Name>)> {
+    pub fn get_lib_features(
+        &self,
+        tcx: TyCtxt<'_, 'tcx, '_>,
+    ) -> &'tcx [(ast::Name, Option<ast::Name>)] {
         // FIXME: For a proc macro crate, not sure whether we should return the "host"
         // features or an empty Vec. Both don't cause ICEs.
-        self.root
+        tcx.arena.alloc_from_iter(self.root
             .lib_features
-            .decode(self)
-            .collect()
+            .decode(self))
     }
 
     /// Iterates over the language items in the given crate.
-    pub fn get_lang_items(&self) -> Vec<(DefId, usize)> {
+    pub fn get_lang_items(
+        &self,
+        tcx: TyCtxt<'_, 'tcx, '_>,
+    ) -> &'tcx [(DefId, usize)] {
         if self.proc_macros.is_some() {
             // Proc macro crates do not export any lang-items to the target.
-            vec![]
+            &[]
         } else {
-            self.root
+            tcx.arena.alloc_from_iter(self.root
                 .lang_items
                 .decode(self)
-                .map(|(def_index, index)| (self.local_def_id(def_index), index))
-                .collect()
+                .map(|(def_index, index)| (self.local_def_id(def_index), index)))
         }
     }
 
@@ -1013,39 +1017,45 @@ fn reverse_translate_def_id(&self, did: DefId) -> Option<DefId> {
         None
     }
 
-    pub fn get_inherent_implementations_for_type(&self, id: DefIndex) -> Vec<DefId> {
-        self.entry(id)
-            .inherent_impls
-            .decode(self)
-            .map(|index| self.local_def_id(index))
-            .collect()
+    pub fn get_inherent_implementations_for_type(
+        &self,
+        tcx: TyCtxt<'_, 'tcx, '_>,
+        id: DefIndex
+    ) -> &'tcx [DefId] {
+        tcx.arena.alloc_from_iter(self.entry(id)
+                                      .inherent_impls
+                                      .decode(self)
+                                      .map(|index| self.local_def_id(index)))
     }
 
-    pub fn get_implementations_for_trait(&self,
-                                         filter: Option<DefId>,
-                                         result: &mut Vec<DefId>) {
+    pub fn get_implementations_for_trait(
+        &self,
+        tcx: TyCtxt<'_, 'tcx, '_>,
+        filter: Option<DefId>,
+    ) -> &'tcx [DefId] {
         if self.proc_macros.is_some() {
             // proc-macro crates export no trait impls.
-            return
+            return &[]
         }
 
         // Do a reverse lookup beforehand to avoid touching the crate_num
         // hash map in the loop below.
         let filter = match filter.map(|def_id| self.reverse_translate_def_id(def_id)) {
             Some(Some(def_id)) => Some((def_id.krate.as_u32(), def_id.index)),
-            Some(None) => return,
+            Some(None) => return &[],
             None => None,
         };
 
         if let Some(filter) = filter {
-            if let Some(impls) = self.trait_impls
-                                     .get(&filter) {
-                result.extend(impls.decode(self).map(|idx| self.local_def_id(idx)));
+            if let Some(impls) = self.trait_impls.get(&filter) {
+                tcx.arena.alloc_from_iter(impls.decode(self).map(|idx| self.local_def_id(idx)))
+            } else {
+                &[]
             }
         } else {
-            for impls in self.trait_impls.values() {
-                result.extend(impls.decode(self).map(|idx| self.local_def_id(idx)));
-            }
+            tcx.arena.alloc_from_iter(self.trait_impls.values().flat_map(|impls| {
+                impls.decode(self).map(|idx| self.local_def_id(idx))
+            }))
         }
     }
 
@@ -1075,36 +1085,43 @@ pub fn get_native_libraries(&self, sess: &Session) -> Vec<NativeLibrary> {
         }
     }
 
-    pub fn get_foreign_modules(&self, sess: &Session) -> Vec<ForeignModule> {
+    pub fn get_foreign_modules(
+        &self,
+        tcx: TyCtxt<'_, 'tcx, '_>,
+    ) -> &'tcx [ForeignModule] {
         if self.proc_macros.is_some() {
             // Proc macro crates do not have any *target* foreign modules.
-            vec![]
+            &[]
         } else {
-            self.root.foreign_modules.decode((self, sess)).collect()
+            tcx.arena.alloc_from_iter(self.root.foreign_modules.decode((self, tcx.sess)))
         }
     }
 
-    pub fn get_dylib_dependency_formats(&self) -> Vec<(CrateNum, LinkagePreference)> {
-        self.root
+    pub fn get_dylib_dependency_formats(
+        &self,
+        tcx: TyCtxt<'_, 'tcx, '_>,
+    ) -> &'tcx [(CrateNum, LinkagePreference)] {
+        tcx.arena.alloc_from_iter(self.root
             .dylib_dependency_formats
             .decode(self)
             .enumerate()
             .flat_map(|(i, link)| {
                 let cnum = CrateNum::new(i + 1);
                 link.map(|link| (self.cnum_map[cnum], link))
-            })
-            .collect()
+            }))
     }
 
-    pub fn get_missing_lang_items(&self) -> Vec<lang_items::LangItem> {
+    pub fn get_missing_lang_items(
+        &self,
+        tcx: TyCtxt<'_, 'tcx, '_>,
+    ) -> &'tcx [lang_items::LangItem] {
         if self.proc_macros.is_some() {
             // Proc macro crates do not depend on any target weak lang-items.
-            vec![]
+            &[]
         } else {
-            self.root
+            tcx.arena.alloc_from_iter(self.root
                 .lang_items_missing
-                .decode(self)
-                .collect()
+                .decode(self))
         }
     }
 
index d81e34a07aba9a980b4a4867c1ad1c551612c66c..1a9d996131dc0ee9325c99e0fcd94696cfd9ae80 100644 (file)
@@ -673,7 +673,7 @@ fn encode_info_for_mod(
 
         let data = ModData {
             reexports: match tcx.module_exports(def_id) {
-                Some(ref exports) => self.lazy_seq_ref(&exports[..]),
+                Some(exports) => self.lazy_seq_ref(exports),
                 _ => LazySeq::empty(),
             },
         };
diff --git a/src/librustc_mir/borrow_check/conflict_errors.rs b/src/librustc_mir/borrow_check/conflict_errors.rs
new file mode 100644 (file)
index 0000000..b00a75b
--- /dev/null
@@ -0,0 +1,1985 @@
+use rustc::hir;
+use rustc::hir::def_id::DefId;
+use rustc::mir::{
+    self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory, Local,
+    LocalDecl, LocalKind, Location, Operand, Place, PlaceBase, PlaceProjection,
+    ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind, VarBindingForm,
+};
+use rustc::ty::{self, Ty};
+use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::indexed_vec::Idx;
+use rustc_errors::{Applicability, DiagnosticBuilder};
+use syntax_pos::Span;
+use syntax::source_map::CompilerDesugaringKind;
+
+use super::nll::explain_borrow::BorrowExplanation;
+use super::nll::region_infer::{RegionName, RegionNameSource};
+use super::prefixes::IsPrefixOf;
+use super::WriteKind;
+use super::borrow_set::BorrowData;
+use super::MirBorrowckCtxt;
+use super::{InitializationRequiringAction, PrefixSet};
+use super::error_reporting::{IncludingDowncast, UseSpans};
+use crate::dataflow::drop_flag_effects;
+use crate::dataflow::indexes::{MovePathIndex, MoveOutIndex};
+use crate::util::borrowck_errors::{BorrowckErrors, Origin};
+
+#[derive(Debug)]
+struct MoveSite {
+    /// Index of the "move out" that we found. The `MoveData` can
+    /// then tell us where the move occurred.
+    moi: MoveOutIndex,
+
+    /// `true` if we traversed a back edge while walking from the point
+    /// of error to the move site.
+    traversed_back_edge: bool
+}
+
+/// Which case a StorageDeadOrDrop is for.
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+enum StorageDeadOrDrop<'tcx> {
+    LocalStorageDead,
+    BoxedStorageDead,
+    Destructor(Ty<'tcx>),
+}
+
+impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
+    pub(super) fn report_use_of_moved_or_uninitialized(
+        &mut self,
+        location: Location,
+        desired_action: InitializationRequiringAction,
+        (moved_place, used_place, span): (&Place<'tcx>, &Place<'tcx>, Span),
+        mpi: MovePathIndex,
+    ) {
+        debug!(
+            "report_use_of_moved_or_uninitialized: location={:?} desired_action={:?} \
+             moved_place={:?} used_place={:?} span={:?} mpi={:?}",
+            location, desired_action, moved_place, used_place, span, mpi
+        );
+
+        let use_spans = self.move_spans(moved_place, location)
+            .or_else(|| self.borrow_spans(span, location));
+        let span = use_spans.args_or_use();
+
+        let move_site_vec = self.get_moved_indexes(location, mpi);
+        debug!(
+            "report_use_of_moved_or_uninitialized: move_site_vec={:?}",
+            move_site_vec
+        );
+        let move_out_indices: Vec<_> = move_site_vec
+            .iter()
+            .map(|move_site| move_site.moi)
+            .collect();
+
+        if move_out_indices.is_empty() {
+            let root_place = self.prefixes(&used_place, PrefixSet::All).last().unwrap();
+
+            if self.uninitialized_error_reported.contains(root_place) {
+                debug!(
+                    "report_use_of_moved_or_uninitialized place: error about {:?} suppressed",
+                    root_place
+                );
+                return;
+            }
+
+            self.uninitialized_error_reported.insert(root_place.clone());
+
+            let item_msg = match self.describe_place_with_options(used_place,
+                                                                  IncludingDowncast(true)) {
+                Some(name) => format!("`{}`", name),
+                None => "value".to_owned(),
+            };
+            let mut err = self.infcx.tcx.cannot_act_on_uninitialized_variable(
+                span,
+                desired_action.as_noun(),
+                &self.describe_place_with_options(moved_place, IncludingDowncast(true))
+                    .unwrap_or_else(|| "_".to_owned()),
+                Origin::Mir,
+            );
+            err.span_label(span, format!("use of possibly uninitialized {}", item_msg));
+
+            use_spans.var_span_label(
+                &mut err,
+                format!("{} occurs due to use{}", desired_action.as_noun(), use_spans.describe()),
+            );
+
+            err.buffer(&mut self.errors_buffer);
+        } else {
+            if let Some((reported_place, _)) = self.move_error_reported.get(&move_out_indices) {
+                if self.prefixes(&reported_place, PrefixSet::All)
+                    .any(|p| p == used_place)
+                {
+                    debug!(
+                        "report_use_of_moved_or_uninitialized place: error suppressed \
+                         mois={:?}",
+                        move_out_indices
+                    );
+                    return;
+                }
+            }
+
+            let msg = ""; //FIXME: add "partially " or "collaterally "
+
+            let mut err = self.infcx.tcx.cannot_act_on_moved_value(
+                span,
+                desired_action.as_noun(),
+                msg,
+                self.describe_place_with_options(&moved_place, IncludingDowncast(true)),
+                Origin::Mir,
+            );
+
+            self.add_moved_or_invoked_closure_note(
+                location,
+                used_place,
+                &mut err,
+            );
+
+            let mut is_loop_move = false;
+            let is_partial_move = move_site_vec.iter().any(|move_site| {
+                let move_out = self.move_data.moves[(*move_site).moi];
+                let moved_place = &self.move_data.move_paths[move_out.path].place;
+                used_place != moved_place && used_place.is_prefix_of(moved_place)
+            });
+            for move_site in &move_site_vec {
+                let move_out = self.move_data.moves[(*move_site).moi];
+                let moved_place = &self.move_data.move_paths[move_out.path].place;
+
+                let move_spans = self.move_spans(moved_place, move_out.source);
+                let move_span = move_spans.args_or_use();
+
+                let move_msg = if move_spans.for_closure() {
+                    " into closure"
+                } else {
+                    ""
+                };
+
+                if span == move_span {
+                    err.span_label(
+                        span,
+                        format!("value moved{} here, in previous iteration of loop", move_msg),
+                    );
+                    if Some(CompilerDesugaringKind::ForLoop) == span.compiler_desugaring_kind() {
+                        if let Ok(snippet) = self.infcx.tcx.sess.source_map()
+                            .span_to_snippet(span)
+                        {
+                            err.span_suggestion(
+                                move_span,
+                                "consider borrowing this to avoid moving it into the for loop",
+                                format!("&{}", snippet),
+                                Applicability::MaybeIncorrect,
+                            );
+                        }
+                    }
+                    is_loop_move = true;
+                } else if move_site.traversed_back_edge {
+                    err.span_label(
+                        move_span,
+                        format!(
+                            "value moved{} here, in previous iteration of loop",
+                            move_msg
+                        ),
+                    );
+                } else {
+                    err.span_label(move_span, format!("value moved{} here", move_msg));
+                    move_spans.var_span_label(
+                        &mut err,
+                        format!("variable moved due to use{}", move_spans.describe()),
+                    );
+                };
+            }
+
+            use_spans.var_span_label(
+                &mut err,
+                format!("{} occurs due to use{}", desired_action.as_noun(), use_spans.describe()),
+            );
+
+            if !is_loop_move {
+                err.span_label(
+                    span,
+                    format!(
+                        "value {} here {}",
+                        desired_action.as_verb_in_past_tense(),
+                        if is_partial_move { "after partial move" } else { "after move" },
+                    ),
+                );
+            }
+
+            let ty = used_place.ty(self.mir, self.infcx.tcx).ty;
+            let needs_note = match ty.sty {
+                ty::Closure(id, _) => {
+                    let tables = self.infcx.tcx.typeck_tables_of(id);
+                    let hir_id = self.infcx.tcx.hir().as_local_hir_id(id).unwrap();
+
+                    tables.closure_kind_origins().get(hir_id).is_none()
+                }
+                _ => true,
+            };
+
+            if needs_note {
+                let mpi = self.move_data.moves[move_out_indices[0]].path;
+                let place = &self.move_data.move_paths[mpi].place;
+
+                let ty = place.ty(self.mir, self.infcx.tcx).ty;
+                let opt_name = self.describe_place_with_options(place, IncludingDowncast(true));
+                let note_msg = match opt_name {
+                    Some(ref name) => format!("`{}`", name),
+                    None => "value".to_owned(),
+                };
+                if let ty::Param(param_ty) = ty.sty {
+                    let tcx = self.infcx.tcx;
+                    let generics = tcx.generics_of(self.mir_def_id);
+                    let def_id = generics.type_param(&param_ty, tcx).def_id;
+                    if let Some(sp) = tcx.hir().span_if_local(def_id) {
+                        err.span_label(
+                            sp,
+                            "consider adding a `Copy` constraint to this type argument",
+                        );
+                    }
+                }
+                if let Place::Base(PlaceBase::Local(local)) = place {
+                    let decl = &self.mir.local_decls[*local];
+                    err.span_label(
+                        decl.source_info.span,
+                        format!(
+                            "move occurs because {} has type `{}`, \
+                                which does not implement the `Copy` trait",
+                            note_msg, ty,
+                    ));
+                } else {
+                    err.note(&format!(
+                        "move occurs because {} has type `{}`, \
+                         which does not implement the `Copy` trait",
+                        note_msg, ty
+                    ));
+                }
+            }
+
+            if let Some((_, mut old_err)) = self.move_error_reported
+                .insert(move_out_indices, (used_place.clone(), err))
+            {
+                // Cancel the old error so it doesn't ICE.
+                old_err.cancel();
+            }
+        }
+    }
+
+    pub(super) fn report_move_out_while_borrowed(
+        &mut self,
+        location: Location,
+        (place, span): (&Place<'tcx>, Span),
+        borrow: &BorrowData<'tcx>,
+    ) {
+        debug!(
+            "report_move_out_while_borrowed: location={:?} place={:?} span={:?} borrow={:?}",
+            location, place, span, borrow
+        );
+        let tcx = self.infcx.tcx;
+        let value_msg = match self.describe_place(place) {
+            Some(name) => format!("`{}`", name),
+            None => "value".to_owned(),
+        };
+        let borrow_msg = match self.describe_place(&borrow.borrowed_place) {
+            Some(name) => format!("`{}`", name),
+            None => "value".to_owned(),
+        };
+
+        let borrow_spans = self.retrieve_borrow_spans(borrow);
+        let borrow_span = borrow_spans.args_or_use();
+
+        let move_spans = self.move_spans(place, location);
+        let span = move_spans.args_or_use();
+
+        let mut err = tcx.cannot_move_when_borrowed(
+            span,
+            &self.describe_place(place).unwrap_or_else(|| "_".to_owned()),
+            Origin::Mir,
+        );
+        err.span_label(borrow_span, format!("borrow of {} occurs here", borrow_msg));
+        err.span_label(span, format!("move out of {} occurs here", value_msg));
+
+        borrow_spans.var_span_label(
+            &mut err,
+            format!("borrow occurs due to use{}", borrow_spans.describe())
+        );
+
+        move_spans.var_span_label(
+            &mut err,
+            format!("move occurs due to use{}", move_spans.describe())
+        );
+
+        self.explain_why_borrow_contains_point(
+            location,
+            borrow,
+            None,
+        ).add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, "", Some(borrow_span));
+        err.buffer(&mut self.errors_buffer);
+    }
+
+    pub(super) fn report_use_while_mutably_borrowed(
+        &mut self,
+        location: Location,
+        (place, _span): (&Place<'tcx>, Span),
+        borrow: &BorrowData<'tcx>,
+    ) -> DiagnosticBuilder<'cx> {
+        let tcx = self.infcx.tcx;
+
+        let borrow_spans = self.retrieve_borrow_spans(borrow);
+        let borrow_span = borrow_spans.args_or_use();
+
+        // Conflicting borrows are reported separately, so only check for move
+        // captures.
+        let use_spans = self.move_spans(place, location);
+        let span = use_spans.var_or_use();
+
+        let mut err = tcx.cannot_use_when_mutably_borrowed(
+            span,
+            &self.describe_place(place).unwrap_or_else(|| "_".to_owned()),
+            borrow_span,
+            &self.describe_place(&borrow.borrowed_place)
+                .unwrap_or_else(|| "_".to_owned()),
+            Origin::Mir,
+        );
+
+        borrow_spans.var_span_label(&mut err, {
+            let place = &borrow.borrowed_place;
+            let desc_place = self.describe_place(place).unwrap_or_else(|| "_".to_owned());
+
+            format!("borrow occurs due to use of `{}`{}", desc_place, borrow_spans.describe())
+        });
+
+        self.explain_why_borrow_contains_point(location, borrow, None)
+            .add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, "", None);
+        err
+    }
+
+    pub(super) fn report_conflicting_borrow(
+        &mut self,
+        location: Location,
+        (place, span): (&Place<'tcx>, Span),
+        gen_borrow_kind: BorrowKind,
+        issued_borrow: &BorrowData<'tcx>,
+    ) -> DiagnosticBuilder<'cx> {
+        let issued_spans = self.retrieve_borrow_spans(issued_borrow);
+        let issued_span = issued_spans.args_or_use();
+
+        let borrow_spans = self.borrow_spans(span, location);
+        let span = borrow_spans.args_or_use();
+
+        let container_name = if issued_spans.for_generator() || borrow_spans.for_generator() {
+            "generator"
+        } else {
+            "closure"
+        };
+
+        let (desc_place, msg_place, msg_borrow, union_type_name) =
+            self.describe_place_for_conflicting_borrow(place, &issued_borrow.borrowed_place);
+
+        let explanation = self.explain_why_borrow_contains_point(location, issued_borrow, None);
+        let second_borrow_desc = if explanation.is_explained() {
+            "second "
+        } else {
+            ""
+        };
+
+        // FIXME: supply non-"" `opt_via` when appropriate
+        let tcx = self.infcx.tcx;
+        let first_borrow_desc;
+        let mut err = match (
+            gen_borrow_kind,
+            "immutable",
+            "mutable",
+            issued_borrow.kind,
+            "immutable",
+            "mutable",
+        ) {
+            (BorrowKind::Shared, lft, _, BorrowKind::Mut { .. }, _, rgt) => {
+                first_borrow_desc = "mutable ";
+                tcx.cannot_reborrow_already_borrowed(
+                    span,
+                    &desc_place,
+                    &msg_place,
+                    lft,
+                    issued_span,
+                    "it",
+                    rgt,
+                    &msg_borrow,
+                    None,
+                    Origin::Mir,
+                )
+            }
+            (BorrowKind::Mut { .. }, _, lft, BorrowKind::Shared, rgt, _) => {
+                first_borrow_desc = "immutable ";
+                tcx.cannot_reborrow_already_borrowed(
+                    span,
+                    &desc_place,
+                    &msg_place,
+                    lft,
+                    issued_span,
+                    "it",
+                    rgt,
+                    &msg_borrow,
+                    None,
+                    Origin::Mir,
+                )
+            }
+
+            (BorrowKind::Mut { .. }, _, _, BorrowKind::Mut { .. }, _, _) => {
+                first_borrow_desc = "first ";
+                tcx.cannot_mutably_borrow_multiply(
+                    span,
+                    &desc_place,
+                    &msg_place,
+                    issued_span,
+                    &msg_borrow,
+                    None,
+                    Origin::Mir,
+                )
+            }
+
+            (BorrowKind::Unique, _, _, BorrowKind::Unique, _, _) => {
+                first_borrow_desc = "first ";
+                tcx.cannot_uniquely_borrow_by_two_closures(
+                    span,
+                    &desc_place,
+                    issued_span,
+                    None,
+                    Origin::Mir,
+                )
+            }
+
+            (BorrowKind::Mut { .. }, _, _, BorrowKind::Shallow, _, _)
+            | (BorrowKind::Unique, _, _, BorrowKind::Shallow, _, _) => {
+                let mut err = tcx.cannot_mutate_in_match_guard(
+                    span,
+                    issued_span,
+                    &desc_place,
+                    "mutably borrow",
+                    Origin::Mir,
+                );
+                borrow_spans.var_span_label(
+                    &mut err,
+                    format!(
+                        "borrow occurs due to use of `{}`{}", desc_place, borrow_spans.describe()
+                    ),
+                );
+
+                return err;
+            }
+
+            (BorrowKind::Unique, _, _, _, _, _) => {
+                first_borrow_desc = "first ";
+                tcx.cannot_uniquely_borrow_by_one_closure(
+                    span,
+                    container_name,
+                    &desc_place,
+                    "",
+                    issued_span,
+                    "it",
+                    "",
+                    None,
+                    Origin::Mir,
+                )
+            },
+
+            (BorrowKind::Shared, lft, _, BorrowKind::Unique, _, _) => {
+                first_borrow_desc = "first ";
+                tcx.cannot_reborrow_already_uniquely_borrowed(
+                    span,
+                    container_name,
+                    &desc_place,
+                    "",
+                    lft,
+                    issued_span,
+                    "",
+                    None,
+                    second_borrow_desc,
+                    Origin::Mir,
+                )
+            }
+
+            (BorrowKind::Mut { .. }, _, lft, BorrowKind::Unique, _, _) => {
+                first_borrow_desc = "first ";
+                tcx.cannot_reborrow_already_uniquely_borrowed(
+                    span,
+                    container_name,
+                    &desc_place,
+                    "",
+                    lft,
+                    issued_span,
+                    "",
+                    None,
+                    second_borrow_desc,
+                    Origin::Mir,
+                )
+            }
+
+            (BorrowKind::Shared, _, _, BorrowKind::Shared, _, _)
+            | (BorrowKind::Shared, _, _, BorrowKind::Shallow, _, _)
+            | (BorrowKind::Shallow, _, _, BorrowKind::Mut { .. }, _, _)
+            | (BorrowKind::Shallow, _, _, BorrowKind::Unique, _, _)
+            | (BorrowKind::Shallow, _, _, BorrowKind::Shared, _, _)
+            | (BorrowKind::Shallow, _, _, BorrowKind::Shallow, _, _) => unreachable!(),
+        };
+
+        if issued_spans == borrow_spans {
+            borrow_spans.var_span_label(
+                &mut err,
+                format!("borrows occur due to use of `{}`{}", desc_place, borrow_spans.describe()),
+            );
+        } else {
+            let borrow_place = &issued_borrow.borrowed_place;
+            let borrow_place_desc = self.describe_place(borrow_place)
+                                        .unwrap_or_else(|| "_".to_owned());
+            issued_spans.var_span_label(
+                &mut err,
+                format!(
+                    "first borrow occurs due to use of `{}`{}",
+                    borrow_place_desc,
+                    issued_spans.describe(),
+                ),
+            );
+
+            borrow_spans.var_span_label(
+                &mut err,
+                format!(
+                    "second borrow occurs due to use of `{}`{}",
+                    desc_place,
+                    borrow_spans.describe(),
+                ),
+            );
+        }
+
+        if union_type_name != "" {
+            err.note(&format!(
+                "`{}` is a field of the union `{}`, so it overlaps the field `{}`",
+                msg_place, union_type_name, msg_borrow,
+            ));
+        }
+
+        explanation.add_explanation_to_diagnostic(
+            self.infcx.tcx,
+            self.mir,
+            &mut err,
+            first_borrow_desc,
+            None,
+        );
+
+        err
+    }
+
+    /// Returns the description of the root place for a conflicting borrow and the full
+    /// descriptions of the places that caused the conflict.
+    ///
+    /// In the simplest case, where there are no unions involved, if a mutable borrow of `x` is
+    /// attempted while a shared borrow is live, then this function will return:
+    ///
+    ///     ("x", "", "")
+    ///
+    /// In the simple union case, if a mutable borrow of a union field `x.z` is attempted while
+    /// a shared borrow of another field `x.y`, then this function will return:
+    ///
+    ///     ("x", "x.z", "x.y")
+    ///
+    /// In the more complex union case, where the union is a field of a struct, then if a mutable
+    /// borrow of a union field in a struct `x.u.z` is attempted while a shared borrow of
+    /// another field `x.u.y`, then this function will return:
+    ///
+    ///     ("x.u", "x.u.z", "x.u.y")
+    ///
+    /// This is used when creating error messages like below:
+    ///
+    /// >  cannot borrow `a.u` (via `a.u.z.c`) as immutable because it is also borrowed as
+    /// >  mutable (via `a.u.s.b`) [E0502]
+    pub(super) fn describe_place_for_conflicting_borrow(
+        &self,
+        first_borrowed_place: &Place<'tcx>,
+        second_borrowed_place: &Place<'tcx>,
+    ) -> (String, String, String, String) {
+        // Define a small closure that we can use to check if the type of a place
+        // is a union.
+        let is_union = |place: &Place<'tcx>| -> bool {
+            place.ty(self.mir, self.infcx.tcx).ty
+                .ty_adt_def()
+                .map(|adt| adt.is_union())
+                .unwrap_or(false)
+        };
+
+        // Start with an empty tuple, so we can use the functions on `Option` to reduce some
+        // code duplication (particularly around returning an empty description in the failure
+        // case).
+        Some(())
+            .filter(|_| {
+                // If we have a conflicting borrow of the same place, then we don't want to add
+                // an extraneous "via x.y" to our diagnostics, so filter out this case.
+                first_borrowed_place != second_borrowed_place
+            })
+            .and_then(|_| {
+                // We're going to want to traverse the first borrowed place to see if we can find
+                // field access to a union. If we find that, then we will keep the place of the
+                // union being accessed and the field that was being accessed so we can check the
+                // second borrowed place for the same union and a access to a different field.
+                let mut current = first_borrowed_place;
+                while let Place::Projection(box PlaceProjection { base, elem }) = current {
+                    match elem {
+                        ProjectionElem::Field(field, _) if is_union(base) => {
+                            return Some((base, field));
+                        },
+                        _ => current = base,
+                    }
+                }
+                None
+            })
+            .and_then(|(target_base, target_field)| {
+                // With the place of a union and a field access into it, we traverse the second
+                // borrowed place and look for a access to a different field of the same union.
+                let mut current = second_borrowed_place;
+                while let Place::Projection(box PlaceProjection { base, elem }) = current {
+                    match elem {
+                        ProjectionElem::Field(field, _) if {
+                            is_union(base) && field != target_field && base == target_base
+                        } => {
+                            let desc_base = self.describe_place(base)
+                                .unwrap_or_else(|| "_".to_owned());
+                            let desc_first = self.describe_place(first_borrowed_place)
+                                .unwrap_or_else(|| "_".to_owned());
+                            let desc_second = self.describe_place(second_borrowed_place)
+                                .unwrap_or_else(|| "_".to_owned());
+
+                            // Also compute the name of the union type, eg. `Foo` so we
+                            // can add a helpful note with it.
+                            let ty = base.ty(self.mir, self.infcx.tcx).ty;
+
+                            return Some((desc_base, desc_first, desc_second, ty.to_string()));
+                        },
+                        _ => current = base,
+                    }
+                }
+                None
+            })
+            .unwrap_or_else(|| {
+                // If we didn't find a field access into a union, or both places match, then
+                // only return the description of the first place.
+                let desc_place = self.describe_place(first_borrowed_place)
+                    .unwrap_or_else(|| "_".to_owned());
+                (desc_place, "".to_string(), "".to_string(), "".to_string())
+            })
+    }
+
+    /// Reports StorageDeadOrDrop of `place` conflicts with `borrow`.
+    ///
+    /// This means that some data referenced by `borrow` needs to live
+    /// past the point where the StorageDeadOrDrop of `place` occurs.
+    /// This is usually interpreted as meaning that `place` has too
+    /// short a lifetime. (But sometimes it is more useful to report
+    /// it as a more direct conflict between the execution of a
+    /// `Drop::drop` with an aliasing borrow.)
+    pub(super) fn report_borrowed_value_does_not_live_long_enough(
+        &mut self,
+        location: Location,
+        borrow: &BorrowData<'tcx>,
+        place_span: (&Place<'tcx>, Span),
+        kind: Option<WriteKind>,
+    ) {
+        debug!(
+            "report_borrowed_value_does_not_live_long_enough(\
+             {:?}, {:?}, {:?}, {:?}\
+             )",
+            location, borrow, place_span, kind
+        );
+
+        let drop_span = place_span.1;
+        let root_place = self.prefixes(&borrow.borrowed_place, PrefixSet::All)
+            .last()
+            .unwrap();
+
+        let borrow_spans = self.retrieve_borrow_spans(borrow);
+        let borrow_span = borrow_spans.var_or_use();
+
+        let proper_span = match *root_place {
+            Place::Base(PlaceBase::Local(local)) => self.mir.local_decls[local].source_info.span,
+            _ => drop_span,
+        };
+
+        if self.access_place_error_reported
+            .contains(&(root_place.clone(), borrow_span))
+        {
+            debug!(
+                "suppressing access_place error when borrow doesn't live long enough for {:?}",
+                borrow_span
+            );
+            return;
+        }
+
+        self.access_place_error_reported
+            .insert((root_place.clone(), borrow_span));
+
+        if let StorageDeadOrDrop::Destructor(dropped_ty) =
+            self.classify_drop_access_kind(&borrow.borrowed_place)
+        {
+            // If a borrow of path `B` conflicts with drop of `D` (and
+            // we're not in the uninteresting case where `B` is a
+            // prefix of `D`), then report this as a more interesting
+            // destructor conflict.
+            if !borrow.borrowed_place.is_prefix_of(place_span.0) {
+                self.report_borrow_conflicts_with_destructor(
+                    location, borrow, place_span, kind, dropped_ty,
+                );
+                return;
+            }
+        }
+
+        let place_desc = self.describe_place(&borrow.borrowed_place);
+
+        let kind_place = kind.filter(|_| place_desc.is_some()).map(|k| (k, place_span.0));
+        let explanation = self.explain_why_borrow_contains_point(location, &borrow, kind_place);
+
+        let err = match (place_desc, explanation) {
+            (Some(_), _) if self.is_place_thread_local(root_place) => {
+                self.report_thread_local_value_does_not_live_long_enough(drop_span, borrow_span)
+            }
+            // If the outlives constraint comes from inside the closure,
+            // for example:
+            //
+            // let x = 0;
+            // let y = &x;
+            // Box::new(|| y) as Box<Fn() -> &'static i32>
+            //
+            // then just use the normal error. The closure isn't escaping
+            // and `move` will not help here.
+            (
+                Some(ref name),
+                BorrowExplanation::MustBeValidFor {
+                    category: category @ ConstraintCategory::Return,
+                    from_closure: false,
+                    ref region_name,
+                    span,
+                    ..
+                },
+            )
+            | (
+                Some(ref name),
+                BorrowExplanation::MustBeValidFor {
+                    category: category @ ConstraintCategory::CallArgument,
+                    from_closure: false,
+                    ref region_name,
+                    span,
+                    ..
+                },
+            ) if borrow_spans.for_closure() => self.report_escaping_closure_capture(
+                borrow_spans.args_or_use(),
+                borrow_span,
+                region_name,
+                category,
+                span,
+                &format!("`{}`", name),
+            ),
+            (
+                ref name,
+                BorrowExplanation::MustBeValidFor {
+                    category: ConstraintCategory::Assignment,
+                    from_closure: false,
+                    region_name: RegionName {
+                        source: RegionNameSource::AnonRegionFromUpvar(upvar_span, ref upvar_name),
+                        ..
+                    },
+                    span,
+                    ..
+                },
+            ) => self.report_escaping_data(borrow_span, name, upvar_span, upvar_name, span),
+            (Some(name), explanation) => self.report_local_value_does_not_live_long_enough(
+                location,
+                &name,
+                &borrow,
+                drop_span,
+                borrow_spans,
+                explanation,
+            ),
+            (None, explanation) => self.report_temporary_value_does_not_live_long_enough(
+                location,
+                &borrow,
+                drop_span,
+                borrow_spans,
+                proper_span,
+                explanation,
+            ),
+        };
+
+        err.buffer(&mut self.errors_buffer);
+    }
+
+    fn report_local_value_does_not_live_long_enough(
+        &mut self,
+        location: Location,
+        name: &str,
+        borrow: &BorrowData<'tcx>,
+        drop_span: Span,
+        borrow_spans: UseSpans,
+        explanation: BorrowExplanation,
+    ) -> DiagnosticBuilder<'cx> {
+        debug!(
+            "report_local_value_does_not_live_long_enough(\
+             {:?}, {:?}, {:?}, {:?}, {:?}\
+             )",
+            location, name, borrow, drop_span, borrow_spans
+        );
+
+        let borrow_span = borrow_spans.var_or_use();
+        if let BorrowExplanation::MustBeValidFor {
+            category,
+            span,
+            ref opt_place_desc,
+            from_closure: false,
+            ..
+        } = explanation {
+            if let Some(diag) = self.try_report_cannot_return_reference_to_local(
+                borrow,
+                borrow_span,
+                span,
+                category,
+                opt_place_desc.as_ref(),
+            ) {
+                return diag;
+            }
+        }
+
+        let mut err = self.infcx.tcx.path_does_not_live_long_enough(
+            borrow_span,
+            &format!("`{}`", name),
+            Origin::Mir,
+        );
+
+        if let Some(annotation) = self.annotate_argument_and_return_for_borrow(borrow) {
+            let region_name = annotation.emit(self, &mut err);
+
+            err.span_label(
+                borrow_span,
+                format!("`{}` would have to be valid for `{}`...", name, region_name),
+            );
+
+            if let Some(fn_hir_id) = self.infcx.tcx.hir().as_local_hir_id(self.mir_def_id) {
+                err.span_label(
+                    drop_span,
+                    format!(
+                        "...but `{}` will be dropped here, when the function `{}` returns",
+                        name,
+                        self.infcx.tcx.hir().name_by_hir_id(fn_hir_id),
+                    ),
+                );
+
+                err.note(
+                    "functions cannot return a borrow to data owned within the function's scope, \
+                     functions can only return borrows to data passed as arguments",
+                );
+                err.note(
+                    "to learn more, visit <https://doc.rust-lang.org/book/ch04-02-\
+                     references-and-borrowing.html#dangling-references>",
+                );
+            } else {
+                err.span_label(
+                    drop_span,
+                    format!("...but `{}` dropped here while still borrowed", name),
+                );
+            }
+
+            if let BorrowExplanation::MustBeValidFor { .. } = explanation {
+            } else {
+                explanation.add_explanation_to_diagnostic(
+                    self.infcx.tcx,
+                    self.mir,
+                    &mut err,
+                    "",
+                    None,
+                );
+            }
+        } else {
+            err.span_label(borrow_span, "borrowed value does not live long enough");
+            err.span_label(
+                drop_span,
+                format!("`{}` dropped here while still borrowed", name),
+            );
+
+            let within = if borrow_spans.for_generator() {
+                " by generator"
+            } else {
+                ""
+            };
+
+            borrow_spans.args_span_label(
+                &mut err,
+                format!("value captured here{}", within),
+            );
+
+            explanation.add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, "", None);
+        }
+
+        err
+    }
+
+    fn report_borrow_conflicts_with_destructor(
+        &mut self,
+        location: Location,
+        borrow: &BorrowData<'tcx>,
+        (place, drop_span): (&Place<'tcx>, Span),
+        kind: Option<WriteKind>,
+        dropped_ty: Ty<'tcx>,
+    ) {
+        debug!(
+            "report_borrow_conflicts_with_destructor(\
+             {:?}, {:?}, ({:?}, {:?}), {:?}\
+             )",
+            location, borrow, place, drop_span, kind,
+        );
+
+        let borrow_spans = self.retrieve_borrow_spans(borrow);
+        let borrow_span = borrow_spans.var_or_use();
+
+        let mut err = self.infcx
+            .tcx
+            .cannot_borrow_across_destructor(borrow_span, Origin::Mir);
+
+        let what_was_dropped = match self.describe_place(place) {
+            Some(name) => format!("`{}`", name.as_str()),
+            None => String::from("temporary value"),
+        };
+
+        let label = match self.describe_place(&borrow.borrowed_place) {
+            Some(borrowed) => format!(
+                "here, drop of {D} needs exclusive access to `{B}`, \
+                 because the type `{T}` implements the `Drop` trait",
+                D = what_was_dropped,
+                T = dropped_ty,
+                B = borrowed
+            ),
+            None => format!(
+                "here is drop of {D}; whose type `{T}` implements the `Drop` trait",
+                D = what_was_dropped,
+                T = dropped_ty
+            ),
+        };
+        err.span_label(drop_span, label);
+
+        // Only give this note and suggestion if they could be relevant.
+        let explanation =
+            self.explain_why_borrow_contains_point(location, borrow, kind.map(|k| (k, place)));
+        match explanation {
+            BorrowExplanation::UsedLater { .. }
+            | BorrowExplanation::UsedLaterWhenDropped { .. } => {
+                err.note("consider using a `let` binding to create a longer lived value");
+            }
+            _ => {}
+        }
+
+        explanation.add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, "", None);
+
+        err.buffer(&mut self.errors_buffer);
+    }
+
+    fn report_thread_local_value_does_not_live_long_enough(
+        &mut self,
+        drop_span: Span,
+        borrow_span: Span,
+    ) -> DiagnosticBuilder<'cx> {
+        debug!(
+            "report_thread_local_value_does_not_live_long_enough(\
+             {:?}, {:?}\
+             )",
+            drop_span, borrow_span
+        );
+
+        let mut err = self.infcx
+            .tcx
+            .thread_local_value_does_not_live_long_enough(borrow_span, Origin::Mir);
+
+        err.span_label(
+            borrow_span,
+            "thread-local variables cannot be borrowed beyond the end of the function",
+        );
+        err.span_label(drop_span, "end of enclosing function is here");
+
+        err
+    }
+
+    fn report_temporary_value_does_not_live_long_enough(
+        &mut self,
+        location: Location,
+        borrow: &BorrowData<'tcx>,
+        drop_span: Span,
+        borrow_spans: UseSpans,
+        proper_span: Span,
+        explanation: BorrowExplanation,
+    ) -> DiagnosticBuilder<'cx> {
+        debug!(
+            "report_temporary_value_does_not_live_long_enough(\
+             {:?}, {:?}, {:?}, {:?}\
+             )",
+            location, borrow, drop_span, proper_span
+        );
+
+        if let BorrowExplanation::MustBeValidFor {
+            category,
+            span,
+            from_closure: false,
+            ..
+        } = explanation {
+            if let Some(diag) = self.try_report_cannot_return_reference_to_local(
+                borrow,
+                proper_span,
+                span,
+                category,
+                None,
+            ) {
+                return diag;
+            }
+        }
+
+        let tcx = self.infcx.tcx;
+        let mut err = tcx.temporary_value_borrowed_for_too_long(proper_span, Origin::Mir);
+        err.span_label(
+            proper_span,
+            "creates a temporary which is freed while still in use",
+        );
+        err.span_label(
+            drop_span,
+            "temporary value is freed at the end of this statement",
+        );
+
+        match explanation {
+            BorrowExplanation::UsedLater(..)
+            | BorrowExplanation::UsedLaterInLoop(..)
+            | BorrowExplanation::UsedLaterWhenDropped { .. } => {
+                // Only give this note and suggestion if it could be relevant.
+                err.note("consider using a `let` binding to create a longer lived value");
+            }
+            _ => {}
+        }
+        explanation.add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, "", None);
+
+        let within = if borrow_spans.for_generator() {
+            " by generator"
+        } else {
+            ""
+        };
+
+        borrow_spans.args_span_label(
+            &mut err,
+            format!("value captured here{}", within),
+        );
+
+        err
+    }
+
+    fn try_report_cannot_return_reference_to_local(
+        &self,
+        borrow: &BorrowData<'tcx>,
+        borrow_span: Span,
+        return_span: Span,
+        category: ConstraintCategory,
+        opt_place_desc: Option<&String>,
+    ) -> Option<DiagnosticBuilder<'cx>> {
+        let tcx = self.infcx.tcx;
+
+        let return_kind = match category {
+            ConstraintCategory::Return => "return",
+            ConstraintCategory::Yield => "yield",
+            _ => return None,
+        };
+
+        // FIXME use a better heuristic than Spans
+        let reference_desc = if return_span == self.mir.source_info(borrow.reserve_location).span {
+            "reference to"
+        } else {
+            "value referencing"
+        };
+
+        let (place_desc, note) = if let Some(place_desc) = opt_place_desc {
+            let local_kind = match borrow.borrowed_place {
+                Place::Base(PlaceBase::Local(local)) => {
+                    match self.mir.local_kind(local) {
+                        LocalKind::ReturnPointer
+                        | LocalKind::Temp => bug!("temporary or return pointer with a name"),
+                        LocalKind::Var => "local variable ",
+                        LocalKind::Arg
+                        if !self.upvars.is_empty()
+                            && local == Local::new(1) => {
+                            "variable captured by `move` "
+                        }
+                        LocalKind::Arg => {
+                            "function parameter "
+                        }
+                    }
+                }
+                _ => "local data ",
+            };
+            (
+                format!("{}`{}`", local_kind, place_desc),
+                format!("`{}` is borrowed here", place_desc),
+            )
+        } else {
+            let root_place = self.prefixes(&borrow.borrowed_place, PrefixSet::All)
+                .last()
+                .unwrap();
+            let local = if let Place::Base(PlaceBase::Local(local)) = *root_place {
+                local
+            } else {
+                bug!("try_report_cannot_return_reference_to_local: not a local")
+            };
+            match self.mir.local_kind(local) {
+                LocalKind::ReturnPointer | LocalKind::Temp => {
+                    (
+                        "temporary value".to_string(),
+                        "temporary value created here".to_string(),
+                    )
+                }
+                LocalKind::Arg => {
+                    (
+                        "function parameter".to_string(),
+                        "function parameter borrowed here".to_string(),
+                    )
+                },
+                LocalKind::Var => bug!("local variable without a name"),
+            }
+        };
+
+        let mut err = tcx.cannot_return_reference_to_local(
+            return_span,
+            return_kind,
+            reference_desc,
+            &place_desc,
+            Origin::Mir,
+        );
+
+        if return_span != borrow_span {
+            err.span_label(borrow_span, note);
+        }
+
+        Some(err)
+    }
+
+    fn report_escaping_closure_capture(
+        &mut self,
+        args_span: Span,
+        var_span: Span,
+        fr_name: &RegionName,
+        category: ConstraintCategory,
+        constraint_span: Span,
+        captured_var: &str,
+    ) -> DiagnosticBuilder<'cx> {
+        let tcx = self.infcx.tcx;
+
+        let mut err = tcx.cannot_capture_in_long_lived_closure(
+            args_span,
+            captured_var,
+            var_span,
+          Origin::Mir,
+        );
+
+        let suggestion = match tcx.sess.source_map().span_to_snippet(args_span) {
+            Ok(string) => format!("move {}", string),
+            Err(_) => "move |<args>| <body>".to_string()
+        };
+
+        err.span_suggestion(
+            args_span,
+            &format!("to force the closure to take ownership of {} (and any \
+                      other referenced variables), use the `move` keyword",
+                      captured_var),
+            suggestion,
+            Applicability::MachineApplicable,
+        );
+
+        match category {
+            ConstraintCategory::Return => {
+                err.span_note(constraint_span, "closure is returned here");
+            }
+            ConstraintCategory::CallArgument => {
+                fr_name.highlight_region_name(&mut err);
+                err.span_note(
+                    constraint_span,
+                    &format!("function requires argument type to outlive `{}`", fr_name),
+                );
+            }
+            _ => bug!("report_escaping_closure_capture called with unexpected constraint \
+                       category: `{:?}`", category),
+        }
+        err
+    }
+
+    fn report_escaping_data(
+        &mut self,
+        borrow_span: Span,
+        name: &Option<String>,
+        upvar_span: Span,
+        upvar_name: &str,
+        escape_span: Span,
+    ) -> DiagnosticBuilder<'cx> {
+        let tcx = self.infcx.tcx;
+
+        let escapes_from = if tcx.is_closure(self.mir_def_id) {
+            let tables = tcx.typeck_tables_of(self.mir_def_id);
+            let mir_hir_id = tcx.hir().def_index_to_hir_id(self.mir_def_id.index);
+            match tables.node_type(mir_hir_id).sty {
+                ty::Closure(..) => "closure",
+                ty::Generator(..) => "generator",
+                _ => bug!("Closure body doesn't have a closure or generator type"),
+            }
+        } else {
+            "function"
+        };
+
+        let mut err = tcx.borrowed_data_escapes_closure(escape_span, escapes_from, Origin::Mir);
+
+        err.span_label(
+            upvar_span,
+            format!(
+                "`{}` is declared here, outside of the {} body",
+                upvar_name, escapes_from
+            ),
+        );
+
+        err.span_label(
+            borrow_span,
+            format!(
+                "borrow is only valid in the {} body",
+                escapes_from
+            ),
+        );
+
+        if let Some(name) = name {
+            err.span_label(
+                escape_span,
+                format!("reference to `{}` escapes the {} body here", name, escapes_from),
+            );
+        } else {
+            err.span_label(
+                escape_span,
+                format!("reference escapes the {} body here", escapes_from),
+            );
+        }
+
+        err
+    }
+
+    fn get_moved_indexes(&mut self, location: Location, mpi: MovePathIndex) -> Vec<MoveSite> {
+        let mir = self.mir;
+
+        let mut stack = Vec::new();
+        stack.extend(mir.predecessor_locations(location).map(|predecessor| {
+            let is_back_edge = location.dominates(predecessor, &self.dominators);
+            (predecessor, is_back_edge)
+        }));
+
+        let mut visited = FxHashSet::default();
+        let mut result = vec![];
+
+        'dfs: while let Some((location, is_back_edge)) = stack.pop() {
+            debug!(
+                "report_use_of_moved_or_uninitialized: (current_location={:?}, back_edge={})",
+                location, is_back_edge
+            );
+
+            if !visited.insert(location) {
+                continue;
+            }
+
+            // check for moves
+            let stmt_kind = mir[location.block]
+                .statements
+                .get(location.statement_index)
+                .map(|s| &s.kind);
+            if let Some(StatementKind::StorageDead(..)) = stmt_kind {
+                // this analysis only tries to find moves explicitly
+                // written by the user, so we ignore the move-outs
+                // created by `StorageDead` and at the beginning
+                // of a function.
+            } else {
+                // If we are found a use of a.b.c which was in error, then we want to look for
+                // moves not only of a.b.c but also a.b and a.
+                //
+                // Note that the moves data already includes "parent" paths, so we don't have to
+                // worry about the other case: that is, if there is a move of a.b.c, it is already
+                // marked as a move of a.b and a as well, so we will generate the correct errors
+                // there.
+                let mut mpis = vec![mpi];
+                let move_paths = &self.move_data.move_paths;
+                mpis.extend(move_paths[mpi].parents(move_paths));
+
+                for moi in &self.move_data.loc_map[location] {
+                    debug!("report_use_of_moved_or_uninitialized: moi={:?}", moi);
+                    if mpis.contains(&self.move_data.moves[*moi].path) {
+                        debug!("report_use_of_moved_or_uninitialized: found");
+                        result.push(MoveSite {
+                            moi: *moi,
+                            traversed_back_edge: is_back_edge,
+                        });
+
+                        // Strictly speaking, we could continue our DFS here. There may be
+                        // other moves that can reach the point of error. But it is kind of
+                        // confusing to highlight them.
+                        //
+                        // Example:
+                        //
+                        // ```
+                        // let a = vec![];
+                        // let b = a;
+                        // let c = a;
+                        // drop(a); // <-- current point of error
+                        // ```
+                        //
+                        // Because we stop the DFS here, we only highlight `let c = a`,
+                        // and not `let b = a`. We will of course also report an error at
+                        // `let c = a` which highlights `let b = a` as the move.
+                        continue 'dfs;
+                    }
+                }
+            }
+
+            // check for inits
+            let mut any_match = false;
+            drop_flag_effects::for_location_inits(
+                self.infcx.tcx,
+                self.mir,
+                self.move_data,
+                location,
+                |m| {
+                    if m == mpi {
+                        any_match = true;
+                    }
+                },
+            );
+            if any_match {
+                continue 'dfs;
+            }
+
+            stack.extend(mir.predecessor_locations(location).map(|predecessor| {
+                let back_edge = location.dominates(predecessor, &self.dominators);
+                (predecessor, is_back_edge || back_edge)
+            }));
+        }
+
+        result
+    }
+
+    pub(super) fn report_illegal_mutation_of_borrowed(
+        &mut self,
+        location: Location,
+        (place, span): (&Place<'tcx>, Span),
+        loan: &BorrowData<'tcx>,
+    ) {
+        let loan_spans = self.retrieve_borrow_spans(loan);
+        let loan_span = loan_spans.args_or_use();
+
+        let tcx = self.infcx.tcx;
+        if loan.kind == BorrowKind::Shallow {
+            let mut err = tcx.cannot_mutate_in_match_guard(
+                span,
+                loan_span,
+                &self.describe_place(place).unwrap_or_else(|| "_".to_owned()),
+                "assign",
+                Origin::Mir,
+            );
+            loan_spans.var_span_label(
+                &mut err,
+                format!("borrow occurs due to use{}", loan_spans.describe()),
+            );
+
+            err.buffer(&mut self.errors_buffer);
+
+            return;
+        }
+
+        let mut err = tcx.cannot_assign_to_borrowed(
+            span,
+            loan_span,
+            &self.describe_place(place).unwrap_or_else(|| "_".to_owned()),
+            Origin::Mir,
+        );
+
+        loan_spans.var_span_label(
+            &mut err,
+            format!("borrow occurs due to use{}", loan_spans.describe()),
+        );
+
+        self.explain_why_borrow_contains_point(location, loan, None)
+            .add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, "", None);
+
+        err.buffer(&mut self.errors_buffer);
+    }
+
+    /// Reports an illegal reassignment; for example, an assignment to
+    /// (part of) a non-`mut` local that occurs potentially after that
+    /// local has already been initialized. `place` is the path being
+    /// assigned; `err_place` is a place providing a reason why
+    /// `place` is not mutable (e.g., the non-`mut` local `x` in an
+    /// assignment to `x.f`).
+    pub(super) fn report_illegal_reassignment(
+        &mut self,
+        _location: Location,
+        (place, span): (&Place<'tcx>, Span),
+        assigned_span: Span,
+        err_place: &Place<'tcx>,
+    ) {
+        let (from_arg, local_decl) = if let Place::Base(PlaceBase::Local(local)) = *err_place {
+            if let LocalKind::Arg = self.mir.local_kind(local) {
+                (true, Some(&self.mir.local_decls[local]))
+            } else {
+                (false, Some(&self.mir.local_decls[local]))
+            }
+        } else {
+            (false, None)
+        };
+
+        // If root local is initialized immediately (everything apart from let
+        // PATTERN;) then make the error refer to that local, rather than the
+        // place being assigned later.
+        let (place_description, assigned_span) = match local_decl {
+            Some(LocalDecl {
+                is_user_variable: Some(ClearCrossCrate::Clear),
+                ..
+            })
+            | Some(LocalDecl {
+                is_user_variable:
+                    Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
+                        opt_match_place: None,
+                        ..
+                    }))),
+                ..
+            })
+            | Some(LocalDecl {
+                is_user_variable: None,
+                ..
+            })
+            | None => (self.describe_place(place), assigned_span),
+            Some(decl) => (self.describe_place(err_place), decl.source_info.span),
+        };
+
+        let mut err = self.infcx.tcx.cannot_reassign_immutable(
+            span,
+            place_description.as_ref().map(AsRef::as_ref).unwrap_or("_"),
+            from_arg,
+            Origin::Mir,
+        );
+        let msg = if from_arg {
+            "cannot assign to immutable argument"
+        } else {
+            "cannot assign twice to immutable variable"
+        };
+        if span != assigned_span {
+            if !from_arg {
+                let value_msg = match place_description {
+                    Some(name) => format!("`{}`", name),
+                    None => "value".to_owned(),
+                };
+                err.span_label(assigned_span, format!("first assignment to {}", value_msg));
+            }
+        }
+        if let Some(decl) = local_decl {
+            if let Some(name) = decl.name {
+                if decl.can_be_made_mutable() {
+                    err.span_suggestion(
+                        decl.source_info.span,
+                        "make this binding mutable",
+                        format!("mut {}", name),
+                        Applicability::MachineApplicable,
+                    );
+                }
+            }
+        }
+        err.span_label(span, msg);
+        err.buffer(&mut self.errors_buffer);
+    }
+
+    fn classify_drop_access_kind(&self, place: &Place<'tcx>) -> StorageDeadOrDrop<'tcx> {
+        let tcx = self.infcx.tcx;
+        match place {
+            Place::Base(PlaceBase::Local(_)) |
+            Place::Base(PlaceBase::Static(_)) => {
+                StorageDeadOrDrop::LocalStorageDead
+            }
+            Place::Projection(box PlaceProjection { base, elem }) => {
+                let base_access = self.classify_drop_access_kind(base);
+                match elem {
+                    ProjectionElem::Deref => match base_access {
+                        StorageDeadOrDrop::LocalStorageDead
+                        | StorageDeadOrDrop::BoxedStorageDead => {
+                            assert!(
+                                base.ty(self.mir, tcx).ty.is_box(),
+                                "Drop of value behind a reference or raw pointer"
+                            );
+                            StorageDeadOrDrop::BoxedStorageDead
+                        }
+                        StorageDeadOrDrop::Destructor(_) => base_access,
+                    },
+                    ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => {
+                        let base_ty = base.ty(self.mir, tcx).ty;
+                        match base_ty.sty {
+                            ty::Adt(def, _) if def.has_dtor(tcx) => {
+                                // Report the outermost adt with a destructor
+                                match base_access {
+                                    StorageDeadOrDrop::Destructor(_) => base_access,
+                                    StorageDeadOrDrop::LocalStorageDead
+                                    | StorageDeadOrDrop::BoxedStorageDead => {
+                                        StorageDeadOrDrop::Destructor(base_ty)
+                                    }
+                                }
+                            }
+                            _ => base_access,
+                        }
+                    }
+
+                    ProjectionElem::ConstantIndex { .. }
+                    | ProjectionElem::Subslice { .. }
+                    | ProjectionElem::Index(_) => base_access,
+                }
+            }
+        }
+    }
+
+    /// Annotate argument and return type of function and closure with (synthesized) lifetime for
+    /// borrow of local value that does not live long enough.
+    fn annotate_argument_and_return_for_borrow(
+        &self,
+        borrow: &BorrowData<'tcx>,
+    ) -> Option<AnnotatedBorrowFnSignature<'tcx>> {
+        // Define a fallback for when we can't match a closure.
+        let fallback = || {
+            let is_closure = self.infcx.tcx.is_closure(self.mir_def_id);
+            if is_closure {
+                None
+            } else {
+                let ty = self.infcx.tcx.type_of(self.mir_def_id);
+                match ty.sty {
+                    ty::FnDef(_, _) | ty::FnPtr(_) => self.annotate_fn_sig(
+                        self.mir_def_id,
+                        self.infcx.tcx.fn_sig(self.mir_def_id),
+                    ),
+                    _ => None,
+                }
+            }
+        };
+
+        // In order to determine whether we need to annotate, we need to check whether the reserve
+        // place was an assignment into a temporary.
+        //
+        // If it was, we check whether or not that temporary is eventually assigned into the return
+        // place. If it was, we can add annotations about the function's return type and arguments
+        // and it'll make sense.
+        let location = borrow.reserve_location;
+        debug!(
+            "annotate_argument_and_return_for_borrow: location={:?}",
+            location
+        );
+        if let Some(&Statement { kind: StatementKind::Assign(ref reservation, _), ..})
+             = &self.mir[location.block].statements.get(location.statement_index)
+        {
+            debug!(
+                "annotate_argument_and_return_for_borrow: reservation={:?}",
+                reservation
+            );
+            // Check that the initial assignment of the reserve location is into a temporary.
+            let mut target = *match reservation {
+                Place::Base(PlaceBase::Local(local))
+                    if self.mir.local_kind(*local) == LocalKind::Temp => local,
+                _ => return None,
+            };
+
+            // Next, look through the rest of the block, checking if we are assigning the
+            // `target` (that is, the place that contains our borrow) to anything.
+            let mut annotated_closure = None;
+            for stmt in &self.mir[location.block].statements[location.statement_index + 1..] {
+                debug!(
+                    "annotate_argument_and_return_for_borrow: target={:?} stmt={:?}",
+                    target, stmt
+                );
+                if let StatementKind::Assign(
+                    Place::Base(PlaceBase::Local(assigned_to)),
+                    box rvalue
+                ) = &stmt.kind {
+                    debug!(
+                        "annotate_argument_and_return_for_borrow: assigned_to={:?} \
+                         rvalue={:?}",
+                        assigned_to, rvalue
+                    );
+                    // Check if our `target` was captured by a closure.
+                    if let Rvalue::Aggregate(
+                        box AggregateKind::Closure(def_id, substs),
+                        operands,
+                    ) = rvalue
+                    {
+                        for operand in operands {
+                            let assigned_from = match operand {
+                                Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
+                                    assigned_from
+                                }
+                                _ => continue,
+                            };
+                            debug!(
+                                "annotate_argument_and_return_for_borrow: assigned_from={:?}",
+                                assigned_from
+                            );
+
+                            // Find the local from the operand.
+                            let assigned_from_local = match assigned_from.local() {
+                                Some(local) => local,
+                                None => continue,
+                            };
+
+                            if assigned_from_local != target {
+                                continue;
+                            }
+
+                            // If a closure captured our `target` and then assigned
+                            // into a place then we should annotate the closure in
+                            // case it ends up being assigned into the return place.
+                            annotated_closure = self.annotate_fn_sig(
+                                *def_id,
+                                self.infcx.closure_sig(*def_id, *substs),
+                            );
+                            debug!(
+                                "annotate_argument_and_return_for_borrow: \
+                                 annotated_closure={:?} assigned_from_local={:?} \
+                                 assigned_to={:?}",
+                                annotated_closure, assigned_from_local, assigned_to
+                            );
+
+                            if *assigned_to == mir::RETURN_PLACE {
+                                // If it was assigned directly into the return place, then
+                                // return now.
+                                return annotated_closure;
+                            } else {
+                                // Otherwise, update the target.
+                                target = *assigned_to;
+                            }
+                        }
+
+                        // If none of our closure's operands matched, then skip to the next
+                        // statement.
+                        continue;
+                    }
+
+                    // Otherwise, look at other types of assignment.
+                    let assigned_from = match rvalue {
+                        Rvalue::Ref(_, _, assigned_from) => assigned_from,
+                        Rvalue::Use(operand) => match operand {
+                            Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
+                                assigned_from
+                            }
+                            _ => continue,
+                        },
+                        _ => continue,
+                    };
+                    debug!(
+                        "annotate_argument_and_return_for_borrow: \
+                         assigned_from={:?}",
+                        assigned_from,
+                    );
+
+                    // Find the local from the rvalue.
+                    let assigned_from_local = match assigned_from.local() {
+                        Some(local) => local,
+                        None => continue,
+                    };
+                    debug!(
+                        "annotate_argument_and_return_for_borrow: \
+                         assigned_from_local={:?}",
+                        assigned_from_local,
+                    );
+
+                    // Check if our local matches the target - if so, we've assigned our
+                    // borrow to a new place.
+                    if assigned_from_local != target {
+                        continue;
+                    }
+
+                    // If we assigned our `target` into a new place, then we should
+                    // check if it was the return place.
+                    debug!(
+                        "annotate_argument_and_return_for_borrow: \
+                         assigned_from_local={:?} assigned_to={:?}",
+                        assigned_from_local, assigned_to
+                    );
+                    if *assigned_to == mir::RETURN_PLACE {
+                        // If it was then return the annotated closure if there was one,
+                        // else, annotate this function.
+                        return annotated_closure.or_else(fallback);
+                    }
+
+                    // If we didn't assign into the return place, then we just update
+                    // the target.
+                    target = *assigned_to;
+                }
+            }
+
+            // Check the terminator if we didn't find anything in the statements.
+            let terminator = &self.mir[location.block].terminator();
+            debug!(
+                "annotate_argument_and_return_for_borrow: target={:?} terminator={:?}",
+                target, terminator
+            );
+            if let TerminatorKind::Call {
+                destination: Some((Place::Base(PlaceBase::Local(assigned_to)), _)),
+                args,
+                ..
+            } = &terminator.kind
+            {
+                debug!(
+                    "annotate_argument_and_return_for_borrow: assigned_to={:?} args={:?}",
+                    assigned_to, args
+                );
+                for operand in args {
+                    let assigned_from = match operand {
+                        Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
+                            assigned_from
+                        }
+                        _ => continue,
+                    };
+                    debug!(
+                        "annotate_argument_and_return_for_borrow: assigned_from={:?}",
+                        assigned_from,
+                    );
+
+                    if let Some(assigned_from_local) = assigned_from.local() {
+                        debug!(
+                            "annotate_argument_and_return_for_borrow: assigned_from_local={:?}",
+                            assigned_from_local,
+                        );
+
+                        if *assigned_to == mir::RETURN_PLACE && assigned_from_local == target {
+                            return annotated_closure.or_else(fallback);
+                        }
+                    }
+                }
+            }
+        }
+
+        // If we haven't found an assignment into the return place, then we need not add
+        // any annotations.
+        debug!("annotate_argument_and_return_for_borrow: none found");
+        None
+    }
+
+    /// Annotate the first argument and return type of a function signature if they are
+    /// references.
+    fn annotate_fn_sig(
+        &self,
+        did: DefId,
+        sig: ty::PolyFnSig<'tcx>,
+    ) -> Option<AnnotatedBorrowFnSignature<'tcx>> {
+        debug!("annotate_fn_sig: did={:?} sig={:?}", did, sig);
+        let is_closure = self.infcx.tcx.is_closure(did);
+        let fn_hir_id = self.infcx.tcx.hir().as_local_hir_id(did)?;
+        let fn_decl = self.infcx.tcx.hir().fn_decl_by_hir_id(fn_hir_id)?;
+
+        // We need to work out which arguments to highlight. We do this by looking
+        // at the return type, where there are three cases:
+        //
+        // 1. If there are named arguments, then we should highlight the return type and
+        //    highlight any of the arguments that are also references with that lifetime.
+        //    If there are no arguments that have the same lifetime as the return type,
+        //    then don't highlight anything.
+        // 2. The return type is a reference with an anonymous lifetime. If this is
+        //    the case, then we can take advantage of (and teach) the lifetime elision
+        //    rules.
+        //
+        //    We know that an error is being reported. So the arguments and return type
+        //    must satisfy the elision rules. Therefore, if there is a single argument
+        //    then that means the return type and first (and only) argument have the same
+        //    lifetime and the borrow isn't meeting that, we can highlight the argument
+        //    and return type.
+        //
+        //    If there are multiple arguments then the first argument must be self (else
+        //    it would not satisfy the elision rules), so we can highlight self and the
+        //    return type.
+        // 3. The return type is not a reference. In this case, we don't highlight
+        //    anything.
+        let return_ty = sig.output();
+        match return_ty.skip_binder().sty {
+            ty::Ref(return_region, _, _) if return_region.has_name() && !is_closure => {
+                // This is case 1 from above, return type is a named reference so we need to
+                // search for relevant arguments.
+                let mut arguments = Vec::new();
+                for (index, argument) in sig.inputs().skip_binder().iter().enumerate() {
+                    if let ty::Ref(argument_region, _, _) = argument.sty {
+                        if argument_region == return_region {
+                            // Need to use the `rustc::ty` types to compare against the
+                            // `return_region`. Then use the `rustc::hir` type to get only
+                            // the lifetime span.
+                            if let hir::TyKind::Rptr(lifetime, _) = &fn_decl.inputs[index].node {
+                                // With access to the lifetime, we can get
+                                // the span of it.
+                                arguments.push((*argument, lifetime.span));
+                            } else {
+                                bug!("ty type is a ref but hir type is not");
+                            }
+                        }
+                    }
+                }
+
+                // We need to have arguments. This shouldn't happen, but it's worth checking.
+                if arguments.is_empty() {
+                    return None;
+                }
+
+                // We use a mix of the HIR and the Ty types to get information
+                // as the HIR doesn't have full types for closure arguments.
+                let return_ty = *sig.output().skip_binder();
+                let mut return_span = fn_decl.output.span();
+                if let hir::FunctionRetTy::Return(ty) = fn_decl.output {
+                    if let hir::TyKind::Rptr(lifetime, _) = ty.into_inner().node {
+                        return_span = lifetime.span;
+                    }
+                }
+
+                Some(AnnotatedBorrowFnSignature::NamedFunction {
+                    arguments,
+                    return_ty,
+                    return_span,
+                })
+            }
+            ty::Ref(_, _, _) if is_closure => {
+                // This is case 2 from above but only for closures, return type is anonymous
+                // reference so we select
+                // the first argument.
+                let argument_span = fn_decl.inputs.first()?.span;
+                let argument_ty = sig.inputs().skip_binder().first()?;
+
+                // Closure arguments are wrapped in a tuple, so we need to get the first
+                // from that.
+                if let ty::Tuple(elems) = argument_ty.sty {
+                    let argument_ty = elems.first()?.expect_ty();
+                    if let ty::Ref(_, _, _) = argument_ty.sty {
+                        return Some(AnnotatedBorrowFnSignature::Closure {
+                            argument_ty,
+                            argument_span,
+                        });
+                    }
+                }
+
+                None
+            }
+            ty::Ref(_, _, _) => {
+                // This is also case 2 from above but for functions, return type is still an
+                // anonymous reference so we select the first argument.
+                let argument_span = fn_decl.inputs.first()?.span;
+                let argument_ty = sig.inputs().skip_binder().first()?;
+
+                let return_span = fn_decl.output.span();
+                let return_ty = *sig.output().skip_binder();
+
+                // We expect the first argument to be a reference.
+                match argument_ty.sty {
+                    ty::Ref(_, _, _) => {}
+                    _ => return None,
+                }
+
+                Some(AnnotatedBorrowFnSignature::AnonymousFunction {
+                    argument_ty,
+                    argument_span,
+                    return_ty,
+                    return_span,
+                })
+            }
+            _ => {
+                // This is case 3 from above, return type is not a reference so don't highlight
+                // anything.
+                None
+            }
+        }
+    }
+}
+
+#[derive(Debug)]
+enum AnnotatedBorrowFnSignature<'tcx> {
+    NamedFunction {
+        arguments: Vec<(Ty<'tcx>, Span)>,
+        return_ty: Ty<'tcx>,
+        return_span: Span,
+    },
+    AnonymousFunction {
+        argument_ty: Ty<'tcx>,
+        argument_span: Span,
+        return_ty: Ty<'tcx>,
+        return_span: Span,
+    },
+    Closure {
+        argument_ty: Ty<'tcx>,
+        argument_span: Span,
+    },
+}
+
+impl<'tcx> AnnotatedBorrowFnSignature<'tcx> {
+    /// Annotate the provided diagnostic with information about borrow from the fn signature that
+    /// helps explain.
+    pub(super) fn emit(
+        &self,
+        cx: &mut MirBorrowckCtxt<'_, '_, 'tcx>,
+        diag: &mut DiagnosticBuilder<'_>,
+    ) -> String {
+        match self {
+            AnnotatedBorrowFnSignature::Closure {
+                argument_ty,
+                argument_span,
+            } => {
+                diag.span_label(
+                    *argument_span,
+                    format!("has type `{}`", cx.get_name_for_ty(argument_ty, 0)),
+                );
+
+                cx.get_region_name_for_ty(argument_ty, 0)
+            }
+            AnnotatedBorrowFnSignature::AnonymousFunction {
+                argument_ty,
+                argument_span,
+                return_ty,
+                return_span,
+            } => {
+                let argument_ty_name = cx.get_name_for_ty(argument_ty, 0);
+                diag.span_label(*argument_span, format!("has type `{}`", argument_ty_name));
+
+                let return_ty_name = cx.get_name_for_ty(return_ty, 0);
+                let types_equal = return_ty_name == argument_ty_name;
+                diag.span_label(
+                    *return_span,
+                    format!(
+                        "{}has type `{}`",
+                        if types_equal { "also " } else { "" },
+                        return_ty_name,
+                    ),
+                );
+
+                diag.note(
+                    "argument and return type have the same lifetime due to lifetime elision rules",
+                );
+                diag.note(
+                    "to learn more, visit <https://doc.rust-lang.org/book/ch10-03-\
+                     lifetime-syntax.html#lifetime-elision>",
+                );
+
+                cx.get_region_name_for_ty(return_ty, 0)
+            }
+            AnnotatedBorrowFnSignature::NamedFunction {
+                arguments,
+                return_ty,
+                return_span,
+            } => {
+                // Region of return type and arguments checked to be the same earlier.
+                let region_name = cx.get_region_name_for_ty(return_ty, 0);
+                for (_, argument_span) in arguments {
+                    diag.span_label(*argument_span, format!("has lifetime `{}`", region_name));
+                }
+
+                diag.span_label(
+                    *return_span,
+                    format!("also has lifetime `{}`", region_name,),
+                );
+
+                diag.help(&format!(
+                    "use data from the highlighted arguments which match the `{}` lifetime of \
+                     the return type",
+                    region_name,
+                ));
+
+                region_name
+            }
+        }
+    }
+}
index 32d182edfdcdebbc231b0fbea5b131d141e1af1d..ec0359794e7be7f6acbd7086a0e48c20aad73466 100644 (file)
-use crate::borrow_check::nll::explain_borrow::BorrowExplanation;
-use crate::borrow_check::nll::region_infer::{RegionName, RegionNameSource};
-use crate::borrow_check::prefixes::IsPrefixOf;
-use crate::borrow_check::WriteKind;
 use rustc::hir;
 use rustc::hir::def::Namespace;
 use rustc::hir::def_id::DefId;
-use rustc::middle::region::ScopeTree;
 use rustc::mir::{
-    self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, Constant,
-    ConstraintCategory, Field, Local, LocalDecl, LocalKind, Location, Operand,
-    Place, PlaceBase, PlaceProjection, ProjectionElem, Rvalue, Statement, StatementKind,
-    Static, StaticKind, TerminatorKind, VarBindingForm,
+    AggregateKind, BindingForm, ClearCrossCrate, Constant, Field, Local,
+    LocalKind, Location, Operand, Place, PlaceBase, ProjectionElem, Rvalue,
+    Statement, StatementKind, Static, StaticKind, TerminatorKind,
 };
 use rustc::ty::{self, DefIdTree, Ty};
 use rustc::ty::layout::VariantIdx;
 use rustc::ty::print::Print;
-use rustc_data_structures::fx::FxHashSet;
-use rustc_data_structures::indexed_vec::Idx;
-use rustc_errors::{Applicability, DiagnosticBuilder};
+use rustc_errors::DiagnosticBuilder;
 use syntax_pos::Span;
-use syntax::source_map::CompilerDesugaringKind;
 use syntax::symbol::sym;
 
 use super::borrow_set::BorrowData;
 use super::{MirBorrowckCtxt};
-use super::{InitializationRequiringAction, PrefixSet};
-use crate::dataflow::drop_flag_effects;
-use crate::dataflow::indexes::{MovePathIndex, MoveOutIndex};
-use crate::util::borrowck_errors::{BorrowckErrors, Origin};
 
-#[derive(Debug)]
-struct MoveSite {
-    /// Index of the "move out" that we found. The `MoveData` can
-    /// then tell us where the move occurred.
-    moi: MoveOutIndex,
-
-    /// `true` if we traversed a back edge while walking from the point
-    /// of error to the move site.
-    traversed_back_edge: bool
-}
-
-impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
-    pub(super) fn report_use_of_moved_or_uninitialized(
-        &mut self,
-        location: Location,
-        desired_action: InitializationRequiringAction,
-        (moved_place, used_place, span): (&Place<'tcx>, &Place<'tcx>, Span),
-        mpi: MovePathIndex,
-    ) {
-        debug!(
-            "report_use_of_moved_or_uninitialized: location={:?} desired_action={:?} \
-             moved_place={:?} used_place={:?} span={:?} mpi={:?}",
-            location, desired_action, moved_place, used_place, span, mpi
-        );
-
-        let use_spans = self.move_spans(moved_place, location)
-            .or_else(|| self.borrow_spans(span, location));
-        let span = use_spans.args_or_use();
-
-        let move_site_vec = self.get_moved_indexes(location, mpi);
-        debug!(
-            "report_use_of_moved_or_uninitialized: move_site_vec={:?}",
-            move_site_vec
-        );
-        let move_out_indices: Vec<_> = move_site_vec
-            .iter()
-            .map(|move_site| move_site.moi)
-            .collect();
-
-        if move_out_indices.is_empty() {
-            let root_place = self.prefixes(&used_place, PrefixSet::All).last().unwrap();
-
-            if self.uninitialized_error_reported.contains(root_place) {
-                debug!(
-                    "report_use_of_moved_or_uninitialized place: error about {:?} suppressed",
-                    root_place
-                );
-                return;
-            }
-
-            self.uninitialized_error_reported.insert(root_place.clone());
-
-            let item_msg = match self.describe_place_with_options(used_place,
-                                                                  IncludingDowncast(true)) {
-                Some(name) => format!("`{}`", name),
-                None => "value".to_owned(),
-            };
-            let mut err = self.infcx.tcx.cannot_act_on_uninitialized_variable(
-                span,
-                desired_action.as_noun(),
-                &self.describe_place_with_options(moved_place, IncludingDowncast(true))
-                    .unwrap_or_else(|| "_".to_owned()),
-                Origin::Mir,
-            );
-            err.span_label(span, format!("use of possibly uninitialized {}", item_msg));
-
-            use_spans.var_span_label(
-                &mut err,
-                format!("{} occurs due to use{}", desired_action.as_noun(), use_spans.describe()),
-            );
-
-            err.buffer(&mut self.errors_buffer);
-        } else {
-            if let Some((reported_place, _)) = self.move_error_reported.get(&move_out_indices) {
-                if self.prefixes(&reported_place, PrefixSet::All)
-                    .any(|p| p == used_place)
-                {
-                    debug!(
-                        "report_use_of_moved_or_uninitialized place: error suppressed \
-                         mois={:?}",
-                        move_out_indices
-                    );
-                    return;
-                }
-            }
-
-            let msg = ""; //FIXME: add "partially " or "collaterally "
-
-            let mut err = self.infcx.tcx.cannot_act_on_moved_value(
-                span,
-                desired_action.as_noun(),
-                msg,
-                self.describe_place_with_options(&moved_place, IncludingDowncast(true)),
-                Origin::Mir,
-            );
-
-            self.add_moved_or_invoked_closure_note(
-                location,
-                used_place,
-                &mut err,
-            );
-
-            let mut is_loop_move = false;
-            let is_partial_move = move_site_vec.iter().any(|move_site| {
-                let move_out = self.move_data.moves[(*move_site).moi];
-                let moved_place = &self.move_data.move_paths[move_out.path].place;
-                used_place != moved_place && used_place.is_prefix_of(moved_place)
-            });
-            for move_site in &move_site_vec {
-                let move_out = self.move_data.moves[(*move_site).moi];
-                let moved_place = &self.move_data.move_paths[move_out.path].place;
-
-                let move_spans = self.move_spans(moved_place, move_out.source);
-                let move_span = move_spans.args_or_use();
-
-                let move_msg = if move_spans.for_closure() {
-                    " into closure"
-                } else {
-                    ""
-                };
-
-                if span == move_span {
-                    err.span_label(
-                        span,
-                        format!("value moved{} here, in previous iteration of loop", move_msg),
-                    );
-                    if Some(CompilerDesugaringKind::ForLoop) == span.compiler_desugaring_kind() {
-                        if let Ok(snippet) = self.infcx.tcx.sess.source_map()
-                            .span_to_snippet(span)
-                        {
-                            err.span_suggestion(
-                                move_span,
-                                "consider borrowing this to avoid moving it into the for loop",
-                                format!("&{}", snippet),
-                                Applicability::MaybeIncorrect,
-                            );
-                        }
-                    }
-                    is_loop_move = true;
-                } else if move_site.traversed_back_edge {
-                    err.span_label(
-                        move_span,
-                        format!(
-                            "value moved{} here, in previous iteration of loop",
-                            move_msg
-                        ),
-                    );
-                } else {
-                    err.span_label(move_span, format!("value moved{} here", move_msg));
-                    move_spans.var_span_label(
-                        &mut err,
-                        format!("variable moved due to use{}", move_spans.describe()),
-                    );
-                };
-            }
-
-            use_spans.var_span_label(
-                &mut err,
-                format!("{} occurs due to use{}", desired_action.as_noun(), use_spans.describe()),
-            );
-
-            if !is_loop_move {
-                err.span_label(
-                    span,
-                    format!(
-                        "value {} here {}",
-                        desired_action.as_verb_in_past_tense(),
-                        if is_partial_move { "after partial move" } else { "after move" },
-                    ),
-                );
-            }
-
-            let ty = used_place.ty(self.mir, self.infcx.tcx).ty;
-            let needs_note = match ty.sty {
-                ty::Closure(id, _) => {
-                    let tables = self.infcx.tcx.typeck_tables_of(id);
-                    let hir_id = self.infcx.tcx.hir().as_local_hir_id(id).unwrap();
-
-                    tables.closure_kind_origins().get(hir_id).is_none()
-                }
-                _ => true,
-            };
-
-            if needs_note {
-                let mpi = self.move_data.moves[move_out_indices[0]].path;
-                let place = &self.move_data.move_paths[mpi].place;
-
-                let ty = place.ty(self.mir, self.infcx.tcx).ty;
-                let opt_name = self.describe_place_with_options(place, IncludingDowncast(true));
-                let note_msg = match opt_name {
-                    Some(ref name) => format!("`{}`", name),
-                    None => "value".to_owned(),
-                };
-                if let ty::Param(param_ty) = ty.sty {
-                    let tcx = self.infcx.tcx;
-                    let generics = tcx.generics_of(self.mir_def_id);
-                    let def_id = generics.type_param(&param_ty, tcx).def_id;
-                    if let Some(sp) = tcx.hir().span_if_local(def_id) {
-                        err.span_label(
-                            sp,
-                            "consider adding a `Copy` constraint to this type argument",
-                        );
-                    }
-                }
-                if let Place::Base(PlaceBase::Local(local)) = place {
-                    let decl = &self.mir.local_decls[*local];
-                    err.span_label(
-                        decl.source_info.span,
-                        format!(
-                            "move occurs because {} has type `{}`, \
-                                which does not implement the `Copy` trait",
-                            note_msg, ty,
-                    ));
-                } else {
-                    err.note(&format!(
-                        "move occurs because {} has type `{}`, \
-                         which does not implement the `Copy` trait",
-                        note_msg, ty
-                    ));
-                }
-            }
-
-            if let Some((_, mut old_err)) = self.move_error_reported
-                .insert(move_out_indices, (used_place.clone(), err))
-            {
-                // Cancel the old error so it doesn't ICE.
-                old_err.cancel();
-            }
-        }
-    }
-
-    pub(super) fn report_move_out_while_borrowed(
-        &mut self,
-        location: Location,
-        (place, span): (&Place<'tcx>, Span),
-        borrow: &BorrowData<'tcx>,
-    ) {
-        debug!(
-            "report_move_out_while_borrowed: location={:?} place={:?} span={:?} borrow={:?}",
-            location, place, span, borrow
-        );
-        let tcx = self.infcx.tcx;
-        let value_msg = match self.describe_place(place) {
-            Some(name) => format!("`{}`", name),
-            None => "value".to_owned(),
-        };
-        let borrow_msg = match self.describe_place(&borrow.borrowed_place) {
-            Some(name) => format!("`{}`", name),
-            None => "value".to_owned(),
-        };
-
-        let borrow_spans = self.retrieve_borrow_spans(borrow);
-        let borrow_span = borrow_spans.args_or_use();
-
-        let move_spans = self.move_spans(place, location);
-        let span = move_spans.args_or_use();
-
-        let mut err = tcx.cannot_move_when_borrowed(
-            span,
-            &self.describe_place(place).unwrap_or_else(|| "_".to_owned()),
-            Origin::Mir,
-        );
-        err.span_label(borrow_span, format!("borrow of {} occurs here", borrow_msg));
-        err.span_label(span, format!("move out of {} occurs here", value_msg));
-
-        borrow_spans.var_span_label(
-            &mut err,
-            format!("borrow occurs due to use{}", borrow_spans.describe())
-        );
-
-        move_spans.var_span_label(
-            &mut err,
-            format!("move occurs due to use{}", move_spans.describe())
-        );
-
-        self.explain_why_borrow_contains_point(
-            location,
-            borrow,
-            None,
-        ).add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, "", Some(borrow_span));
-        err.buffer(&mut self.errors_buffer);
-    }
-
-    pub(super) fn report_use_while_mutably_borrowed(
-        &mut self,
-        location: Location,
-        (place, _span): (&Place<'tcx>, Span),
-        borrow: &BorrowData<'tcx>,
-    ) -> DiagnosticBuilder<'cx> {
-        let tcx = self.infcx.tcx;
-
-        let borrow_spans = self.retrieve_borrow_spans(borrow);
-        let borrow_span = borrow_spans.args_or_use();
-
-        // Conflicting borrows are reported separately, so only check for move
-        // captures.
-        let use_spans = self.move_spans(place, location);
-        let span = use_spans.var_or_use();
-
-        let mut err = tcx.cannot_use_when_mutably_borrowed(
-            span,
-            &self.describe_place(place).unwrap_or_else(|| "_".to_owned()),
-            borrow_span,
-            &self.describe_place(&borrow.borrowed_place)
-                .unwrap_or_else(|| "_".to_owned()),
-            Origin::Mir,
-        );
-
-        borrow_spans.var_span_label(&mut err, {
-            let place = &borrow.borrowed_place;
-            let desc_place = self.describe_place(place).unwrap_or_else(|| "_".to_owned());
-
-            format!("borrow occurs due to use of `{}`{}", desc_place, borrow_spans.describe())
-        });
-
-        self.explain_why_borrow_contains_point(location, borrow, None)
-            .add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, "", None);
-        err
-    }
-
-    pub(super) fn report_conflicting_borrow(
-        &mut self,
-        location: Location,
-        (place, span): (&Place<'tcx>, Span),
-        gen_borrow_kind: BorrowKind,
-        issued_borrow: &BorrowData<'tcx>,
-    ) -> DiagnosticBuilder<'cx> {
-        let issued_spans = self.retrieve_borrow_spans(issued_borrow);
-        let issued_span = issued_spans.args_or_use();
-
-        let borrow_spans = self.borrow_spans(span, location);
-        let span = borrow_spans.args_or_use();
-
-        let container_name = if issued_spans.for_generator() || borrow_spans.for_generator() {
-            "generator"
-        } else {
-            "closure"
-        };
-
-        let (desc_place, msg_place, msg_borrow, union_type_name) =
-            self.describe_place_for_conflicting_borrow(place, &issued_borrow.borrowed_place);
-
-        let explanation = self.explain_why_borrow_contains_point(location, issued_borrow, None);
-        let second_borrow_desc = if explanation.is_explained() {
-            "second "
-        } else {
-            ""
-        };
-
-        // FIXME: supply non-"" `opt_via` when appropriate
-        let tcx = self.infcx.tcx;
-        let first_borrow_desc;
-        let mut err = match (
-            gen_borrow_kind,
-            "immutable",
-            "mutable",
-            issued_borrow.kind,
-            "immutable",
-            "mutable",
-        ) {
-            (BorrowKind::Shared, lft, _, BorrowKind::Mut { .. }, _, rgt) => {
-                first_borrow_desc = "mutable ";
-                tcx.cannot_reborrow_already_borrowed(
-                    span,
-                    &desc_place,
-                    &msg_place,
-                    lft,
-                    issued_span,
-                    "it",
-                    rgt,
-                    &msg_borrow,
-                    None,
-                    Origin::Mir,
-                )
-            }
-            (BorrowKind::Mut { .. }, _, lft, BorrowKind::Shared, rgt, _) => {
-                first_borrow_desc = "immutable ";
-                tcx.cannot_reborrow_already_borrowed(
-                    span,
-                    &desc_place,
-                    &msg_place,
-                    lft,
-                    issued_span,
-                    "it",
-                    rgt,
-                    &msg_borrow,
-                    None,
-                    Origin::Mir,
-                )
-            }
-
-            (BorrowKind::Mut { .. }, _, _, BorrowKind::Mut { .. }, _, _) => {
-                first_borrow_desc = "first ";
-                tcx.cannot_mutably_borrow_multiply(
-                    span,
-                    &desc_place,
-                    &msg_place,
-                    issued_span,
-                    &msg_borrow,
-                    None,
-                    Origin::Mir,
-                )
-            }
-
-            (BorrowKind::Unique, _, _, BorrowKind::Unique, _, _) => {
-                first_borrow_desc = "first ";
-                tcx.cannot_uniquely_borrow_by_two_closures(
-                    span,
-                    &desc_place,
-                    issued_span,
-                    None,
-                    Origin::Mir,
-                )
-            }
-
-            (BorrowKind::Mut { .. }, _, _, BorrowKind::Shallow, _, _)
-            | (BorrowKind::Unique, _, _, BorrowKind::Shallow, _, _) => {
-                let mut err = tcx.cannot_mutate_in_match_guard(
-                    span,
-                    issued_span,
-                    &desc_place,
-                    "mutably borrow",
-                    Origin::Mir,
-                );
-                borrow_spans.var_span_label(
-                    &mut err,
-                    format!(
-                        "borrow occurs due to use of `{}`{}", desc_place, borrow_spans.describe()
-                    ),
-                );
-
-                return err;
-            }
-
-            (BorrowKind::Unique, _, _, _, _, _) => {
-                first_borrow_desc = "first ";
-                tcx.cannot_uniquely_borrow_by_one_closure(
-                    span,
-                    container_name,
-                    &desc_place,
-                    "",
-                    issued_span,
-                    "it",
-                    "",
-                    None,
-                    Origin::Mir,
-                )
-            },
-
-            (BorrowKind::Shared, lft, _, BorrowKind::Unique, _, _) => {
-                first_borrow_desc = "first ";
-                tcx.cannot_reborrow_already_uniquely_borrowed(
-                    span,
-                    container_name,
-                    &desc_place,
-                    "",
-                    lft,
-                    issued_span,
-                    "",
-                    None,
-                    second_borrow_desc,
-                    Origin::Mir,
-                )
-            }
-
-            (BorrowKind::Mut { .. }, _, lft, BorrowKind::Unique, _, _) => {
-                first_borrow_desc = "first ";
-                tcx.cannot_reborrow_already_uniquely_borrowed(
-                    span,
-                    container_name,
-                    &desc_place,
-                    "",
-                    lft,
-                    issued_span,
-                    "",
-                    None,
-                    second_borrow_desc,
-                    Origin::Mir,
-                )
-            }
-
-            (BorrowKind::Shared, _, _, BorrowKind::Shared, _, _)
-            | (BorrowKind::Shared, _, _, BorrowKind::Shallow, _, _)
-            | (BorrowKind::Shallow, _, _, BorrowKind::Mut { .. }, _, _)
-            | (BorrowKind::Shallow, _, _, BorrowKind::Unique, _, _)
-            | (BorrowKind::Shallow, _, _, BorrowKind::Shared, _, _)
-            | (BorrowKind::Shallow, _, _, BorrowKind::Shallow, _, _) => unreachable!(),
-        };
-
-        if issued_spans == borrow_spans {
-            borrow_spans.var_span_label(
-                &mut err,
-                format!("borrows occur due to use of `{}`{}", desc_place, borrow_spans.describe()),
-            );
-        } else {
-            let borrow_place = &issued_borrow.borrowed_place;
-            let borrow_place_desc = self.describe_place(borrow_place)
-                                        .unwrap_or_else(|| "_".to_owned());
-            issued_spans.var_span_label(
-                &mut err,
-                format!(
-                    "first borrow occurs due to use of `{}`{}",
-                    borrow_place_desc,
-                    issued_spans.describe(),
-                ),
-            );
-
-            borrow_spans.var_span_label(
-                &mut err,
-                format!(
-                    "second borrow occurs due to use of `{}`{}",
-                    desc_place,
-                    borrow_spans.describe(),
-                ),
-            );
-        }
-
-        if union_type_name != "" {
-            err.note(&format!(
-                "`{}` is a field of the union `{}`, so it overlaps the field `{}`",
-                msg_place, union_type_name, msg_borrow,
-            ));
-        }
-
-        explanation.add_explanation_to_diagnostic(
-            self.infcx.tcx,
-            self.mir,
-            &mut err,
-            first_borrow_desc,
-            None,
-        );
-
-        err
-    }
-
-    /// Returns the description of the root place for a conflicting borrow and the full
-    /// descriptions of the places that caused the conflict.
-    ///
-    /// In the simplest case, where there are no unions involved, if a mutable borrow of `x` is
-    /// attempted while a shared borrow is live, then this function will return:
-    ///
-    ///     ("x", "", "")
-    ///
-    /// In the simple union case, if a mutable borrow of a union field `x.z` is attempted while
-    /// a shared borrow of another field `x.y`, then this function will return:
-    ///
-    ///     ("x", "x.z", "x.y")
-    ///
-    /// In the more complex union case, where the union is a field of a struct, then if a mutable
-    /// borrow of a union field in a struct `x.u.z` is attempted while a shared borrow of
-    /// another field `x.u.y`, then this function will return:
-    ///
-    ///     ("x.u", "x.u.z", "x.u.y")
-    ///
-    /// This is used when creating error messages like below:
-    ///
-    /// >  cannot borrow `a.u` (via `a.u.z.c`) as immutable because it is also borrowed as
-    /// >  mutable (via `a.u.s.b`) [E0502]
-    pub(super) fn describe_place_for_conflicting_borrow(
-        &self,
-        first_borrowed_place: &Place<'tcx>,
-        second_borrowed_place: &Place<'tcx>,
-    ) -> (String, String, String, String) {
-        // Define a small closure that we can use to check if the type of a place
-        // is a union.
-        let is_union = |place: &Place<'tcx>| -> bool {
-            place.ty(self.mir, self.infcx.tcx).ty
-                .ty_adt_def()
-                .map(|adt| adt.is_union())
-                .unwrap_or(false)
-        };
-
-        // Start with an empty tuple, so we can use the functions on `Option` to reduce some
-        // code duplication (particularly around returning an empty description in the failure
-        // case).
-        Some(())
-            .filter(|_| {
-                // If we have a conflicting borrow of the same place, then we don't want to add
-                // an extraneous "via x.y" to our diagnostics, so filter out this case.
-                first_borrowed_place != second_borrowed_place
-            })
-            .and_then(|_| {
-                // We're going to want to traverse the first borrowed place to see if we can find
-                // field access to a union. If we find that, then we will keep the place of the
-                // union being accessed and the field that was being accessed so we can check the
-                // second borrowed place for the same union and a access to a different field.
-                let mut current = first_borrowed_place;
-                while let Place::Projection(box PlaceProjection { base, elem }) = current {
-                    match elem {
-                        ProjectionElem::Field(field, _) if is_union(base) => {
-                            return Some((base, field));
-                        },
-                        _ => current = base,
-                    }
-                }
-                None
-            })
-            .and_then(|(target_base, target_field)| {
-                // With the place of a union and a field access into it, we traverse the second
-                // borrowed place and look for a access to a different field of the same union.
-                let mut current = second_borrowed_place;
-                while let Place::Projection(box PlaceProjection { base, elem }) = current {
-                    match elem {
-                        ProjectionElem::Field(field, _) if {
-                            is_union(base) && field != target_field && base == target_base
-                        } => {
-                            let desc_base = self.describe_place(base)
-                                .unwrap_or_else(|| "_".to_owned());
-                            let desc_first = self.describe_place(first_borrowed_place)
-                                .unwrap_or_else(|| "_".to_owned());
-                            let desc_second = self.describe_place(second_borrowed_place)
-                                .unwrap_or_else(|| "_".to_owned());
-
-                            // Also compute the name of the union type, eg. `Foo` so we
-                            // can add a helpful note with it.
-                            let ty = base.ty(self.mir, self.infcx.tcx).ty;
-
-                            return Some((desc_base, desc_first, desc_second, ty.to_string()));
-                        },
-                        _ => current = base,
-                    }
-                }
-                None
-            })
-            .unwrap_or_else(|| {
-                // If we didn't find a field access into a union, or both places match, then
-                // only return the description of the first place.
-                let desc_place = self.describe_place(first_borrowed_place)
-                    .unwrap_or_else(|| "_".to_owned());
-                (desc_place, "".to_string(), "".to_string(), "".to_string())
-            })
-    }
-
-    /// Reports StorageDeadOrDrop of `place` conflicts with `borrow`.
-    ///
-    /// This means that some data referenced by `borrow` needs to live
-    /// past the point where the StorageDeadOrDrop of `place` occurs.
-    /// This is usually interpreted as meaning that `place` has too
-    /// short a lifetime. (But sometimes it is more useful to report
-    /// it as a more direct conflict between the execution of a
-    /// `Drop::drop` with an aliasing borrow.)
-    pub(super) fn report_borrowed_value_does_not_live_long_enough(
-        &mut self,
-        location: Location,
-        borrow: &BorrowData<'tcx>,
-        place_span: (&Place<'tcx>, Span),
-        kind: Option<WriteKind>,
-    ) {
-        debug!(
-            "report_borrowed_value_does_not_live_long_enough(\
-             {:?}, {:?}, {:?}, {:?}\
-             )",
-            location, borrow, place_span, kind
-        );
-
-        let drop_span = place_span.1;
-        let scope_tree = self.infcx.tcx.region_scope_tree(self.mir_def_id);
-        let root_place = self.prefixes(&borrow.borrowed_place, PrefixSet::All)
-            .last()
-            .unwrap();
-
-        let borrow_spans = self.retrieve_borrow_spans(borrow);
-        let borrow_span = borrow_spans.var_or_use();
-
-        let proper_span = match *root_place {
-            Place::Base(PlaceBase::Local(local)) => self.mir.local_decls[local].source_info.span,
-            _ => drop_span,
-        };
-
-        if self.access_place_error_reported
-            .contains(&(root_place.clone(), borrow_span))
-        {
-            debug!(
-                "suppressing access_place error when borrow doesn't live long enough for {:?}",
-                borrow_span
-            );
-            return;
-        }
-
-        self.access_place_error_reported
-            .insert((root_place.clone(), borrow_span));
-
-        if let StorageDeadOrDrop::Destructor(dropped_ty) =
-            self.classify_drop_access_kind(&borrow.borrowed_place)
-        {
-            // If a borrow of path `B` conflicts with drop of `D` (and
-            // we're not in the uninteresting case where `B` is a
-            // prefix of `D`), then report this as a more interesting
-            // destructor conflict.
-            if !borrow.borrowed_place.is_prefix_of(place_span.0) {
-                self.report_borrow_conflicts_with_destructor(
-                    location, borrow, place_span, kind, dropped_ty,
-                );
-                return;
-            }
-        }
-
-        let place_desc = self.describe_place(&borrow.borrowed_place);
-
-        let kind_place = kind.filter(|_| place_desc.is_some()).map(|k| (k, place_span.0));
-        let explanation = self.explain_why_borrow_contains_point(location, &borrow, kind_place);
-
-        let err = match (place_desc, explanation) {
-            (Some(_), _) if self.is_place_thread_local(root_place) => {
-                self.report_thread_local_value_does_not_live_long_enough(drop_span, borrow_span)
-            }
-            // If the outlives constraint comes from inside the closure,
-            // for example:
-            //
-            // let x = 0;
-            // let y = &x;
-            // Box::new(|| y) as Box<Fn() -> &'static i32>
-            //
-            // then just use the normal error. The closure isn't escaping
-            // and `move` will not help here.
-            (
-                Some(ref name),
-                BorrowExplanation::MustBeValidFor {
-                    category: category @ ConstraintCategory::Return,
-                    from_closure: false,
-                    ref region_name,
-                    span,
-                    ..
-                },
-            )
-            | (
-                Some(ref name),
-                BorrowExplanation::MustBeValidFor {
-                    category: category @ ConstraintCategory::CallArgument,
-                    from_closure: false,
-                    ref region_name,
-                    span,
-                    ..
-                },
-            ) if borrow_spans.for_closure() => self.report_escaping_closure_capture(
-                borrow_spans.args_or_use(),
-                borrow_span,
-                region_name,
-                category,
-                span,
-                &format!("`{}`", name),
-            ),
-            (
-                ref name,
-                BorrowExplanation::MustBeValidFor {
-                    category: ConstraintCategory::Assignment,
-                    from_closure: false,
-                    region_name: RegionName {
-                        source: RegionNameSource::AnonRegionFromUpvar(upvar_span, ref upvar_name),
-                        ..
-                    },
-                    span,
-                    ..
-                },
-            ) => self.report_escaping_data(borrow_span, name, upvar_span, upvar_name, span),
-            (Some(name), explanation) => self.report_local_value_does_not_live_long_enough(
-                location,
-                &name,
-                &scope_tree,
-                &borrow,
-                drop_span,
-                borrow_spans,
-                explanation,
-            ),
-            (None, explanation) => self.report_temporary_value_does_not_live_long_enough(
-                location,
-                &scope_tree,
-                &borrow,
-                drop_span,
-                borrow_spans,
-                proper_span,
-                explanation,
-            ),
-        };
-
-        err.buffer(&mut self.errors_buffer);
-    }
-
-    fn report_local_value_does_not_live_long_enough(
-        &mut self,
-        location: Location,
-        name: &str,
-        scope_tree: &'tcx ScopeTree,
-        borrow: &BorrowData<'tcx>,
-        drop_span: Span,
-        borrow_spans: UseSpans,
-        explanation: BorrowExplanation,
-    ) -> DiagnosticBuilder<'cx> {
-        debug!(
-            "report_local_value_does_not_live_long_enough(\
-             {:?}, {:?}, {:?}, {:?}, {:?}, {:?}\
-             )",
-            location, name, scope_tree, borrow, drop_span, borrow_spans
-        );
-
-        let borrow_span = borrow_spans.var_or_use();
-        if let BorrowExplanation::MustBeValidFor {
-            category,
-            span,
-            ref opt_place_desc,
-            from_closure: false,
-            ..
-        } = explanation {
-            if let Some(diag) = self.try_report_cannot_return_reference_to_local(
-                borrow,
-                borrow_span,
-                span,
-                category,
-                opt_place_desc.as_ref(),
-            ) {
-                return diag;
-            }
-        }
-
-        let mut err = self.infcx.tcx.path_does_not_live_long_enough(
-            borrow_span,
-            &format!("`{}`", name),
-            Origin::Mir,
-        );
-
-        if let Some(annotation) = self.annotate_argument_and_return_for_borrow(borrow) {
-            let region_name = annotation.emit(self, &mut err);
-
-            err.span_label(
-                borrow_span,
-                format!("`{}` would have to be valid for `{}`...", name, region_name),
-            );
-
-            if let Some(fn_hir_id) = self.infcx.tcx.hir().as_local_hir_id(self.mir_def_id) {
-                err.span_label(
-                    drop_span,
-                    format!(
-                        "...but `{}` will be dropped here, when the function `{}` returns",
-                        name,
-                        self.infcx.tcx.hir().name_by_hir_id(fn_hir_id),
-                    ),
-                );
-
-                err.note(
-                    "functions cannot return a borrow to data owned within the function's scope, \
-                     functions can only return borrows to data passed as arguments",
-                );
-                err.note(
-                    "to learn more, visit <https://doc.rust-lang.org/book/ch04-02-\
-                     references-and-borrowing.html#dangling-references>",
-                );
-            } else {
-                err.span_label(
-                    drop_span,
-                    format!("...but `{}` dropped here while still borrowed", name),
-                );
-            }
-
-            if let BorrowExplanation::MustBeValidFor { .. } = explanation {
-            } else {
-                explanation.add_explanation_to_diagnostic(
-                    self.infcx.tcx,
-                    self.mir,
-                    &mut err,
-                    "",
-                    None,
-                );
-            }
-        } else {
-            err.span_label(borrow_span, "borrowed value does not live long enough");
-            err.span_label(
-                drop_span,
-                format!("`{}` dropped here while still borrowed", name),
-            );
-
-            let within = if borrow_spans.for_generator() {
-                " by generator"
-            } else {
-                ""
-            };
-
-            borrow_spans.args_span_label(
-                &mut err,
-                format!("value captured here{}", within),
-            );
-
-            explanation.add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, "", None);
-        }
-
-        err
-    }
-
-    fn report_borrow_conflicts_with_destructor(
-        &mut self,
-        location: Location,
-        borrow: &BorrowData<'tcx>,
-        (place, drop_span): (&Place<'tcx>, Span),
-        kind: Option<WriteKind>,
-        dropped_ty: Ty<'tcx>,
-    ) {
-        debug!(
-            "report_borrow_conflicts_with_destructor(\
-             {:?}, {:?}, ({:?}, {:?}), {:?}\
-             )",
-            location, borrow, place, drop_span, kind,
-        );
-
-        let borrow_spans = self.retrieve_borrow_spans(borrow);
-        let borrow_span = borrow_spans.var_or_use();
-
-        let mut err = self.infcx
-            .tcx
-            .cannot_borrow_across_destructor(borrow_span, Origin::Mir);
-
-        let what_was_dropped = match self.describe_place(place) {
-            Some(name) => format!("`{}`", name.as_str()),
-            None => String::from("temporary value"),
-        };
-
-        let label = match self.describe_place(&borrow.borrowed_place) {
-            Some(borrowed) => format!(
-                "here, drop of {D} needs exclusive access to `{B}`, \
-                 because the type `{T}` implements the `Drop` trait",
-                D = what_was_dropped,
-                T = dropped_ty,
-                B = borrowed
-            ),
-            None => format!(
-                "here is drop of {D}; whose type `{T}` implements the `Drop` trait",
-                D = what_was_dropped,
-                T = dropped_ty
-            ),
-        };
-        err.span_label(drop_span, label);
-
-        // Only give this note and suggestion if they could be relevant.
-        let explanation =
-            self.explain_why_borrow_contains_point(location, borrow, kind.map(|k| (k, place)));
-        match explanation {
-            BorrowExplanation::UsedLater { .. }
-            | BorrowExplanation::UsedLaterWhenDropped { .. } => {
-                err.note("consider using a `let` binding to create a longer lived value");
-            }
-            _ => {}
-        }
-
-        explanation.add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, "", None);
-
-        err.buffer(&mut self.errors_buffer);
-    }
-
-    fn report_thread_local_value_does_not_live_long_enough(
-        &mut self,
-        drop_span: Span,
-        borrow_span: Span,
-    ) -> DiagnosticBuilder<'cx> {
-        debug!(
-            "report_thread_local_value_does_not_live_long_enough(\
-             {:?}, {:?}\
-             )",
-            drop_span, borrow_span
-        );
-
-        let mut err = self.infcx
-            .tcx
-            .thread_local_value_does_not_live_long_enough(borrow_span, Origin::Mir);
-
-        err.span_label(
-            borrow_span,
-            "thread-local variables cannot be borrowed beyond the end of the function",
-        );
-        err.span_label(drop_span, "end of enclosing function is here");
-
-        err
-    }
-
-    fn report_temporary_value_does_not_live_long_enough(
-        &mut self,
-        location: Location,
-        scope_tree: &'tcx ScopeTree,
-        borrow: &BorrowData<'tcx>,
-        drop_span: Span,
-        borrow_spans: UseSpans,
-        proper_span: Span,
-        explanation: BorrowExplanation,
-    ) -> DiagnosticBuilder<'cx> {
-        debug!(
-            "report_temporary_value_does_not_live_long_enough(\
-             {:?}, {:?}, {:?}, {:?}, {:?}\
-             )",
-            location, scope_tree, borrow, drop_span, proper_span
-        );
-
-        if let BorrowExplanation::MustBeValidFor {
-            category,
-            span,
-            from_closure: false,
-            ..
-        } = explanation {
-            if let Some(diag) = self.try_report_cannot_return_reference_to_local(
-                borrow,
-                proper_span,
-                span,
-                category,
-                None,
-            ) {
-                return diag;
-            }
-        }
-
-        let tcx = self.infcx.tcx;
-        let mut err = tcx.temporary_value_borrowed_for_too_long(proper_span, Origin::Mir);
-        err.span_label(
-            proper_span,
-            "creates a temporary which is freed while still in use",
-        );
-        err.span_label(
-            drop_span,
-            "temporary value is freed at the end of this statement",
-        );
-
-        match explanation {
-            BorrowExplanation::UsedLater(..)
-            | BorrowExplanation::UsedLaterInLoop(..)
-            | BorrowExplanation::UsedLaterWhenDropped { .. } => {
-                // Only give this note and suggestion if it could be relevant.
-                err.note("consider using a `let` binding to create a longer lived value");
-            }
-            _ => {}
-        }
-        explanation.add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, "", None);
-
-        let within = if borrow_spans.for_generator() {
-            " by generator"
-        } else {
-            ""
-        };
-
-        borrow_spans.args_span_label(
-            &mut err,
-            format!("value captured here{}", within),
-        );
-
-        err
-    }
-
-    fn try_report_cannot_return_reference_to_local(
-        &self,
-        borrow: &BorrowData<'tcx>,
-        borrow_span: Span,
-        return_span: Span,
-        category: ConstraintCategory,
-        opt_place_desc: Option<&String>,
-    ) -> Option<DiagnosticBuilder<'cx>> {
-        let tcx = self.infcx.tcx;
-
-        let return_kind = match category {
-            ConstraintCategory::Return => "return",
-            ConstraintCategory::Yield => "yield",
-            _ => return None,
-        };
-
-        // FIXME use a better heuristic than Spans
-        let reference_desc = if return_span == self.mir.source_info(borrow.reserve_location).span {
-            "reference to"
-        } else {
-            "value referencing"
-        };
-
-        let (place_desc, note) = if let Some(place_desc) = opt_place_desc {
-            let local_kind = match borrow.borrowed_place {
-                Place::Base(PlaceBase::Local(local)) => {
-                    match self.mir.local_kind(local) {
-                        LocalKind::ReturnPointer
-                        | LocalKind::Temp => bug!("temporary or return pointer with a name"),
-                        LocalKind::Var => "local variable ",
-                        LocalKind::Arg
-                        if !self.upvars.is_empty()
-                            && local == Local::new(1) => {
-                            "variable captured by `move` "
-                        }
-                        LocalKind::Arg => {
-                            "function parameter "
-                        }
-                    }
-                }
-                _ => "local data ",
-            };
-            (
-                format!("{}`{}`", local_kind, place_desc),
-                format!("`{}` is borrowed here", place_desc),
-            )
-        } else {
-            let root_place = self.prefixes(&borrow.borrowed_place, PrefixSet::All)
-                .last()
-                .unwrap();
-            let local = if let Place::Base(PlaceBase::Local(local)) = *root_place {
-                local
-            } else {
-                bug!("try_report_cannot_return_reference_to_local: not a local")
-            };
-            match self.mir.local_kind(local) {
-                LocalKind::ReturnPointer | LocalKind::Temp => {
-                    (
-                        "temporary value".to_string(),
-                        "temporary value created here".to_string(),
-                    )
-                }
-                LocalKind::Arg => {
-                    (
-                        "function parameter".to_string(),
-                        "function parameter borrowed here".to_string(),
-                    )
-                },
-                LocalKind::Var => bug!("local variable without a name"),
-            }
-        };
-
-        let mut err = tcx.cannot_return_reference_to_local(
-            return_span,
-            return_kind,
-            reference_desc,
-            &place_desc,
-            Origin::Mir,
-        );
-
-        if return_span != borrow_span {
-            err.span_label(borrow_span, note);
-        }
-
-        Some(err)
-    }
-
-    fn report_escaping_closure_capture(
-        &mut self,
-        args_span: Span,
-        var_span: Span,
-        fr_name: &RegionName,
-        category: ConstraintCategory,
-        constraint_span: Span,
-        captured_var: &str,
-    ) -> DiagnosticBuilder<'cx> {
-        let tcx = self.infcx.tcx;
-
-        let mut err = tcx.cannot_capture_in_long_lived_closure(
-            args_span,
-            captured_var,
-            var_span,
-          Origin::Mir,
-        );
-
-        let suggestion = match tcx.sess.source_map().span_to_snippet(args_span) {
-            Ok(string) => format!("move {}", string),
-            Err(_) => "move |<args>| <body>".to_string()
-        };
-
-        err.span_suggestion(
-            args_span,
-            &format!("to force the closure to take ownership of {} (and any \
-                      other referenced variables), use the `move` keyword",
-                      captured_var),
-            suggestion,
-            Applicability::MachineApplicable,
-        );
-
-        match category {
-            ConstraintCategory::Return => {
-                err.span_note(constraint_span, "closure is returned here");
-            }
-            ConstraintCategory::CallArgument => {
-                fr_name.highlight_region_name(&mut err);
-                err.span_note(
-                    constraint_span,
-                    &format!("function requires argument type to outlive `{}`", fr_name),
-                );
-            }
-            _ => bug!("report_escaping_closure_capture called with unexpected constraint \
-                       category: `{:?}`", category),
-        }
-        err
-    }
-
-    fn report_escaping_data(
-        &mut self,
-        borrow_span: Span,
-        name: &Option<String>,
-        upvar_span: Span,
-        upvar_name: &str,
-        escape_span: Span,
-    ) -> DiagnosticBuilder<'cx> {
-        let tcx = self.infcx.tcx;
-
-        let escapes_from = if tcx.is_closure(self.mir_def_id) {
-            let tables = tcx.typeck_tables_of(self.mir_def_id);
-            let mir_hir_id = tcx.hir().def_index_to_hir_id(self.mir_def_id.index);
-            match tables.node_type(mir_hir_id).sty {
-                ty::Closure(..) => "closure",
-                ty::Generator(..) => "generator",
-                _ => bug!("Closure body doesn't have a closure or generator type"),
-            }
-        } else {
-            "function"
-        };
-
-        let mut err = tcx.borrowed_data_escapes_closure(escape_span, escapes_from, Origin::Mir);
-
-        err.span_label(
-            upvar_span,
-            format!(
-                "`{}` is declared here, outside of the {} body",
-                upvar_name, escapes_from
-            ),
-        );
-
-        err.span_label(
-            borrow_span,
-            format!(
-                "borrow is only valid in the {} body",
-                escapes_from
-            ),
-        );
-
-        if let Some(name) = name {
-            err.span_label(
-                escape_span,
-                format!("reference to `{}` escapes the {} body here", name, escapes_from),
-            );
-        } else {
-            err.span_label(
-                escape_span,
-                format!("reference escapes the {} body here", escapes_from),
-            );
-        }
-
-        err
-    }
-
-    fn get_moved_indexes(&mut self, location: Location, mpi: MovePathIndex) -> Vec<MoveSite> {
-        let mir = self.mir;
-
-        let mut stack = Vec::new();
-        stack.extend(mir.predecessor_locations(location).map(|predecessor| {
-            let is_back_edge = location.dominates(predecessor, &self.dominators);
-            (predecessor, is_back_edge)
-        }));
-
-        let mut visited = FxHashSet::default();
-        let mut result = vec![];
-
-        'dfs: while let Some((location, is_back_edge)) = stack.pop() {
-            debug!(
-                "report_use_of_moved_or_uninitialized: (current_location={:?}, back_edge={})",
-                location, is_back_edge
-            );
-
-            if !visited.insert(location) {
-                continue;
-            }
-
-            // check for moves
-            let stmt_kind = mir[location.block]
-                .statements
-                .get(location.statement_index)
-                .map(|s| &s.kind);
-            if let Some(StatementKind::StorageDead(..)) = stmt_kind {
-                // this analysis only tries to find moves explicitly
-                // written by the user, so we ignore the move-outs
-                // created by `StorageDead` and at the beginning
-                // of a function.
-            } else {
-                // If we are found a use of a.b.c which was in error, then we want to look for
-                // moves not only of a.b.c but also a.b and a.
-                //
-                // Note that the moves data already includes "parent" paths, so we don't have to
-                // worry about the other case: that is, if there is a move of a.b.c, it is already
-                // marked as a move of a.b and a as well, so we will generate the correct errors
-                // there.
-                let mut mpis = vec![mpi];
-                let move_paths = &self.move_data.move_paths;
-                mpis.extend(move_paths[mpi].parents(move_paths));
-
-                for moi in &self.move_data.loc_map[location] {
-                    debug!("report_use_of_moved_or_uninitialized: moi={:?}", moi);
-                    if mpis.contains(&self.move_data.moves[*moi].path) {
-                        debug!("report_use_of_moved_or_uninitialized: found");
-                        result.push(MoveSite {
-                            moi: *moi,
-                            traversed_back_edge: is_back_edge,
-                        });
-
-                        // Strictly speaking, we could continue our DFS here. There may be
-                        // other moves that can reach the point of error. But it is kind of
-                        // confusing to highlight them.
-                        //
-                        // Example:
-                        //
-                        // ```
-                        // let a = vec![];
-                        // let b = a;
-                        // let c = a;
-                        // drop(a); // <-- current point of error
-                        // ```
-                        //
-                        // Because we stop the DFS here, we only highlight `let c = a`,
-                        // and not `let b = a`. We will of course also report an error at
-                        // `let c = a` which highlights `let b = a` as the move.
-                        continue 'dfs;
-                    }
-                }
-            }
-
-            // check for inits
-            let mut any_match = false;
-            drop_flag_effects::for_location_inits(
-                self.infcx.tcx,
-                self.mir,
-                self.move_data,
-                location,
-                |m| {
-                    if m == mpi {
-                        any_match = true;
-                    }
-                },
-            );
-            if any_match {
-                continue 'dfs;
-            }
-
-            stack.extend(mir.predecessor_locations(location).map(|predecessor| {
-                let back_edge = location.dominates(predecessor, &self.dominators);
-                (predecessor, is_back_edge || back_edge)
-            }));
-        }
-
-        result
-    }
-
-    pub(super) fn report_illegal_mutation_of_borrowed(
-        &mut self,
-        location: Location,
-        (place, span): (&Place<'tcx>, Span),
-        loan: &BorrowData<'tcx>,
-    ) {
-        let loan_spans = self.retrieve_borrow_spans(loan);
-        let loan_span = loan_spans.args_or_use();
-
-        let tcx = self.infcx.tcx;
-        if loan.kind == BorrowKind::Shallow {
-            let mut err = tcx.cannot_mutate_in_match_guard(
-                span,
-                loan_span,
-                &self.describe_place(place).unwrap_or_else(|| "_".to_owned()),
-                "assign",
-                Origin::Mir,
-            );
-            loan_spans.var_span_label(
-                &mut err,
-                format!("borrow occurs due to use{}", loan_spans.describe()),
-            );
-
-            err.buffer(&mut self.errors_buffer);
-
-            return;
-        }
-
-        let mut err = tcx.cannot_assign_to_borrowed(
-            span,
-            loan_span,
-            &self.describe_place(place).unwrap_or_else(|| "_".to_owned()),
-            Origin::Mir,
-        );
-
-        loan_spans.var_span_label(
-            &mut err,
-            format!("borrow occurs due to use{}", loan_spans.describe()),
-        );
-
-        self.explain_why_borrow_contains_point(location, loan, None)
-            .add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, "", None);
-
-        err.buffer(&mut self.errors_buffer);
-    }
-
-    /// Reports an illegal reassignment; for example, an assignment to
-    /// (part of) a non-`mut` local that occurs potentially after that
-    /// local has already been initialized. `place` is the path being
-    /// assigned; `err_place` is a place providing a reason why
-    /// `place` is not mutable (e.g., the non-`mut` local `x` in an
-    /// assignment to `x.f`).
-    pub(super) fn report_illegal_reassignment(
-        &mut self,
-        _location: Location,
-        (place, span): (&Place<'tcx>, Span),
-        assigned_span: Span,
-        err_place: &Place<'tcx>,
-    ) {
-        let (from_arg, local_decl) = if let Place::Base(PlaceBase::Local(local)) = *err_place {
-            if let LocalKind::Arg = self.mir.local_kind(local) {
-                (true, Some(&self.mir.local_decls[local]))
-            } else {
-                (false, Some(&self.mir.local_decls[local]))
-            }
-        } else {
-            (false, None)
-        };
-
-        // If root local is initialized immediately (everything apart from let
-        // PATTERN;) then make the error refer to that local, rather than the
-        // place being assigned later.
-        let (place_description, assigned_span) = match local_decl {
-            Some(LocalDecl {
-                is_user_variable: Some(ClearCrossCrate::Clear),
-                ..
-            })
-            | Some(LocalDecl {
-                is_user_variable:
-                    Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
-                        opt_match_place: None,
-                        ..
-                    }))),
-                ..
-            })
-            | Some(LocalDecl {
-                is_user_variable: None,
-                ..
-            })
-            | None => (self.describe_place(place), assigned_span),
-            Some(decl) => (self.describe_place(err_place), decl.source_info.span),
-        };
-
-        let mut err = self.infcx.tcx.cannot_reassign_immutable(
-            span,
-            place_description.as_ref().map(AsRef::as_ref).unwrap_or("_"),
-            from_arg,
-            Origin::Mir,
-        );
-        let msg = if from_arg {
-            "cannot assign to immutable argument"
-        } else {
-            "cannot assign twice to immutable variable"
-        };
-        if span != assigned_span {
-            if !from_arg {
-                let value_msg = match place_description {
-                    Some(name) => format!("`{}`", name),
-                    None => "value".to_owned(),
-                };
-                err.span_label(assigned_span, format!("first assignment to {}", value_msg));
-            }
-        }
-        if let Some(decl) = local_decl {
-            if let Some(name) = decl.name {
-                if decl.can_be_made_mutable() {
-                    err.span_suggestion(
-                        decl.source_info.span,
-                        "make this binding mutable",
-                        format!("mut {}", name),
-                        Applicability::MachineApplicable,
-                    );
-                }
-            }
-        }
-        err.span_label(span, msg);
-        err.buffer(&mut self.errors_buffer);
-    }
-}
-
-pub(super) struct IncludingDowncast(bool);
-
-/// Which case a StorageDeadOrDrop is for.
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-enum StorageDeadOrDrop<'tcx> {
-    LocalStorageDead,
-    BoxedStorageDead,
-    Destructor(Ty<'tcx>),
-}
+pub(super) struct IncludingDowncast(pub(super) bool);
 
 impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
     /// Adds a suggestion when a closure is invoked twice with a moved variable or when a closure
@@ -1759,15 +276,15 @@ fn append_place_to_string(
     }
 
     /// Appends end-user visible description of the `local` place to `buf`. If `local` doesn't have
-    /// a name, then `Err` is returned
+    /// a name, or its name was generated by the compiler, then `Err` is returned
     fn append_local_to_string(&self, local_index: Local, buf: &mut String) -> Result<(), ()> {
         let local = &self.mir.local_decls[local_index];
         match local.name {
-            Some(name) => {
-                buf.push_str(&name.to_string());
+            Some(name) if !local.from_compiler_desugaring() => {
+                buf.push_str(name.as_str().get());
                 Ok(())
             }
-            None => Err(()),
+            _ => Err(()),
         }
     }
 
@@ -1865,507 +382,12 @@ pub fn is_place_thread_local(&self, place: &Place<'tcx>) -> bool {
             false
         }
     }
-
-    fn classify_drop_access_kind(&self, place: &Place<'tcx>) -> StorageDeadOrDrop<'tcx> {
-        let tcx = self.infcx.tcx;
-        match place {
-            Place::Base(PlaceBase::Local(_)) |
-            Place::Base(PlaceBase::Static(_)) => {
-                StorageDeadOrDrop::LocalStorageDead
-            }
-            Place::Projection(box PlaceProjection { base, elem }) => {
-                let base_access = self.classify_drop_access_kind(base);
-                match elem {
-                    ProjectionElem::Deref => match base_access {
-                        StorageDeadOrDrop::LocalStorageDead
-                        | StorageDeadOrDrop::BoxedStorageDead => {
-                            assert!(
-                                base.ty(self.mir, tcx).ty.is_box(),
-                                "Drop of value behind a reference or raw pointer"
-                            );
-                            StorageDeadOrDrop::BoxedStorageDead
-                        }
-                        StorageDeadOrDrop::Destructor(_) => base_access,
-                    },
-                    ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => {
-                        let base_ty = base.ty(self.mir, tcx).ty;
-                        match base_ty.sty {
-                            ty::Adt(def, _) if def.has_dtor(tcx) => {
-                                // Report the outermost adt with a destructor
-                                match base_access {
-                                    StorageDeadOrDrop::Destructor(_) => base_access,
-                                    StorageDeadOrDrop::LocalStorageDead
-                                    | StorageDeadOrDrop::BoxedStorageDead => {
-                                        StorageDeadOrDrop::Destructor(base_ty)
-                                    }
-                                }
-                            }
-                            _ => base_access,
-                        }
-                    }
-
-                    ProjectionElem::ConstantIndex { .. }
-                    | ProjectionElem::Subslice { .. }
-                    | ProjectionElem::Index(_) => base_access,
-                }
-            }
-        }
-    }
-
-    /// Annotate argument and return type of function and closure with (synthesized) lifetime for
-    /// borrow of local value that does not live long enough.
-    fn annotate_argument_and_return_for_borrow(
-        &self,
-        borrow: &BorrowData<'tcx>,
-    ) -> Option<AnnotatedBorrowFnSignature<'tcx>> {
-        // Define a fallback for when we can't match a closure.
-        let fallback = || {
-            let is_closure = self.infcx.tcx.is_closure(self.mir_def_id);
-            if is_closure {
-                None
-            } else {
-                let ty = self.infcx.tcx.type_of(self.mir_def_id);
-                match ty.sty {
-                    ty::FnDef(_, _) | ty::FnPtr(_) => self.annotate_fn_sig(
-                        self.mir_def_id,
-                        self.infcx.tcx.fn_sig(self.mir_def_id),
-                    ),
-                    _ => None,
-                }
-            }
-        };
-
-        // In order to determine whether we need to annotate, we need to check whether the reserve
-        // place was an assignment into a temporary.
-        //
-        // If it was, we check whether or not that temporary is eventually assigned into the return
-        // place. If it was, we can add annotations about the function's return type and arguments
-        // and it'll make sense.
-        let location = borrow.reserve_location;
-        debug!(
-            "annotate_argument_and_return_for_borrow: location={:?}",
-            location
-        );
-        if let Some(&Statement { kind: StatementKind::Assign(ref reservation, _), ..})
-             = &self.mir[location.block].statements.get(location.statement_index)
-        {
-            debug!(
-                "annotate_argument_and_return_for_borrow: reservation={:?}",
-                reservation
-            );
-            // Check that the initial assignment of the reserve location is into a temporary.
-            let mut target = *match reservation {
-                Place::Base(PlaceBase::Local(local))
-                    if self.mir.local_kind(*local) == LocalKind::Temp => local,
-                _ => return None,
-            };
-
-            // Next, look through the rest of the block, checking if we are assigning the
-            // `target` (that is, the place that contains our borrow) to anything.
-            let mut annotated_closure = None;
-            for stmt in &self.mir[location.block].statements[location.statement_index + 1..] {
-                debug!(
-                    "annotate_argument_and_return_for_borrow: target={:?} stmt={:?}",
-                    target, stmt
-                );
-                if let StatementKind::Assign(
-                    Place::Base(PlaceBase::Local(assigned_to)),
-                    box rvalue
-                ) = &stmt.kind {
-                    debug!(
-                        "annotate_argument_and_return_for_borrow: assigned_to={:?} \
-                         rvalue={:?}",
-                        assigned_to, rvalue
-                    );
-                    // Check if our `target` was captured by a closure.
-                    if let Rvalue::Aggregate(
-                        box AggregateKind::Closure(def_id, substs),
-                        operands,
-                    ) = rvalue
-                    {
-                        for operand in operands {
-                            let assigned_from = match operand {
-                                Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
-                                    assigned_from
-                                }
-                                _ => continue,
-                            };
-                            debug!(
-                                "annotate_argument_and_return_for_borrow: assigned_from={:?}",
-                                assigned_from
-                            );
-
-                            // Find the local from the operand.
-                            let assigned_from_local = match assigned_from.local() {
-                                Some(local) => local,
-                                None => continue,
-                            };
-
-                            if assigned_from_local != target {
-                                continue;
-                            }
-
-                            // If a closure captured our `target` and then assigned
-                            // into a place then we should annotate the closure in
-                            // case it ends up being assigned into the return place.
-                            annotated_closure = self.annotate_fn_sig(
-                                *def_id,
-                                self.infcx.closure_sig(*def_id, *substs),
-                            );
-                            debug!(
-                                "annotate_argument_and_return_for_borrow: \
-                                 annotated_closure={:?} assigned_from_local={:?} \
-                                 assigned_to={:?}",
-                                annotated_closure, assigned_from_local, assigned_to
-                            );
-
-                            if *assigned_to == mir::RETURN_PLACE {
-                                // If it was assigned directly into the return place, then
-                                // return now.
-                                return annotated_closure;
-                            } else {
-                                // Otherwise, update the target.
-                                target = *assigned_to;
-                            }
-                        }
-
-                        // If none of our closure's operands matched, then skip to the next
-                        // statement.
-                        continue;
-                    }
-
-                    // Otherwise, look at other types of assignment.
-                    let assigned_from = match rvalue {
-                        Rvalue::Ref(_, _, assigned_from) => assigned_from,
-                        Rvalue::Use(operand) => match operand {
-                            Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
-                                assigned_from
-                            }
-                            _ => continue,
-                        },
-                        _ => continue,
-                    };
-                    debug!(
-                        "annotate_argument_and_return_for_borrow: \
-                         assigned_from={:?}",
-                        assigned_from,
-                    );
-
-                    // Find the local from the rvalue.
-                    let assigned_from_local = match assigned_from.local() {
-                        Some(local) => local,
-                        None => continue,
-                    };
-                    debug!(
-                        "annotate_argument_and_return_for_borrow: \
-                         assigned_from_local={:?}",
-                        assigned_from_local,
-                    );
-
-                    // Check if our local matches the target - if so, we've assigned our
-                    // borrow to a new place.
-                    if assigned_from_local != target {
-                        continue;
-                    }
-
-                    // If we assigned our `target` into a new place, then we should
-                    // check if it was the return place.
-                    debug!(
-                        "annotate_argument_and_return_for_borrow: \
-                         assigned_from_local={:?} assigned_to={:?}",
-                        assigned_from_local, assigned_to
-                    );
-                    if *assigned_to == mir::RETURN_PLACE {
-                        // If it was then return the annotated closure if there was one,
-                        // else, annotate this function.
-                        return annotated_closure.or_else(fallback);
-                    }
-
-                    // If we didn't assign into the return place, then we just update
-                    // the target.
-                    target = *assigned_to;
-                }
-            }
-
-            // Check the terminator if we didn't find anything in the statements.
-            let terminator = &self.mir[location.block].terminator();
-            debug!(
-                "annotate_argument_and_return_for_borrow: target={:?} terminator={:?}",
-                target, terminator
-            );
-            if let TerminatorKind::Call {
-                destination: Some((Place::Base(PlaceBase::Local(assigned_to)), _)),
-                args,
-                ..
-            } = &terminator.kind
-            {
-                debug!(
-                    "annotate_argument_and_return_for_borrow: assigned_to={:?} args={:?}",
-                    assigned_to, args
-                );
-                for operand in args {
-                    let assigned_from = match operand {
-                        Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
-                            assigned_from
-                        }
-                        _ => continue,
-                    };
-                    debug!(
-                        "annotate_argument_and_return_for_borrow: assigned_from={:?}",
-                        assigned_from,
-                    );
-
-                    if let Some(assigned_from_local) = assigned_from.local() {
-                        debug!(
-                            "annotate_argument_and_return_for_borrow: assigned_from_local={:?}",
-                            assigned_from_local,
-                        );
-
-                        if *assigned_to == mir::RETURN_PLACE && assigned_from_local == target {
-                            return annotated_closure.or_else(fallback);
-                        }
-                    }
-                }
-            }
-        }
-
-        // If we haven't found an assignment into the return place, then we need not add
-        // any annotations.
-        debug!("annotate_argument_and_return_for_borrow: none found");
-        None
-    }
-
-    /// Annotate the first argument and return type of a function signature if they are
-    /// references.
-    fn annotate_fn_sig(
-        &self,
-        did: DefId,
-        sig: ty::PolyFnSig<'tcx>,
-    ) -> Option<AnnotatedBorrowFnSignature<'tcx>> {
-        debug!("annotate_fn_sig: did={:?} sig={:?}", did, sig);
-        let is_closure = self.infcx.tcx.is_closure(did);
-        let fn_hir_id = self.infcx.tcx.hir().as_local_hir_id(did)?;
-        let fn_decl = self.infcx.tcx.hir().fn_decl_by_hir_id(fn_hir_id)?;
-
-        // We need to work out which arguments to highlight. We do this by looking
-        // at the return type, where there are three cases:
-        //
-        // 1. If there are named arguments, then we should highlight the return type and
-        //    highlight any of the arguments that are also references with that lifetime.
-        //    If there are no arguments that have the same lifetime as the return type,
-        //    then don't highlight anything.
-        // 2. The return type is a reference with an anonymous lifetime. If this is
-        //    the case, then we can take advantage of (and teach) the lifetime elision
-        //    rules.
-        //
-        //    We know that an error is being reported. So the arguments and return type
-        //    must satisfy the elision rules. Therefore, if there is a single argument
-        //    then that means the return type and first (and only) argument have the same
-        //    lifetime and the borrow isn't meeting that, we can highlight the argument
-        //    and return type.
-        //
-        //    If there are multiple arguments then the first argument must be self (else
-        //    it would not satisfy the elision rules), so we can highlight self and the
-        //    return type.
-        // 3. The return type is not a reference. In this case, we don't highlight
-        //    anything.
-        let return_ty = sig.output();
-        match return_ty.skip_binder().sty {
-            ty::Ref(return_region, _, _) if return_region.has_name() && !is_closure => {
-                // This is case 1 from above, return type is a named reference so we need to
-                // search for relevant arguments.
-                let mut arguments = Vec::new();
-                for (index, argument) in sig.inputs().skip_binder().iter().enumerate() {
-                    if let ty::Ref(argument_region, _, _) = argument.sty {
-                        if argument_region == return_region {
-                            // Need to use the `rustc::ty` types to compare against the
-                            // `return_region`. Then use the `rustc::hir` type to get only
-                            // the lifetime span.
-                            if let hir::TyKind::Rptr(lifetime, _) = &fn_decl.inputs[index].node {
-                                // With access to the lifetime, we can get
-                                // the span of it.
-                                arguments.push((*argument, lifetime.span));
-                            } else {
-                                bug!("ty type is a ref but hir type is not");
-                            }
-                        }
-                    }
-                }
-
-                // We need to have arguments. This shouldn't happen, but it's worth checking.
-                if arguments.is_empty() {
-                    return None;
-                }
-
-                // We use a mix of the HIR and the Ty types to get information
-                // as the HIR doesn't have full types for closure arguments.
-                let return_ty = *sig.output().skip_binder();
-                let mut return_span = fn_decl.output.span();
-                if let hir::FunctionRetTy::Return(ty) = fn_decl.output {
-                    if let hir::TyKind::Rptr(lifetime, _) = ty.into_inner().node {
-                        return_span = lifetime.span;
-                    }
-                }
-
-                Some(AnnotatedBorrowFnSignature::NamedFunction {
-                    arguments,
-                    return_ty,
-                    return_span,
-                })
-            }
-            ty::Ref(_, _, _) if is_closure => {
-                // This is case 2 from above but only for closures, return type is anonymous
-                // reference so we select
-                // the first argument.
-                let argument_span = fn_decl.inputs.first()?.span;
-                let argument_ty = sig.inputs().skip_binder().first()?;
-
-                // Closure arguments are wrapped in a tuple, so we need to get the first
-                // from that.
-                if let ty::Tuple(elems) = argument_ty.sty {
-                    let argument_ty = elems.first()?.expect_ty();
-                    if let ty::Ref(_, _, _) = argument_ty.sty {
-                        return Some(AnnotatedBorrowFnSignature::Closure {
-                            argument_ty,
-                            argument_span,
-                        });
-                    }
-                }
-
-                None
-            }
-            ty::Ref(_, _, _) => {
-                // This is also case 2 from above but for functions, return type is still an
-                // anonymous reference so we select the first argument.
-                let argument_span = fn_decl.inputs.first()?.span;
-                let argument_ty = sig.inputs().skip_binder().first()?;
-
-                let return_span = fn_decl.output.span();
-                let return_ty = *sig.output().skip_binder();
-
-                // We expect the first argument to be a reference.
-                match argument_ty.sty {
-                    ty::Ref(_, _, _) => {}
-                    _ => return None,
-                }
-
-                Some(AnnotatedBorrowFnSignature::AnonymousFunction {
-                    argument_ty,
-                    argument_span,
-                    return_ty,
-                    return_span,
-                })
-            }
-            _ => {
-                // This is case 3 from above, return type is not a reference so don't highlight
-                // anything.
-                None
-            }
-        }
-    }
-}
-
-#[derive(Debug)]
-enum AnnotatedBorrowFnSignature<'tcx> {
-    NamedFunction {
-        arguments: Vec<(Ty<'tcx>, Span)>,
-        return_ty: Ty<'tcx>,
-        return_span: Span,
-    },
-    AnonymousFunction {
-        argument_ty: Ty<'tcx>,
-        argument_span: Span,
-        return_ty: Ty<'tcx>,
-        return_span: Span,
-    },
-    Closure {
-        argument_ty: Ty<'tcx>,
-        argument_span: Span,
-    },
-}
-
-impl<'tcx> AnnotatedBorrowFnSignature<'tcx> {
-    /// Annotate the provided diagnostic with information about borrow from the fn signature that
-    /// helps explain.
-    fn emit(
-        &self,
-        cx: &mut MirBorrowckCtxt<'_, '_, 'tcx>,
-        diag: &mut DiagnosticBuilder<'_>,
-    ) -> String {
-        match self {
-            AnnotatedBorrowFnSignature::Closure {
-                argument_ty,
-                argument_span,
-            } => {
-                diag.span_label(
-                    *argument_span,
-                    format!("has type `{}`", cx.get_name_for_ty(argument_ty, 0)),
-                );
-
-                cx.get_region_name_for_ty(argument_ty, 0)
-            }
-            AnnotatedBorrowFnSignature::AnonymousFunction {
-                argument_ty,
-                argument_span,
-                return_ty,
-                return_span,
-            } => {
-                let argument_ty_name = cx.get_name_for_ty(argument_ty, 0);
-                diag.span_label(*argument_span, format!("has type `{}`", argument_ty_name));
-
-                let return_ty_name = cx.get_name_for_ty(return_ty, 0);
-                let types_equal = return_ty_name == argument_ty_name;
-                diag.span_label(
-                    *return_span,
-                    format!(
-                        "{}has type `{}`",
-                        if types_equal { "also " } else { "" },
-                        return_ty_name,
-                    ),
-                );
-
-                diag.note(
-                    "argument and return type have the same lifetime due to lifetime elision rules",
-                );
-                diag.note(
-                    "to learn more, visit <https://doc.rust-lang.org/book/ch10-03-\
-                     lifetime-syntax.html#lifetime-elision>",
-                );
-
-                cx.get_region_name_for_ty(return_ty, 0)
-            }
-            AnnotatedBorrowFnSignature::NamedFunction {
-                arguments,
-                return_ty,
-                return_span,
-            } => {
-                // Region of return type and arguments checked to be the same earlier.
-                let region_name = cx.get_region_name_for_ty(return_ty, 0);
-                for (_, argument_span) in arguments {
-                    diag.span_label(*argument_span, format!("has lifetime `{}`", region_name));
-                }
-
-                diag.span_label(
-                    *return_span,
-                    format!("also has lifetime `{}`", region_name,),
-                );
-
-                diag.help(&format!(
-                    "use data from the highlighted arguments which match the `{}` lifetime of \
-                     the return type",
-                    region_name,
-                ));
-
-                region_name
-            }
-        }
-    }
 }
 
 impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
     /// Return the name of the provided `Ty` (that must be a reference) with a synthesized lifetime
     /// name where required.
-    fn get_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String {
+    pub(super) fn get_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String {
         let mut s = String::new();
         let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, &mut s, Namespace::TypeNS);
 
@@ -2388,7 +410,7 @@ fn get_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String {
 
     /// Returns the name of the provided `Ty` (that must be a reference)'s region with a
     /// synthesized lifetime name where required.
-    fn get_region_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String {
+    pub(super) fn get_region_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String {
         let mut s = String::new();
         let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, &mut s, Namespace::TypeNS);
 
@@ -2468,7 +490,7 @@ pub(super) fn var_span_label(
     }
 
     /// Returns `false` if this place is not used in a closure.
-    fn for_closure(&self) -> bool {
+    pub(super) fn for_closure(&self) -> bool {
         match *self {
             UseSpans::ClosureUse { is_generator, .. } => !is_generator,
             _ => false,
@@ -2476,7 +498,7 @@ fn for_closure(&self) -> bool {
     }
 
     /// Returns `false` if this place is not used in a generator.
-    fn for_generator(&self) -> bool {
+    pub(super) fn for_generator(&self) -> bool {
         match *self {
             UseSpans::ClosureUse { is_generator, .. } => is_generator,
             _ => false,
@@ -2484,7 +506,7 @@ fn for_generator(&self) -> bool {
     }
 
     /// Describe the span associated with a use of a place.
-    fn describe(&self) -> String {
+    pub(super) fn describe(&self) -> String {
         match *self {
             UseSpans::ClosureUse { is_generator, .. } => if is_generator {
                 " in generator".to_string()
index cf02878ec82ed28db372f7877d2b2c1626c9781c..437f95e332a3d8d09a8bed37720d47ab487cf3ea 100644 (file)
@@ -54,6 +54,7 @@
 mod error_reporting;
 mod flows;
 mod location;
+mod conflict_errors;
 mod move_errors;
 mod mutability_errors;
 mod path_utils;
index 4bee7f9c4bf8616745d81365454d9a82a7ef23b5..16fbc8d6bb2997dfcb3e53fd13100af3aac9488d 100644 (file)
@@ -420,28 +420,31 @@ pub(super) fn report_mutability_error(
                     );
                 }
 
-                if let Some(name) = local_decl.name {
-                    err.span_label(
-                        span,
-                        format!(
-                            "`{NAME}` is a `{SIGIL}` {DESC}, \
-                             so the data it refers to cannot be {ACTED_ON}",
-                            NAME = name,
-                            SIGIL = pointer_sigil,
-                            DESC = pointer_desc,
-                            ACTED_ON = acted_on
-                        ),
-                    );
-                } else {
-                    err.span_label(
-                        span,
-                        format!(
-                            "cannot {ACT} through `{SIGIL}` {DESC}",
-                            ACT = act,
-                            SIGIL = pointer_sigil,
-                            DESC = pointer_desc
-                        ),
-                    );
+                match local_decl.name {
+                    Some(name) if !local_decl.from_compiler_desugaring() => {
+                        err.span_label(
+                            span,
+                            format!(
+                                "`{NAME}` is a `{SIGIL}` {DESC}, \
+                                so the data it refers to cannot be {ACTED_ON}",
+                                NAME = name,
+                                SIGIL = pointer_sigil,
+                                DESC = pointer_desc,
+                                ACTED_ON = acted_on
+                            ),
+                        );
+                    }
+                    _ => {
+                        err.span_label(
+                            span,
+                            format!(
+                                "cannot {ACT} through `{SIGIL}` {DESC}",
+                                ACT = act,
+                                SIGIL = pointer_sigil,
+                                DESC = pointer_desc
+                            ),
+                        );
+                    }
                 }
             }
 
index 35efc6195be39709d4bfcdd273afe53e07a838bc..6bca470bf3e5f8928f967b84059b585bf1215c3c 100644 (file)
@@ -112,7 +112,7 @@ pub(in crate::borrow_check) fn add_explanation_to_diagnostic<'cx, 'gcx, 'tcx>(
                 };
 
                 match local_decl.name {
-                    Some(local_name) => {
+                    Some(local_name) if !local_decl.from_compiler_desugaring() => {
                         let message = format!(
                             "{B}borrow might be used here, when `{LOC}` is dropped \
                              and runs the {DTOR} for {TYPE}",
@@ -130,7 +130,7 @@ pub(in crate::borrow_check) fn add_explanation_to_diagnostic<'cx, 'gcx, 'tcx>(
                             );
                         }
                     }
-                    None => {
+                    _ => {
                         err.span_label(
                             local_decl.source_info.span,
                             format!(
index 3091570d14802b48b448f083969b20b964911fdd..2afcbe8a151373bbc6ca64ae8c155e9d8c554c53 100644 (file)
@@ -454,29 +454,6 @@ fn visit_expr(&mut self, expr: &'a Expr) {
             ExprKind::InlineAsm(..) if !self.session.target.target.options.allow_asm => {
                 span_err!(self.session, expr.span, E0472, "asm! is unsupported on this target");
             }
-            ExprKind::ObsoleteInPlace(ref place, ref val) => {
-                let mut err = self.err_handler().struct_span_err(
-                    expr.span,
-                    "emplacement syntax is obsolete (for now, anyway)",
-                );
-                err.note(
-                    "for more information, see \
-                     <https://github.com/rust-lang/rust/issues/27779#issuecomment-378416911>"
-                );
-                match val.node {
-                    ExprKind::Lit(ref v) if v.node.is_numeric() => {
-                        err.span_suggestion(
-                            place.span.between(val.span),
-                            "if you meant to write a comparison against a negative value, add a \
-                             space in between `<` and `-`",
-                            "< -".to_string(),
-                            Applicability::MaybeIncorrect
-                        );
-                    }
-                    _ => {}
-                }
-                err.emit();
-            }
             _ => {}
         }
 
index 1df42a95042751d3160892ab931b3c8adf252253..65b6a89aa0b4d4225cd98e14e44144f42d73feb3 100644 (file)
@@ -24,7 +24,6 @@
 use rustc::ty::subst::InternalSubsts;
 use rustc::util::nodemap::HirIdSet;
 use rustc_data_structures::fx::FxHashSet;
-use rustc_data_structures::sync::Lrc;
 use syntax::ast::Ident;
 use syntax::attr;
 use syntax::symbol::{kw, sym};
@@ -67,7 +66,7 @@ fn visit(&mut self, ty_fragment: impl TypeFoldable<'tcx>) -> bool {
     fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> bool {
         self.skeleton().visit_trait(trait_ref)
     }
-    fn visit_predicates(&mut self, predicates: Lrc<ty::GenericPredicates<'tcx>>) -> bool {
+    fn visit_predicates(&mut self, predicates: &ty::GenericPredicates<'tcx>) -> bool {
         self.skeleton().visit_predicates(predicates)
     }
 }
@@ -89,8 +88,8 @@ fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> bool {
         (!self.def_id_visitor.shallow() && substs.visit_with(self))
     }
 
-    fn visit_predicates(&mut self, predicates: Lrc<ty::GenericPredicates<'tcx>>) -> bool {
-        let ty::GenericPredicates { parent: _, predicates } = &*predicates;
+    fn visit_predicates(&mut self, predicates: &ty::GenericPredicates<'tcx>) -> bool {
+        let ty::GenericPredicates { parent: _, predicates } = predicates;
         for (predicate, _span) in predicates {
             match predicate {
                 ty::Predicate::Trait(poly_predicate) => {
@@ -1851,7 +1850,7 @@ fn check_mod_privacy<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>, module_def_id: DefId) {
 fn privacy_access_levels<'tcx>(
     tcx: TyCtxt<'_, 'tcx, 'tcx>,
     krate: CrateNum,
-) -> Lrc<AccessLevels> {
+) -> &'tcx AccessLevels {
     assert_eq!(krate, LOCAL_CRATE);
 
     // Build up a set of all exported items in the AST. This is a set of all
@@ -1872,7 +1871,7 @@ fn privacy_access_levels<'tcx>(
     }
     visitor.update(hir::CRATE_HIR_ID, Some(AccessLevel::Public));
 
-    Lrc::new(visitor.access_levels)
+    tcx.arena.alloc(visitor.access_levels)
 }
 
 fn check_private_in_public<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>, krate: CrateNum) {
index d34f5633946bfa281773da81d21cab2b44013bcc..55471dbc00be5c75a3dfbdbd8bd3b8ba8966078f 100644 (file)
@@ -24,7 +24,6 @@
 use rustc::ty::{self, DefIdTree, TyCtxt};
 use rustc::{bug, span_bug};
 use rustc_codegen_utils::link::{filename_for_metadata, out_filename};
-use rustc_data_structures::sync::Lrc;
 
 use std::cell::Cell;
 use std::default::Default;
@@ -110,8 +109,8 @@ pub fn get_external_crates(&self) -> Vec<ExternalCrateData> {
         let mut result = Vec::with_capacity(self.tcx.crates().len());
 
         for &n in self.tcx.crates().iter() {
-            let span = match *self.tcx.extern_crate(n.as_def_id()) {
-                Some(ExternCrate { span, .. }) => span,
+            let span = match self.tcx.extern_crate(n.as_def_id()) {
+                Some(&ExternCrate { span, .. }) => span,
                 None => {
                     debug!("Skipping crate {}, no data", n);
                     continue;
@@ -1120,7 +1119,7 @@ pub fn process_crate<'l, 'tcx, H: SaveHandler>(
         // fallback in case the access levels couldn't have been correctly computed.
         let access_levels = match tcx.sess.compile_status() {
             Ok(..) => tcx.privacy_access_levels(LOCAL_CRATE),
-            Err(..) => Lrc::new(AccessLevels::default()),
+            Err(..) => tcx.arena.alloc(AccessLevels::default()),
         };
 
         let save_ctxt = SaveContext {
index 4110a55840196e950e694b40e9f07b2bba74231b..3a2b0178ce4d099c525ea7457ed1bc3bc7bb5737 100644 (file)
@@ -17,7 +17,6 @@
 use rustc::ty::subst::{Kind, Subst, InternalSubsts, SubstsRef};
 use rustc::ty::wf::object_region_bounds;
 use rustc::mir::interpret::ConstValue;
-use rustc_data_structures::sync::Lrc;
 use rustc_target::spec::abi;
 use crate::require_c_abi_if_c_variadic;
 use smallvec::SmallVec;
@@ -46,7 +45,7 @@ pub trait AstConv<'gcx, 'tcx> {
     /// Returns the set of bounds in scope for the type parameter with
     /// the given id.
     fn get_type_parameter_bounds(&self, span: Span, def_id: DefId)
-                                 -> Lrc<ty::GenericPredicates<'tcx>>;
+                                 -> &'tcx ty::GenericPredicates<'tcx>;
 
     /// What lifetime should we use when a lifetime is omitted (and not elided)?
     fn re_infer(&self, span: Span, _def: Option<&ty::GenericParamDef>)
index 8d68179b495c6015738344919f05b2af1a07daca..a4e687b8f9080f4b4e8e535af1b36200c26dc7dc 100644 (file)
@@ -306,11 +306,12 @@ fn is_hir_id_from_struct_pattern_shorthand_field(&self, hir_id: hir::HirId, sp:
     /// In addition of this check, it also checks between references mutability state. If the
     /// expected is mutable but the provided isn't, maybe we could just say "Hey, try with
     /// `&mut`!".
-    pub fn check_ref(&self,
-                 expr: &hir::Expr,
-                 checked_ty: Ty<'tcx>,
-                 expected: Ty<'tcx>)
-                 -> Option<(Span, &'static str, String)> {
+    pub fn check_ref(
+        &self,
+        expr: &hir::Expr,
+        checked_ty: Ty<'tcx>,
+        expected: Ty<'tcx>,
+    ) -> Option<(Span, &'static str, String)> {
         let cm = self.sess().source_map();
         let sp = expr.span;
         if !cm.span_to_filename(sp).is_real() {
@@ -397,6 +398,29 @@ pub fn check_ref(&self,
                         } else {
                             String::new()
                         };
+                        if let Some(hir::Node::Expr(hir::Expr {
+                            node: hir::ExprKind::Assign(left_expr, _),
+                            ..
+                        })) = self.tcx.hir().find_by_hir_id(
+                            self.tcx.hir().get_parent_node_by_hir_id(expr.hir_id),
+                        ) {
+                            if mutability == hir::Mutability::MutMutable {
+                                // Found the following case:
+                                // fn foo(opt: &mut Option<String>){ opt = None }
+                                //                                   ---   ^^^^
+                                //                                   |     |
+                                //    consider dereferencing here: `*opt`  |
+                                // expected mutable reference, found enum `Option`
+                                if let Ok(src) = cm.span_to_snippet(left_expr.span) {
+                                    return Some((
+                                        left_expr.span,
+                                        "consider dereferencing here to assign to the mutable \
+                                         borrowed piece of memory",
+                                        format!("*{}", src),
+                                    ));
+                                }
+                            }
+                        }
                         return Some(match mutability {
                             hir::Mutability::MutMutable => (
                                 sp,
index 77d2ffab8efb4e1bb32c8b9a64f52afe2c9b10f8..dfe21edee41f3fb629f05580f2b477971f21a1c5 100644 (file)
@@ -6,7 +6,6 @@
 use crate::namespace::Namespace;
 use crate::util::nodemap::FxHashSet;
 use errors::{Applicability, DiagnosticBuilder};
-use rustc_data_structures::sync::Lrc;
 use rustc::hir::{self, ExprKind, Node, QPath};
 use rustc::hir::def::{Res, DefKind};
 use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, DefId};
@@ -844,7 +843,7 @@ fn handle_external_res(tcx: TyCtxt<'_, '_, '_>,
 pub fn provide(providers: &mut ty::query::Providers<'_>) {
     providers.all_traits = |tcx, cnum| {
         assert_eq!(cnum, LOCAL_CRATE);
-        Lrc::new(compute_all_traits(tcx))
+        &tcx.arena.alloc(compute_all_traits(tcx))[..]
     }
 }
 
index a20a91b3e6f6d88e522c8b6fd24edb5ad5660bcb..655bf5722ae5af7eb2959a3790d34286178343ff 100644 (file)
@@ -97,7 +97,6 @@
 use rustc::infer::{self, InferCtxt, InferOk, InferResult};
 use rustc::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
 use rustc_data_structures::indexed_vec::Idx;
-use rustc_data_structures::sync::Lrc;
 use rustc_target::spec::abi::Abi;
 use rustc::infer::opaque_types::OpaqueTypeDecl;
 use rustc::infer::type_variable::{TypeVariableOrigin};
@@ -808,8 +807,8 @@ fn has_typeck_tables<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
 fn used_trait_imports<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                 def_id: DefId)
-                                -> Lrc<DefIdSet> {
-    tcx.typeck_tables_of(def_id).used_trait_imports.clone()
+                                -> &'tcx DefIdSet {
+    &*tcx.typeck_tables_of(def_id).used_trait_imports
 }
 
 fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
@@ -1907,7 +1906,7 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> {
     fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.tcx }
 
     fn get_type_parameter_bounds(&self, _: Span, def_id: DefId)
-                                 -> Lrc<ty::GenericPredicates<'tcx>>
+                                 -> &'tcx ty::GenericPredicates<'tcx>
     {
         let tcx = self.tcx;
         let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
@@ -1915,7 +1914,7 @@ fn get_type_parameter_bounds(&self, _: Span, def_id: DefId)
         let item_def_id = tcx.hir().local_def_id_from_hir_id(item_id);
         let generics = tcx.generics_of(item_def_id);
         let index = generics.param_def_id_to_index[&def_id];
-        Lrc::new(ty::GenericPredicates {
+        tcx.arena.alloc(ty::GenericPredicates {
             parent: None,
             predicates: self.param_env.caller_bounds.iter().filter_map(|&predicate| {
                 match predicate {
index d167c7fcafbe4807ce8f7a0bf7bb44623e14c730..644d95963e652cdf5a882fbf05675178dafaec9c 100644 (file)
 use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use rustc::ty::{self, CrateInherentImpls, TyCtxt};
 
-use rustc_data_structures::sync::Lrc;
 use syntax::ast;
 use syntax_pos::Span;
 
 /// On-demand query: yields a map containing all types mapped to their inherent impls.
 pub fn crate_inherent_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                       crate_num: CrateNum)
-                                      -> Lrc<CrateInherentImpls> {
+                                      -> &'tcx CrateInherentImpls {
     assert_eq!(crate_num, LOCAL_CRATE);
 
     let krate = tcx.hir().krate();
@@ -29,13 +28,13 @@ pub fn crate_inherent_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         impls_map: Default::default(),
     };
     krate.visit_all_item_likes(&mut collect);
-    Lrc::new(collect.impls_map)
+    tcx.arena.alloc(collect.impls_map)
 }
 
 /// On-demand query: yields a vector of the inherent impls for a specific type.
 pub fn inherent_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                 ty_def_id: DefId)
-                                -> Lrc<Vec<DefId>> {
+                                -> &'tcx [DefId] {
     assert!(ty_def_id.is_local());
 
     // NB. Until we adopt the red-green dep-tracking algorithm (see
@@ -53,15 +52,11 @@ pub fn inherent_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     //
     // [the plan]: https://github.com/rust-lang/rust-roadmap/issues/4
 
-    thread_local! {
-        static EMPTY_DEF_ID_VEC: Lrc<Vec<DefId>> = Lrc::new(vec![])
-    }
-
     let result = tcx.dep_graph.with_ignore(|| {
         let crate_map = tcx.crate_inherent_impls(ty_def_id.krate);
         match crate_map.inherent_impls.get(&ty_def_id) {
-            Some(v) => v.clone(),
-            None => EMPTY_DEF_ID_VEC.with(|v| v.clone())
+            Some(v) => &v[..],
+            None => &[],
         }
     });
 
@@ -289,13 +284,8 @@ fn check_def_id(&mut self, item: &hir::Item, def_id: DefId) {
             // type def ID, if there is a base type for this implementation and
             // the implementation does not have any associated traits.
             let impl_def_id = self.tcx.hir().local_def_id_from_hir_id(item.hir_id);
-            let mut rc_vec = self.impls_map.inherent_impls
-                                           .entry(def_id)
-                                           .or_default();
-
-            // At this point, there should not be any clones of the
-            // `Lrc`, so we can still safely push into it in place:
-            Lrc::get_mut(&mut rc_vec).unwrap().push(impl_def_id);
+            let vec = self.impls_map.inherent_impls.entry(def_id).or_default();
+            vec.push(impl_def_id);
         } else {
             struct_span_err!(self.tcx.sess,
                              item.span,
index 2a4d8f304b59266adf1f2652054320270e621966..45380d757b97d77d981c89366f7c20d090cff79b 100644 (file)
@@ -31,7 +31,6 @@
 use rustc::ty::{ReprOptions, ToPredicate};
 use rustc::util::captures::Captures;
 use rustc::util::nodemap::FxHashMap;
-use rustc_data_structures::sync::Lrc;
 use rustc_target::spec::abi;
 
 use syntax::ast;
@@ -178,7 +177,7 @@ fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> {
     }
 
     fn get_type_parameter_bounds(&self, span: Span, def_id: DefId)
-                                 -> Lrc<ty::GenericPredicates<'tcx>> {
+                                 -> &'tcx ty::GenericPredicates<'tcx> {
         self.tcx
             .at(span)
             .type_param_predicates((self.item_def_id, def_id))
@@ -243,7 +242,7 @@ fn record_ty(&self, _hir_id: hir::HirId, _ty: Ty<'tcx>, _span: Span) {
 fn type_param_predicates<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     (item_def_id, def_id): (DefId, DefId),
-) -> Lrc<ty::GenericPredicates<'tcx>> {
+) -> &'tcx ty::GenericPredicates<'tcx> {
     use rustc::hir::*;
 
     // In the AST, bounds can derive from two places. Either
@@ -264,16 +263,11 @@ fn type_param_predicates<'a, 'tcx>(
         tcx.generics_of(item_def_id).parent
     };
 
-    let mut result = parent.map_or_else(
-        || Lrc::new(ty::GenericPredicates {
-            parent: None,
-            predicates: vec![],
-        }),
-        |parent| {
-            let icx = ItemCtxt::new(tcx, parent);
-            icx.get_type_parameter_bounds(DUMMY_SP, def_id)
-        },
-    );
+    let result = parent.map_or(&tcx.common.empty_predicates, |parent| {
+        let icx = ItemCtxt::new(tcx, parent);
+        icx.get_type_parameter_bounds(DUMMY_SP, def_id)
+    });
+    let mut extend = None;
 
     let item_hir_id = tcx.hir().as_local_hir_id(item_def_id).unwrap();
     let ast_generics = match tcx.hir().get_by_hir_id(item_hir_id) {
@@ -298,9 +292,7 @@ fn type_param_predicates<'a, 'tcx>(
                     // Implied `Self: Trait` and supertrait bounds.
                     if param_id == item_hir_id {
                         let identity_trait_ref = ty::TraitRef::identity(tcx, item_def_id);
-                        Lrc::make_mut(&mut result)
-                            .predicates
-                            .push((identity_trait_ref.to_predicate(), item.span));
+                        extend = Some((identity_trait_ref.to_predicate(), item.span));
                     }
                     generics
                 }
@@ -317,11 +309,12 @@ fn type_param_predicates<'a, 'tcx>(
     };
 
     let icx = ItemCtxt::new(tcx, item_def_id);
-    Lrc::make_mut(&mut result)
-        .predicates
-        .extend(icx.type_parameter_bounds_in_generics(ast_generics, param_id, ty,
-            OnlySelfBounds(true)));
-    result
+    let mut result = (*result).clone();
+    result.predicates.extend(extend.into_iter());
+    result.predicates
+          .extend(icx.type_parameter_bounds_in_generics(ast_generics, param_id, ty,
+                  OnlySelfBounds(true)));
+    tcx.arena.alloc(result)
 }
 
 impl<'a, 'tcx> ItemCtxt<'a, 'tcx> {
@@ -690,7 +683,7 @@ fn adt_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty::Ad
 fn super_predicates_of<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     trait_def_id: DefId,
-) -> Lrc<ty::GenericPredicates<'tcx>> {
+) -> &'tcx ty::GenericPredicates<'tcx> {
     debug!("super_predicates(trait_def_id={:?})", trait_def_id);
     let trait_hir_id = tcx.hir().as_local_hir_id(trait_def_id).unwrap();
 
@@ -734,7 +727,7 @@ fn super_predicates_of<'a, 'tcx>(
         }
     }
 
-    Lrc::new(ty::GenericPredicates {
+    tcx.arena.alloc(ty::GenericPredicates {
         parent: None,
         predicates: superbounds,
     })
@@ -1842,7 +1835,7 @@ fn early_bound_lifetimes_from_generics<'a, 'tcx>(
 fn predicates_defined_on<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     def_id: DefId,
-) -> Lrc<ty::GenericPredicates<'tcx>> {
+) -> &'tcx ty::GenericPredicates<'tcx> {
     debug!("predicates_defined_on({:?})", def_id);
     let mut result = tcx.explicit_predicates_of(def_id);
     debug!(
@@ -1858,9 +1851,9 @@ fn predicates_defined_on<'a, 'tcx>(
             def_id,
             inferred_outlives,
         );
-        Lrc::make_mut(&mut result)
-            .predicates
-            .extend(inferred_outlives.iter().map(|&p| (p, span)));
+        let mut predicates = (*result).clone();
+        predicates.predicates.extend(inferred_outlives.iter().map(|&p| (p, span)));
+        result = tcx.arena.alloc(predicates);
     }
     debug!("predicates_defined_on({:?}) = {:?}", def_id, result);
     result
@@ -1872,7 +1865,7 @@ fn predicates_defined_on<'a, 'tcx>(
 fn predicates_of<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     def_id: DefId,
-) -> Lrc<ty::GenericPredicates<'tcx>> {
+) -> &'tcx ty::GenericPredicates<'tcx> {
     let mut result = tcx.predicates_defined_on(def_id);
 
     if tcx.is_trait(def_id) {
@@ -1889,9 +1882,9 @@ fn predicates_of<'a, 'tcx>(
         // used, and adding the predicate into this list ensures
         // that this is done.
         let span = tcx.def_span(def_id);
-        Lrc::make_mut(&mut result)
-            .predicates
-            .push((ty::TraitRef::identity(tcx, def_id).to_predicate(), span));
+        let mut predicates = (*result).clone();
+        predicates.predicates.push((ty::TraitRef::identity(tcx, def_id).to_predicate(), span));
+        result = tcx.arena.alloc(predicates);
     }
     debug!("predicates_of(def_id={:?}) = {:?}", def_id, result);
     result
@@ -1902,7 +1895,7 @@ fn predicates_of<'a, 'tcx>(
 fn explicit_predicates_of<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     def_id: DefId,
-) -> Lrc<ty::GenericPredicates<'tcx>> {
+) -> &'tcx ty::GenericPredicates<'tcx> {
     use rustc::hir::*;
     use rustc_data_structures::fx::FxHashSet;
 
@@ -2017,7 +2010,7 @@ fn extend<I: IntoIterator<Item = (ty::Predicate<'tcx>, Span)>>(&mut self, iter:
 
                     if impl_trait_fn.is_some() {
                         // impl Trait
-                        return Lrc::new(ty::GenericPredicates {
+                        return tcx.arena.alloc(ty::GenericPredicates {
                             parent: None,
                             predicates: bounds.predicates(tcx, opaque_ty),
                         });
@@ -2228,7 +2221,7 @@ fn extend<I: IntoIterator<Item = (ty::Predicate<'tcx>, Span)>>(&mut self, iter:
         );
     }
 
-    let result = Lrc::new(ty::GenericPredicates {
+    let result = tcx.arena.alloc(ty::GenericPredicates {
         parent: generics.parent,
         predicates,
     });
index a6b5b99982ec6b5ba8a4cb72b36446268a17999c..57787a75e4aefd683a7a6320aac19899215b4756 100644 (file)
@@ -4,7 +4,6 @@
 use rustc::ty::query::Providers;
 use rustc::ty::subst::UnpackedKind;
 use rustc::ty::{self, CratePredicatesMap, TyCtxt};
-use rustc_data_structures::sync::Lrc;
 use syntax::symbol::sym;
 
 mod explicit;
@@ -74,7 +73,7 @@ fn inferred_outlives_of<'a, 'tcx>(
 fn inferred_outlives_crate<'tcx>(
     tcx: TyCtxt<'_, 'tcx, 'tcx>,
     crate_num: CrateNum,
-) -> Lrc<CratePredicatesMap<'tcx>> {
+) -> &'tcx CratePredicatesMap<'tcx> {
     assert_eq!(crate_num, LOCAL_CRATE);
 
     // Compute a map from each struct/enum/union S to the **explicit**
@@ -120,7 +119,7 @@ fn inferred_outlives_crate<'tcx>(
             (def_id, &*predicates)
         }).collect();
 
-    Lrc::new(ty::CratePredicatesMap {
+    tcx.arena.alloc(ty::CratePredicatesMap {
         predicates,
     })
 }
index 88ee1d79f5435dd165bc30e1402a1c191f5915fa..47c4a9b39c865e024dc91be4c9984783f85ec1db 100644 (file)
@@ -9,7 +9,6 @@
 use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
 use rustc::ty::{self, CrateVariancesMap, TyCtxt};
 use rustc::ty::query::Providers;
-use rustc_data_structures::sync::Lrc;
 
 /// Defines the `TermsContext` basically houses an arena where we can
 /// allocate terms.
@@ -36,12 +35,12 @@ pub fn provide(providers: &mut Providers<'_>) {
 }
 
 fn crate_variances<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum)
-                             -> Lrc<CrateVariancesMap<'tcx>> {
+                             -> &'tcx CrateVariancesMap<'tcx> {
     assert_eq!(crate_num, LOCAL_CRATE);
     let mut arena = arena::TypedArena::default();
     let terms_cx = terms::determine_parameters_to_be_inferred(tcx, &mut arena);
     let constraints_cx = constraints::add_constraints_from_crate(terms_cx);
-    Lrc::new(solve::solve_constraints(constraints_cx))
+    tcx.arena.alloc(solve::solve_constraints(constraints_cx))
 }
 
 fn variances_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_def_id: DefId)
index 11e8192521d79901d131832bf575f83964fb90f9..8e2460a14b87a7e6d62c9e82540f5294d1094c16 100644 (file)
@@ -104,8 +104,10 @@ pub fn get_auto_trait_impls(
                     // Instead, we generate `impl !Send for Foo<T>`, which better
                     // expresses the fact that `Foo<T>` never implements `Send`,
                     // regardless of the choice of `T`.
-                    let params = (self.cx.tcx.generics_of(param_env_def_id), &Default::default())
-                        .clean(self.cx).params;
+                    let params = (
+                        self.cx.tcx.generics_of(param_env_def_id),
+                        &&self.cx.tcx.common.empty_predicates,
+                    ).clean(self.cx).params;
 
                     Generics {
                         params,
index 1bbbe581c3ce15c259b9f127027a83f8251eeafa..9c3f522d8470fcbd69fe30dc66d8d840a80b5104 100644 (file)
@@ -10,7 +10,6 @@
 mod blanket_impl;
 
 use rustc_data_structures::indexed_vec::{IndexVec, Idx};
-use rustc_data_structures::sync::Lrc;
 use rustc_target::spec::abi::Abi;
 use rustc_typeck::hir_ty_to_ty;
 use rustc::infer::region_constraints::{RegionConstraintData, Constraint};
@@ -1687,7 +1686,7 @@ fn is_impl_trait(param: &hir::GenericParam) -> bool {
 }
 
 impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics,
-                                    &'a Lrc<ty::GenericPredicates<'tcx>>) {
+                                    &'a &'tcx ty::GenericPredicates<'tcx>) {
     fn clean(&self, cx: &DocContext<'_>) -> Generics {
         use self::WherePredicate as WP;
 
@@ -4434,7 +4433,7 @@ pub fn path_to_def(tcx: TyCtxt<'_, '_, '_>, path: &[Symbol]) -> Option<DefId> {
         loop {
             let segment = path_it.next()?;
 
-            for item in mem::replace(&mut items, Lrc::new(vec![])).iter() {
+            for item in mem::replace(&mut items, &[]).iter() {
                 if item.ident.name == *segment {
                     if path_it.peek().is_none() {
                         return match item.res {
index 84ef0468cac7a420db1f694a6535b00c20cdcb6e..3276f152575f7780e2d888594738d81a8ae9d3c3 100644 (file)
@@ -1037,7 +1037,6 @@ pub(super) fn to_ty(&self) -> Option<P<Ty>> {
     pub fn precedence(&self) -> ExprPrecedence {
         match self.node {
             ExprKind::Box(_) => ExprPrecedence::Box,
-            ExprKind::ObsoleteInPlace(..) => ExprPrecedence::ObsoleteInPlace,
             ExprKind::Array(_) => ExprPrecedence::Array,
             ExprKind::Call(..) => ExprPrecedence::Call,
             ExprKind::MethodCall(..) => ExprPrecedence::MethodCall,
@@ -1099,8 +1098,6 @@ pub enum RangeLimits {
 pub enum ExprKind {
     /// A `box x` expression.
     Box(P<Expr>),
-    /// First expr is the place; second expr is the value.
-    ObsoleteInPlace(P<Expr>, P<Expr>),
     /// An array (`[a, b, c, d]`)
     Array(Vec<P<Expr>>),
     /// A function call
index 2f75a8c9db57e453f9165f5bb5819aef15c06791..48948e4d0d79c1829c30cbbf199319c4ab046737 100644 (file)
@@ -278,7 +278,14 @@ pub fn meta(&self) -> Option<MetaItem> {
     pub fn parse<'a, T, F>(&self, sess: &'a ParseSess, mut f: F) -> PResult<'a, T>
         where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>,
     {
-        let mut parser = Parser::new(sess, self.tokens.clone(), None, false, false);
+        let mut parser = Parser::new(
+            sess,
+            self.tokens.clone(),
+            None,
+            false,
+            false,
+            Some("attribute"),
+        );
         let result = f(&mut parser)?;
         if parser.token != token::Eof {
             parser.unexpected()?;
index f1a20d54065743fd4de8578406d75aa0f6b64662..dbec379e76995cc0025b28e960ab437d54ce64f2 100644 (file)
@@ -11,7 +11,7 @@
 use crate::parse::token;
 use crate::ptr::P;
 use crate::symbol::{kw, sym, Ident, Symbol};
-use crate::ThinVec;
+use crate::{ThinVec, MACRO_ARGUMENTS};
 use crate::tokenstream::{self, TokenStream};
 
 use errors::{DiagnosticBuilder, DiagnosticId};
@@ -850,7 +850,7 @@ pub fn monotonic_expander<'b>(&'b mut self) -> expand::MacroExpander<'b, 'a> {
     }
 
     pub fn new_parser_from_tts(&self, tts: &[tokenstream::TokenTree]) -> parser::Parser<'a> {
-        parse::stream_to_parser(self.parse_sess, tts.iter().cloned().collect())
+        parse::stream_to_parser(self.parse_sess, tts.iter().cloned().collect(), MACRO_ARGUMENTS)
     }
     pub fn source_map(&self) -> &'a SourceMap { self.parse_sess.source_map() }
     pub fn parse_sess(&self) -> &'a parse::ParseSess { self.parse_sess }
index fa1f85c0e7b572a3f4cd903c7bec7acb95afea40..e55226b8579bda2566c2929225d8212c72343c96 100644 (file)
@@ -658,7 +658,14 @@ pub fn parse(
     recurse_into_modules: bool,
 ) -> NamedParseResult {
     // Create a parser that can be used for the "black box" parts.
-    let mut parser = Parser::new(sess, tts, directory, recurse_into_modules, true);
+    let mut parser = Parser::new(
+        sess,
+        tts,
+        directory,
+        recurse_into_modules,
+        true,
+        crate::MACRO_ARGUMENTS,
+    );
 
     // A queue of possible matcher positions. We initialize it with the matcher position in which
     // the "dot" is before the first token of the first token tree in `ms`. `inner_parse_loop` then
index 37c49112dcaaceb22dcd42b1841620734fc2435c..2debd8f048bc35a578fafd2429062c9ebfd81c0d 100644 (file)
@@ -172,7 +172,7 @@ fn generic_extension<'cx>(cx: &'cx mut ExtCtxt<'_>,
                     path: Cow::from(cx.current_expansion.module.directory.as_path()),
                     ownership: cx.current_expansion.directory_ownership,
                 };
-                let mut p = Parser::new(cx.parse_sess(), tts, Some(directory), true, false);
+                let mut p = Parser::new(cx.parse_sess(), tts, Some(directory), true, false, None);
                 p.root_module_name = cx.current_expansion.module.mod_path.last()
                     .map(|id| id.as_str().to_string());
 
index 0f1bf436eca1a39acb14fe7762c7a61673010d8e..6a049b80acae225c851ab9af390fc92593ce82e3 100644 (file)
@@ -2117,9 +2117,6 @@ fn visit_expr(&mut self, e: &'a ast::Expr) {
                                        "type ascription is experimental");
                 }
             }
-            ast::ExprKind::ObsoleteInPlace(..) => {
-                // these get a hard error in ast-validation
-            }
             ast::ExprKind::Yield(..) => {
                 gate_feature_post!(&self, generators,
                                   e.span,
index 5eda975bc9ee464c62c8aafedcde336a1b5c0118..4229121b3d0759cdf370a535e66700b1aac43679 100644 (file)
@@ -31,6 +31,8 @@
 use ast::AttrId;
 use syntax_pos::edition::Edition;
 
+const MACRO_ARGUMENTS: Option<&'static str> = Some("macro arguments");
+
 // A variant of 'try!' that panics on an Err. This is used as a crutch on the
 // way towards a non-panic!-prone parser. It should be used for fatal parsing
 // errors; eventually we plan to convert all code using panictry to just use
index e743248ef4b59057a10b5c3b7b2150098b58e7b2..0016c0d4d7e2b26ade57deeecdd568b5fb016c53 100644 (file)
@@ -1099,10 +1099,6 @@ pub fn noop_visit_anon_const<T: MutVisitor>(AnonConst { id, value }: &mut AnonCo
 pub fn noop_visit_expr<T: MutVisitor>(Expr { node, id, span, attrs }: &mut Expr, vis: &mut T) {
     match node {
         ExprKind::Box(expr) => vis.visit_expr(expr),
-        ExprKind::ObsoleteInPlace(a, b) => {
-            vis.visit_expr(a);
-            vis.visit_expr(b);
-        }
         ExprKind::Array(exprs) => visit_exprs(exprs, vis),
         ExprKind::Repeat(expr, count) => {
             vis.visit_expr(expr);
index d48fcbbd6720d96e4b27581e7e0d69e4af5544d9..810acc9cc923e25fc47c38600abceadc881f7818 100644 (file)
@@ -1,16 +1,19 @@
 use crate::ast;
-use crate::ast::{BlockCheckMode, Expr, ExprKind, Item, ItemKind, Pat, PatKind, QSelf, Ty, TyKind};
-use crate::parse::parser::{BlockMode, PathStyle, TokenType, SemiColonMode};
+use crate::ast::{
+    BlockCheckMode, Expr, ExprKind, Item, ItemKind, Pat, PatKind, QSelf, Ty, TyKind, VariantData,
+};
+use crate::parse::parser::{BlockMode, PathStyle, SemiColonMode, TokenType};
 use crate::parse::token;
 use crate::parse::PResult;
 use crate::parse::Parser;
 use crate::print::pprust;
 use crate::ptr::P;
+use crate::source_map::Spanned;
 use crate::symbol::kw;
 use crate::ThinVec;
 use errors::{Applicability, DiagnosticBuilder};
-use syntax_pos::Span;
 use log::debug;
+use syntax_pos::{Span, DUMMY_SP};
 
 pub trait RecoverQPath: Sized + 'static {
     const PATH_STYLE: PathStyle = PathStyle::Expr;
@@ -79,6 +82,44 @@ impl<'a> Parser<'a> {
         }
     }
 
+    crate fn maybe_report_invalid_custom_discriminants(
+        &mut self,
+        discriminant_spans: Vec<Span>,
+        variants: &[Spanned<ast::Variant_>],
+    ) {
+        let has_fields = variants.iter().any(|variant| match variant.node.data {
+            VariantData::Tuple(..) | VariantData::Struct(..) => true,
+            VariantData::Unit(..) => false,
+        });
+
+        if !discriminant_spans.is_empty() && has_fields {
+            let mut err = self.struct_span_err(
+                discriminant_spans.clone(),
+                "custom discriminant values are not allowed in enums with fields",
+            );
+            for sp in discriminant_spans {
+                err.span_label(sp, "invalid custom discriminant");
+            }
+            for variant in variants.iter() {
+                if let VariantData::Struct(fields, ..) | VariantData::Tuple(fields, ..) =
+                    &variant.node.data
+                {
+                    let fields = if fields.len() > 1 {
+                        "fields"
+                    } else {
+                        "a field"
+                    };
+                    err.span_label(
+                        variant.span,
+                        &format!("variant with {fields} defined here", fields = fields),
+                    );
+
+                }
+            }
+            err.emit();
+        }
+    }
+
     crate fn maybe_recover_from_bad_type_plus(
         &mut self,
         allow_plus: bool,
@@ -160,7 +201,7 @@ impl<'a> Parser<'a> {
 
         let mut path = ast::Path {
             segments: Vec::new(),
-            span: syntax_pos::DUMMY_SP,
+            span: DUMMY_SP,
         };
         self.parse_path_segments(&mut path.segments, T::PATH_STYLE)?;
         path.span = ty_span.to(self.prev_span);
@@ -226,6 +267,58 @@ impl<'a> Parser<'a> {
         }
     }
 
+    /// Create a `DiagnosticBuilder` for an unexpected token `t` and try to recover if it is a
+    /// closing delimiter.
+    pub fn unexpected_try_recover(
+        &mut self,
+        t: &token::Token,
+    ) -> PResult<'a, bool /* recovered */> {
+        let token_str = pprust::token_to_string(t);
+        let this_token_str = self.this_token_descr();
+        let (prev_sp, sp) = match (&self.token, self.subparser_name) {
+            // Point at the end of the macro call when reaching end of macro arguments.
+            (token::Token::Eof, Some(_)) => {
+                let sp = self.sess.source_map().next_point(self.span);
+                (sp, sp)
+            }
+            // We don't want to point at the following span after DUMMY_SP.
+            // This happens when the parser finds an empty TokenStream.
+            _ if self.prev_span == DUMMY_SP => (self.span, self.span),
+            // EOF, don't want to point at the following char, but rather the last token.
+            (token::Token::Eof, None) => (self.prev_span, self.span),
+            _ => (self.sess.source_map().next_point(self.prev_span), self.span),
+        };
+        let msg = format!(
+            "expected `{}`, found {}",
+            token_str,
+            match (&self.token, self.subparser_name) {
+                (token::Token::Eof, Some(origin)) => format!("end of {}", origin),
+                _ => this_token_str,
+            },
+        );
+        let mut err = self.struct_span_err(sp, &msg);
+        let label_exp = format!("expected `{}`", token_str);
+        match self.recover_closing_delimiter(&[t.clone()], err) {
+            Err(e) => err = e,
+            Ok(recovered) => {
+                return Ok(recovered);
+            }
+        }
+        let cm = self.sess.source_map();
+        match (cm.lookup_line(prev_sp.lo()), cm.lookup_line(sp.lo())) {
+            (Ok(ref a), Ok(ref b)) if a.line == b.line => {
+                // When the spans are in the same line, it means that the only content
+                // between them is whitespace, point only at the found token.
+                err.span_label(sp, label_exp);
+            }
+            _ => {
+                err.span_label(prev_sp, label_exp);
+                err.span_label(sp, "unexpected token");
+            }
+        }
+        Err(err)
+    }
+
     /// Consume alternative await syntaxes like `await <expr>`, `await? <expr>`, `await(<expr>)`
     /// and `await { <expr> }`.
     crate fn parse_incorrect_await_syntax(
@@ -521,4 +614,23 @@ impl<'a> Parser<'a> {
         }
     }
 
+    crate fn expected_expression_found(&self) -> DiagnosticBuilder<'a> {
+        let (span, msg) = match (&self.token, self.subparser_name) {
+            (&token::Token::Eof, Some(origin)) => {
+                let sp = self.sess.source_map().next_point(self.span);
+                (sp, format!("expected expression, found end of {}", origin))
+            }
+            _ => (self.span, format!(
+                "expected expression, found {}",
+                self.this_token_descr(),
+            )),
+        };
+        let mut err = self.struct_span_err(span, &msg);
+        let sp = self.sess.source_map().start_point(self.span);
+        if let Some(sp) = self.sess.ambiguous_block_expr_parse.borrow().get(&sp) {
+            self.sess.expr_parentheses_needed(&mut err, *sp, None);
+        }
+        err.span_label(span, "expected expression");
+        err
+    }
 }
index 1073fc6f3ab4d3a00e760aa918fdb2a9a92a7772..f7a7aba9ecbaa1fdf3063012ebc4ed77a3d2b065 100644 (file)
@@ -236,7 +236,7 @@ fn maybe_source_file_to_parser(
 ) -> Result<Parser<'_>, Vec<Diagnostic>> {
     let end_pos = source_file.end_pos;
     let (stream, unclosed_delims) = maybe_file_to_stream(sess, source_file, None)?;
-    let mut parser = stream_to_parser(sess, stream);
+    let mut parser = stream_to_parser(sess, stream, None);
     parser.unclosed_delims = unclosed_delims;
     if parser.token == token::Eof && parser.span.is_dummy() {
         parser.span = Span::new(end_pos, end_pos, parser.span.ctxt());
@@ -248,7 +248,7 @@ fn maybe_source_file_to_parser(
 // must preserve old name for now, because quote! from the *existing*
 // compiler expands into it
 pub fn new_parser_from_tts(sess: &ParseSess, tts: Vec<TokenTree>) -> Parser<'_> {
-    stream_to_parser(sess, tts.into_iter().collect())
+    stream_to_parser(sess, tts.into_iter().collect(), crate::MACRO_ARGUMENTS)
 }
 
 
@@ -328,8 +328,12 @@ pub fn maybe_file_to_stream(
 }
 
 /// Given stream and the `ParseSess`, produces a parser.
-pub fn stream_to_parser(sess: &ParseSess, stream: TokenStream) -> Parser<'_> {
-    Parser::new(sess, stream, None, true, false)
+pub fn stream_to_parser<'a>(
+    sess: &'a ParseSess,
+    stream: TokenStream,
+    subparser_name: Option<&'static str>,
+) -> Parser<'a> {
+    Parser::new(sess, stream, None, true, false, subparser_name)
 }
 
 /// Given stream, the `ParseSess` and the base directory, produces a parser.
@@ -343,10 +347,12 @@ pub fn stream_to_parser(sess: &ParseSess, stream: TokenStream) -> Parser<'_> {
 /// The main usage of this function is outside of rustc, for those who uses
 /// libsyntax as a library. Please do not remove this function while refactoring
 /// just because it is not used in rustc codebase!
-pub fn stream_to_parser_with_base_dir<'a>(sess: &'a ParseSess,
-                                          stream: TokenStream,
-                                          base_dir: Directory<'a>) -> Parser<'a> {
-    Parser::new(sess, stream, Some(base_dir), true, false)
+pub fn stream_to_parser_with_base_dir<'a>(
+    sess: &'a ParseSess,
+    stream: TokenStream,
+    base_dir: Directory<'a>,
+) -> Parser<'a> {
+    Parser::new(sess, stream, Some(base_dir), true, false, None)
 }
 
 /// A sequence separator.
index ae3665c834bd3e9c0b949a5281d3f4ff9eac5d34..56951ae08012a5230d8ddd671c6cc40a7bd80401 100644 (file)
@@ -51,7 +51,7 @@
 use errors::{Applicability, DiagnosticBuilder, DiagnosticId, FatalError};
 use rustc_target::spec::abi::{self, Abi};
 use syntax_pos::{
-    Span, MultiSpan, BytePos, FileName,
+    BytePos, DUMMY_SP, FileName, MultiSpan, Span,
     hygiene::CompilerDesugaringKind,
 };
 use log::{debug, trace};
@@ -233,6 +233,8 @@ pub struct Parser<'a> {
     /// error.
     crate unclosed_delims: Vec<UnmatchedBrace>,
     last_unexpected_token_span: Option<Span>,
+    /// If present, this `Parser` is not parsing Rust code but rather a macro call.
+    crate subparser_name: Option<&'static str>,
 }
 
 impl<'a> Drop for Parser<'a> {
@@ -309,7 +311,7 @@ fn next(&mut self) -> TokenAndSpan {
                 self.frame = frame;
                 continue
             } else {
-                return TokenAndSpan { tok: token::Eof, sp: syntax_pos::DUMMY_SP }
+                return TokenAndSpan { tok: token::Eof, sp: DUMMY_SP }
             };
 
             match self.frame.last_token {
@@ -533,17 +535,19 @@ enum TokenExpectType {
 }
 
 impl<'a> Parser<'a> {
-    pub fn new(sess: &'a ParseSess,
-               tokens: TokenStream,
-               directory: Option<Directory<'a>>,
-               recurse_into_file_modules: bool,
-               desugar_doc_comments: bool)
-               -> Self {
+    pub fn new(
+        sess: &'a ParseSess,
+        tokens: TokenStream,
+        directory: Option<Directory<'a>>,
+        recurse_into_file_modules: bool,
+        desugar_doc_comments: bool,
+        subparser_name: Option<&'static str>,
+    ) -> Self {
         let mut parser = Parser {
             sess,
             token: token::Whitespace,
-            span: syntax_pos::DUMMY_SP,
-            prev_span: syntax_pos::DUMMY_SP,
+            span: DUMMY_SP,
+            prev_span: DUMMY_SP,
             meta_var_span: None,
             prev_token_kind: PrevTokenKind::Other,
             restrictions: Restrictions::empty(),
@@ -568,6 +572,7 @@ pub fn new(sess: &'a ParseSess,
             max_angle_bracket_count: 0,
             unclosed_delims: Vec::new(),
             last_unexpected_token_span: None,
+            subparser_name,
         };
 
         let tok = parser.next_tok();
@@ -631,44 +636,13 @@ fn token_descr(&self) -> Option<&'static str> {
     }
 
     /// Expects and consumes the token `t`. Signals an error if the next token is not `t`.
-    pub fn expect(&mut self, t: &token::Token) -> PResult<'a,  bool /* recovered */> {
+    pub fn expect(&mut self, t: &token::Token) -> PResult<'a, bool /* recovered */> {
         if self.expected_tokens.is_empty() {
             if self.token == *t {
                 self.bump();
                 Ok(false)
             } else {
-                let token_str = pprust::token_to_string(t);
-                let this_token_str = self.this_token_descr();
-                let mut err = self.fatal(&format!("expected `{}`, found {}",
-                                                  token_str,
-                                                  this_token_str));
-
-                let sp = if self.token == token::Token::Eof {
-                    // EOF, don't want to point at the following char, but rather the last token
-                    self.prev_span
-                } else {
-                    self.sess.source_map().next_point(self.prev_span)
-                };
-                let label_exp = format!("expected `{}`", token_str);
-                match self.recover_closing_delimiter(&[t.clone()], err) {
-                    Err(e) => err = e,
-                    Ok(recovered) => {
-                        return Ok(recovered);
-                    }
-                }
-                let cm = self.sess.source_map();
-                match (cm.lookup_line(self.span.lo()), cm.lookup_line(sp.lo())) {
-                    (Ok(ref a), Ok(ref b)) if a.line == b.line => {
-                        // When the spans are in the same line, it means that the only content
-                        // between them is whitespace, point only at the found token.
-                        err.span_label(self.span, label_exp);
-                    }
-                    _ => {
-                        err.span_label(sp, label_exp);
-                        err.span_label(self.span, "unexpected token");
-                    }
-                }
-                Err(err)
+                self.unexpected_try_recover(t)
             }
         } else {
             self.expect_one_of(slice::from_ref(t), &[])
@@ -812,7 +786,7 @@ fn tokens_to_string(tokens: &[TokenType]) -> String {
                     //   |                   expected one of 8 possible tokens here
                     err.span_label(self.span, label_exp);
                 }
-                _ if self.prev_span == syntax_pos::DUMMY_SP => {
+                _ if self.prev_span == DUMMY_SP => {
                     // Account for macro context where the previous span might not be
                     // available to avoid incorrect output (#54841).
                     err.span_label(self.span, "unexpected token");
@@ -2041,7 +2015,7 @@ fn parse_qpath(&mut self, style: PathStyle) -> PResult<'a, (QSelf, ast::Path)> {
             path = self.parse_path(PathStyle::Type)?;
             path_span = path_lo.to(self.prev_span);
         } else {
-            path = ast::Path { segments: Vec::new(), span: syntax_pos::DUMMY_SP };
+            path = ast::Path { segments: Vec::new(), span: DUMMY_SP };
             path_span = self.span.to(self.span);
         }
 
@@ -2627,17 +2601,7 @@ fn parse_bottom_expr(&mut self) -> PResult<'a, P<Expr>> {
                         }
                         Err(mut err) => {
                             self.cancel(&mut err);
-                            let msg = format!("expected expression, found {}",
-                                              self.this_token_descr());
-                            let mut err = self.fatal(&msg);
-                            let sp = self.sess.source_map().start_point(self.span);
-                            if let Some(sp) = self.sess.ambiguous_block_expr_parse.borrow()
-                                .get(&sp)
-                            {
-                                self.sess.expr_parentheses_needed(&mut err, *sp, None);
-                            }
-                            err.span_label(self.span, "expected expression");
-                            return Err(err);
+                            return Err(self.expected_expression_found());
                         }
                     }
                 }
@@ -3252,17 +3216,6 @@ fn parse_prefix_expr(&mut self,
                 let (span, e) = self.interpolated_or_expr_span(e)?;
                 (lo.to(span), ExprKind::AddrOf(m, e))
             }
-            token::Ident(..) if self.token.is_keyword(kw::In) => {
-                self.bump();
-                let place = self.parse_expr_res(
-                    Restrictions::NO_STRUCT_LITERAL,
-                    None,
-                )?;
-                let blk = self.parse_block()?;
-                let span = blk.span;
-                let blk_expr = self.mk_expr(span, ExprKind::Block(blk, None), ThinVec::new());
-                (lo.to(span), ExprKind::ObsoleteInPlace(place, blk_expr))
-            }
             token::Ident(..) if self.token.is_keyword(kw::Box) => {
                 self.bump();
                 let e = self.parse_prefix_expr(None);
@@ -3500,8 +3453,6 @@ fn parse_assoc_expr_with(&mut self,
                     self.mk_expr(span, binary, ThinVec::new())
                 }
                 AssocOp::Assign => self.mk_expr(span, ExprKind::Assign(lhs, rhs), ThinVec::new()),
-                AssocOp::ObsoleteInPlace =>
-                    self.mk_expr(span, ExprKind::ObsoleteInPlace(lhs, rhs), ThinVec::new()),
                 AssocOp::AssignOp(k) => {
                     let aop = match k {
                         token::Plus =>    BinOpKind::Add,
@@ -3820,9 +3771,6 @@ fn parse_for_expr(&mut self, opt_label: Option<Label>,
                 String::new(),
                 Applicability::MachineApplicable,
             );
-            err.note("if you meant to use emplacement syntax, it is obsolete (for now, anyway)");
-            err.note("for more information on the status of emplacement syntax, see <\
-                      https://github.com/rust-lang/rust/issues/27779#issuecomment-378416911>");
             err.emit();
         }
         let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
@@ -5608,7 +5556,7 @@ fn parse_generics(&mut self) -> PResult<'a, ast::Generics> {
                 where_clause: WhereClause {
                     id: ast::DUMMY_NODE_ID,
                     predicates: Vec::new(),
-                    span: syntax_pos::DUMMY_SP,
+                    span: DUMMY_SP,
                 },
                 span: span_lo.to(self.prev_span),
             })
@@ -5854,7 +5802,7 @@ fn parse_where_clause(&mut self) -> PResult<'a, WhereClause> {
         let mut where_clause = WhereClause {
             id: ast::DUMMY_NODE_ID,
             predicates: Vec::new(),
-            span: syntax_pos::DUMMY_SP,
+            span: DUMMY_SP,
         };
 
         if !self.eat_keyword(kw::Where) {
@@ -7021,7 +6969,7 @@ fn parse_item_mod(&mut self, outer_attrs: &[Attribute]) -> PResult<'a, ItemInfo>
                             Ident::with_empty_ctxt(sym::warn_directory_ownership)),
                         tokens: TokenStream::empty(),
                         is_sugared_doc: false,
-                        span: syntax_pos::DUMMY_SP,
+                        span: DUMMY_SP,
                     };
                     attr::mark_known(&attr);
                     attrs.push(attr);
@@ -7029,7 +6977,7 @@ fn parse_item_mod(&mut self, outer_attrs: &[Attribute]) -> PResult<'a, ItemInfo>
                 Ok((id, ItemKind::Mod(module), Some(attrs)))
             } else {
                 let placeholder = ast::Mod {
-                    inner: syntax_pos::DUMMY_SP,
+                    inner: DUMMY_SP,
                     items: Vec::new(),
                     inline: false
                 };
@@ -7466,7 +7414,6 @@ fn parse_existential_or_alias(
     /// Parses the part of an enum declaration following the `{`.
     fn parse_enum_def(&mut self, _generics: &ast::Generics) -> PResult<'a, EnumDef> {
         let mut variants = Vec::new();
-        let mut all_nullary = true;
         let mut any_disr = vec![];
         while self.token != token::CloseDelim(token::Brace) {
             let variant_attrs = self.parse_outer_attributes()?;
@@ -7478,11 +7425,9 @@ fn parse_enum_def(&mut self, _generics: &ast::Generics) -> PResult<'a, EnumDef>
             let ident = self.parse_ident()?;
             if self.check(&token::OpenDelim(token::Brace)) {
                 // Parse a struct variant.
-                all_nullary = false;
                 let (fields, recovered) = self.parse_record_struct_body()?;
                 struct_def = VariantData::Struct(fields, recovered);
             } else if self.check(&token::OpenDelim(token::Paren)) {
-                all_nullary = false;
                 struct_def = VariantData::Tuple(
                     self.parse_tuple_struct_body()?,
                     ast::DUMMY_NODE_ID,
@@ -7526,16 +7471,7 @@ fn parse_enum_def(&mut self, _generics: &ast::Generics) -> PResult<'a, EnumDef>
             }
         }
         self.expect(&token::CloseDelim(token::Brace))?;
-        if !any_disr.is_empty() && !all_nullary {
-            let mut err = self.struct_span_err(
-                any_disr.clone(),
-                "discriminator values can only be used with a field-less enum",
-            );
-            for sp in any_disr {
-                err.span_label(sp, "only valid in field-less enums");
-            }
-            err.emit();
-        }
+        self.maybe_report_invalid_custom_discriminants(any_disr, &variants);
 
         Ok(ast::EnumDef { variants })
     }
@@ -8433,6 +8369,8 @@ fn construct_async_arguments(&mut self, asyncness: &mut Spanned<IsAsync>, decl:
             for (index, input) in decl.inputs.iter_mut().enumerate() {
                 let id = ast::DUMMY_NODE_ID;
                 let span = input.pat.span;
+                let desugared_span = self.sess.source_map()
+                    .mark_span_with_reason(CompilerDesugaringKind::Async, span, None);
 
                 // Construct a name for our temporary argument.
                 let name = format!("__arg{}", index);
@@ -8449,8 +8387,7 @@ fn construct_async_arguments(&mut self, asyncness: &mut Spanned<IsAsync>, decl:
                         // this would affect the input to procedural macros, but they can have
                         // their span marked as being the result of a compiler desugaring so
                         // that they aren't linted against.
-                        input.pat.span = self.sess.source_map().mark_span_with_reason(
-                            CompilerDesugaringKind::Async, span, None);
+                        input.pat.span = desugared_span;
 
                         (binding_mode, ident, true)
                     }
@@ -8470,7 +8407,7 @@ fn construct_async_arguments(&mut self, asyncness: &mut Spanned<IsAsync>, decl:
                             node: PatKind::Ident(
                                 BindingMode::ByValue(Mutability::Immutable), ident, None,
                             ),
-                            span,
+                            span: desugared_span,
                         }),
                         source: ArgSource::AsyncFn(input.pat.clone()),
                     })
@@ -8483,7 +8420,7 @@ fn construct_async_arguments(&mut self, asyncness: &mut Spanned<IsAsync>, decl:
                     pat: P(Pat {
                         id,
                         node: PatKind::Ident(binding_mode, ident, None),
-                        span,
+                        span: desugared_span,
                     }),
                     // We explicitly do not specify the type for this statement. When the user's
                     // argument type is `impl Trait` then this would require the
index 88a5033f3b55f43d7330d06dc42e9f1b7c7e772d..cf546332c2c9dde920ef7b292a05df82cc3c8b45 100644 (file)
@@ -2005,13 +2005,6 @@ fn print_expr_outer_attr_style(&mut self,
                 self.word_space("box")?;
                 self.print_expr_maybe_paren(expr, parser::PREC_PREFIX)?;
             }
-            ast::ExprKind::ObsoleteInPlace(ref place, ref expr) => {
-                let prec = AssocOp::ObsoleteInPlace.precedence() as i8;
-                self.print_expr_maybe_paren(place, prec + 1)?;
-                self.s.space()?;
-                self.word_space("<-")?;
-                self.print_expr_maybe_paren(expr, prec)?;
-            }
             ast::ExprKind::Array(ref exprs) => {
                 self.print_expr_vec(&exprs[..], attrs)?;
             }
index 6789fea28cad6daf1798c2da3e1c31d5e9282931..7e306d59e35ce5363fe946b03c24111a87c7fb14 100644 (file)
@@ -45,8 +45,6 @@ pub enum AssocOp {
     GreaterEqual,
     /// `=`
     Assign,
-    /// `<-`
-    ObsoleteInPlace,
     /// `?=` where ? is one of the BinOpToken
     AssignOp(BinOpToken),
     /// `as`
@@ -75,7 +73,6 @@ pub fn from_token(t: &Token) -> Option<AssocOp> {
         use AssocOp::*;
         match *t {
             Token::BinOpEq(k) => Some(AssignOp(k)),
-            Token::LArrow => Some(ObsoleteInPlace),
             Token::Eq => Some(Assign),
             Token::BinOp(BinOpToken::Star) => Some(Multiply),
             Token::BinOp(BinOpToken::Slash) => Some(Divide),
@@ -145,7 +142,6 @@ pub fn precedence(&self) -> usize {
             LAnd => 6,
             LOr => 5,
             DotDot | DotDotEq => 4,
-            ObsoleteInPlace => 3,
             Assign | AssignOp(_) => 2,
         }
     }
@@ -155,7 +151,7 @@ pub fn fixity(&self) -> Fixity {
         use AssocOp::*;
         // NOTE: it is a bug to have an operators that has same precedence but different fixities!
         match *self {
-            ObsoleteInPlace | Assign | AssignOp(_) => Fixity::Right,
+            Assign | AssignOp(_) => Fixity::Right,
             As | Multiply | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd |
             BitXor | BitOr | Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual |
             LAnd | LOr | Colon => Fixity::Left,
@@ -167,7 +163,7 @@ pub fn is_comparison(&self) -> bool {
         use AssocOp::*;
         match *self {
             Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => true,
-            ObsoleteInPlace | Assign | AssignOp(_) | As | Multiply | Divide | Modulus | Add |
+            Assign | AssignOp(_) | As | Multiply | Divide | Modulus | Add |
             Subtract | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd | LOr |
             DotDot | DotDotEq | Colon => false
         }
@@ -176,7 +172,7 @@ pub fn is_comparison(&self) -> bool {
     pub fn is_assign_like(&self) -> bool {
         use AssocOp::*;
         match *self {
-            Assign | AssignOp(_) | ObsoleteInPlace => true,
+            Assign | AssignOp(_) => true,
             Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual | As | Multiply | Divide |
             Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd |
             LOr | DotDot | DotDotEq | Colon => false
@@ -204,7 +200,7 @@ pub fn to_ast_binop(&self) -> Option<BinOpKind> {
             BitOr => Some(BinOpKind::BitOr),
             LAnd => Some(BinOpKind::And),
             LOr => Some(BinOpKind::Or),
-            ObsoleteInPlace | Assign | AssignOp(_) | As | DotDot | DotDotEq | Colon => None
+            Assign | AssignOp(_) | As | DotDot | DotDotEq | Colon => None
         }
     }
 
@@ -256,7 +252,6 @@ pub enum ExprPrecedence {
 
     Binary(BinOpKind),
 
-    ObsoleteInPlace,
     Cast,
     Type,
 
@@ -314,7 +309,6 @@ pub fn order(self) -> i8 {
 
             // Binop-like expr kinds, handled by `AssocOp`.
             ExprPrecedence::Binary(op) => AssocOp::from_ast_binop(op).precedence() as i8,
-            ExprPrecedence::ObsoleteInPlace => AssocOp::ObsoleteInPlace.precedence() as i8,
             ExprPrecedence::Cast => AssocOp::As.precedence() as i8,
             ExprPrecedence::Type => AssocOp::Colon.precedence() as i8,
 
index 0503e5644dbc58112bd6547e974c1c2865b9f6df..4e096d68235b5c35c9823fc82b1dc0fa7a497731 100644 (file)
@@ -676,10 +676,6 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
         ExprKind::Box(ref subexpression) => {
             visitor.visit_expr(subexpression)
         }
-        ExprKind::ObsoleteInPlace(ref place, ref subexpression) => {
-            visitor.visit_expr(place);
-            visitor.visit_expr(subexpression)
-        }
         ExprKind::Array(ref subexpressions) => {
             walk_list!(visitor, visit_expr, subexpressions);
         }
index b8e89c3ecf8762191b77c84cd88ca3416f98a956..704665e0a84d66917d135ad035327988f7a146c7 100644 (file)
@@ -138,7 +138,11 @@ fn parse_inline_asm<'a>(
                 if p2.token != token::Eof {
                     let mut extra_tts = p2.parse_all_token_trees()?;
                     extra_tts.extend(tts[first_colon..].iter().cloned());
-                    p = parse::stream_to_parser(cx.parse_sess, extra_tts.into_iter().collect());
+                    p = parse::stream_to_parser(
+                        cx.parse_sess,
+                        extra_tts.into_iter().collect(),
+                        Some("inline assembly"),
+                    );
                 }
 
                 asm = s;
index e73110717e97968209e3b82eb5ab1ceeddd68328..975d96951dc5571d54d8090ca80b1362e5ecb44d 100644 (file)
@@ -89,7 +89,7 @@ fn expand(&self,
         let error_count_before = ecx.parse_sess.span_diagnostic.err_count();
         let msg = "proc-macro derive produced unparseable tokens";
 
-        let mut parser = parse::stream_to_parser(ecx.parse_sess, stream);
+        let mut parser = parse::stream_to_parser(ecx.parse_sess, stream, Some("proc-macro derive"));
         let mut items = vec![];
 
         loop {
index 3c9a365fd4f7b3c6a4077716e9ef151d105f0f2b..393478460d48f58bacdf46660eb79dab85d8a521 100644 (file)
@@ -1,4 +1,5 @@
 // min-lldb-version: 310
+// ignore-cdb: Fails with exit code 0xc0000135 ("the application failed to initialize properly")
 
 // aux-build:issue-13213-aux.rs
 
index 82802eff08abbd093fd48decf2e3051ee8d31874..a684d3b88fd07dbc98c6b85a0cf25f8c35d419a7 100644 (file)
@@ -1,6 +1,5 @@
-// ignore-windows failing on win32 bot
 // ignore-freebsd: gdb package too new
-// ignore-test // Test temporarily ignored due to debuginfo tests being disabled, see PR 47155
+// only-cdb // "Temporarily" ignored on GDB/LLDB due to debuginfo tests being disabled, see PR 47155
 // ignore-android: FIXME(#10381)
 // compile-flags:-g
 // min-gdb-version 7.7
 // lldb-check:[...]$5 = None
 
 
+// === CDB TESTS ==================================================================================
+
+// cdb-command: g
+
+// cdb-command: dx slice,d
+// cdb-check:slice,d [...]
+// NOTE: While slices have a .natvis entry that works in VS & VS Code, it fails in CDB 10.0.18362.1
+
+// cdb-command: dx vec,d
+// cdb-check:vec,d [...] : { size=4 } [Type: [...]::Vec<u64>]
+// cdb-check:    [size]           : 4 [Type: [...]]
+// cdb-check:    [capacity]       : [...] [Type: [...]]
+// cdb-check:    [0]              : 4 [Type: unsigned __int64]
+// cdb-check:    [1]              : 5 [Type: unsigned __int64]
+// cdb-check:    [2]              : 6 [Type: unsigned __int64]
+// cdb-check:    [3]              : 7 [Type: unsigned __int64]
+
+// cdb-command: dx str_slice
+// cdb-check:str_slice [...]
+// NOTE: While string slices have a .natvis entry that works in VS & VS Code, it fails in CDB
+
+// cdb-command: dx string
+// cdb-check:string           : "IAMA string!" [Type: [...]::String]
+// cdb-check:    [<Raw View>]     [Type: [...]::String]
+// cdb-check:    [size]           : 0xc [Type: [...]]
+// cdb-check:    [capacity]       : 0xc [Type: [...]]
+// cdb-check:    [0]              : 73 'I' [Type: char]
+// cdb-check:    [1]              : 65 'A' [Type: char]
+// cdb-check:    [2]              : 77 'M' [Type: char]
+// cdb-check:    [3]              : 65 'A' [Type: char]
+// cdb-check:    [4]              : 32 ' ' [Type: char]
+// cdb-check:    [5]              : 115 's' [Type: char]
+// cdb-check:    [6]              : 116 't' [Type: char]
+// cdb-check:    [7]              : 114 'r' [Type: char]
+// cdb-check:    [8]              : 105 'i' [Type: char]
+// cdb-check:    [9]              : 110 'n' [Type: char]
+// cdb-check:    [10]             : 103 'g' [Type: char]
+// cdb-check:    [11]             : 33 '!' [Type: char]
+
+// cdb-command: dx os_string
+// cdb-check:os_string        [Type: [...]::OsString]
+// NOTE: OsString doesn't have a .natvis entry yet.
+
+// cdb-command: dx some
+// cdb-check:some             : { Some 8 } [Type: [...]::Option<i16>]
+// cdb-command: dx none
+// cdb-check:none             : { None } [Type: [...]::Option<i64>]
+// cdb-command: dx some_string
+// cdb-check:some_string      : { Some "IAMA optional string!" } [[...]::Option<[...]::String>]
+
 #![allow(unused_variables)]
 use std::ffi::OsString;
 
index 8765c018b102265a0e34de91c7f1c4fb49816b87..1e0d22cbce40453443f465fd7e82ca482514b4fa 100644 (file)
 // lldb-command:print x
 // lldb-check:[...]$0 = 5
 
+// === CDB TESTS ==================================================================================
+
+// cdb-command:g
+
+// cdb-command:dx x
+// cdb-check:string [...] : 5 [Type: [...]]
+
 fn main() {
     let x = 1;
 
index 4102eb32580f025143f6e7bd5627790e18e4fc7b..27287d06d54b171b4573b235d1345fb42e6a56c7 100644 (file)
@@ -7,7 +7,6 @@ pub trait T2 { }
 #[cfg(cfail2)]
 pub trait T2: T1 { }
 //[cfail2]~^ ERROR cycle detected when computing the supertraits of `T2`
-//[cfail2]~| ERROR cycle detected when computing the supertraits of `T2`
 
 pub trait T1: T2 { }
 
index 4e43aa96e1d853895e90754a9cd747a36fb83d12..1bab3f01aba04707ecd058eefcd21ba57037afbe 100644 (file)
@@ -47,8 +47,8 @@ fn metadata_loader(&self) -> Box<MetadataLoader + Sync> {
     fn provide(&self, providers: &mut Providers) {
         rustc_codegen_utils::symbol_names::provide(providers);
 
-        providers.target_features_whitelist = |_tcx, _cnum| {
-            Default::default() // Just a dummy
+        providers.target_features_whitelist = |tcx, _cnum| {
+            tcx.arena.alloc(Default::default()) // Just a dummy
         };
         providers.is_reachable_non_generic = |_tcx, _defid| true;
         providers.exported_symbols = |_tcx, _crate| Arc::new(Vec::new());
index 336b67852cd015da6e839d3b2478622ae2490f46..d3609acfdff63edd44e05599669eeb292e2083d2 100644 (file)
@@ -16,7 +16,6 @@ struct A<T>
     where T : Trait,
           T : Add<T::Item>
     //~^ ERROR cycle detected
-    //~| ERROR associated type `Item` not found for `T`
 {
     data: T
 }
index e5a5e2897cd0a101ec195127bb66a324858d7763..59815138e2e36f32853b6a2cdfdb3960ee77ba61 100644 (file)
@@ -11,13 +11,6 @@ note: cycle used when processing `A`
 LL |           T : Add<T::Item>
    |                   ^^^^^^^
 
-error[E0220]: associated type `Item` not found for `T`
-  --> $DIR/cycle-projection-based-on-where-clause.rs:17:19
-   |
-LL |           T : Add<T::Item>
-   |                   ^^^^^^^ associated type `Item` not found
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0220, E0391.
-For more information about an error, try `rustc --explain E0220`.
+For more information about this error, try `rustc --explain E0391`.
index 36551e7014f10cd4df110ad7bda21c3e9002eb8a..1500bc831528a599dcbd72bc45dbe8bc9d6c3616 100644 (file)
@@ -1,6 +1,5 @@
 trait T : Iterator<Item=Self::Item>
 //~^ ERROR cycle detected
-//~| ERROR associated type `Item` not found for `Self`
 {}
 
 fn main() {}
index 3b5dd975ce9e92540e9086709e8cc157c02d1129..d64636310a3687344adff5d67cd2482889abe8ae 100644 (file)
@@ -3,7 +3,6 @@ error[E0391]: cycle detected when computing the supertraits of `T`
    |
 LL | / trait T : Iterator<Item=Self::Item>
 LL | |
-LL | |
 LL | | {}
    | |__^
    |
@@ -13,17 +12,9 @@ note: cycle used when collecting item types in top-level module
    |
 LL | / trait T : Iterator<Item=Self::Item>
 LL | |
-LL | |
 LL | | {}
    | |__^
 
-error[E0220]: associated type `Item` not found for `Self`
-  --> $DIR/issue-20772.rs:1:25
-   |
-LL | trait T : Iterator<Item=Self::Item>
-   |                         ^^^^^^^^^^ associated type `Item` not found
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0220, E0391.
-For more information about an error, try `rustc --explain E0220`.
+For more information about this error, try `rustc --explain E0391`.
index 9d153696b885e2f11dbf46a29b84004828a7039f..258e362d1317c5ee38b7f0bb66d1320182fac0d7 100644 (file)
@@ -5,6 +5,5 @@ trait Trait {
 
 fn foo<T: Trait<A = T::B>>() { }
 //~^ ERROR cycle detected
-//~| ERROR associated type `B` not found for `T`
 
 fn main() { }
index 6841fe85dd79298bf2a4085124db989c3d3e99f8..00d9a3c46a723a5b98a5975da6bda4a3e7f08fbf 100644 (file)
@@ -11,13 +11,6 @@ note: cycle used when processing `foo`
 LL | fn foo<T: Trait<A = T::B>>() { }
    |                     ^^^^
 
-error[E0220]: associated type `B` not found for `T`
-  --> $DIR/issue-21177.rs:6:21
-   |
-LL | fn foo<T: Trait<A = T::B>>() { }
-   |                     ^^^^ associated type `B` not found
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0220, E0391.
-For more information about an error, try `rustc --explain E0220`.
+For more information about this error, try `rustc --explain E0391`.
index e17c5eea2a4454e7df41607bbed1a4edc7027c9d..da75f330798865ff2190f84c6009ff253716ee8e 100644 (file)
@@ -1,5 +1,4 @@
 const A: i32 = B; //~ ERROR cycle detected
-//~^ ERROR cycle detected
 
 const B: i32 = A;
 
index 94624640809b77c5b6e0baed5c84bec7bd2f18b7..a7d643987f710293fc124fff8c16d8949a41709a 100644 (file)
@@ -10,36 +10,18 @@ note: ...which requires checking which parts of `A` are promotable to static...
 LL | const A: i32 = B;
    |                ^
 note: ...which requires const checking if rvalue is promotable to static `B`...
-  --> $DIR/issue-23302-3.rs:4:1
+  --> $DIR/issue-23302-3.rs:3:1
    |
 LL | const B: i32 = A;
    | ^^^^^^^^^^^^^^^^^
 note: ...which requires checking which parts of `B` are promotable to static...
-  --> $DIR/issue-23302-3.rs:4:16
+  --> $DIR/issue-23302-3.rs:3:16
    |
 LL | const B: i32 = A;
    |                ^
    = note: ...which again requires const checking if rvalue is promotable to static `A`, completing the cycle
    = note: cycle used when running analysis passes on this crate
 
-error[E0391]: cycle detected when processing `A`
-  --> $DIR/issue-23302-3.rs:1:16
-   |
-LL | const A: i32 = B;
-   |                ^
-   |
-note: ...which requires processing `B`...
-  --> $DIR/issue-23302-3.rs:4:16
-   |
-LL | const B: i32 = A;
-   |                ^
-   = note: ...which again requires processing `A`, completing the cycle
-note: cycle used when processing `A`
-  --> $DIR/issue-23302-3.rs:1:1
-   |
-LL | const A: i32 = B;
-   | ^^^^^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0391`.
index b887f66e94bd6ceff6787c4d30546a3f80eff7c1..21c8ba7d6ce4e6be5f4343f47ba277afc5d0b516 100644 (file)
@@ -1,4 +1,7 @@
 fn main() {
     let x: u8 = 256;
     //~^ error: literal out of range for `u8`
+
+    for _ in 0..256u8 {}
+    //~^ error: range endpoint is out of range for `u8`
 }
index 1263a7bb7fd1b364b2c5799386840ddcc80701c1..c97872b5222e82c2f250f8f7b6f5866d432bb8a7 100644 (file)
@@ -6,5 +6,11 @@ LL |     let x: u8 = 256;
    |
    = note: #[deny(overflowing_literals)] on by default
 
-error: aborting due to previous error
+error: range endpoint is out of range for `u8`
+  --> $DIR/deny-overflowing-literals.rs:5:14
+   |
+LL |     for _ in 0..256u8 {}
+   |              ^^^^^^^^ help: use an inclusive range instead: `0..=255u8`
+
+error: aborting due to 2 previous errors
 
index b634cf2d9944c1d826eb5283a89101c1ea74205d..fd4f93091944cd5af20d48bfad1f05a82f47584d 100644 (file)
@@ -12,17 +12,17 @@ error: expected expression, found keyword `struct`
 LL |     format!(struct);
    |             ^^^^^^ expected expression
 
-error: expected expression, found `<eof>`
-  --> $DIR/format-parse-errors.rs:4:23
+error: expected expression, found end of macro arguments
+  --> $DIR/format-parse-errors.rs:4:24
    |
 LL |     format!("s", name =);
-   |                       ^ expected expression
+   |                        ^ expected expression
 
-error: expected `=`, found `<eof>`
-  --> $DIR/format-parse-errors.rs:5:29
+error: expected `=`, found end of macro arguments
+  --> $DIR/format-parse-errors.rs:5:32
    |
 LL |     format!("s", foo = foo, bar);
-   |                             ^^^ expected `=`
+   |                                ^ expected `=`
 
 error: expected expression, found keyword `struct`
   --> $DIR/format-parse-errors.rs:6:24
index 74d22102c664df426763d75cdc0cbe2e07e0e7e6..36cc58f7e268e0b18d8a82a35db869c839fb76e0 100644 (file)
@@ -1,17 +1,13 @@
-#[derive(Copy(Bad))]
-//~^ ERROR expected one of `)`, `,`, or `::`, found `(`
+#[derive(Copy(Bad))] //~ ERROR expected one of `)`, `,`, or `::`, found `(`
 struct Test1;
 
-#[derive(Copy="bad")]
-//~^ ERROR expected one of `)`, `,`, or `::`, found `=`
+#[derive(Copy="bad")] //~ ERROR expected one of `)`, `,`, or `::`, found `=`
 struct Test2;
 
-#[derive()]
-//~^ WARNING empty trait list
+#[derive()] //~ WARNING empty trait list
 struct Test3;
 
-#[derive]
-//~^ ERROR attribute must be of the form
+#[derive] //~ ERROR attribute must be of the form `#[derive(Trait1, Trait2, ...)]`
 struct Test4;
 
 fn main() {}
index f546f74220a1c699b522a8f84dec080c2177e930..0dc18f6811117db2aee44282bec634814a8fcb40 100644 (file)
@@ -5,19 +5,19 @@ LL | #[derive(Copy(Bad))]
    |              ^ expected one of `)`, `,`, or `::` here
 
 error: expected one of `)`, `,`, or `::`, found `=`
-  --> $DIR/malformed-derive-entry.rs:5:14
+  --> $DIR/malformed-derive-entry.rs:4:14
    |
 LL | #[derive(Copy="bad")]
    |              ^ expected one of `)`, `,`, or `::` here
 
 warning: empty trait list in `derive`
-  --> $DIR/malformed-derive-entry.rs:9:1
+  --> $DIR/malformed-derive-entry.rs:7:1
    |
 LL | #[derive()]
    | ^^^^^^^^^^^
 
 error: attribute must be of the form `#[derive(Trait1, Trait2, ...)]`
-  --> $DIR/malformed-derive-entry.rs:13:1
+  --> $DIR/malformed-derive-entry.rs:10:1
    |
 LL | #[derive]
    | ^^^^^^^^^
index f91c6bedb2b2130b8b76049f0afe9bc7c957d4bc..4d00755aea09df5175e75a3b18cbe22f1d42d519 100644 (file)
@@ -1,4 +1,4 @@
-#[cfg_attr] //~ ERROR expected `(`, found `<eof>`
+#[cfg_attr] //~ ERROR expected `(`, found end of attribute
 struct S1;
 
 #[cfg_attr = ""] //~ ERROR expected `(`, found `=`
index 8c23424087c04aaf76b5aba56c83dd3f8b083157..a93f03589e383ce95ab6cbe588715e4d053c98c6 100644 (file)
@@ -1,13 +1,14 @@
-error: expected `(`, found `<eof>`
+error: expected `(`, found end of attribute
+  --> $DIR/malformed-special-attrs.rs:1:1
+   |
+LL | #[cfg_attr]
+   | ^ expected `(`
 
 error: expected `(`, found `=`
   --> $DIR/malformed-special-attrs.rs:4:12
    |
-LL | #[cfg_attr]
-   | - expected `(`
-...
 LL | #[cfg_attr = ""]
-   |            ^ unexpected token
+   |            ^ expected `(`
 
 error: attribute must be of the form `#[derive(Trait1, Trait2, ...)]`
   --> $DIR/malformed-special-attrs.rs:7:1
diff --git a/src/test/ui/nll/dont-print-desugared-async.rs b/src/test/ui/nll/dont-print-desugared-async.rs
new file mode 100644 (file)
index 0000000..8150a26
--- /dev/null
@@ -0,0 +1,9 @@
+// Test that we don't show variables with from async fn desugaring
+
+// edition:2018
+#![feature(async_await)]
+
+async fn async_fn(&ref mut s: &[i32]) {}
+//~^ ERROR cannot borrow data in a `&` reference as mutable [E0596]
+
+fn main() {}
diff --git a/src/test/ui/nll/dont-print-desugared-async.stderr b/src/test/ui/nll/dont-print-desugared-async.stderr
new file mode 100644 (file)
index 0000000..47726ba
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0596]: cannot borrow data in a `&` reference as mutable
+  --> $DIR/dont-print-desugared-async.rs:6:20
+   |
+LL | async fn async_fn(&ref mut s: &[i32]) {}
+   |                   -^^^^^^^^^
+   |                   ||
+   |                   |cannot borrow as mutable through `&` reference
+   |                   help: consider changing this to be a mutable reference: `&mut ref mut s`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/src/test/ui/nll/dont-print-desugared.rs b/src/test/ui/nll/dont-print-desugared.rs
new file mode 100644 (file)
index 0000000..829d78e
--- /dev/null
@@ -0,0 +1,21 @@
+// Test that we don't show variables with from for loop desugaring
+
+fn for_loop(s: &[i32]) {
+    for &ref mut x in s {}
+    //~^ ERROR cannot borrow data in a `&` reference as mutable [E0596]
+}
+
+struct D<'a>(&'a ());
+
+impl Drop for D<'_> {
+    fn drop(&mut self) {}
+}
+
+fn for_loop_dropck(v: Vec<D<'static>>) {
+    for ref mut d in v {
+        let y = ();
+        *d = D(&y); //~ ERROR `y` does not live long enough
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/dont-print-desugared.stderr b/src/test/ui/nll/dont-print-desugared.stderr
new file mode 100644 (file)
index 0000000..45d7cbc
--- /dev/null
@@ -0,0 +1,27 @@
+error[E0596]: cannot borrow data in a `&` reference as mutable
+  --> $DIR/dont-print-desugared.rs:4:10
+   |
+LL |     for &ref mut x in s {}
+   |         -^^^^^^^^^
+   |         ||
+   |         |cannot borrow as mutable through `&` reference
+   |         help: consider changing this to be a mutable reference: `&mut ref mut x`
+
+error[E0597]: `y` does not live long enough
+  --> $DIR/dont-print-desugared.rs:17:16
+   |
+LL |     for ref mut d in v {
+   |                      - a temporary with access to the borrow is created here ...
+LL |         let y = ();
+LL |         *d = D(&y);
+   |                ^^ borrowed value does not live long enough
+LL |     }
+   |     -
+   |     |
+   |     `y` dropped here while still borrowed
+   |     ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0596, E0597.
+For more information about an error, try `rustc --explain E0596`.
index 468577ab168c770c4b7ebebef88a51e8c4110319..d895981050ae98932ca273ec3df85c576a953f51 100644 (file)
@@ -1,18 +1,19 @@
-error: emplacement syntax is obsolete (for now, anyway)
-  --> $DIR/bad.rs:9:5
-   |
-LL |     x <- y;
-   |     ^^^^^^
-   |
-   = note: for more information, see <https://github.com/rust-lang/rust/issues/27779#issuecomment-378416911>
-
-error: emplacement syntax is obsolete (for now, anyway)
+error: expected expression, found keyword `in`
   --> $DIR/bad.rs:10:5
    |
 LL |     in(foo) { bar };
-   |     ^^^^^^^^^^^^^^^
+   |     ^^ expected expression
+
+error[E0282]: type annotations needed
+  --> $DIR/bad.rs:9:8
+   |
+LL |     let (x, y, foo, bar);
+   |         ---------------- consider giving the pattern a type
+LL |     x <- y;
+   |        ^^^ cannot infer type
    |
-   = note: for more information, see <https://github.com/rust-lang/rust/issues/27779#issuecomment-378416911>
+   = note: type must be known at this point
 
 error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0282`.
index f35d297e552ee09e1e137dbdb09a13450a7f4ccd..67676857e8da0046306709f77ec2d1a0f0b3e90d 100644 (file)
@@ -1,15 +1,12 @@
 // Check that `<-` and `in` syntax gets a hard error.
 
-// revisions: good bad
-//[good] run-pass
-
-#[cfg(bad)]
-fn main() {
-    let (x, y, foo, bar);
-    x <- y; //[bad]~ ERROR emplacement syntax is obsolete
-    in(foo) { bar }; //[bad]~ ERROR emplacement syntax is obsolete
+fn foo() {
+    let (x, y) = (0, 0);
+    x <- y; //~ ERROR expected one of
+    //~^ ERROR mismatched types
 }
 
-#[cfg(good)]
 fn main() {
+    let (foo, bar) = (0, 0);
+    in(foo) { bar }; //~ ERROR expected expression, found keyword `in`
 }
diff --git a/src/test/ui/obsolete-in-place/bad.stderr b/src/test/ui/obsolete-in-place/bad.stderr
new file mode 100644 (file)
index 0000000..91ea82a
--- /dev/null
@@ -0,0 +1,27 @@
+error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `<-`
+  --> $DIR/bad.rs:5:7
+   |
+LL |     x <- y;
+   |       ^^ expected one of 8 possible tokens here
+
+error: expected expression, found keyword `in`
+  --> $DIR/bad.rs:11:5
+   |
+LL |     in(foo) { bar };
+   |     ^^ expected expression
+
+error[E0308]: mismatched types
+  --> $DIR/bad.rs:5:5
+   |
+LL | fn foo() {
+   |          - possibly return type missing here?
+LL |     let (x, y) = (0, 0);
+LL |     x <- y;
+   |     ^ expected (), found integer
+   |
+   = note: expected type `()`
+              found type `{integer}`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
index 9926fcc0858e546b13e349f0dbe19cf262ae2f11..1adb4429ec7d0b426041cc57ddcbcbaad5c84540 100644 (file)
@@ -5,9 +5,6 @@ LL |     for i in in 1..2 {
    |           ---^^
    |           |
    |           help: remove the duplicated `in`
-   |
-   = note: if you meant to use emplacement syntax, it is obsolete (for now, anyway)
-   = note: for more information on the status of emplacement syntax, see <https://github.com/rust-lang/rust/issues/27779#issuecomment-378416911>
 
 error: aborting due to previous error
 
index 04cd43d0b10714af5d02205711dbf05ea34b29e8..f95005cd914838605d401bc8ff71edb7c4f1f2ee 100644 (file)
@@ -1,6 +1,6 @@
 enum X {
     A = 3,
-    //~^ ERROR discriminator values can only be used with a field-less enum
+    //~^ ERROR custom discriminant values are not allowed in enums with fields
     B(usize)
 }
 
index 57caa3372a629dc076a17a7cc51f0e015c4f54ef..37abd0ff5e1f49cb8248347aae0f20f7d6bfb6d2 100644 (file)
@@ -1,8 +1,11 @@
-error: discriminator values can only be used with a field-less enum
+error: custom discriminant values are not allowed in enums with fields
   --> $DIR/issue-17383.rs:2:9
    |
 LL |     A = 3,
-   |         ^ only valid in field-less enums
+   |         ^ invalid custom discriminant
+LL |
+LL |     B(usize)
+   |     -------- variant with a field defined here
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/macro/bad-macro-argument.rs b/src/test/ui/parser/macro/bad-macro-argument.rs
new file mode 100644 (file)
index 0000000..4b6d238
--- /dev/null
@@ -0,0 +1,4 @@
+fn main() {
+    let message = "world";
+    println!("Hello, {}", message/); //~ ERROR expected expression
+}
diff --git a/src/test/ui/parser/macro/bad-macro-argument.stderr b/src/test/ui/parser/macro/bad-macro-argument.stderr
new file mode 100644 (file)
index 0000000..3cd8acc
--- /dev/null
@@ -0,0 +1,8 @@
+error: expected expression, found end of macro arguments
+  --> $DIR/bad-macro-argument.rs:3:35
+   |
+LL |     println!("Hello, {}", message/);
+   |                                   ^ expected expression
+
+error: aborting due to previous error
+
index 83a3b727982b5401e648ab537302ba7ad03dc6a7..305edc4ad5a0489d3e178abfad86a064ba651ec2 100644 (file)
@@ -1,11 +1,12 @@
 enum Color {
     Red = 0xff0000,
-    //~^ ERROR discriminator values can only be used with a field-less enum
+    //~^ ERROR custom discriminant values are not allowed in enums with fields
     Green = 0x00ff00,
     Blue = 0x0000ff,
     Black = 0x000000,
     White = 0xffffff,
     Other(usize),
+    Other2(usize, usize),
 }
 
 fn main() {}
index 884e9672cb12d205af85672ddc3c4dfeba054739..2d3b28395312438439814cdf3067eb0c6a8aab5c 100644 (file)
@@ -1,17 +1,21 @@
-error: discriminator values can only be used with a field-less enum
+error: custom discriminant values are not allowed in enums with fields
   --> $DIR/tag-variant-disr-non-nullary.rs:2:11
    |
 LL |     Red = 0xff0000,
-   |           ^^^^^^^^ only valid in field-less enums
+   |           ^^^^^^^^ invalid custom discriminant
 LL |
 LL |     Green = 0x00ff00,
-   |             ^^^^^^^^ only valid in field-less enums
+   |             ^^^^^^^^ invalid custom discriminant
 LL |     Blue = 0x0000ff,
-   |            ^^^^^^^^ only valid in field-less enums
+   |            ^^^^^^^^ invalid custom discriminant
 LL |     Black = 0x000000,
-   |             ^^^^^^^^ only valid in field-less enums
+   |             ^^^^^^^^ invalid custom discriminant
 LL |     White = 0xffffff,
-   |             ^^^^^^^^ only valid in field-less enums
+   |             ^^^^^^^^ invalid custom discriminant
+LL |     Other(usize),
+   |     ------------ variant with a field defined here
+LL |     Other2(usize, usize),
+   |     -------------------- variant with fields defined here
 
 error: aborting due to previous error
 
index ac6fed1558f5392f8404ff590a5000518af56842..2edd78ec8ab3d3065b2b095293c36beca4b2e805 100644 (file)
@@ -1,7 +1,6 @@
 fn main() {
     let x = -5;
-    if x<-1 {
-    //~^ ERROR emplacement syntax is obsolete
+    if x<-1 { //~ ERROR expected `{`, found `<-`
         println!("ok");
     }
 }
index 350aaa9bdddc1a7f8fd24f8b830a9235cbb40dda..e90acce168e47a0cd402c43dfe81462436e6e7d8 100644 (file)
@@ -1,14 +1,10 @@
-error: emplacement syntax is obsolete (for now, anyway)
-  --> $DIR/placement-syntax.rs:3:8
+error: expected `{`, found `<-`
+  --> $DIR/placement-syntax.rs:3:9
    |
 LL |     if x<-1 {
-   |        ^^^^
-   |
-   = note: for more information, see <https://github.com/rust-lang/rust/issues/27779#issuecomment-378416911>
-help: if you meant to write a comparison against a negative value, add a space in between `<` and `-`
-   |
-LL |     if x< -1 {
-   |         ^^^
+   |     --  ^^ expected `{`
+   |     |
+   |     this `if` statement has a condition, but no block
 
 error: aborting due to previous error
 
index c609cae90240ced7031f9e90a659c469a9411ad3..fab98f0ce5ebe68f1411d3681d994d2049785462 100644 (file)
@@ -9,7 +9,7 @@
 
 fn main() {
     let _ = #[no_output] "Hello, world!";
-    //~^ ERROR expected expression, found `<eof>`
+    //~^ ERROR expected expression, found end of macro arguments
 
     let _ = #[duplicate] "Hello, world!";
     //~^ ERROR macro expansion ignores token `,` and any following
index 5d2fb59ff1f66b0051d2f478463afd47a9b826da..49fe0bd0fcfe280cd9e1f9a81c6ed735ca4bdb7a 100644 (file)
@@ -1,4 +1,4 @@
-error: expected expression, found `<eof>`
+error: expected expression, found end of macro arguments
   --> $DIR/attr-invalid-exprs.rs:11:13
    |
 LL |     let _ = #[no_output] "Hello, world!";
diff --git a/src/test/ui/suggestions/mut-ref-reassignment.rs b/src/test/ui/suggestions/mut-ref-reassignment.rs
new file mode 100644 (file)
index 0000000..1428324
--- /dev/null
@@ -0,0 +1,17 @@
+fn suggestion(opt: &mut Option<String>) {
+    opt = None; //~ ERROR mismatched types
+}
+
+fn no_suggestion(opt: &mut Result<String, ()>) {
+    opt = None //~ ERROR mismatched types
+}
+
+fn suggestion2(opt: &mut Option<String>) {
+    opt = Some(String::new())//~ ERROR mismatched types
+}
+
+fn no_suggestion2(opt: &mut Option<String>) {
+    opt = Some(42)//~ ERROR mismatched types
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/mut-ref-reassignment.stderr b/src/test/ui/suggestions/mut-ref-reassignment.stderr
new file mode 100644 (file)
index 0000000..66b78a1
--- /dev/null
@@ -0,0 +1,47 @@
+error[E0308]: mismatched types
+  --> $DIR/mut-ref-reassignment.rs:2:11
+   |
+LL |     opt = None;
+   |           ^^^^ expected mutable reference, found enum `std::option::Option`
+   |
+   = note: expected type `&mut std::option::Option<std::string::String>`
+              found type `std::option::Option<_>`
+help: consider dereferencing here to assign to the mutable borrowed piece of memory
+   |
+LL |     *opt = None;
+   |     ^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/mut-ref-reassignment.rs:6:11
+   |
+LL |     opt = None
+   |           ^^^^ expected mutable reference, found enum `std::option::Option`
+   |
+   = note: expected type `&mut std::result::Result<std::string::String, ()>`
+              found type `std::option::Option<_>`
+
+error[E0308]: mismatched types
+  --> $DIR/mut-ref-reassignment.rs:10:11
+   |
+LL |     opt = Some(String::new())
+   |           ^^^^^^^^^^^^^^^^^^^ expected mutable reference, found enum `std::option::Option`
+   |
+   = note: expected type `&mut std::option::Option<std::string::String>`
+              found type `std::option::Option<std::string::String>`
+help: consider dereferencing here to assign to the mutable borrowed piece of memory
+   |
+LL |     *opt = Some(String::new())
+   |     ^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/mut-ref-reassignment.rs:14:11
+   |
+LL |     opt = Some(42)
+   |           ^^^^^^^^ expected mutable reference, found enum `std::option::Option`
+   |
+   = note: expected type `&mut std::option::Option<std::string::String>`
+              found type `std::option::Option<{integer}>`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
index 3c878410f77107370e5b024dfedb81ccbc55dd09..56ab1a270a75d4f3db5788345d58cc104841ac5f 100644 (file)
@@ -19,4 +19,5 @@ fn next(&mut self) -> Option<Void> {
 fn main() {
     for _ in unimplemented!() as Void {}
     //~^ ERROR unreachable pattern
+    //~^^ ERROR unreachable pattern
 }
index d2f255c3e104dca77ddd9a39f6af2fd07d314757..254d1178d142e39c67ddab6de71d5cc9270cae3e 100644 (file)
@@ -10,5 +10,11 @@ note: lint level defined here
 LL | #![deny(unreachable_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to previous error
+error: unreachable pattern
+  --> $DIR/unreachable-loop-patterns.rs:20:14
+   |
+LL |     for _ in unimplemented!() as Void {}
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
 
index 3126b44f0d61846a835aefcad4367106c4cf4759..14035eedbb44b4d15af533dbc03c0e2bcde1fab6 100644 (file)
@@ -61,7 +61,7 @@ struct Test {
     Test {
         name: "webrender",
         repo: "https://github.com/servo/webrender",
-        sha: "57250b2b8fa63934f80e5376a29f7dcb3f759ad6",
+        sha: "cdadd068f4c7218bd983d856981d561e605270ab",
         lock: None,
         packages: &[],
     },
index 4699dee1716a9ac690bdccc662adb628dfaa27ef..722979c3c1402b3a2ff070401067e2ef6a3f6ad3 100644 (file)
@@ -1,5 +1,6 @@
 pub use self::Mode::*;
 
+use std::ffi::OsString;
 use std::fmt;
 use std::path::{Path, PathBuf};
 use std::str::FromStr;
@@ -15,7 +16,8 @@ pub enum Mode {
     RunPass,
     RunPassValgrind,
     Pretty,
-    DebugInfoBoth,
+    DebugInfoCdb,
+    DebugInfoGdbLldb,
     DebugInfoGdb,
     DebugInfoLldb,
     Codegen,
@@ -33,9 +35,10 @@ impl Mode {
     pub fn disambiguator(self) -> &'static str {
         // Run-pass and pretty run-pass tests could run concurrently, and if they do,
         // they need to keep their output segregated. Same is true for debuginfo tests that
-        // can be run both on gdb and lldb.
+        // can be run on cdb, gdb, and lldb.
         match self {
             Pretty => ".pretty",
+            DebugInfoCdb => ".cdb",
             DebugInfoGdb => ".gdb",
             DebugInfoLldb => ".lldb",
             _ => "",
@@ -52,7 +55,8 @@ fn from_str(s: &str) -> Result<Mode, ()> {
             "run-pass" => Ok(RunPass),
             "run-pass-valgrind" => Ok(RunPassValgrind),
             "pretty" => Ok(Pretty),
-            "debuginfo-both" => Ok(DebugInfoBoth),
+            "debuginfo-cdb" => Ok(DebugInfoCdb),
+            "debuginfo-gdb+lldb" => Ok(DebugInfoGdbLldb),
             "debuginfo-lldb" => Ok(DebugInfoLldb),
             "debuginfo-gdb" => Ok(DebugInfoGdb),
             "codegen" => Ok(Codegen),
@@ -77,7 +81,8 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
             RunPass => "run-pass",
             RunPassValgrind => "run-pass-valgrind",
             Pretty => "pretty",
-            DebugInfoBoth => "debuginfo-both",
+            DebugInfoCdb => "debuginfo-cdb",
+            DebugInfoGdbLldb => "debuginfo-gdb+lldb",
             DebugInfoGdb => "debuginfo-gdb",
             DebugInfoLldb => "debuginfo-lldb",
             Codegen => "codegen",
@@ -198,6 +203,9 @@ pub struct Config {
     /// Host triple for the compiler being invoked
     pub host: String,
 
+    /// Path to / name of the Microsoft Console Debugger (CDB) executable
+    pub cdb: Option<OsString>,
+
     /// Path to / name of the GDB executable
     pub gdb: Option<String>,
 
index dbc477585cbfc0b6e30f0e2d63f864f3df986447..ab5594f36050d6ea85acd1dd64240063611da986 100644 (file)
@@ -57,9 +57,9 @@ enum ParsedNameDirective {
     NoMatch,
     /// Match.
     Match,
-    /// Mode was DebugInfoBoth and this matched gdb.
+    /// Mode was DebugInfoGdbLldb and this matched gdb.
     MatchGdb,
-    /// Mode was DebugInfoBoth and this matched lldb.
+    /// Mode was DebugInfoGdbLldb and this matched lldb.
     MatchLldb,
 }
 
@@ -81,13 +81,17 @@ pub fn from_file(config: &Config, testfile: &Path) -> Self {
             revisions: vec![],
         };
 
-        if config.mode == common::DebugInfoBoth {
+        if config.mode == common::DebugInfoGdbLldb {
             if config.lldb_python_dir.is_none() {
                 props.ignore = props.ignore.no_lldb();
             }
             if config.gdb_version.is_none() {
                 props.ignore = props.ignore.no_gdb();
             }
+        } else if config.mode == common::DebugInfoCdb {
+            if config.cdb.is_none() {
+                props.ignore = Ignore::Ignore;
+            }
         }
 
         let rustc_has_profiler_support = env::var_os("RUSTC_PROFILER_SUPPORT").is_some();
@@ -133,12 +137,12 @@ pub fn from_file(config: &Config, testfile: &Path) -> Self {
                 }
             }
 
-            if (config.mode == common::DebugInfoGdb || config.mode == common::DebugInfoBoth) &&
+            if (config.mode == common::DebugInfoGdb || config.mode == common::DebugInfoGdbLldb) &&
                 props.ignore.can_run_gdb() && ignore_gdb(config, ln) {
                 props.ignore = props.ignore.no_gdb();
             }
 
-            if (config.mode == common::DebugInfoLldb || config.mode == common::DebugInfoBoth) &&
+            if (config.mode == common::DebugInfoLldb || config.mode == common::DebugInfoGdbLldb) &&
                 props.ignore.can_run_lldb() && ignore_lldb(config, ln) {
                 props.ignore = props.ignore.no_lldb();
             }
@@ -804,7 +808,7 @@ fn parse_cfg_name_directive(&self, line: &str, prefix: &str) -> ParsedNameDirect
                 ParsedNameDirective::Match
             } else {
                 match self.mode {
-                    common::DebugInfoBoth => {
+                    common::DebugInfoGdbLldb => {
                         if name == "gdb" {
                             ParsedNameDirective::MatchGdb
                         } else if name == "lldb" {
@@ -813,6 +817,11 @@ fn parse_cfg_name_directive(&self, line: &str, prefix: &str) -> ParsedNameDirect
                             ParsedNameDirective::NoMatch
                         }
                     },
+                    common::DebugInfoCdb => if name == "cdb" {
+                        ParsedNameDirective::Match
+                    } else {
+                        ParsedNameDirective::NoMatch
+                    },
                     common::DebugInfoGdb => if name == "gdb" {
                         ParsedNameDirective::Match
                     } else {
index 442e58bfd74e1408c1ff9b9e31c5ed018ff507de..d0dc9d11d3963ee1910bbe1f9fe7eafbd71d3e8b 100644 (file)
@@ -8,7 +8,7 @@
 use crate::common::CompareMode;
 use crate::common::{expected_output_path, output_base_dir, output_relative_path, UI_EXTENSIONS};
 use crate::common::{Config, TestPaths};
-use crate::common::{DebugInfoBoth, DebugInfoGdb, DebugInfoLldb, Mode, Pretty};
+use crate::common::{DebugInfoCdb, DebugInfoGdbLldb, DebugInfoGdb, DebugInfoLldb, Mode, Pretty};
 use getopts::Options;
 use std::env;
 use std::ffi::OsString;
@@ -164,6 +164,12 @@ pub fn parse_config(args: Vec<String>) -> Config {
         .optopt("", "logfile", "file to log test execution to", "FILE")
         .optopt("", "target", "the target to build for", "TARGET")
         .optopt("", "host", "the host to build for", "HOST")
+        .optopt(
+            "",
+            "cdb",
+            "path to CDB to use for CDB debuginfo tests",
+            "PATH",
+        )
         .optopt(
             "",
             "gdb",
@@ -273,6 +279,7 @@ fn make_absolute(path: PathBuf) -> PathBuf {
 
     let target = opt_str2(matches.opt_str("target"));
     let android_cross_path = opt_path(matches, "android-cross-path");
+    let cdb = analyze_cdb(matches.opt_str("cdb"), &target);
     let (gdb, gdb_version, gdb_native_rust) = analyze_gdb(matches.opt_str("gdb"), &target,
                                                           &android_cross_path);
     let (lldb_version, lldb_native_rust) = extract_lldb_version(matches.opt_str("lldb-version"));
@@ -319,6 +326,7 @@ fn make_absolute(path: PathBuf) -> PathBuf {
         target_rustcflags: matches.opt_str("target-rustcflags"),
         target: target,
         host: opt_str2(matches.opt_str("host")),
+        cdb,
         gdb,
         gdb_version,
         gdb_native_rust,
@@ -421,7 +429,7 @@ pub fn opt_str2(maybestr: Option<String>) -> String {
 
 pub fn run_tests(config: &Config) {
     if config.target.contains("android") {
-        if config.mode == DebugInfoGdb || config.mode == DebugInfoBoth {
+        if config.mode == DebugInfoGdb || config.mode == DebugInfoGdbLldb {
             println!(
                 "{} debug-info test uses tcp 5039 port.\
                  please reserve it",
@@ -440,8 +448,8 @@ pub fn run_tests(config: &Config) {
 
     match config.mode {
         // Note that we don't need to emit the gdb warning when
-        // DebugInfoBoth, so it is ok to list that here.
-        DebugInfoBoth | DebugInfoLldb => {
+        // DebugInfoGdbLldb, so it is ok to list that here.
+        DebugInfoGdbLldb | DebugInfoLldb => {
             if let Some(lldb_version) = config.lldb_version.as_ref() {
                 if is_blacklisted_lldb_version(&lldb_version[..]) {
                     println!(
@@ -470,7 +478,8 @@ pub fn run_tests(config: &Config) {
                 return;
             }
         }
-        _ => { /* proceed */ }
+
+        DebugInfoCdb | _ => { /* proceed */ }
     }
 
     // FIXME(#33435) Avoid spurious failures in codegen-units/partitioning tests.
@@ -667,7 +676,7 @@ pub fn make_test(config: &Config, testpaths: &TestPaths) -> Vec<test::TestDescAn
                     &early_props,
                     revision.map(|s| s.as_str()),
                 )
-                || ((config.mode == DebugInfoBoth ||
+                || ((config.mode == DebugInfoGdbLldb || config.mode == DebugInfoCdb ||
                      config.mode == DebugInfoGdb || config.mode == DebugInfoLldb)
                     && config.target.contains("emscripten"))
                 || (config.mode == DebugInfoGdb && !early_props.ignore.can_run_gdb())
@@ -815,7 +824,7 @@ fn make_test_closure(
     revision: Option<&String>,
 ) -> test::TestFn {
     let mut config = config.clone();
-    if config.mode == DebugInfoBoth {
+    if config.mode == DebugInfoGdbLldb {
         // If both gdb and lldb were ignored, then the test as a whole
         // would be ignored.
         if !ignore.can_run_gdb() {
@@ -841,6 +850,47 @@ fn is_android_gdb_target(target: &String) -> bool {
     }
 }
 
+/// Returns `true` if the given target is a MSVC target for the purpouses of CDB testing.
+fn is_pc_windows_msvc_target(target: &String) -> bool {
+    target.ends_with("-pc-windows-msvc")
+}
+
+fn find_cdb(target: &String) -> Option<OsString> {
+    if !(cfg!(windows) && is_pc_windows_msvc_target(target)) {
+        return None;
+    }
+
+    let pf86 = env::var_os("ProgramFiles(x86)").or(env::var_os("ProgramFiles"))?;
+    let cdb_arch = if cfg!(target_arch="x86") {
+        "x86"
+    } else if cfg!(target_arch="x86_64") {
+        "x64"
+    } else if cfg!(target_arch="aarch64") {
+        "arm64"
+    } else if cfg!(target_arch="arm") {
+        "arm"
+    } else {
+        return None; // No compatible CDB.exe in the Windows 10 SDK
+    };
+
+    let mut path = PathBuf::new();
+    path.push(pf86);
+    path.push(r"Windows Kits\10\Debuggers"); // We could check 8.1 etc. too?
+    path.push(cdb_arch);
+    path.push(r"cdb.exe");
+
+    if !path.exists() {
+        return None;
+    }
+
+    Some(path.into_os_string())
+}
+
+/// Returns Path to CDB
+fn analyze_cdb(cdb: Option<String>, target: &String) -> Option<OsString> {
+    cdb.map(|s| OsString::from(s)).or(find_cdb(target))
+}
+
 /// Returns (Path to GDB, GDB Version, GDB has Rust Support)
 fn analyze_gdb(gdb: Option<String>, target: &String, android_cross_path: &PathBuf)
                -> (Option<String>, Option<u32>, bool) {
index 2082de7cbce3454e83759ba5659ef7d01ada246b..d87bd66a1ac70ceab4dd9f35cb7b4c0dd4367bb1 100644 (file)
@@ -3,7 +3,8 @@
 use crate::common::CompareMode;
 use crate::common::{expected_output_path, UI_EXTENSIONS, UI_FIXED, UI_STDERR, UI_STDOUT};
 use crate::common::{output_base_dir, output_base_name, output_testname_unique};
-use crate::common::{Codegen, CodegenUnits, DebugInfoBoth, DebugInfoGdb, DebugInfoLldb, Rustdoc};
+use crate::common::{Codegen, CodegenUnits, Rustdoc};
+use crate::common::{DebugInfoCdb, DebugInfoGdbLldb, DebugInfoGdb, DebugInfoLldb};
 use crate::common::{CompileFail, Pretty, RunFail, RunPass, RunPassValgrind};
 use crate::common::{Config, TestPaths};
 use crate::common::{Incremental, MirOpt, RunMake, Ui, JsDocTest, Assembly};
@@ -242,7 +243,11 @@ pub fn compute_stamp_hash(config: &Config) -> String {
     let mut hash = DefaultHasher::new();
     config.stage_id.hash(&mut hash);
 
-    if config.mode == DebugInfoGdb || config.mode == DebugInfoBoth {
+    if config.mode == DebugInfoCdb {
+        config.cdb.hash(&mut hash);
+    }
+
+    if config.mode == DebugInfoGdb || config.mode == DebugInfoGdbLldb {
         match config.gdb {
             None => env::var_os("PATH").hash(&mut hash),
             Some(ref s) if s.is_empty() => env::var_os("PATH").hash(&mut hash),
@@ -250,7 +255,7 @@ pub fn compute_stamp_hash(config: &Config) -> String {
         };
     }
 
-    if config.mode == DebugInfoLldb || config.mode == DebugInfoBoth {
+    if config.mode == DebugInfoLldb || config.mode == DebugInfoGdbLldb {
         env::var_os("PATH").hash(&mut hash);
         env::var_os("PYTHONPATH").hash(&mut hash);
     }
@@ -285,10 +290,11 @@ fn run_revision(&self) {
             RunFail => self.run_rfail_test(),
             RunPassValgrind => self.run_valgrind_test(),
             Pretty => self.run_pretty_test(),
-            DebugInfoBoth => {
+            DebugInfoGdbLldb => {
                 self.run_debuginfo_gdb_test();
                 self.run_debuginfo_lldb_test();
             },
+            DebugInfoCdb => self.run_debuginfo_cdb_test(),
             DebugInfoGdb => self.run_debuginfo_gdb_test(),
             DebugInfoLldb => self.run_debuginfo_lldb_test(),
             Codegen => self.run_codegen_test(),
@@ -656,6 +662,95 @@ fn typecheck_source(&self, src: String) -> ProcRes {
         self.compose_and_run_compiler(rustc, Some(src))
     }
 
+    fn run_debuginfo_cdb_test(&self) {
+        assert!(self.revision.is_none(), "revisions not relevant here");
+
+        let config = Config {
+            target_rustcflags: self.cleanup_debug_info_options(&self.config.target_rustcflags),
+            host_rustcflags: self.cleanup_debug_info_options(&self.config.host_rustcflags),
+            mode: DebugInfoCdb,
+            ..self.config.clone()
+        };
+
+        let test_cx = TestCx {
+            config: &config,
+            ..*self
+        };
+
+        test_cx.run_debuginfo_cdb_test_no_opt();
+    }
+
+    fn run_debuginfo_cdb_test_no_opt(&self) {
+        // compile test file (it should have 'compile-flags:-g' in the header)
+        let compile_result = self.compile_test();
+        if !compile_result.status.success() {
+            self.fatal_proc_rec("compilation failed!", &compile_result);
+        }
+
+        let exe_file = self.make_exe_name();
+
+        let prefixes = {
+            static PREFIXES: &'static [&'static str] = &["cdb", "cdbg"];
+            // No "native rust support" variation for CDB yet.
+            PREFIXES
+        };
+
+        // Parse debugger commands etc from test files
+        let DebuggerCommands {
+            commands,
+            check_lines,
+            breakpoint_lines,
+            ..
+        } = self.parse_debugger_commands(prefixes);
+
+        // https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/debugger-commands
+        let mut script_str = String::with_capacity(2048);
+        script_str.push_str("version\n"); // List CDB (and more) version info in test output
+        script_str.push_str(".nvlist\n"); // List loaded `*.natvis` files, bulk of custom MSVC debug
+
+        // Set breakpoints on every line that contains the string "#break"
+        let source_file_name = self.testpaths.file.file_name().unwrap().to_string_lossy();
+        for line in &breakpoint_lines {
+            script_str.push_str(&format!(
+                "bp `{}:{}`\n",
+                source_file_name, line
+            ));
+        }
+
+        // Append the other `cdb-command:`s
+        for line in &commands {
+            script_str.push_str(line);
+            script_str.push_str("\n");
+        }
+
+        script_str.push_str("\nqq\n"); // Quit the debugger (including remote debugger, if any)
+
+        // Write the script into a file
+        debug!("script_str = {}", script_str);
+        self.dump_output_file(&script_str, "debugger.script");
+        let debugger_script = self.make_out_name("debugger.script");
+
+        let cdb_path = &self.config.cdb.as_ref().unwrap();
+        let mut cdb = Command::new(cdb_path);
+        cdb
+            .arg("-lines") // Enable source line debugging.
+            .arg("-cf").arg(&debugger_script)
+            .arg(&exe_file);
+
+        let debugger_run_result = self.compose_and_run(
+            cdb,
+            self.config.run_lib_path.to_str().unwrap(),
+            None, // aux_path
+            None  // input
+        );
+
+        if !debugger_run_result.status.success() {
+            self.fatal_proc_rec("Error while running CDB", &debugger_run_result);
+        }
+
+        self.check_debugger_output(&debugger_run_result, &check_lines);
+    }
+
     fn run_debuginfo_gdb_test(&self) {
         assert!(self.revision.is_none(), "revisions not relevant here");
 
@@ -1429,7 +1524,7 @@ fn compile_test(&self) -> ProcRes {
             RunPass | Ui => self.should_run_successfully(),
             Incremental => self.revision.unwrap().starts_with("r"),
             RunFail | RunPassValgrind | MirOpt |
-            DebugInfoBoth | DebugInfoGdb | DebugInfoLldb => true,
+            DebugInfoCdb | DebugInfoGdbLldb | DebugInfoGdb | DebugInfoLldb => true,
             _ => false,
         };
         let output_file = if will_execute {
@@ -1870,8 +1965,8 @@ fn make_compile_args(&self, input_file: &Path, output_file: TargetLocation) -> C
 
                 rustc.arg(dir_opt);
             }
-            RunFail | RunPassValgrind | Pretty | DebugInfoBoth | DebugInfoGdb | DebugInfoLldb
-            | Codegen | Rustdoc | RunMake | CodegenUnits | JsDocTest | Assembly => {
+            RunFail | RunPassValgrind | Pretty | DebugInfoCdb | DebugInfoGdbLldb | DebugInfoGdb
+            | DebugInfoLldb | Codegen | Rustdoc | RunMake | CodegenUnits | JsDocTest | Assembly => {
                 // do not use JSON output
             }
         }