From 71e50180713eaaaa3bedc827e6890cede03baa0b Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Wed, 30 Oct 2019 12:26:02 +0100 Subject: [PATCH 01/28] ci: replace MINGW_URL with CUSTOM_MINGW=1 This commit replaces the mirrors base URL contained in the MINGW_URL with a CUSTOM_MINGW=1 environment variable. The mirrors base URL will be fetched instead through the MIRRORS_BASE environment variable, defined in src/ci/shared.sh. --- src/ci/azure-pipelines/auto.yml | 12 ++++++------ src/ci/scripts/install-clang.sh | 2 +- src/ci/scripts/install-mingw.sh | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/ci/azure-pipelines/auto.yml b/src/ci/azure-pipelines/auto.yml index 836f81a781656..f69808c3702bc 100644 --- a/src/ci/azure-pipelines/auto.yml +++ b/src/ci/azure-pipelines/auto.yml @@ -284,7 +284,7 @@ jobs: MSYS_BITS: 32 RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu SCRIPT: make ci-mingw-subset-1 - MINGW_URL: https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc + CUSTOM_MINGW: 1 MINGW_ARCHIVE: i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z MINGW_DIR: mingw32 # FIXME(#59637) @@ -294,14 +294,14 @@ jobs: MSYS_BITS: 32 RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu SCRIPT: make ci-mingw-subset-2 - MINGW_URL: https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc + CUSTOM_MINGW: 1 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-mingw-subset-1 RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu - MINGW_URL: https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc + CUSTOM_MINGW: 1 MINGW_ARCHIVE: x86_64-6.3.0-release-posix-seh-rt_v5-rev2.7z MINGW_DIR: mingw64 # FIXME(#59637) @@ -311,7 +311,7 @@ jobs: MSYS_BITS: 64 SCRIPT: make ci-mingw-subset-2 RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu - MINGW_URL: https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc + CUSTOM_MINGW: 1 MINGW_ARCHIVE: x86_64-6.3.0-release-posix-seh-rt_v5-rev2.7z MINGW_DIR: mingw64 @@ -340,7 +340,7 @@ jobs: MSYS_BITS: 32 RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-full-tools --enable-profiler SCRIPT: python x.py dist - MINGW_URL: https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc + CUSTOM_MINGW: 1 MINGW_ARCHIVE: i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z MINGW_DIR: mingw32 DIST_REQUIRE_ALL_TOOLS: 1 @@ -349,7 +349,7 @@ jobs: MSYS_BITS: 64 SCRIPT: python x.py dist RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-full-tools --enable-profiler - MINGW_URL: https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc + CUSTOM_MINGW: 1 MINGW_ARCHIVE: x86_64-6.3.0-release-posix-seh-rt_v5-rev2.7z MINGW_DIR: mingw64 DIST_REQUIRE_ALL_TOOLS: 1 diff --git a/src/ci/scripts/install-clang.sh b/src/ci/scripts/install-clang.sh index b1e9bf92ca5d2..f0179994e8e4c 100755 --- a/src/ci/scripts/install-clang.sh +++ b/src/ci/scripts/install-clang.sh @@ -17,7 +17,7 @@ if isMacOS; then # Configure `AR` specifically so rustbuild doesn't try to infer it as # `clang-ar` by accident. ciCommandSetEnv AR "ar" -elif isWindows && [[ -z ${MINGW_URL+x} ]]; then +elif isWindows && [[ ${CUSTOM_MINGW-0} -ne 1 ]]; then # If we're compiling for MSVC then we, like most other distribution builders, # switch to clang as the compiler. This'll allow us eventually to enable LTO # amongst LLVM and rustc. Note that we only do this on MSVC as I don't think diff --git a/src/ci/scripts/install-mingw.sh b/src/ci/scripts/install-mingw.sh index b4e8b889f520a..8b11e59fb639d 100755 --- a/src/ci/scripts/install-mingw.sh +++ b/src/ci/scripts/install-mingw.sh @@ -28,7 +28,7 @@ IFS=$'\n\t' source "$(cd "$(dirname "$0")" && pwd)/../shared.sh" if isWindows; then - if [[ -z "${MINGW_URL+x}" ]]; then + if [[ "${CUSTOM_MINGW-0}" -ne 1 ]]; then arch=i686 if [ "$MSYS_BITS" = "64" ]; then arch=x86_64 @@ -37,9 +37,9 @@ if isWindows; then mingw-w64-$arch-gcc mingw-w64-$arch-python2 ciCommandAddPath "${SYSTEM_WORKFOLDER}/msys2/mingw${MSYS_BITS}/bin" else - curl -o mingw.7z "${MINGW_URL}/${MINGW_ARCHIVE}" + curl -o mingw.7z "${MIRRORS_BASE}/${MINGW_ARCHIVE}" 7z x -y mingw.7z > /dev/null - curl -o "${MINGW_DIR}/bin/gdborig.exe" "${MINGW_URL}/2017-04-20-${MSYS_BITS}bit-gdborig.exe" + curl -o "${MINGW_DIR}/bin/gdborig.exe" "${MIRRORS_BASE}/2017-04-20-${MSYS_BITS}bit-gdborig.exe" ciCommandAddPath "$(pwd)/${MINGW_DIR}/bin" fi fi From 53c2c04d63b3c043ec5b1b4f401e04868a1139a4 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Wed, 30 Oct 2019 12:35:55 +0100 Subject: [PATCH 02/28] ci: remove the MINGW_DIR and MINGW_ARCHIVE env vars --- src/ci/azure-pipelines/auto.yml | 12 ------------ src/ci/scripts/install-mingw.sh | 15 ++++++++++++--- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/src/ci/azure-pipelines/auto.yml b/src/ci/azure-pipelines/auto.yml index f69808c3702bc..74fb237eebd1e 100644 --- a/src/ci/azure-pipelines/auto.yml +++ b/src/ci/azure-pipelines/auto.yml @@ -285,8 +285,6 @@ jobs: RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu SCRIPT: make ci-mingw-subset-1 CUSTOM_MINGW: 1 - 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 @@ -295,15 +293,11 @@ jobs: RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu SCRIPT: make ci-mingw-subset-2 CUSTOM_MINGW: 1 - 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-mingw-subset-1 RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu CUSTOM_MINGW: 1 - 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 @@ -312,8 +306,6 @@ jobs: SCRIPT: make ci-mingw-subset-2 RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu CUSTOM_MINGW: 1 - 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: @@ -341,8 +333,6 @@ jobs: RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-full-tools --enable-profiler SCRIPT: python x.py dist CUSTOM_MINGW: 1 - 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: @@ -350,8 +340,6 @@ jobs: SCRIPT: python x.py dist RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-full-tools --enable-profiler CUSTOM_MINGW: 1 - MINGW_ARCHIVE: x86_64-6.3.0-release-posix-seh-rt_v5-rev2.7z - MINGW_DIR: mingw64 DIST_REQUIRE_ALL_TOOLS: 1 DEPLOY: 1 diff --git a/src/ci/scripts/install-mingw.sh b/src/ci/scripts/install-mingw.sh index 8b11e59fb639d..631d5e575a5dc 100755 --- a/src/ci/scripts/install-mingw.sh +++ b/src/ci/scripts/install-mingw.sh @@ -27,6 +27,9 @@ IFS=$'\n\t' source "$(cd "$(dirname "$0")" && pwd)/../shared.sh" +MINGW_ARCHIVE_32="i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z" +MINGW_ARCHIVE_64="x86_64-6.3.0-release-posix-seh-rt_v5-rev2.7z" + if isWindows; then if [[ "${CUSTOM_MINGW-0}" -ne 1 ]]; then arch=i686 @@ -37,9 +40,15 @@ if isWindows; then mingw-w64-$arch-gcc mingw-w64-$arch-python2 ciCommandAddPath "${SYSTEM_WORKFOLDER}/msys2/mingw${MSYS_BITS}/bin" else - curl -o mingw.7z "${MIRRORS_BASE}/${MINGW_ARCHIVE}" + mingw_archive="${MINGW_ARCHIVE_32}" + if [[ "${MSYS_BITS}" = "64" ]]; then + mingw_archive="${MINGW_ARCHIVE_64}" + fi + mingw_dir="mingw${MSYS_BITS}" + + curl -o mingw.7z "${MIRRORS_BASE}/${mingw_archive}" 7z x -y mingw.7z > /dev/null - curl -o "${MINGW_DIR}/bin/gdborig.exe" "${MIRRORS_BASE}/2017-04-20-${MSYS_BITS}bit-gdborig.exe" - ciCommandAddPath "$(pwd)/${MINGW_DIR}/bin" + curl -o "${mingw_dir}/bin/gdborig.exe" "${MIRRORS_BASE}/2017-04-20-${MSYS_BITS}bit-gdborig.exe" + ciCommandAddPath "$(pwd)/${mingw_dir}/bin" fi fi From af6b26646b41e1b9614be12ae126f7033a3fa908 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Wed, 30 Oct 2019 12:45:03 +0100 Subject: [PATCH 03/28] ci: remove the MSYS_BITS env var --- src/ci/azure-pipelines/auto.yml | 17 --------------- src/ci/azure-pipelines/steps/run.yml | 14 ++++++------ src/ci/azure-pipelines/try.yml | 1 - src/ci/scripts/install-mingw.sh | 32 ++++++++++++++++++---------- 4 files changed, 28 insertions(+), 36 deletions(-) diff --git a/src/ci/azure-pipelines/auto.yml b/src/ci/azure-pipelines/auto.yml index 74fb237eebd1e..946eb483c2946 100644 --- a/src/ci/azure-pipelines/auto.yml +++ b/src/ci/azure-pipelines/auto.yml @@ -223,25 +223,21 @@ jobs: matrix: # 32/64 bit MSVC tests x86_64-msvc-1: - MSYS_BITS: 64 RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-profiler SCRIPT: make ci-subset-1 # FIXME(#59637) NO_DEBUG_ASSERTIONS: 1 NO_LLVM_ASSERTIONS: 1 x86_64-msvc-2: - MSYS_BITS: 64 RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-profiler SCRIPT: make ci-subset-2 i686-msvc-1: - MSYS_BITS: 32 RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc SCRIPT: make ci-subset-1 # FIXME(#59637) NO_DEBUG_ASSERTIONS: 1 NO_LLVM_ASSERTIONS: 1 i686-msvc-2: - MSYS_BITS: 32 RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc SCRIPT: make ci-subset-2 # FIXME(#59637) @@ -249,11 +245,9 @@ jobs: NO_LLVM_ASSERTIONS: 1 # MSVC aux tests x86_64-msvc-aux: - MSYS_BITS: 64 RUST_CHECK_TARGET: check-aux EXCLUDE_CARGO=1 RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc x86_64-msvc-cargo: - MSYS_BITS: 64 SCRIPT: python x.py test src/tools/cargotest src/tools/cargo RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc VCVARS_BAT: vcvars64.bat @@ -262,10 +256,8 @@ jobs: NO_LLVM_ASSERTIONS: 1 # MSVC tools tests x86_64-msvc-tools: - MSYS_BITS: 64 SCRIPT: src/ci/docker/x86_64-gnu-tools/checktools.sh x.py /tmp/toolstate/toolstates.json windows RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --save-toolstates=/tmp/toolstate/toolstates.json - DEPLOY_TOOLSTATES_JSON: toolstates-windows.json # 32/64-bit MinGW builds. # @@ -281,7 +273,6 @@ jobs: # came from the mingw-w64 SourceForge download site. Unfortunately # SourceForge is notoriously flaky, so we mirror it on our own infrastructure. i686-mingw-1: - MSYS_BITS: 32 RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu SCRIPT: make ci-mingw-subset-1 CUSTOM_MINGW: 1 @@ -289,12 +280,10 @@ jobs: NO_DEBUG_ASSERTIONS: 1 NO_LLVM_ASSERTIONS: 1 i686-mingw-2: - MSYS_BITS: 32 RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu SCRIPT: make ci-mingw-subset-2 CUSTOM_MINGW: 1 x86_64-mingw-1: - MSYS_BITS: 64 SCRIPT: make ci-mingw-subset-1 RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu CUSTOM_MINGW: 1 @@ -302,14 +291,12 @@ jobs: NO_DEBUG_ASSERTIONS: 1 NO_LLVM_ASSERTIONS: 1 x86_64-mingw-2: - MSYS_BITS: 64 SCRIPT: make ci-mingw-subset-2 RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu CUSTOM_MINGW: 1 # 32/64 bit MSVC and GNU deployment dist-x86_64-msvc: - MSYS_BITS: 64 RUST_CONFIGURE_ARGS: >- --build=x86_64-pc-windows-msvc --target=x86_64-pc-windows-msvc,aarch64-pc-windows-msvc @@ -319,7 +306,6 @@ jobs: DIST_REQUIRE_ALL_TOOLS: 1 DEPLOY: 1 dist-i686-msvc: - MSYS_BITS: 32 RUST_CONFIGURE_ARGS: >- --build=i686-pc-windows-msvc --target=i586-pc-windows-msvc @@ -329,14 +315,12 @@ jobs: DIST_REQUIRE_ALL_TOOLS: 1 DEPLOY: 1 dist-i686-mingw: - MSYS_BITS: 32 RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-full-tools --enable-profiler SCRIPT: python x.py dist CUSTOM_MINGW: 1 DIST_REQUIRE_ALL_TOOLS: 1 DEPLOY: 1 dist-x86_64-mingw: - MSYS_BITS: 64 SCRIPT: python x.py dist RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-full-tools --enable-profiler CUSTOM_MINGW: 1 @@ -345,7 +329,6 @@ jobs: # "alternate" deployment, see .travis.yml for more info dist-x86_64-msvc-alt: - MSYS_BITS: 64 RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-extended --enable-profiler SCRIPT: python x.py dist DEPLOY_ALT: 1 diff --git a/src/ci/azure-pipelines/steps/run.yml b/src/ci/azure-pipelines/steps/run.yml index cef2d235602f1..4d7c68593223a 100644 --- a/src/ci/azure-pipelines/steps/run.yml +++ b/src/ci/azure-pipelines/steps/run.yml @@ -8,6 +8,13 @@ steps: +# Configure our CI_JOB_NAME variable which log analyzers can use for the main +# step to see what's going on. +- bash: | + builder=$(echo $AGENT_JOBNAME | cut -d ' ' -f 2) + echo "##vso[task.setvariable variable=CI_JOB_NAME]$builder" + displayName: Configure Job Name + # Disable automatic line ending conversion, which is enabled by default on # Azure's Windows image. Having the conversion enabled caused regressions both # in our test suite (it broke miri tests) and in the ecosystem, since we @@ -135,13 +142,6 @@ steps: condition: and(succeeded(), not(variables.SKIP_JOB)) displayName: Install awscli -# Configure our CI_JOB_NAME variable which log analyzers can use for the main -# step to see what's going on. -- bash: | - builder=$(echo $AGENT_JOBNAME | cut -d ' ' -f 2) - echo "##vso[task.setvariable variable=CI_JOB_NAME]$builder" - displayName: Configure Job Name - # As a quick smoke check on the otherwise very fast mingw-check linux builder # check our own internal scripts. - bash: | diff --git a/src/ci/azure-pipelines/try.yml b/src/ci/azure-pipelines/try.yml index c919b1023a0eb..fe39ce3e24116 100644 --- a/src/ci/azure-pipelines/try.yml +++ b/src/ci/azure-pipelines/try.yml @@ -72,7 +72,6 @@ jobs: # DEPLOY: 1 # # dist-x86_64-msvc-alt: -# MSYS_BITS: 64 # RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-extended --enable-profiler # SCRIPT: python x.py dist # DEPLOY_ALT: 1 diff --git a/src/ci/scripts/install-mingw.sh b/src/ci/scripts/install-mingw.sh index 631d5e575a5dc..8b579587b9e1f 100755 --- a/src/ci/scripts/install-mingw.sh +++ b/src/ci/scripts/install-mingw.sh @@ -31,24 +31,34 @@ MINGW_ARCHIVE_32="i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z" MINGW_ARCHIVE_64="x86_64-6.3.0-release-posix-seh-rt_v5-rev2.7z" if isWindows; then + case "${CI_JOB_NAME}" in + *i686*) + bits=32 + arch=i686 + mingw_archive="${MINGW_ARCHIVE_32}" + ;; + *x86_64*) + bits=64 + arch=x86_64 + mingw_archive="${MINGW_ARCHIVE_64}" + ;; + *) + echo "src/ci/scripts/install-mingw.sh can't detect the builder's architecture" + echo "please tweak it to recognize the builder named '${CI_JOB_NAME}'" + exit 1 + ;; + esac + if [[ "${CUSTOM_MINGW-0}" -ne 1 ]]; then - arch=i686 - if [ "$MSYS_BITS" = "64" ]; then - arch=x86_64 - fi pacman -S --noconfirm --needed mingw-w64-$arch-toolchain mingw-w64-$arch-cmake \ mingw-w64-$arch-gcc mingw-w64-$arch-python2 - ciCommandAddPath "${SYSTEM_WORKFOLDER}/msys2/mingw${MSYS_BITS}/bin" + ciCommandAddPath "${SYSTEM_WORKFOLDER}/msys2/mingw${bits}/bin" else - mingw_archive="${MINGW_ARCHIVE_32}" - if [[ "${MSYS_BITS}" = "64" ]]; then - mingw_archive="${MINGW_ARCHIVE_64}" - fi - mingw_dir="mingw${MSYS_BITS}" + mingw_dir="mingw${bits}" curl -o mingw.7z "${MIRRORS_BASE}/${mingw_archive}" 7z x -y mingw.7z > /dev/null - curl -o "${mingw_dir}/bin/gdborig.exe" "${MIRRORS_BASE}/2017-04-20-${MSYS_BITS}bit-gdborig.exe" + curl -o "${mingw_dir}/bin/gdborig.exe" "${MIRRORS_BASE}/2017-04-20-${bits}bit-gdborig.exe" ciCommandAddPath "$(pwd)/${mingw_dir}/bin" fi fi From 6104aa77eb97050c3b302a0d13934040de84cda9 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Wed, 30 Oct 2019 18:13:18 +0100 Subject: [PATCH 04/28] ci: extract validate-toolstate into a script --- src/ci/azure-pipelines/steps/run.yml | 13 +------------ src/ci/scripts/validate-toolstate.sh | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 12 deletions(-) create mode 100755 src/ci/scripts/validate-toolstate.sh diff --git a/src/ci/azure-pipelines/steps/run.yml b/src/ci/azure-pipelines/steps/run.yml index 4d7c68593223a..4df315d5d5cd3 100644 --- a/src/ci/azure-pipelines/steps/run.yml +++ b/src/ci/azure-pipelines/steps/run.yml @@ -144,18 +144,7 @@ steps: # As a quick smoke check on the otherwise very fast mingw-check linux builder # check our own internal scripts. -- bash: | - set -e - git clone --depth=1 https://github.com/rust-lang-nursery/rust-toolstate.git - cd rust-toolstate - python2.7 "$BUILD_SOURCESDIRECTORY/src/tools/publish_toolstate.py" "$(git rev-parse HEAD)" "$(git log --format=%s -n1 HEAD)" "" "" - # Only check maintainers if this build is supposed to publish toolstate. - # Builds that are not supposed to publish don't have the access token. - if [ -n "${TOOLSTATE_PUBLISH+is_set}" ]; then - TOOLSTATE_VALIDATE_MAINTAINERS_REPO=rust-lang/rust python2.7 "${BUILD_SOURCESDIRECTORY}/src/tools/publish_toolstate.py" - fi - cd .. - rm -rf rust-toolstate +- bash: src/ci/scripts/validate-toolstate.sh env: TOOLSTATE_REPO_ACCESS_TOKEN: $(TOOLSTATE_REPO_ACCESS_TOKEN) condition: and(succeeded(), not(variables.SKIP_JOB), eq(variables['IMAGE'], 'mingw-check')) diff --git a/src/ci/scripts/validate-toolstate.sh b/src/ci/scripts/validate-toolstate.sh new file mode 100755 index 0000000000000..93e645b24a859 --- /dev/null +++ b/src/ci/scripts/validate-toolstate.sh @@ -0,0 +1,18 @@ +#!/bin/bash +# A quick smoke test to make sure publish_tooolstate.py works. + +set -euo pipefail +IFS=$'\n\t' + +source "$(cd "$(dirname "$0")" && pwd)/../shared.sh" + +git clone --depth=1 https://github.com/rust-lang-nursery/rust-toolstate.git +cd rust-toolstate +python2.7 "${BUILD_SOURCESDIRECTORY}/src/tools/publish_toolstate.py" "$(git rev-parse HEAD)" "$(git log --format=%s -n1 HEAD)" "" "" +# Only check maintainers if this build is supposed to publish toolstate. +# Builds that are not supposed to publish don't have the access token. +if [ -n "${TOOLSTATE_PUBLISH+is_set}" ]; then + TOOLSTATE_VALIDATE_MAINTAINERS_REPO=rust-lang/rust python2.7 "${BUILD_SOURCESDIRECTORY}/src/tools/publish_toolstate.py" +fi +cd .. +rm -rf rust-toolstate From d623c56f4c2eab00a9cb5ba12e9e708430945f1a Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Wed, 30 Oct 2019 18:18:49 +0100 Subject: [PATCH 05/28] ci: extract running the build into a script --- src/ci/azure-pipelines/steps/run.yml | 15 +-------------- src/ci/scripts/run-build-from-ci.sh | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 14 deletions(-) create mode 100755 src/ci/scripts/run-build-from-ci.sh diff --git a/src/ci/azure-pipelines/steps/run.yml b/src/ci/azure-pipelines/steps/run.yml index 4df315d5d5cd3..fe2bee507152d 100644 --- a/src/ci/azure-pipelines/steps/run.yml +++ b/src/ci/azure-pipelines/steps/run.yml @@ -150,22 +150,9 @@ steps: condition: and(succeeded(), not(variables.SKIP_JOB), eq(variables['IMAGE'], 'mingw-check')) displayName: Verify the publish_toolstate script works -- bash: | - set -e - # Remove any preexisting rustup installation since it can interfere - # with the cargotest step and its auto-detection of things like Clippy in - # the environment - rustup self uninstall -y || true - if [ "$IMAGE" = "" ]; then - src/ci/run.sh - else - src/ci/docker/run.sh $IMAGE - fi - #timeoutInMinutes: 180 +- bash: src/ci/scripts/run-build-from-ci.sh timeoutInMinutes: 600 env: - CI: true - SRC: . AWS_ACCESS_KEY_ID: $(SCCACHE_AWS_ACCESS_KEY_ID) AWS_SECRET_ACCESS_KEY: $(SCCACHE_AWS_SECRET_ACCESS_KEY) TOOLSTATE_REPO_ACCESS_TOKEN: $(TOOLSTATE_REPO_ACCESS_TOKEN) diff --git a/src/ci/scripts/run-build-from-ci.sh b/src/ci/scripts/run-build-from-ci.sh new file mode 100755 index 0000000000000..c02117f459de0 --- /dev/null +++ b/src/ci/scripts/run-build-from-ci.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# Start the CI build. You shouldn't run this locally: call either src/ci/run.sh +# or src/ci/docker/run.sh instead. + +set -euo pipefail +IFS=$'\n\t' + +source "$(cd "$(dirname "$0")" && pwd)/../shared.sh" + +export CI="true" +export SRC=. + +# Remove any preexisting rustup installation since it can interfere +# with the cargotest step and its auto-detection of things like Clippy in +# the environment +rustup self uninstall -y || true +if [ -z "${IMAGE+x}" ]; then + src/ci/run.sh +else + src/ci/docker/run.sh "${IMAGE}" +fi From e209ee42e99cd76d7fefd0c53fbd84f0d2123935 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Wed, 30 Oct 2019 18:56:40 +0100 Subject: [PATCH 06/28] ci: extract collecting cpu stats into a script --- src/ci/azure-pipelines/steps/run.yml | 7 ++----- src/ci/scripts/collect-cpu-stats.sh | 9 +++++++++ 2 files changed, 11 insertions(+), 5 deletions(-) create mode 100755 src/ci/scripts/collect-cpu-stats.sh diff --git a/src/ci/azure-pipelines/steps/run.yml b/src/ci/azure-pipelines/steps/run.yml index fe2bee507152d..e856207b17d49 100644 --- a/src/ci/azure-pipelines/steps/run.yml +++ b/src/ci/azure-pipelines/steps/run.yml @@ -31,11 +31,8 @@ steps: - bash: src/ci/scripts/should-skip-this.sh displayName: Decide whether to run this job -# Spawn a background process to collect CPU usage statistics which we'll upload -# at the end of the build. See the comments in the script here for more -# information. -- bash: python src/ci/cpu-usage-over-time.py &> cpu-usage.csv & - displayName: "Collect CPU-usage statistics in the background" +- bash: src/ci/scripts/collect-cpu-stats.sh + displayName: Collect CPU-usage statistics in the background - bash: src/ci/scripts/dump-environment.sh displayName: Show the current environment diff --git a/src/ci/scripts/collect-cpu-stats.sh b/src/ci/scripts/collect-cpu-stats.sh new file mode 100755 index 0000000000000..08065431f9816 --- /dev/null +++ b/src/ci/scripts/collect-cpu-stats.sh @@ -0,0 +1,9 @@ +#!/bin/bash +# Spawn a background process to collect CPU usage statistics which we'll upload +# at the end of the build. See the comments in the script here for more +# information. + +set -euo pipefail +IFS=$'\n\t' + +python src/ci/cpu-usage-over-time.py &> cpu-usage.csv & From c90cc12b0721cc6e80ba62041bf0b82058428580 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Thu, 31 Oct 2019 16:56:11 +0100 Subject: [PATCH 07/28] ci: move validate-toolstate.sh in the mingw-check image The task was already run just there, so this cleans things up. --- src/ci/azure-pipelines/steps/run.yml | 8 -------- src/ci/docker/mingw-check/Dockerfile | 5 ++++- .../mingw-check}/validate-toolstate.sh | 9 +++++---- 3 files changed, 9 insertions(+), 13 deletions(-) rename src/ci/{scripts => docker/mingw-check}/validate-toolstate.sh (57%) diff --git a/src/ci/azure-pipelines/steps/run.yml b/src/ci/azure-pipelines/steps/run.yml index e856207b17d49..214c11fd69024 100644 --- a/src/ci/azure-pipelines/steps/run.yml +++ b/src/ci/azure-pipelines/steps/run.yml @@ -139,14 +139,6 @@ steps: condition: and(succeeded(), not(variables.SKIP_JOB)) displayName: Install awscli -# As a quick smoke check on the otherwise very fast mingw-check linux builder -# check our own internal scripts. -- bash: src/ci/scripts/validate-toolstate.sh - env: - TOOLSTATE_REPO_ACCESS_TOKEN: $(TOOLSTATE_REPO_ACCESS_TOKEN) - condition: and(succeeded(), not(variables.SKIP_JOB), eq(variables['IMAGE'], 'mingw-check')) - displayName: Verify the publish_toolstate script works - - bash: src/ci/scripts/run-build-from-ci.sh timeoutInMinutes: 600 env: diff --git a/src/ci/docker/mingw-check/Dockerfile b/src/ci/docker/mingw-check/Dockerfile index 24e2dea4ca773..b2d96aed2a9e8 100644 --- a/src/ci/docker/mingw-check/Dockerfile +++ b/src/ci/docker/mingw-check/Dockerfile @@ -19,7 +19,10 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh +COPY mingw-check/validate-toolstate.sh /scripts/ + ENV RUN_CHECK_WITH_PARALLEL_QUERIES 1 ENV SCRIPT python2.7 ../x.py check --target=i686-pc-windows-gnu --host=i686-pc-windows-gnu && \ python2.7 ../x.py build --stage 0 src/tools/build-manifest && \ - python2.7 ../x.py test --stage 0 src/tools/compiletest + python2.7 ../x.py test --stage 0 src/tools/compiletest && \ + /scripts/validate-toolstate.sh diff --git a/src/ci/scripts/validate-toolstate.sh b/src/ci/docker/mingw-check/validate-toolstate.sh similarity index 57% rename from src/ci/scripts/validate-toolstate.sh rename to src/ci/docker/mingw-check/validate-toolstate.sh index 93e645b24a859..2ebf1d6d5ae7f 100755 --- a/src/ci/scripts/validate-toolstate.sh +++ b/src/ci/docker/mingw-check/validate-toolstate.sh @@ -4,15 +4,16 @@ set -euo pipefail IFS=$'\n\t' -source "$(cd "$(dirname "$0")" && pwd)/../shared.sh" - +rm -rf rust-toolstate 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)" "" "" +python2.7 "../../src/tools/publish_toolstate.py" "$(git rev-parse HEAD)" \ + "$(git log --format=%s -n1 HEAD)" "" "" # Only check maintainers if this build is supposed to publish toolstate. # Builds that are not supposed to publish don't have the access token. if [ -n "${TOOLSTATE_PUBLISH+is_set}" ]; then - TOOLSTATE_VALIDATE_MAINTAINERS_REPO=rust-lang/rust python2.7 "${BUILD_SOURCESDIRECTORY}/src/tools/publish_toolstate.py" + TOOLSTATE_VALIDATE_MAINTAINERS_REPO=rust-lang/rust python2.7 \ + "../../src/tools/publish_toolstate.py" fi cd .. rm -rf rust-toolstate From 14da85c68e6b5cd8a64a1f2f5ba5cd50c725e38b Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Mon, 4 Nov 2019 17:40:18 +0100 Subject: [PATCH 08/28] ci: move mirrors to https://ci-mirrors.rust-lang.org --- src/ci/docker/armhf-gnu/Dockerfile | 2 +- src/ci/docker/dist-armv7-linux/crosstool-ng.sh | 2 +- src/ci/docker/dist-various-1/install-mips-musl.sh | 2 +- src/ci/docker/dist-various-1/install-mipsel-musl.sh | 2 +- src/ci/docker/dist-various-2/build-wasi-toolchain.sh | 2 +- src/ci/docker/dist-x86_64-linux/build-curl.sh | 2 +- src/ci/docker/dist-x86_64-linux/build-openssl.sh | 2 +- src/ci/docker/dist-x86_64-netbsd/build-netbsd-toolchain.sh | 2 +- src/ci/docker/scripts/freebsd-toolchain.sh | 2 +- src/ci/docker/scripts/sccache.sh | 2 +- src/ci/shared.sh | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/ci/docker/armhf-gnu/Dockerfile b/src/ci/docker/armhf-gnu/Dockerfile index 9493b33698708..5373612279bca 100644 --- a/src/ci/docker/armhf-gnu/Dockerfile +++ b/src/ci/docker/armhf-gnu/Dockerfile @@ -72,7 +72,7 @@ RUN arm-linux-gnueabihf-gcc addentropy.c -o rootfs/addentropy -static # TODO: What is this?! # Source of the file: https://github.com/vfdev-5/qemu-rpi2-vexpress/raw/master/vexpress-v2p-ca15-tc1.dtb -RUN curl -O https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/vexpress-v2p-ca15-tc1.dtb +RUN curl -O https://ci-mirrors.rust-lang.org/rustc/vexpress-v2p-ca15-tc1.dtb COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh diff --git a/src/ci/docker/dist-armv7-linux/crosstool-ng.sh b/src/ci/docker/dist-armv7-linux/crosstool-ng.sh index ae737d9677d87..fb067a79a5c85 100644 --- a/src/ci/docker/dist-armv7-linux/crosstool-ng.sh +++ b/src/ci/docker/dist-armv7-linux/crosstool-ng.sh @@ -1,7 +1,7 @@ set -ex # Mirrored from https://github.com/crosstool-ng/crosstool-ng/archive/crosstool-ng-1.24.0.tar.gz -url="https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/crosstool-ng-1.24.0.tar.gz" +url="https://ci-mirrors.rust-lang.org/rustc/crosstool-ng-1.24.0.tar.gz" curl -Lf $url | tar xzf - cd crosstool-ng-crosstool-ng-1.24.0 ./bootstrap diff --git a/src/ci/docker/dist-various-1/install-mips-musl.sh b/src/ci/docker/dist-various-1/install-mips-musl.sh index 29cfb5d96083e..9584258d23403 100755 --- a/src/ci/docker/dist-various-1/install-mips-musl.sh +++ b/src/ci/docker/dist-various-1/install-mips-musl.sh @@ -5,7 +5,7 @@ mkdir /usr/local/mips-linux-musl # originally from # https://downloads.openwrt.org/snapshots/trunk/ar71xx/generic/ # OpenWrt-Toolchain-ar71xx-generic_gcc-5.3.0_musl-1.1.16.Linux-x86_64.tar.bz2 -URL="https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc" +URL="https://ci-mirrors.rust-lang.org/rustc" FILE="OpenWrt-Toolchain-ar71xx-generic_gcc-5.3.0_musl-1.1.16.Linux-x86_64.tar.bz2" curl -L "$URL/$FILE" | tar xjf - -C /usr/local/mips-linux-musl --strip-components=2 diff --git a/src/ci/docker/dist-various-1/install-mipsel-musl.sh b/src/ci/docker/dist-various-1/install-mipsel-musl.sh index de8c359d16757..50a8e554b1675 100755 --- a/src/ci/docker/dist-various-1/install-mipsel-musl.sh +++ b/src/ci/docker/dist-various-1/install-mipsel-musl.sh @@ -5,7 +5,7 @@ mkdir /usr/local/mipsel-linux-musl # Note that this originally came from: # https://downloads.openwrt.org/snapshots/trunk/malta/generic/ # OpenWrt-Toolchain-malta-le_gcc-5.3.0_musl-1.1.15.Linux-x86_64.tar.bz2 -URL="https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc" +URL="https://ci-mirrors.rust-lang.org/rustc" FILE="OpenWrt-Toolchain-malta-le_gcc-5.3.0_musl-1.1.15.Linux-x86_64.tar.bz2" curl -L "$URL/$FILE" | tar xjf - -C /usr/local/mipsel-linux-musl --strip-components=2 diff --git a/src/ci/docker/dist-various-2/build-wasi-toolchain.sh b/src/ci/docker/dist-various-2/build-wasi-toolchain.sh index c63ea6facca64..17aa78945cf21 100755 --- a/src/ci/docker/dist-various-2/build-wasi-toolchain.sh +++ b/src/ci/docker/dist-various-2/build-wasi-toolchain.sh @@ -5,7 +5,7 @@ set -ex # Originally from https://releases.llvm.org/9.0.0/clang+llvm-9.0.0-x86_64-linux-gnu-ubuntu-14.04.tar.xz -curl https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/clang%2Bllvm-9.0.0-x86_64-linux-gnu-ubuntu-14.04.tar.xz | \ +curl https://ci-mirrors.rust-lang.org/rustc/clang%2Bllvm-9.0.0-x86_64-linux-gnu-ubuntu-14.04.tar.xz | \ tar xJf - export PATH=`pwd`/clang+llvm-9.0.0-x86_64-linux-gnu-ubuntu-14.04/bin:$PATH diff --git a/src/ci/docker/dist-x86_64-linux/build-curl.sh b/src/ci/docker/dist-x86_64-linux/build-curl.sh index 8200bbe2fdce5..a65e3de5cfc26 100755 --- a/src/ci/docker/dist-x86_64-linux/build-curl.sh +++ b/src/ci/docker/dist-x86_64-linux/build-curl.sh @@ -5,7 +5,7 @@ source shared.sh VERSION=7.66.0 -curl https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/curl-$VERSION.tar.xz \ +curl https://ci-mirrors.rust-lang.org/rustc/curl-$VERSION.tar.xz \ | xz --decompress \ | tar xf - diff --git a/src/ci/docker/dist-x86_64-linux/build-openssl.sh b/src/ci/docker/dist-x86_64-linux/build-openssl.sh index be8a6c93945e9..0d9bdf7a09929 100755 --- a/src/ci/docker/dist-x86_64-linux/build-openssl.sh +++ b/src/ci/docker/dist-x86_64-linux/build-openssl.sh @@ -4,7 +4,7 @@ set -ex source shared.sh VERSION=1.0.2k -URL=https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/openssl-$VERSION.tar.gz +URL=https://ci-mirrors.rust-lang.org/rustc/openssl-$VERSION.tar.gz curl $URL | tar xzf - diff --git a/src/ci/docker/dist-x86_64-netbsd/build-netbsd-toolchain.sh b/src/ci/docker/dist-x86_64-netbsd/build-netbsd-toolchain.sh index 797f674b954f2..f8697c698b9fb 100755 --- a/src/ci/docker/dist-x86_64-netbsd/build-netbsd-toolchain.sh +++ b/src/ci/docker/dist-x86_64-netbsd/build-netbsd-toolchain.sh @@ -25,7 +25,7 @@ cd netbsd mkdir -p /x-tools/x86_64-unknown-netbsd/sysroot -URL=https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc +URL=https://ci-mirrors.rust-lang.org/rustc # Originally from ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-$BSD/source/sets/*.tgz curl $URL/2018-03-01-netbsd-src.tgz | tar xzf - diff --git a/src/ci/docker/scripts/freebsd-toolchain.sh b/src/ci/docker/scripts/freebsd-toolchain.sh index 70155e770a960..5670e10be23cf 100755 --- a/src/ci/docker/scripts/freebsd-toolchain.sh +++ b/src/ci/docker/scripts/freebsd-toolchain.sh @@ -59,7 +59,7 @@ done # Originally downloaded from: # https://download.freebsd.org/ftp/releases/${freebsd_arch}/${freebsd_version}-RELEASE/base.txz -URL=https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/2019-04-04-freebsd-${freebsd_arch}-${freebsd_version}-RELEASE-base.txz +URL=https://ci-mirrors.rust-lang.org/rustc/2019-04-04-freebsd-${freebsd_arch}-${freebsd_version}-RELEASE-base.txz curl "$URL" | tar xJf - -C "$sysroot" --wildcards "${files_to_extract[@]}" # Fix up absolute symlinks from the system image. This can be removed diff --git a/src/ci/docker/scripts/sccache.sh b/src/ci/docker/scripts/sccache.sh index efeb0ed0d72d0..552afbfee7c17 100644 --- a/src/ci/docker/scripts/sccache.sh +++ b/src/ci/docker/scripts/sccache.sh @@ -1,6 +1,6 @@ set -ex curl -fo /usr/local/bin/sccache \ - https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/2018-04-02-sccache-x86_64-unknown-linux-musl + https://ci-mirrors.rust-lang.org/rustc/2018-04-02-sccache-x86_64-unknown-linux-musl chmod +x /usr/local/bin/sccache diff --git a/src/ci/shared.sh b/src/ci/shared.sh index 718a5379ae558..862ded0d5dbf0 100644 --- a/src/ci/shared.sh +++ b/src/ci/shared.sh @@ -4,7 +4,7 @@ # `source shared.sh`, hence the invalid shebang and not being # marked as an executable file in git. -export MIRRORS_BASE="https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc" +export MIRRORS_BASE="https://ci-mirrors.rust-lang.org/rustc" # See http://unix.stackexchange.com/questions/82598 # Duplicated in docker/dist-various-2/shared.sh From 85132b20c4b3f6858ea273ec276c4ad9162603f8 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Wed, 6 Nov 2019 18:58:57 +0100 Subject: [PATCH 09/28] ci: download curl and openssl from s3 for dist-x86_64-linux CentOS 5 only supports SSLv3 without SNI, and to get newer protocols working we need to download and compile OpenSSL and cURL from our mirror. Because of that, we can't use the CDN, as CloudFront requires TLSv1 with SNI. This commit changes the dist-x86_64-linux image to bypass the CDN for OpenSSL and cURL. --- src/ci/docker/dist-x86_64-linux/build-curl.sh | 5 ++++- src/ci/docker/dist-x86_64-linux/build-openssl.sh | 6 +++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/ci/docker/dist-x86_64-linux/build-curl.sh b/src/ci/docker/dist-x86_64-linux/build-curl.sh index a65e3de5cfc26..0c7eb5fdac9be 100755 --- a/src/ci/docker/dist-x86_64-linux/build-curl.sh +++ b/src/ci/docker/dist-x86_64-linux/build-curl.sh @@ -5,7 +5,10 @@ source shared.sh VERSION=7.66.0 -curl https://ci-mirrors.rust-lang.org/rustc/curl-$VERSION.tar.xz \ +# This needs to be downloaded directly from S3, it can't go through the CDN. +# That's because the CDN is backed by CloudFront, which requires SNI and TLSv1 +# (without paying an absurd amount of money). +curl https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/curl-$VERSION.tar.xz \ | xz --decompress \ | tar xf - diff --git a/src/ci/docker/dist-x86_64-linux/build-openssl.sh b/src/ci/docker/dist-x86_64-linux/build-openssl.sh index 0d9bdf7a09929..d8f6bdb51b8d5 100755 --- a/src/ci/docker/dist-x86_64-linux/build-openssl.sh +++ b/src/ci/docker/dist-x86_64-linux/build-openssl.sh @@ -4,7 +4,11 @@ set -ex source shared.sh VERSION=1.0.2k -URL=https://ci-mirrors.rust-lang.org/rustc/openssl-$VERSION.tar.gz + +# This needs to be downloaded directly from S3, it can't go through the CDN. +# That's because the CDN is backed by CloudFront, which requires SNI and TLSv1 +# (without paying an absurd amount of money). +URL=https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/openssl-$VERSION.tar.gz curl $URL | tar xzf - From 71cf364c3cf1c6b437be0e9352fa6d3ee8191404 Mon Sep 17 00:00:00 2001 From: Stefan Schindler Date: Fri, 15 Nov 2019 02:02:09 +0100 Subject: [PATCH 10/28] Fix the source code highlighting on source comments --- src/librustdoc/html/static/main.js | 56 +++++++++++++++++------------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 04c0a0f005b82..e992c0b62bf00 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -396,38 +396,46 @@ function getSearchElement() { document.onkeypress = handleShortcut; document.onkeydown = handleShortcut; - document.onclick = function(ev) { - if (hasClass(ev.target, "collapse-toggle")) { - collapseDocs(ev.target, "toggle"); - } else if (hasClass(ev.target.parentNode, "collapse-toggle")) { - collapseDocs(ev.target.parentNode, "toggle"); - } else if (ev.target.tagName === "SPAN" && hasClass(ev.target.parentNode, "line-numbers")) { - var prev_id = 0; - var set_fragment = function(name) { - if (browserSupportsHistoryApi()) { - history.replaceState(null, null, "#" + name); - highlightSourceLines(); - } else { - location.replace("#" + name); - } - }; + var handleSourceHighlight = (function() { + var prev_line_id = 0; + + var set_fragment = function(name) { + if (browserSupportsHistoryApi()) { + history.replaceState(null, null, "#" + name); + highlightSourceLines(); + } else { + location.replace("#" + name); + } + }; - var cur_id = parseInt(ev.target.id, 10); + return function(ev) { + var cur_line_id = parseInt(ev.target.id, 10); - if (ev.shiftKey && prev_id) { - if (prev_id > cur_id) { - var tmp = prev_id; - prev_id = cur_id; - cur_id = tmp; + if (ev.shiftKey && prev_line_id) { + // Swap selection if needed + if (prev_line_id > cur_line_id) { + var tmp = prev_line_id; + prev_line_id = cur_line_id; + cur_line_id = tmp; } - set_fragment(prev_id + "-" + cur_id); + set_fragment(prev_line_id + "-" + cur_line_id); } else { - prev_id = cur_id; + prev_line_id = cur_line_id; - set_fragment(cur_id); + set_fragment(cur_line_id); } + } + })(); + + document.onclick = function(ev) { + if (hasClass(ev.target, "collapse-toggle")) { + collapseDocs(ev.target, "toggle"); + } else if (hasClass(ev.target.parentNode, "collapse-toggle")) { + collapseDocs(ev.target.parentNode, "toggle"); + } else if (ev.target.tagName === "SPAN" && hasClass(ev.target.parentNode, "line-numbers")) { + handleSourceHighlight(ev); } else if (hasClass(getHelpElement(), "hidden") === false) { var help = getHelpElement(); var is_inside_help_popup = ev.target !== help && help.contains(ev.target); From 1bbb8168ec5aa2d03e1b49d5a38eda0300c67da4 Mon Sep 17 00:00:00 2001 From: Stefan Schindler Date: Fri, 15 Nov 2019 02:30:44 +0100 Subject: [PATCH 11/28] Prevent jumps when selecting one or many lines --- src/librustdoc/html/static/main.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index e992c0b62bf00..4db02d58c51ac 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -401,16 +401,21 @@ function getSearchElement() { var prev_line_id = 0; var set_fragment = function(name) { + var x = window.scrollX, + y = window.scrollY; if (browserSupportsHistoryApi()) { history.replaceState(null, null, "#" + name); highlightSourceLines(); } else { location.replace("#" + name); } + // Prevent jumps when selecting one or many lines + window.scrollTo(x, y); }; return function(ev) { var cur_line_id = parseInt(ev.target.id, 10); + ev.preventDefault(); if (ev.shiftKey && prev_line_id) { // Swap selection if needed From 4e1eeb9a4543c9c1bfbbac0b7813520c5b0be5ef Mon Sep 17 00:00:00 2001 From: clemencetbk Date: Sat, 16 Nov 2019 12:04:17 -0500 Subject: [PATCH 12/28] Add explanation message for E0641 --- src/librustc_error_codes/error_codes.rs | 2 +- src/librustc_error_codes/error_codes/E0641.md | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 src/librustc_error_codes/error_codes/E0641.md diff --git a/src/librustc_error_codes/error_codes.rs b/src/librustc_error_codes/error_codes.rs index ffefe51f854f5..f886d06b96d1b 100644 --- a/src/librustc_error_codes/error_codes.rs +++ b/src/librustc_error_codes/error_codes.rs @@ -351,6 +351,7 @@ E0635: include_str!("./error_codes/E0635.md"), E0636: include_str!("./error_codes/E0636.md"), E0638: include_str!("./error_codes/E0638.md"), E0639: include_str!("./error_codes/E0639.md"), +E0641: include_str!("./error_codes/E0641.md"), E0642: include_str!("./error_codes/E0642.md"), E0643: include_str!("./error_codes/E0643.md"), E0644: include_str!("./error_codes/E0644.md"), @@ -585,7 +586,6 @@ E0744: include_str!("./error_codes/E0744.md"), E0634, // type has conflicting packed representaton hints E0637, // "'_" is not a valid lifetime bound E0640, // infer outlives requirements - E0641, // cannot cast to/from a pointer with an unknown kind // E0645, // trait aliases not finished E0657, // `impl Trait` can only capture lifetimes bound at the fn level E0667, // `impl Trait` in projections diff --git a/src/librustc_error_codes/error_codes/E0641.md b/src/librustc_error_codes/error_codes/E0641.md new file mode 100644 index 0000000000000..e39bebce1fea6 --- /dev/null +++ b/src/librustc_error_codes/error_codes/E0641.md @@ -0,0 +1,19 @@ +Attempted to cast to/from a pointer with an unknown kind. + +Erroneous code examples: + +```compile_fail,E0641 +let b = 0 as *const _; // error +``` + +Must give information for type of pointer that is being cast from/to if the +type cannot be inferred. + +``` +// Creating a pointer from reference: type can be inferred +let a = &(String::from("Hello world!")) as *const _; // Ok + +let b = 0 as *const i32; // Ok + +let c: *const i32 = 0 as *const _; // Ok +``` \ No newline at end of file From dc137dd868daaa2d7821997e6a87d49fbb9e4ca8 Mon Sep 17 00:00:00 2001 From: clemencetbk Date: Sat, 16 Nov 2019 12:05:26 -0500 Subject: [PATCH 13/28] Update ui tests --- src/test/ui/issues/issue-45730.stderr | 1 + src/test/ui/order-dependent-cast-inference.stderr | 1 + 2 files changed, 2 insertions(+) diff --git a/src/test/ui/issues/issue-45730.stderr b/src/test/ui/issues/issue-45730.stderr index 4fc1e3835f7ad..3c400d6eefaa8 100644 --- a/src/test/ui/issues/issue-45730.stderr +++ b/src/test/ui/issues/issue-45730.stderr @@ -30,3 +30,4 @@ LL | let x = 0 as *const i32 as *const _ as *mut _; error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0641`. diff --git a/src/test/ui/order-dependent-cast-inference.stderr b/src/test/ui/order-dependent-cast-inference.stderr index 01e59f8f022fd..081038c573acf 100644 --- a/src/test/ui/order-dependent-cast-inference.stderr +++ b/src/test/ui/order-dependent-cast-inference.stderr @@ -10,3 +10,4 @@ LL | let mut y = 0 as *const _; error: aborting due to previous error +For more information about this error, try `rustc --explain E0641`. From 0487f0c0c38c1bae95bd786bc044307a3ff082e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 8 Nov 2019 18:04:05 -0800 Subject: [PATCH 14/28] Suggest calling async closure when needed When using an async closure as a value in a place that expects a future, suggest calling the closure. Fix #65923. --- src/librustc/traits/error_reporting.rs | 153 ++++++++++++------ ...as-arg-where-it-should-have-been-called.rs | 3 + ...rg-where-it-should-have-been-called.stderr | 21 ++- ...as-arg-where-it-should-have-been-called.rs | 2 + ...rg-where-it-should-have-been-called.stderr | 19 ++- 5 files changed, 143 insertions(+), 55 deletions(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index c7e51ff321771..4a51ce2b780df 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -1238,60 +1238,109 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { points_at_arg: bool, ) { let self_ty = trait_ref.self_ty(); - match self_ty.kind { + let (def_id, output_ty, callable) = match self_ty.kind { + ty::Closure(def_id, substs) => { + (def_id, self.closure_sig(def_id, substs).output(), "closure") + } ty::FnDef(def_id, _) => { - // We tried to apply the bound to an `fn`. Check whether calling it would evaluate - // to a type that *would* satisfy the trait binding. If it would, suggest calling - // it: `bar(foo)` -> `bar(foo)`. This case is *very* likely to be hit if `foo` is - // `async`. - let output_ty = self_ty.fn_sig(self.tcx).output(); - let new_trait_ref = ty::TraitRef { - def_id: trait_ref.def_id(), - substs: self.tcx.mk_substs_trait(output_ty.skip_binder(), &[]), - }; - let obligation = Obligation::new( - obligation.cause.clone(), - obligation.param_env, - new_trait_ref.to_predicate(), - ); - match self.evaluate_obligation(&obligation) { - Ok(EvaluationResult::EvaluatedToOk) | - Ok(EvaluationResult::EvaluatedToOkModuloRegions) | - Ok(EvaluationResult::EvaluatedToAmbig) => { - if let Some(hir::Node::Item(hir::Item { - ident, - kind: hir::ItemKind::Fn(.., body_id), - .. - })) = self.tcx.hir().get_if_local(def_id) { - let body = self.tcx.hir().body(*body_id); - let msg = "use parentheses to call the function"; - let snippet = format!( - "{}({})", - ident, - body.params.iter() - .map(|arg| match &arg.pat.kind { - hir::PatKind::Binding(_, _, ident, None) - if ident.name != kw::SelfLower => ident.to_string(), - _ => "_".to_string(), - }).collect::>().join(", "), - ); - // When the obligation error has been ensured to have been caused by - // an argument, the `obligation.cause.span` points at the expression - // of the argument, so we can provide a suggestion. This is signaled - // by `points_at_arg`. Otherwise, we give a more general note. - if points_at_arg { - err.span_suggestion( - obligation.cause.span, - msg, - snippet, - Applicability::HasPlaceholders, - ); - } else { - err.help(&format!("{}: `{}`", msg, snippet)); - } - } + (def_id, self_ty.fn_sig(self.tcx).output(), "function") + } + _ => return, + }; + let msg = format!("use parentheses to call the {}", callable); + // We tried to apply the bound to an `fn` or closure. Check whether calling it would + // evaluate to a type that *would* satisfy the trait binding. If it would, suggest calling + // it: `bar(foo)` → `bar(foo())`. This case is *very* likely to be hit if `foo` is `async`. + + let new_trait_ref = ty::TraitRef { + def_id: trait_ref.def_id(), + substs: self.tcx.mk_substs_trait(output_ty.skip_binder(), &[]), + }; + let obligation = Obligation::new( + obligation.cause.clone(), + obligation.param_env, + new_trait_ref.to_predicate(), + ); + let get_name = |err: &mut DiagnosticBuilder<'_>, kind: &hir::PatKind| -> Option { + // Get the local name of this closure. This can be inaccurate because + // of the possibility of reassignment, but this should be good enough. + match &kind { + hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, name, None) => { + Some(format!("{}", name)) + } + _ => { + err.note(&msg); + None + } + } + }; + match self.evaluate_obligation(&obligation) { + Ok(EvaluationResult::EvaluatedToOk) | + Ok(EvaluationResult::EvaluatedToOkModuloRegions) | + Ok(EvaluationResult::EvaluatedToAmbig) => { + let hir = self.tcx.hir(); + // Get the name of the callable and the arguments to be used in the suggestion. + let snippet = match hir.get_if_local(def_id) { + Some(hir::Node::Expr(hir::Expr { + kind: hir::ExprKind::Closure(_, decl, _, span, ..), + .. + })) => { + err.span_label(*span, "consider calling this closure"); + let hir_id = match hir.as_local_hir_id(def_id) { + Some(hir_id) => hir_id, + None => return, + }; + let parent_node = hir.get_parent_node(hir_id); + let name = match hir.find(parent_node) { + Some(hir::Node::Stmt(hir::Stmt { + kind: hir::StmtKind::Local(local), .. + })) => match get_name(err, &local.pat.kind) { + Some(name) => name, + None => return, + }, + // Different to previous arm because one is `&hir::Local` and the other + // is `P`. + Some(hir::Node::Local(local)) => match get_name(err, &local.pat.kind) { + Some(name) => name, + None => return, + }, + _ => return, + }; + let args = decl.inputs.iter() + .map(|_| "_") + .collect::>().join(", "); + format!("{}({})", name, args) + } + Some(hir::Node::Item(hir::Item { + ident, + kind: hir::ItemKind::Fn(.., body_id), + .. + })) => { + err.span_label(ident.span, "consider calling this function"); + let body = hir.body(*body_id); + let args = body.params.iter() + .map(|arg| match &arg.pat.kind { + hir::PatKind::Binding(_, _, ident, None) + if ident.name != kw::SelfLower => ident.to_string(), + _ => "_".to_string(), + }).collect::>().join(", "); + format!("{}({})", ident, args) } - _ => {} + _ => return, + }; + if points_at_arg { + // When the obligation error has been ensured to have been caused by + // an argument, the `obligation.cause.span` points at the expression + // of the argument, so we can provide a suggestion. This is signaled + // by `points_at_arg`. Otherwise, we give a more general note. + err.span_suggestion( + obligation.cause.span, + &msg, + snippet, + Applicability::HasPlaceholders, + ); + } else { + err.help(&format!("{}: `{}`", msg, snippet)); } } _ => {} diff --git a/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs b/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs index a2d2ba145bc5e..156162c9027c3 100644 --- a/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs +++ b/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs @@ -1,4 +1,5 @@ // edition:2018 +#![feature(async_closure)] use std::future::Future; async fn foo() {} @@ -7,4 +8,6 @@ fn bar(f: impl Future) {} fn main() { bar(foo); //~ERROR E0277 + let async_closure = async || (); + bar(async_closure); //~ERROR E0277 } diff --git a/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr b/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr index 1cc704b443366..05583876a066c 100644 --- a/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr +++ b/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr @@ -1,6 +1,9 @@ error[E0277]: the trait bound `fn() -> impl std::future::Future {foo}: std::future::Future` is not satisfied - --> $DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:9:9 + --> $DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:10:9 | +LL | async fn foo() {} + | --- consider calling this function +LL | LL | fn bar(f: impl Future) {} | --- ----------------- required by this bound in `bar` ... @@ -10,6 +13,20 @@ LL | bar(foo); | the trait `std::future::Future` is not implemented for `fn() -> impl std::future::Future {foo}` | help: use parentheses to call the function: `foo()` -error: aborting due to previous error +error[E0277]: the trait bound `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:36]: std::future::Future` is not satisfied + --> $DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:12:9 + | +LL | fn bar(f: impl Future) {} + | --- ----------------- required by this bound in `bar` +... +LL | let async_closure = async || (); + | -------- consider calling this closure +LL | bar(async_closure); + | ^^^^^^^^^^^^^ + | | + | the trait `std::future::Future` is not implemented for `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:36]` + | help: use parentheses to call the closure: `async_closure()` + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.rs b/src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.rs index acd149c5854e8..4303e5c540569 100644 --- a/src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.rs +++ b/src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.rs @@ -15,4 +15,6 @@ fn bar(f: impl T) {} fn main() { bar(foo); //~ERROR E0277 + let closure = || S; + bar(closure); //~ERROR E0277 } diff --git a/src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr b/src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr index 7a49031bde7c2..91f60e8f426c4 100644 --- a/src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr +++ b/src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr @@ -1,6 +1,9 @@ error[E0277]: the trait bound `fn() -> impl T {foo}: T` is not satisfied --> $DIR/fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:17:9 | +LL | fn foo() -> impl T { S } + | --- consider calling this function +LL | LL | fn bar(f: impl T) {} | --- ------- required by this bound in `bar` ... @@ -10,6 +13,20 @@ LL | bar(foo); | the trait `T` is not implemented for `fn() -> impl T {foo}` | help: use parentheses to call the function: `foo()` -error: aborting due to previous error +error[E0277]: the trait bound `[closure@$DIR/fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:18:19: 18:23]: T` is not satisfied + --> $DIR/fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:19:9 + | +LL | fn bar(f: impl T) {} + | --- ------- required by this bound in `bar` +... +LL | let closure = || S; + | -- consider calling this closure +LL | bar(closure); + | ^^^^^^^ + | | + | the trait `T` is not implemented for `[closure@$DIR/fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:18:19: 18:23]` + | help: use parentheses to call the closure: `closure()` + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. From d7efa5bd6a22a07cf50a7abe0542a830d91aa182 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 16 Nov 2019 17:10:13 -0800 Subject: [PATCH 15/28] review comments --- src/librustc/traits/error_reporting.rs | 172 +++++++++++++------------ 1 file changed, 91 insertions(+), 81 deletions(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 4a51ce2b780df..b1652f58772d0 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -1230,6 +1230,24 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } + fn mk_obligation_for_def_id( + &self, + def_id: DefId, + output_ty: Ty<'tcx>, + cause: ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ) -> PredicateObligation<'tcx> { + let new_trait_ref = ty::TraitRef { + def_id, + substs: self.tcx.mk_substs_trait(output_ty, &[]), + }; + Obligation::new(cause, param_env, new_trait_ref.to_predicate()) + } + + + /// We tried to apply the bound to an `fn` or closure. Check whether calling it would + /// evaluate to a type that *would* satisfy the trait binding. If it would, suggest calling + /// it: `bar(foo)` → `bar(foo())`. This case is *very* likely to be hit if `foo` is `async`. fn suggest_fn_call( &self, obligation: &PredicateObligation<'tcx>, @@ -1248,19 +1266,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { _ => return, }; let msg = format!("use parentheses to call the {}", callable); - // We tried to apply the bound to an `fn` or closure. Check whether calling it would - // evaluate to a type that *would* satisfy the trait binding. If it would, suggest calling - // it: `bar(foo)` → `bar(foo())`. This case is *very* likely to be hit if `foo` is `async`. - let new_trait_ref = ty::TraitRef { - def_id: trait_ref.def_id(), - substs: self.tcx.mk_substs_trait(output_ty.skip_binder(), &[]), - }; - let obligation = Obligation::new( + let obligation = self.mk_obligation_for_def_id( + trait_ref.def_id(), + output_ty.skip_binder(), obligation.cause.clone(), obligation.param_env, - new_trait_ref.to_predicate(), ); + let get_name = |err: &mut DiagnosticBuilder<'_>, kind: &hir::PatKind| -> Option { // Get the local name of this closure. This can be inaccurate because // of the possibility of reassignment, but this should be good enough. @@ -1277,73 +1290,72 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { match self.evaluate_obligation(&obligation) { Ok(EvaluationResult::EvaluatedToOk) | Ok(EvaluationResult::EvaluatedToOkModuloRegions) | - Ok(EvaluationResult::EvaluatedToAmbig) => { - let hir = self.tcx.hir(); - // Get the name of the callable and the arguments to be used in the suggestion. - let snippet = match hir.get_if_local(def_id) { - Some(hir::Node::Expr(hir::Expr { - kind: hir::ExprKind::Closure(_, decl, _, span, ..), - .. - })) => { - err.span_label(*span, "consider calling this closure"); - let hir_id = match hir.as_local_hir_id(def_id) { - Some(hir_id) => hir_id, - None => return, - }; - let parent_node = hir.get_parent_node(hir_id); - let name = match hir.find(parent_node) { - Some(hir::Node::Stmt(hir::Stmt { - kind: hir::StmtKind::Local(local), .. - })) => match get_name(err, &local.pat.kind) { - Some(name) => name, - None => return, - }, - // Different to previous arm because one is `&hir::Local` and the other - // is `P`. - Some(hir::Node::Local(local)) => match get_name(err, &local.pat.kind) { - Some(name) => name, - None => return, - }, - _ => return, - }; - let args = decl.inputs.iter() - .map(|_| "_") - .collect::>().join(", "); - format!("{}({})", name, args) - } - Some(hir::Node::Item(hir::Item { - ident, - kind: hir::ItemKind::Fn(.., body_id), - .. - })) => { - err.span_label(ident.span, "consider calling this function"); - let body = hir.body(*body_id); - let args = body.params.iter() - .map(|arg| match &arg.pat.kind { - hir::PatKind::Binding(_, _, ident, None) - if ident.name != kw::SelfLower => ident.to_string(), - _ => "_".to_string(), - }).collect::>().join(", "); - format!("{}({})", ident, args) - } + Ok(EvaluationResult::EvaluatedToAmbig) => {} + _ => return, + } + let hir = self.tcx.hir(); + // Get the name of the callable and the arguments to be used in the suggestion. + let snippet = match hir.get_if_local(def_id) { + Some(hir::Node::Expr(hir::Expr { + kind: hir::ExprKind::Closure(_, decl, _, span, ..), + .. + })) => { + err.span_label(*span, "consider calling this closure"); + let hir_id = match hir.as_local_hir_id(def_id) { + Some(hir_id) => hir_id, + None => return, + }; + let parent_node = hir.get_parent_node(hir_id); + let name = match hir.find(parent_node) { + Some(hir::Node::Stmt(hir::Stmt { + kind: hir::StmtKind::Local(local), .. + })) => match get_name(err, &local.pat.kind) { + Some(name) => name, + None => return, + }, + // Different to previous arm because one is `&hir::Local` and the other + // is `P`. + Some(hir::Node::Local(local)) => match get_name(err, &local.pat.kind) { + Some(name) => name, + None => return, + }, _ => return, }; - if points_at_arg { - // When the obligation error has been ensured to have been caused by - // an argument, the `obligation.cause.span` points at the expression - // of the argument, so we can provide a suggestion. This is signaled - // by `points_at_arg`. Otherwise, we give a more general note. - err.span_suggestion( - obligation.cause.span, - &msg, - snippet, - Applicability::HasPlaceholders, - ); - } else { - err.help(&format!("{}: `{}`", msg, snippet)); - } + let args = decl.inputs.iter() + .map(|_| "_") + .collect::>().join(", "); + format!("{}({})", name, args) + } + Some(hir::Node::Item(hir::Item { + ident, + kind: hir::ItemKind::Fn(.., body_id), + .. + })) => { + err.span_label(ident.span, "consider calling this function"); + let body = hir.body(*body_id); + let args = body.params.iter() + .map(|arg| match &arg.pat.kind { + hir::PatKind::Binding(_, _, ident, None) + if ident.name != kw::SelfLower => ident.to_string(), + _ => "_".to_string(), + }).collect::>().join(", "); + format!("{}({})", ident, args) } - _ => {} + _ => return, + }; + if points_at_arg { + // When the obligation error has been ensured to have been caused by + // an argument, the `obligation.cause.span` points at the expression + // of the argument, so we can provide a suggestion. This is signaled + // by `points_at_arg`. Otherwise, we give a more general note. + err.span_suggestion( + obligation.cause.span, + &msg, + snippet, + Applicability::HasPlaceholders, + ); + } else { + err.help(&format!("{}: `{}`", msg, snippet)); } } @@ -1377,12 +1389,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { if let ty::Ref(_, t_type, _) = trait_type.kind { trait_type = t_type; - let substs = self.tcx.mk_substs_trait(trait_type, &[]); - let new_trait_ref = ty::TraitRef::new(trait_ref.def_id, substs); - let new_obligation = Obligation::new( + let new_obligation = self.mk_obligation_for_def_id( + trait_ref.def_id, + trait_type, ObligationCause::dummy(), obligation.param_env, - new_trait_ref.to_predicate(), ); if self.predicate_may_hold(&new_obligation) { @@ -1440,12 +1451,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { hir::Mutability::Immutable => self.tcx.mk_mut_ref(region, t_type), }; - let substs = self.tcx.mk_substs_trait(&trait_type, &[]); - let new_trait_ref = ty::TraitRef::new(trait_ref.skip_binder().def_id, substs); - let new_obligation = Obligation::new( + let new_obligation = self.mk_obligation_for_def_id( + trait_ref.skip_binder().def_id, + trait_type, ObligationCause::dummy(), obligation.param_env, - new_trait_ref.to_predicate(), ); if self.evaluate_obligation_no_overflow( From d8ea7866fc766c8366ff5d0fc04225270cdf11f6 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Mon, 18 Nov 2019 00:47:38 +0900 Subject: [PATCH 16/28] Add JohnTitor to rustc-guide toolstate notification list Also update org names of some books --- src/tools/publish_toolstate.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py index 4383cd9d5be43..61762ae1d9b04 100755 --- a/src/tools/publish_toolstate.py +++ b/src/tools/publish_toolstate.py @@ -41,7 +41,7 @@ 'ryankurte', 'thejpster', 'therealprof', }, 'edition-guide': {'ehuss', 'Centril', 'steveklabnik'}, - 'rustc-guide': {'mark-i-m', 'spastorino', 'amanjeev'}, + 'rustc-guide': {'mark-i-m', 'spastorino', 'amanjeev', 'JohnTitor'}, } REPOS = { @@ -50,11 +50,11 @@ 'rls': 'https://github.com/rust-lang/rls', 'rustfmt': 'https://github.com/rust-lang/rustfmt', 'book': 'https://github.com/rust-lang/book', - 'nomicon': 'https://github.com/rust-lang-nursery/nomicon', - 'reference': 'https://github.com/rust-lang-nursery/reference', + 'nomicon': 'https://github.com/rust-lang/nomicon', + 'reference': 'https://github.com/rust-lang/reference', 'rust-by-example': 'https://github.com/rust-lang/rust-by-example', 'embedded-book': 'https://github.com/rust-embedded/book', - 'edition-guide': 'https://github.com/rust-lang-nursery/edition-guide', + 'edition-guide': 'https://github.com/rust-lang/edition-guide', 'rustc-guide': 'https://github.com/rust-lang/rustc-guide', } From de122e673ac06f47652a593e0895f8367e049290 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Fri, 15 Nov 2019 14:29:35 +0100 Subject: [PATCH 17/28] std::error::Chain: remove Copy remove Copy from Iterator as per comment https://github.com/rust-lang/rust/issues/58520#issuecomment-553682166 --- src/libstd/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/error.rs b/src/libstd/error.rs index df24b6635f411..d1cb0862d82a8 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -791,7 +791,7 @@ impl dyn Error { /// /// [`Error`]: trait.Error.html #[unstable(feature = "error_iter", issue = "58520")] -#[derive(Copy, Clone, Debug)] +#[derive(Clone, Debug)] pub struct Chain<'a> { current: Option<&'a (dyn Error + 'static)>, } From 4610867c2bd01901a936fc84710360c3a2a47dd8 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 6 Nov 2019 13:58:38 +0100 Subject: [PATCH 18/28] Add long error explanation for E0594 --- src/librustc_mir/error_codes.rs | 2577 +++++++++++++++++++++++++++++++ 1 file changed, 2577 insertions(+) create mode 100644 src/librustc_mir/error_codes.rs diff --git a/src/librustc_mir/error_codes.rs b/src/librustc_mir/error_codes.rs new file mode 100644 index 0000000000000..5e9bf4be75ead --- /dev/null +++ b/src/librustc_mir/error_codes.rs @@ -0,0 +1,2577 @@ +syntax::register_diagnostics! { + + +E0001: r##" +#### Note: this error code is no longer emitted by the compiler. + +This error suggests that the expression arm corresponding to the noted pattern +will never be reached as for all possible values of the expression being +matched, one of the preceding patterns will match. + +This means that perhaps some of the preceding patterns are too general, this +one is too specific or the ordering is incorrect. + +For example, the following `match` block has too many arms: + +``` +match Some(0) { + Some(bar) => {/* ... */} + x => {/* ... */} // This handles the `None` case + _ => {/* ... */} // All possible cases have already been handled +} +``` + +`match` blocks have their patterns matched in order, so, for example, putting +a wildcard arm above a more specific arm will make the latter arm irrelevant. + +Ensure the ordering of the match arm is correct and remove any superfluous +arms. +"##, + +E0002: r##" +#### Note: this error code is no longer emitted by the compiler. + +This error indicates that an empty match expression is invalid because the type +it is matching on is non-empty (there exist values of this type). In safe code +it is impossible to create an instance of an empty type, so empty match +expressions are almost never desired. This error is typically fixed by adding +one or more cases to the match expression. + +An example of an empty type is `enum Empty { }`. So, the following will work: + +``` +enum Empty {} + +fn foo(x: Empty) { + match x { + // empty + } +} +``` + +However, this won't: + +```compile_fail +fn foo(x: Option) { + match x { + // empty + } +} +``` +"##, + +E0004: r##" +This error indicates that the compiler cannot guarantee a matching pattern for +one or more possible inputs to a match expression. Guaranteed matches are +required in order to assign values to match expressions, or alternatively, +determine the flow of execution. + +Erroneous code example: + +```compile_fail,E0004 +enum Terminator { + HastaLaVistaBaby, + TalkToMyHand, +} + +let x = Terminator::HastaLaVistaBaby; + +match x { // error: non-exhaustive patterns: `HastaLaVistaBaby` not covered + Terminator::TalkToMyHand => {} +} +``` + +If you encounter this error you must alter your patterns so that every possible +value of the input type is matched. For types with a small number of variants +(like enums) you should probably cover all cases explicitly. Alternatively, the +underscore `_` wildcard pattern can be added after all other patterns to match +"anything else". Example: + +``` +enum Terminator { + HastaLaVistaBaby, + TalkToMyHand, +} + +let x = Terminator::HastaLaVistaBaby; + +match x { + Terminator::TalkToMyHand => {} + Terminator::HastaLaVistaBaby => {} +} + +// or: + +match x { + Terminator::TalkToMyHand => {} + _ => {} +} +``` +"##, + +E0005: r##" +Patterns used to bind names must be irrefutable, that is, they must guarantee +that a name will be extracted in all cases. + +Erroneous code example: + +```compile_fail,E0005 +let x = Some(1); +let Some(y) = x; +// error: refutable pattern in local binding: `None` not covered +``` + +If you encounter this error you probably need to use a `match` or `if let` to +deal with the possibility of failure. Example: + +``` +let x = Some(1); + +match x { + Some(y) => { + // do something + }, + None => {} +} + +// or: + +if let Some(y) = x { + // do something +} +``` +"##, + +E0007: r##" +This error indicates that the bindings in a match arm would require a value to +be moved into more than one location, thus violating unique ownership. Code +like the following is invalid as it requires the entire `Option` to be +moved into a variable called `op_string` while simultaneously requiring the +inner `String` to be moved into a variable called `s`. + +Erroneous code example: + +```compile_fail,E0007 +let x = Some("s".to_string()); + +match x { + op_string @ Some(s) => {}, // error: cannot bind by-move with sub-bindings + None => {}, +} +``` + +See also the error E0303. +"##, + +E0009: r##" +In a pattern, all values that don't implement the `Copy` trait have to be bound +the same way. The goal here is to avoid binding simultaneously by-move and +by-ref. + +This limitation may be removed in a future version of Rust. + +Erroneous code example: + +```compile_fail,E0009 +struct X { x: (), } + +let x = Some((X { x: () }, X { x: () })); +match x { + Some((y, ref z)) => {}, // error: cannot bind by-move and by-ref in the + // same pattern + None => panic!() +} +``` + +You have two solutions: + +Solution #1: Bind the pattern's values the same way. + +``` +struct X { x: (), } + +let x = Some((X { x: () }, X { x: () })); +match x { + Some((ref y, ref z)) => {}, + // or Some((y, z)) => {} + None => panic!() +} +``` + +Solution #2: Implement the `Copy` trait for the `X` structure. + +However, please keep in mind that the first solution should be preferred. + +``` +#[derive(Clone, Copy)] +struct X { x: (), } + +let x = Some((X { x: () }, X { x: () })); +match x { + Some((y, ref z)) => {}, + None => panic!() +} +``` +"##, + +E0010: r##" +The value of statics and constants must be known at compile time, and they live +for the entire lifetime of a program. Creating a boxed value allocates memory on +the heap at runtime, and therefore cannot be done at compile time. + +Erroneous code example: + +```compile_fail,E0010 +#![feature(box_syntax)] + +const CON : Box = box 0; +``` +"##, + +E0013: r##" +Static and const variables can refer to other const variables. But a const +variable cannot refer to a static variable. + +Erroneous code example: + +```compile_fail,E0013 +static X: i32 = 42; +const Y: i32 = X; +``` + +In this example, `Y` cannot refer to `X` here. To fix this, the value can be +extracted as a const and then used: + +``` +const A: i32 = 42; +static X: i32 = A; +const Y: i32 = A; +``` +"##, + +// FIXME(#57563) Change the language here when const fn stabilizes +E0015: r##" +The only functions that can be called in static or constant expressions are +`const` functions, and struct/enum constructors. `const` functions are only +available on a nightly compiler. Rust currently does not support more general +compile-time function execution. + +``` +const FOO: Option = Some(1); // enum constructor +struct Bar {x: u8} +const BAR: Bar = Bar {x: 1}; // struct constructor +``` + +See [RFC 911] for more details on the design of `const fn`s. + +[RFC 911]: https://github.com/rust-lang/rfcs/blob/master/text/0911-const-fn.md +"##, + +E0017: r##" +References in statics and constants may only refer to immutable values. + +Erroneous code example: + +```compile_fail,E0017 +static X: i32 = 1; +const C: i32 = 2; + +// these three are not allowed: +const CR: &mut i32 = &mut C; +static STATIC_REF: &'static mut i32 = &mut X; +static CONST_REF: &'static mut i32 = &mut C; +``` + +Statics are shared everywhere, and if they refer to mutable data one might +violate memory safety since holding multiple mutable references to shared data +is not allowed. + +If you really want global mutable state, try using `static mut` or a global +`UnsafeCell`. +"##, + +E0019: r##" +A function call isn't allowed in the const's initialization expression +because the expression's value must be known at compile-time. + +Erroneous code example: + +```compile_fail,E0019 +#![feature(box_syntax)] + +fn main() { + struct MyOwned; + + static STATIC11: Box = box MyOwned; // error! +} +``` + +Remember: you can't use a function call inside a const's initialization +expression! However, you can totally use it anywhere else: + +``` +enum Test { + V1 +} + +impl Test { + fn func(&self) -> i32 { + 12 + } +} + +fn main() { + const FOO: Test = Test::V1; + + FOO.func(); // here is good + let x = FOO.func(); // or even here! +} +``` +"##, + +E0030: r##" +When matching against a range, the compiler verifies that the range is +non-empty. Range patterns include both end-points, so this is equivalent to +requiring the start of the range to be less than or equal to the end of the +range. + +Erroneous code example: + +```compile_fail,E0030 +match 5u32 { + // This range is ok, albeit pointless. + 1 ..= 1 => {} + // This range is empty, and the compiler can tell. + 1000 ..= 5 => {} +} +``` +"##, + +E0133: r##" +Unsafe code was used outside of an unsafe function or block. + +Erroneous code example: + +```compile_fail,E0133 +unsafe fn f() { return; } // This is the unsafe code + +fn main() { + f(); // error: call to unsafe function requires unsafe function or block +} +``` + +Using unsafe functionality is potentially dangerous and disallowed by safety +checks. Examples: + +* Dereferencing raw pointers +* Calling functions via FFI +* Calling functions marked unsafe + +These safety checks can be relaxed for a section of the code by wrapping the +unsafe instructions with an `unsafe` block. For instance: + +``` +unsafe fn f() { return; } + +fn main() { + unsafe { f(); } // ok! +} +``` + +See also https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html +"##, + +E0158: r##" +An associated const has been referenced in a pattern. + +Erroneous code example: + +```compile_fail,E0158 +enum EFoo { A, B, C, D } + +trait Foo { + const X: EFoo; +} + +fn test(arg: EFoo) { + match arg { + A::X => { // error! + println!("A::X"); + } + } +} +``` + +`const` and `static` mean different things. A `const` is a compile-time +constant, an alias for a literal value. This property means you can match it +directly within a pattern. + +The `static` keyword, on the other hand, guarantees a fixed location in memory. +This does not always mean that the value is constant. For example, a global +mutex can be declared `static` as well. + +If you want to match against a `static`, consider using a guard instead: + +``` +static FORTY_TWO: i32 = 42; + +match Some(42) { + Some(x) if x == FORTY_TWO => {} + _ => {} +} +``` +"##, + +E0161: r##" +A value was moved. However, its size was not known at compile time, and only +values of a known size can be moved. + +Erroneous code example: + +```compile_fail,E0161 +#![feature(box_syntax)] + +fn main() { + let array: &[isize] = &[1, 2, 3]; + let _x: Box<[isize]> = box *array; + // error: cannot move a value of type [isize]: the size of [isize] cannot + // be statically determined +} +``` + +In Rust, you can only move a value when its size is known at compile time. + +To work around this restriction, consider "hiding" the value behind a reference: +either `&x` or `&mut x`. Since a reference has a fixed size, this lets you move +it around as usual. Example: + +``` +#![feature(box_syntax)] + +fn main() { + let array: &[isize] = &[1, 2, 3]; + let _x: Box<&[isize]> = box array; // ok! +} +``` +"##, + +E0162: r##" +#### Note: this error code is no longer emitted by the compiler. + +An if-let pattern attempts to match the pattern, and enters the body if the +match was successful. If the match is irrefutable (when it cannot fail to +match), use a regular `let`-binding instead. For instance: + +``` +struct Irrefutable(i32); +let irr = Irrefutable(0); + +// This fails to compile because the match is irrefutable. +if let Irrefutable(x) = irr { + // This body will always be executed. + // ... +} +``` + +Try this instead: + +``` +struct Irrefutable(i32); +let irr = Irrefutable(0); + +let Irrefutable(x) = irr; +println!("{}", x); +``` +"##, + +E0165: r##" +#### Note: this error code is no longer emitted by the compiler. + +A while-let pattern attempts to match the pattern, and enters the body if the +match was successful. If the match is irrefutable (when it cannot fail to +match), use a regular `let`-binding inside a `loop` instead. For instance: + +```no_run +struct Irrefutable(i32); +let irr = Irrefutable(0); + +// This fails to compile because the match is irrefutable. +while let Irrefutable(x) = irr { + // ... +} +``` + +Try this instead: + +```no_run +struct Irrefutable(i32); +let irr = Irrefutable(0); + +loop { + let Irrefutable(x) = irr; + // ... +} +``` +"##, + +E0170: r##" +Enum variants are qualified by default. For example, given this type: + +``` +enum Method { + GET, + POST, +} +``` + +You would match it using: + +``` +enum Method { + GET, + POST, +} + +let m = Method::GET; + +match m { + Method::GET => {}, + Method::POST => {}, +} +``` + +If you don't qualify the names, the code will bind new variables named "GET" and +"POST" instead. This behavior is likely not what you want, so `rustc` warns when +that happens. + +Qualified names are good practice, and most code works well with them. But if +you prefer them unqualified, you can import the variants into scope: + +``` +use Method::*; +enum Method { GET, POST } +# fn main() {} +``` + +If you want others to be able to import variants from your module directly, use +`pub use`: + +``` +pub use Method::*; +pub enum Method { GET, POST } +# fn main() {} +``` +"##, + + +E0297: r##" +#### Note: this error code is no longer emitted by the compiler. + +Patterns used to bind names must be irrefutable. That is, they must guarantee +that a name will be extracted in all cases. Instead of pattern matching the +loop variable, consider using a `match` or `if let` inside the loop body. For +instance: + +```compile_fail,E0005 +let xs : Vec> = vec![Some(1), None]; + +// This fails because `None` is not covered. +for Some(x) in xs { + // ... +} +``` + +Match inside the loop instead: + +``` +let xs : Vec> = vec![Some(1), None]; + +for item in xs { + match item { + Some(x) => {}, + None => {}, + } +} +``` + +Or use `if let`: + +``` +let xs : Vec> = vec![Some(1), None]; + +for item in xs { + if let Some(x) = item { + // ... + } +} +``` +"##, + +E0301: r##" +#### Note: this error code is no longer emitted by the compiler. + +Mutable borrows are not allowed in pattern guards, because matching cannot have +side effects. Side effects could alter the matched object or the environment +on which the match depends in such a way, that the match would not be +exhaustive. For instance, the following would not match any arm if mutable +borrows were allowed: + +```compile_fail,E0596 +match Some(()) { + None => { }, + option if option.take().is_none() => { + /* impossible, option is `Some` */ + }, + Some(_) => { } // When the previous match failed, the option became `None`. +} +``` +"##, + +E0302: r##" +#### Note: this error code is no longer emitted by the compiler. + +Assignments are not allowed in pattern guards, because matching cannot have +side effects. Side effects could alter the matched object or the environment +on which the match depends in such a way, that the match would not be +exhaustive. For instance, the following would not match any arm if assignments +were allowed: + +```compile_fail,E0594 +match Some(()) { + None => { }, + option if { option = None; false } => { }, + Some(_) => { } // When the previous match failed, the option became `None`. +} +``` +"##, + +E0303: r##" +In certain cases it is possible for sub-bindings to violate memory safety. +Updates to the borrow checker in a future version of Rust may remove this +restriction, but for now patterns must be rewritten without sub-bindings. + +Before: + +```compile_fail,E0303 +match Some("hi".to_string()) { + ref op_string_ref @ Some(s) => {}, + None => {}, +} +``` + +After: + +``` +match Some("hi".to_string()) { + Some(ref s) => { + let op_string_ref = &Some(s); + // ... + }, + None => {}, +} +``` + +The `op_string_ref` binding has type `&Option<&String>` in both cases. + +See also https://github.com/rust-lang/rust/issues/14587 +"##, + +E0373: r##" +This error occurs when an attempt is made to use data captured by a closure, +when that data may no longer exist. It's most commonly seen when attempting to +return a closure: + +```compile_fail,E0373 +fn foo() -> Box u32> { + let x = 0u32; + Box::new(|y| x + y) +} +``` + +Notice that `x` is stack-allocated by `foo()`. By default, Rust captures +closed-over data by reference. This means that once `foo()` returns, `x` no +longer exists. An attempt to access `x` within the closure would thus be +unsafe. + +Another situation where this might be encountered is when spawning threads: + +```compile_fail,E0373 +fn foo() { + let x = 0u32; + let y = 1u32; + + let thr = std::thread::spawn(|| { + x + y + }); +} +``` + +Since our new thread runs in parallel, the stack frame containing `x` and `y` +may well have disappeared by the time we try to use them. Even if we call +`thr.join()` within foo (which blocks until `thr` has completed, ensuring the +stack frame won't disappear), we will not succeed: the compiler cannot prove +that this behaviour is safe, and so won't let us do it. + +The solution to this problem is usually to switch to using a `move` closure. +This approach moves (or copies, where possible) data into the closure, rather +than taking references to it. For example: + +``` +fn foo() -> Box u32> { + let x = 0u32; + Box::new(move |y| x + y) +} +``` + +Now that the closure has its own copy of the data, there's no need to worry +about safety. +"##, + +E0381: r##" +It is not allowed to use or capture an uninitialized variable. + +Erroneous code example: + +```compile_fail,E0381 +fn main() { + let x: i32; + let y = x; // error, use of possibly-uninitialized variable +} +``` + +To fix this, ensure that any declared variables are initialized before being +used. Example: + +``` +fn main() { + let x: i32 = 0; + let y = x; // ok! +} +``` +"##, + +E0382: r##" +This error occurs when an attempt is made to use a variable after its contents +have been moved elsewhere. + +Erroneous code example: + +```compile_fail,E0382 +struct MyStruct { s: u32 } + +fn main() { + let mut x = MyStruct{ s: 5u32 }; + let y = x; + x.s = 6; + println!("{}", x.s); +} +``` + +Since `MyStruct` is a type that is not marked `Copy`, the data gets moved out +of `x` when we set `y`. This is fundamental to Rust's ownership system: outside +of workarounds like `Rc`, a value cannot be owned by more than one variable. + +Sometimes we don't need to move the value. Using a reference, we can let another +function borrow the value without changing its ownership. In the example below, +we don't actually have to move our string to `calculate_length`, we can give it +a reference to it with `&` instead. + +``` +fn main() { + let s1 = String::from("hello"); + + let len = calculate_length(&s1); + + println!("The length of '{}' is {}.", s1, len); +} + +fn calculate_length(s: &String) -> usize { + s.len() +} +``` + +A mutable reference can be created with `&mut`. + +Sometimes we don't want a reference, but a duplicate. All types marked `Clone` +can be duplicated by calling `.clone()`. Subsequent changes to a clone do not +affect the original variable. + +Most types in the standard library are marked `Clone`. The example below +demonstrates using `clone()` on a string. `s1` is first set to "many", and then +copied to `s2`. Then the first character of `s1` is removed, without affecting +`s2`. "any many" is printed to the console. + +``` +fn main() { + let mut s1 = String::from("many"); + let s2 = s1.clone(); + s1.remove(0); + println!("{} {}", s1, s2); +} +``` + +If we control the definition of a type, we can implement `Clone` on it ourselves +with `#[derive(Clone)]`. + +Some types have no ownership semantics at all and are trivial to duplicate. An +example is `i32` and the other number types. We don't have to call `.clone()` to +clone them, because they are marked `Copy` in addition to `Clone`. Implicit +cloning is more convenient in this case. We can mark our own types `Copy` if +all their members also are marked `Copy`. + +In the example below, we implement a `Point` type. Because it only stores two +integers, we opt-out of ownership semantics with `Copy`. Then we can +`let p2 = p1` without `p1` being moved. + +``` +#[derive(Copy, Clone)] +struct Point { x: i32, y: i32 } + +fn main() { + let mut p1 = Point{ x: -1, y: 2 }; + let p2 = p1; + p1.x = 1; + println!("p1: {}, {}", p1.x, p1.y); + println!("p2: {}, {}", p2.x, p2.y); +} +``` + +Alternatively, if we don't control the struct's definition, or mutable shared +ownership is truly required, we can use `Rc` and `RefCell`: + +``` +use std::cell::RefCell; +use std::rc::Rc; + +struct MyStruct { s: u32 } + +fn main() { + let mut x = Rc::new(RefCell::new(MyStruct{ s: 5u32 })); + let y = x.clone(); + x.borrow_mut().s = 6; + println!("{}", x.borrow().s); +} +``` + +With this approach, x and y share ownership of the data via the `Rc` (reference +count type). `RefCell` essentially performs runtime borrow checking: ensuring +that at most one writer or multiple readers can access the data at any one time. + +If you wish to learn more about ownership in Rust, start with the chapter in the +Book: + +https://doc.rust-lang.org/book/ch04-00-understanding-ownership.html +"##, + +E0383: r##" +#### Note: this error code is no longer emitted by the compiler. + +This error occurs when an attempt is made to partially reinitialize a +structure that is currently uninitialized. + +For example, this can happen when a drop has taken place: + +```compile_fail +struct Foo { + a: u32, +} +impl Drop for Foo { + fn drop(&mut self) { /* ... */ } +} + +let mut x = Foo { a: 1 }; +drop(x); // `x` is now uninitialized +x.a = 2; // error, partial reinitialization of uninitialized structure `t` +``` + +This error can be fixed by fully reinitializing the structure in question: + +``` +struct Foo { + a: u32, +} +impl Drop for Foo { + fn drop(&mut self) { /* ... */ } +} + +let mut x = Foo { a: 1 }; +drop(x); +x = Foo { a: 2 }; +``` +"##, + +E0384: r##" +This error occurs when an attempt is made to reassign an immutable variable. + +Erroneous code example: + +```compile_fail,E0384 +fn main() { + let x = 3; + x = 5; // error, reassignment of immutable variable +} +``` + +By default, variables in Rust are immutable. To fix this error, add the keyword +`mut` after the keyword `let` when declaring the variable. For example: + +``` +fn main() { + let mut x = 3; + x = 5; +} +``` +"##, + +E0386: r##" +#### Note: this error code is no longer emitted by the compiler. + +This error occurs when an attempt is made to mutate the target of a mutable +reference stored inside an immutable container. + +For example, this can happen when storing a `&mut` inside an immutable `Box`: + +``` +let mut x: i64 = 1; +let y: Box<_> = Box::new(&mut x); +**y = 2; // error, cannot assign to data in an immutable container +``` + +This error can be fixed by making the container mutable: + +``` +let mut x: i64 = 1; +let mut y: Box<_> = Box::new(&mut x); +**y = 2; +``` + +It can also be fixed by using a type with interior mutability, such as `Cell` +or `RefCell`: + +``` +use std::cell::Cell; + +let x: i64 = 1; +let y: Box> = Box::new(Cell::new(x)); +y.set(2); +``` +"##, + +E0387: r##" +#### Note: this error code is no longer emitted by the compiler. + +This error occurs when an attempt is made to mutate or mutably reference data +that a closure has captured immutably. + +Erroneous code example: + +```compile_fail +// Accepts a function or a closure that captures its environment immutably. +// Closures passed to foo will not be able to mutate their closed-over state. +fn foo(f: F) { } + +// Attempts to mutate closed-over data. Error message reads: +// `cannot assign to data in a captured outer variable...` +fn mutable() { + let mut x = 0u32; + foo(|| x = 2); +} + +// Attempts to take a mutable reference to closed-over data. Error message +// reads: `cannot borrow data mutably in a captured outer variable...` +fn mut_addr() { + let mut x = 0u32; + foo(|| { let y = &mut x; }); +} +``` + +The problem here is that foo is defined as accepting a parameter of type `Fn`. +Closures passed into foo will thus be inferred to be of type `Fn`, meaning that +they capture their context immutably. + +If the definition of `foo` is under your control, the simplest solution is to +capture the data mutably. This can be done by defining `foo` to take FnMut +rather than Fn: + +``` +fn foo(f: F) { } +``` + +Alternatively, we can consider using the `Cell` and `RefCell` types to achieve +interior mutability through a shared reference. Our example's `mutable` +function could be redefined as below: + +``` +use std::cell::Cell; + +fn foo(f: F) { } + +fn mutable() { + let x = Cell::new(0u32); + foo(|| x.set(2)); +} +``` + +You can read more about cell types in the API documentation: + +https://doc.rust-lang.org/std/cell/ +"##, + +E0388: r##" +#### Note: this error code is no longer emitted by the compiler. +"##, + +E0389: r##" +#### Note: this error code is no longer emitted by the compiler. + +An attempt was made to mutate data using a non-mutable reference. This +commonly occurs when attempting to assign to a non-mutable reference of a +mutable reference (`&(&mut T)`). + +Erroneous code example: + +```compile_fail +struct FancyNum { + num: u8, +} + +fn main() { + let mut fancy = FancyNum{ num: 5 }; + let fancy_ref = &(&mut fancy); + fancy_ref.num = 6; // error: cannot assign to data in a `&` reference + println!("{}", fancy_ref.num); +} +``` + +Here, `&mut fancy` is mutable, but `&(&mut fancy)` is not. Creating an +immutable reference to a value borrows it immutably. There can be multiple +references of type `&(&mut T)` that point to the same value, so they must be +immutable to prevent multiple mutable references to the same value. + +To fix this, either remove the outer reference: + +``` +struct FancyNum { + num: u8, +} + +fn main() { + let mut fancy = FancyNum{ num: 5 }; + + let fancy_ref = &mut fancy; + // `fancy_ref` is now &mut FancyNum, rather than &(&mut FancyNum) + + fancy_ref.num = 6; // No error! + + println!("{}", fancy_ref.num); +} +``` + +Or make the outer reference mutable: + +``` +struct FancyNum { + num: u8 +} + +fn main() { + let mut fancy = FancyNum{ num: 5 }; + + let fancy_ref = &mut (&mut fancy); + // `fancy_ref` is now &mut(&mut FancyNum), rather than &(&mut FancyNum) + + fancy_ref.num = 6; // No error! + + println!("{}", fancy_ref.num); +} +``` +"##, + +E0492: r##" +A borrow of a constant containing interior mutability was attempted. + +Erroneous code example: + +```compile_fail,E0492 +use std::sync::atomic::AtomicUsize; + +const A: AtomicUsize = AtomicUsize::new(0); +static B: &'static AtomicUsize = &A; +// error: cannot borrow a constant which may contain interior mutability, +// create a static instead +``` + +A `const` represents a constant value that should never change. If one takes +a `&` reference to the constant, then one is taking a pointer to some memory +location containing the value. Normally this is perfectly fine: most values +can't be changed via a shared `&` pointer, but interior mutability would allow +it. That is, a constant value could be mutated. On the other hand, a `static` is +explicitly a single memory location, which can be mutated at will. + +So, in order to solve this error, either use statics which are `Sync`: + +``` +use std::sync::atomic::AtomicUsize; + +static A: AtomicUsize = AtomicUsize::new(0); +static B: &'static AtomicUsize = &A; // ok! +``` + +You can also have this error while using a cell type: + +```compile_fail,E0492 +use std::cell::Cell; + +const A: Cell = Cell::new(1); +const B: &Cell = &A; +// error: cannot borrow a constant which may contain interior mutability, +// create a static instead + +// or: +struct C { a: Cell } + +const D: C = C { a: Cell::new(1) }; +const E: &Cell = &D.a; // error + +// or: +const F: &C = &D; // error +``` + +This is because cell types do operations that are not thread-safe. Due to this, +they don't implement Sync and thus can't be placed in statics. + +However, if you still wish to use these types, you can achieve this by an unsafe +wrapper: + +``` +use std::cell::Cell; +use std::marker::Sync; + +struct NotThreadSafe { + value: Cell, +} + +unsafe impl Sync for NotThreadSafe {} + +static A: NotThreadSafe = NotThreadSafe { value : Cell::new(1) }; +static B: &'static NotThreadSafe = &A; // ok! +``` + +Remember this solution is unsafe! You will have to ensure that accesses to the +cell are synchronized. +"##, + +E0493: r##" +A type with a `Drop` implementation was destructured when trying to initialize +a static item. + +Erroneous code example: + +```compile_fail,E0493 +enum DropType { + A, +} + +impl Drop for DropType { + fn drop(&mut self) {} +} + +struct Foo { + field1: DropType, +} + +static FOO: Foo = Foo { ..Foo { field1: DropType::A } }; // error! +``` + +The problem here is that if the given type or one of its fields implements the +`Drop` trait, this `Drop` implementation cannot be called during the static +type initialization which might cause a memory leak. To prevent this issue, +you need to instantiate all the static type's fields by hand. + +``` +enum DropType { + A, +} + +impl Drop for DropType { + fn drop(&mut self) {} +} + +struct Foo { + field1: DropType, +} + +static FOO: Foo = Foo { field1: DropType::A }; // We initialize all fields + // by hand. +``` +"##, + +E0499: r##" +A variable was borrowed as mutable more than once. + +Erroneous code example: + +```compile_fail,E0499 +let mut i = 0; +let mut x = &mut i; +let mut a = &mut i; +x; +// error: cannot borrow `i` as mutable more than once at a time +``` + +Please note that in rust, you can either have many immutable references, or one +mutable reference. Take a look at +https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html for more +information. Example: + + +``` +let mut i = 0; +let mut x = &mut i; // ok! + +// or: +let mut i = 0; +let a = &i; // ok! +let b = &i; // still ok! +let c = &i; // still ok! +b; +a; +``` +"##, + +E0500: r##" +A borrowed variable was used by a closure. + +Erroneous code example: + +```compile_fail,E0500 +fn you_know_nothing(jon_snow: &mut i32) { + let nights_watch = &jon_snow; + let starks = || { + *jon_snow = 3; // error: closure requires unique access to `jon_snow` + // but it is already borrowed + }; + println!("{}", nights_watch); +} +``` + +In here, `jon_snow` is already borrowed by the `nights_watch` reference, so it +cannot be borrowed by the `starks` closure at the same time. To fix this issue, +you can create the closure after the borrow has ended: + +``` +fn you_know_nothing(jon_snow: &mut i32) { + let nights_watch = &jon_snow; + println!("{}", nights_watch); + let starks = || { + *jon_snow = 3; + }; +} +``` + +Or, if the type implements the `Clone` trait, you can clone it between +closures: + +``` +fn you_know_nothing(jon_snow: &mut i32) { + let mut jon_copy = jon_snow.clone(); + let starks = || { + *jon_snow = 3; + }; + println!("{}", jon_copy); +} +``` +"##, + +E0501: r##" +This error indicates that a mutable variable is being used while it is still +captured by a closure. Because the closure has borrowed the variable, it is not +available for use until the closure goes out of scope. + +Note that a capture will either move or borrow a variable, but in this +situation, the closure is borrowing the variable. Take a look at +http://rustbyexample.com/fn/closures/capture.html for more information about +capturing. + +Erroneous code example: + +```compile_fail,E0501 +fn inside_closure(x: &mut i32) { + // Actions which require unique access +} + +fn outside_closure(x: &mut i32) { + // Actions which require unique access +} + +fn foo(a: &mut i32) { + let mut bar = || { + inside_closure(a) + }; + outside_closure(a); // error: cannot borrow `*a` as mutable because previous + // closure requires unique access. + bar(); +} +``` + +To fix this error, you can finish using the closure before using the captured +variable: + +``` +fn inside_closure(x: &mut i32) {} +fn outside_closure(x: &mut i32) {} + +fn foo(a: &mut i32) { + let mut bar = || { + inside_closure(a) + }; + bar(); + // borrow on `a` ends. + outside_closure(a); // ok! +} +``` + +Or you can pass the variable as a parameter to the closure: + +``` +fn inside_closure(x: &mut i32) {} +fn outside_closure(x: &mut i32) {} + +fn foo(a: &mut i32) { + let mut bar = |s: &mut i32| { + inside_closure(s) + }; + outside_closure(a); + bar(a); +} +``` + +It may be possible to define the closure later: + +``` +fn inside_closure(x: &mut i32) {} +fn outside_closure(x: &mut i32) {} + +fn foo(a: &mut i32) { + outside_closure(a); + let mut bar = || { + inside_closure(a) + }; + bar(); +} +``` +"##, + +E0502: r##" +This error indicates that you are trying to borrow a variable as mutable when it +has already been borrowed as immutable. + +Erroneous code example: + +```compile_fail,E0502 +fn bar(x: &mut i32) {} +fn foo(a: &mut i32) { + let ref y = a; // a is borrowed as immutable. + bar(a); // error: cannot borrow `*a` as mutable because `a` is also borrowed + // as immutable + println!("{}", y); +} +``` + +To fix this error, ensure that you don't have any other references to the +variable before trying to access it mutably: + +``` +fn bar(x: &mut i32) {} +fn foo(a: &mut i32) { + bar(a); + let ref y = a; // ok! + println!("{}", y); +} +``` + +For more information on the rust ownership system, take a look at +https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html. +"##, + +E0503: r##" +A value was used after it was mutably borrowed. + +Erroneous code example: + +```compile_fail,E0503 +fn main() { + let mut value = 3; + // Create a mutable borrow of `value`. + let borrow = &mut value; + let _sum = value + 1; // error: cannot use `value` because + // it was mutably borrowed + println!("{}", borrow); +} +``` + +In this example, `value` is mutably borrowed by `borrow` and cannot be +used to calculate `sum`. This is not possible because this would violate +Rust's mutability rules. + +You can fix this error by finishing using the borrow before the next use of +the value: + +``` +fn main() { + let mut value = 3; + let borrow = &mut value; + println!("{}", borrow); + // The block has ended and with it the borrow. + // You can now use `value` again. + let _sum = value + 1; +} +``` + +Or by cloning `value` before borrowing it: + +``` +fn main() { + let mut value = 3; + // We clone `value`, creating a copy. + let value_cloned = value.clone(); + // The mutable borrow is a reference to `value` and + // not to `value_cloned`... + let borrow = &mut value; + // ... which means we can still use `value_cloned`, + let _sum = value_cloned + 1; + // even though the borrow only ends here. + println!("{}", borrow); +} +``` + +You can find more information about borrowing in the rust-book: +http://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html +"##, + +E0504: r##" +#### Note: this error code is no longer emitted by the compiler. + +This error occurs when an attempt is made to move a borrowed variable into a +closure. + +Erroneous code example: + +```compile_fail +struct FancyNum { + num: u8, +} + +fn main() { + let fancy_num = FancyNum { num: 5 }; + let fancy_ref = &fancy_num; + + let x = move || { + println!("child function: {}", fancy_num.num); + // error: cannot move `fancy_num` into closure because it is borrowed + }; + + x(); + println!("main function: {}", fancy_ref.num); +} +``` + +Here, `fancy_num` is borrowed by `fancy_ref` and so cannot be moved into +the closure `x`. There is no way to move a value into a closure while it is +borrowed, as that would invalidate the borrow. + +If the closure can't outlive the value being moved, try using a reference +rather than moving: + +``` +struct FancyNum { + num: u8, +} + +fn main() { + let fancy_num = FancyNum { num: 5 }; + let fancy_ref = &fancy_num; + + let x = move || { + // fancy_ref is usable here because it doesn't move `fancy_num` + println!("child function: {}", fancy_ref.num); + }; + + x(); + + println!("main function: {}", fancy_num.num); +} +``` + +If the value has to be borrowed and then moved, try limiting the lifetime of +the borrow using a scoped block: + +``` +struct FancyNum { + num: u8, +} + +fn main() { + let fancy_num = FancyNum { num: 5 }; + + { + let fancy_ref = &fancy_num; + println!("main function: {}", fancy_ref.num); + // `fancy_ref` goes out of scope here + } + + let x = move || { + // `fancy_num` can be moved now (no more references exist) + println!("child function: {}", fancy_num.num); + }; + + x(); +} +``` + +If the lifetime of a reference isn't enough, such as in the case of threading, +consider using an `Arc` to create a reference-counted value: + +``` +use std::sync::Arc; +use std::thread; + +struct FancyNum { + num: u8, +} + +fn main() { + let fancy_ref1 = Arc::new(FancyNum { num: 5 }); + let fancy_ref2 = fancy_ref1.clone(); + + let x = thread::spawn(move || { + // `fancy_ref1` can be moved and has a `'static` lifetime + println!("child thread: {}", fancy_ref1.num); + }); + + x.join().expect("child thread should finish"); + println!("main thread: {}", fancy_ref2.num); +} +``` +"##, + +E0505: r##" +A value was moved out while it was still borrowed. + +Erroneous code example: + +```compile_fail,E0505 +struct Value {} + +fn borrow(val: &Value) {} + +fn eat(val: Value) {} + +fn main() { + let x = Value{}; + let _ref_to_val: &Value = &x; + eat(x); + borrow(_ref_to_val); +} +``` + +Here, the function `eat` takes ownership of `x`. However, +`x` cannot be moved because the borrow to `_ref_to_val` +needs to last till the function `borrow`. +To fix that you can do a few different things: + +* Try to avoid moving the variable. +* Release borrow before move. +* Implement the `Copy` trait on the type. + +Examples: + +``` +struct Value {} + +fn borrow(val: &Value) {} + +fn eat(val: &Value) {} + +fn main() { + let x = Value{}; + + let ref_to_val: &Value = &x; + eat(&x); // pass by reference, if it's possible + borrow(ref_to_val); +} +``` + +Or: + +``` +struct Value {} + +fn borrow(val: &Value) {} + +fn eat(val: Value) {} + +fn main() { + let x = Value{}; + + let ref_to_val: &Value = &x; + borrow(ref_to_val); + // ref_to_val is no longer used. + eat(x); +} +``` + +Or: + +``` +#[derive(Clone, Copy)] // implement Copy trait +struct Value {} + +fn borrow(val: &Value) {} + +fn eat(val: Value) {} + +fn main() { + let x = Value{}; + let ref_to_val: &Value = &x; + eat(x); // it will be copied here. + borrow(ref_to_val); +} +``` + +You can find more information about borrowing in the rust-book: +http://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html +"##, + +E0506: r##" +This error occurs when an attempt is made to assign to a borrowed value. + +Erroneous code example: + +```compile_fail,E0506 +struct FancyNum { + num: u8, +} + +fn main() { + let mut fancy_num = FancyNum { num: 5 }; + let fancy_ref = &fancy_num; + fancy_num = FancyNum { num: 6 }; + // error: cannot assign to `fancy_num` because it is borrowed + + println!("Num: {}, Ref: {}", fancy_num.num, fancy_ref.num); +} +``` + +Because `fancy_ref` still holds a reference to `fancy_num`, `fancy_num` can't +be assigned to a new value as it would invalidate the reference. + +Alternatively, we can move out of `fancy_num` into a second `fancy_num`: + +``` +struct FancyNum { + num: u8, +} + +fn main() { + let mut fancy_num = FancyNum { num: 5 }; + let moved_num = fancy_num; + fancy_num = FancyNum { num: 6 }; + + println!("Num: {}, Moved num: {}", fancy_num.num, moved_num.num); +} +``` + +If the value has to be borrowed, try limiting the lifetime of the borrow using +a scoped block: + +``` +struct FancyNum { + num: u8, +} + +fn main() { + let mut fancy_num = FancyNum { num: 5 }; + + { + let fancy_ref = &fancy_num; + println!("Ref: {}", fancy_ref.num); + } + + // Works because `fancy_ref` is no longer in scope + fancy_num = FancyNum { num: 6 }; + println!("Num: {}", fancy_num.num); +} +``` + +Or by moving the reference into a function: + +``` +struct FancyNum { + num: u8, +} + +fn main() { + let mut fancy_num = FancyNum { num: 5 }; + + print_fancy_ref(&fancy_num); + + // Works because function borrow has ended + fancy_num = FancyNum { num: 6 }; + println!("Num: {}", fancy_num.num); +} + +fn print_fancy_ref(fancy_ref: &FancyNum){ + println!("Ref: {}", fancy_ref.num); +} +``` +"##, + +E0507: r##" +You tried to move out of a value which was borrowed. + +This can also happen when using a type implementing `Fn` or `FnMut`, as neither +allows moving out of them (they usually represent closures which can be called +more than once). Much of the text following applies equally well to non-`FnOnce` +closure bodies. + +Erroneous code example: + +```compile_fail,E0507 +use std::cell::RefCell; + +struct TheDarkKnight; + +impl TheDarkKnight { + fn nothing_is_true(self) {} +} + +fn main() { + let x = RefCell::new(TheDarkKnight); + + x.borrow().nothing_is_true(); // error: cannot move out of borrowed content +} +``` + +Here, the `nothing_is_true` method takes the ownership of `self`. However, +`self` cannot be moved because `.borrow()` only provides an `&TheDarkKnight`, +which is a borrow of the content owned by the `RefCell`. To fix this error, +you have three choices: + +* Try to avoid moving the variable. +* Somehow reclaim the ownership. +* Implement the `Copy` trait on the type. + +Examples: + +``` +use std::cell::RefCell; + +struct TheDarkKnight; + +impl TheDarkKnight { + fn nothing_is_true(&self) {} // First case, we don't take ownership +} + +fn main() { + let x = RefCell::new(TheDarkKnight); + + x.borrow().nothing_is_true(); // ok! +} +``` + +Or: + +``` +use std::cell::RefCell; + +struct TheDarkKnight; + +impl TheDarkKnight { + fn nothing_is_true(self) {} +} + +fn main() { + let x = RefCell::new(TheDarkKnight); + let x = x.into_inner(); // we get back ownership + + x.nothing_is_true(); // ok! +} +``` + +Or: + +``` +use std::cell::RefCell; + +#[derive(Clone, Copy)] // we implement the Copy trait +struct TheDarkKnight; + +impl TheDarkKnight { + fn nothing_is_true(self) {} +} + +fn main() { + let x = RefCell::new(TheDarkKnight); + + x.borrow().nothing_is_true(); // ok! +} +``` + +Moving a member out of a mutably borrowed struct will also cause E0507 error: + +```compile_fail,E0507 +struct TheDarkKnight; + +impl TheDarkKnight { + fn nothing_is_true(self) {} +} + +struct Batcave { + knight: TheDarkKnight +} + +fn main() { + let mut cave = Batcave { + knight: TheDarkKnight + }; + let borrowed = &mut cave; + + borrowed.knight.nothing_is_true(); // E0507 +} +``` + +It is fine only if you put something back. `mem::replace` can be used for that: + +``` +# struct TheDarkKnight; +# impl TheDarkKnight { fn nothing_is_true(self) {} } +# struct Batcave { knight: TheDarkKnight } +use std::mem; + +let mut cave = Batcave { + knight: TheDarkKnight +}; +let borrowed = &mut cave; + +mem::replace(&mut borrowed.knight, TheDarkKnight).nothing_is_true(); // ok! +``` + +You can find more information about borrowing in the rust-book: +http://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html +"##, + +E0508: r##" +A value was moved out of a non-copy fixed-size array. + +Erroneous code example: + +```compile_fail,E0508 +struct NonCopy; + +fn main() { + let array = [NonCopy; 1]; + let _value = array[0]; // error: cannot move out of type `[NonCopy; 1]`, + // a non-copy fixed-size array +} +``` + +The first element was moved out of the array, but this is not +possible because `NonCopy` does not implement the `Copy` trait. + +Consider borrowing the element instead of moving it: + +``` +struct NonCopy; + +fn main() { + let array = [NonCopy; 1]; + let _value = &array[0]; // Borrowing is allowed, unlike moving. +} +``` + +Alternatively, if your type implements `Clone` and you need to own the value, +consider borrowing and then cloning: + +``` +#[derive(Clone)] +struct NonCopy; + +fn main() { + let array = [NonCopy; 1]; + // Now you can clone the array element. + let _value = array[0].clone(); +} +``` +"##, + +E0509: r##" +This error occurs when an attempt is made to move out of a value whose type +implements the `Drop` trait. + +Erroneous code example: + +```compile_fail,E0509 +struct FancyNum { + num: usize +} + +struct DropStruct { + fancy: FancyNum +} + +impl Drop for DropStruct { + fn drop(&mut self) { + // Destruct DropStruct, possibly using FancyNum + } +} + +fn main() { + let drop_struct = DropStruct{fancy: FancyNum{num: 5}}; + let fancy_field = drop_struct.fancy; // Error E0509 + println!("Fancy: {}", fancy_field.num); + // implicit call to `drop_struct.drop()` as drop_struct goes out of scope +} +``` + +Here, we tried to move a field out of a struct of type `DropStruct` which +implements the `Drop` trait. However, a struct cannot be dropped if one or +more of its fields have been moved. + +Structs implementing the `Drop` trait have an implicit destructor that gets +called when they go out of scope. This destructor may use the fields of the +struct, so moving out of the struct could make it impossible to run the +destructor. Therefore, we must think of all values whose type implements the +`Drop` trait as single units whose fields cannot be moved. + +This error can be fixed by creating a reference to the fields of a struct, +enum, or tuple using the `ref` keyword: + +``` +struct FancyNum { + num: usize +} + +struct DropStruct { + fancy: FancyNum +} + +impl Drop for DropStruct { + fn drop(&mut self) { + // Destruct DropStruct, possibly using FancyNum + } +} + +fn main() { + let drop_struct = DropStruct{fancy: FancyNum{num: 5}}; + let ref fancy_field = drop_struct.fancy; // No more errors! + println!("Fancy: {}", fancy_field.num); + // implicit call to `drop_struct.drop()` as drop_struct goes out of scope +} +``` + +Note that this technique can also be used in the arms of a match expression: + +``` +struct FancyNum { + num: usize +} + +enum DropEnum { + Fancy(FancyNum) +} + +impl Drop for DropEnum { + fn drop(&mut self) { + // Destruct DropEnum, possibly using FancyNum + } +} + +fn main() { + // Creates and enum of type `DropEnum`, which implements `Drop` + let drop_enum = DropEnum::Fancy(FancyNum{num: 10}); + match drop_enum { + // Creates a reference to the inside of `DropEnum::Fancy` + DropEnum::Fancy(ref fancy_field) => // No error! + println!("It was fancy-- {}!", fancy_field.num), + } + // implicit call to `drop_enum.drop()` as drop_enum goes out of scope +} +``` +"##, + +E0510: r##" +Cannot mutate place in this match guard. + +When matching on a variable it cannot be mutated in the match guards, as this +could cause the match to be non-exhaustive: + +```compile_fail,E0510 +let mut x = Some(0); +match x { + None => (), + Some(_) if { x = None; false } => (), + Some(v) => (), // No longer matches +} +``` + +Here executing `x = None` would modify the value being matched and require us +to go "back in time" to the `None` arm. +"##, + +E0515: r##" +Cannot return value that references local variable + +Local variables, function parameters and temporaries are all dropped before the +end of the function body. So a reference to them cannot be returned. + +Erroneous code example: + +```compile_fail,E0515 +fn get_dangling_reference() -> &'static i32 { + let x = 0; + &x +} +``` + +```compile_fail,E0515 +use std::slice::Iter; +fn get_dangling_iterator<'a>() -> Iter<'a, i32> { + let v = vec![1, 2, 3]; + v.iter() +} +``` + +Consider returning an owned value instead: + +``` +use std::vec::IntoIter; + +fn get_integer() -> i32 { + let x = 0; + x +} + +fn get_owned_iterator() -> IntoIter { + let v = vec![1, 2, 3]; + v.into_iter() +} +``` +"##, + +E0524: r##" +A variable which requires unique access is being used in more than one closure +at the same time. + +Erroneous code example: + +```compile_fail,E0524 +fn set(x: &mut isize) { + *x += 4; +} + +fn dragoooon(x: &mut isize) { + let mut c1 = || set(x); + let mut c2 = || set(x); // error! + + c2(); + c1(); +} +``` + +To solve this issue, multiple solutions are available. First, is it required +for this variable to be used in more than one closure at a time? If it is the +case, use reference counted types such as `Rc` (or `Arc` if it runs +concurrently): + +``` +use std::rc::Rc; +use std::cell::RefCell; + +fn set(x: &mut isize) { + *x += 4; +} + +fn dragoooon(x: &mut isize) { + let x = Rc::new(RefCell::new(x)); + let y = Rc::clone(&x); + let mut c1 = || { let mut x2 = x.borrow_mut(); set(&mut x2); }; + let mut c2 = || { let mut x2 = y.borrow_mut(); set(&mut x2); }; // ok! + + c2(); + c1(); +} +``` + +If not, just run closures one at a time: + +``` +fn set(x: &mut isize) { + *x += 4; +} + +fn dragoooon(x: &mut isize) { + { // This block isn't necessary since non-lexical lifetimes, it's just to + // make it more clear. + let mut c1 = || set(&mut *x); + c1(); + } // `c1` has been dropped here so we're free to use `x` again! + let mut c2 = || set(&mut *x); + c2(); +} +``` +"##, + +E0579: r##" +When matching against an exclusive range, the compiler verifies that the range +is non-empty. Exclusive range patterns include the start point but not the end +point, so this is equivalent to requiring the start of the range to be less +than the end of the range. + +Erroneous code example: + +```compile_fail,E0579 +#![feature(exclusive_range_pattern)] + +fn main() { + match 5u32 { + // This range is ok, albeit pointless. + 1 .. 2 => {} + // This range is empty, and the compiler can tell. + 5 .. 5 => {} // error! + } +} +``` +"##, + +E0594: r##" +A non-mutable value was assigned a value. + +Erroneous code example: + +```compile_fail,E0594 +struct SolarSystem { + earth: i32, +} + +let ss = SolarSystem { earth: 3 }; +ss.earth = 2; // error! +``` + +To fix this error, just declare `ss` as mutable by using the `mut` keyword: + +``` +struct SolarSystem { + earth: i32, +} + +let mut ss = SolarSystem { earth: 3 }; // declaring `ss` as mutable +ss.earth = 2; // ok! +``` +"##, + +E0595: r##" +#### Note: this error code is no longer emitted by the compiler. + +Closures cannot mutate immutable captured variables. + +Erroneous code example: + +```compile_fail,E0594 +let x = 3; // error: closure cannot assign to immutable local variable `x` +let mut c = || { x += 1 }; +``` + +Make the variable binding mutable: + +``` +let mut x = 3; // ok! +let mut c = || { x += 1 }; +``` +"##, + +E0596: r##" +This error occurs because you tried to mutably borrow a non-mutable variable. + +Erroneous code example: + +```compile_fail,E0596 +let x = 1; +let y = &mut x; // error: cannot borrow mutably +``` + +In here, `x` isn't mutable, so when we try to mutably borrow it in `y`, it +fails. To fix this error, you need to make `x` mutable: + +``` +let mut x = 1; +let y = &mut x; // ok! +``` +"##, + +E0597: r##" +This error occurs because a value was dropped while it was still borrowed + +Erroneous code example: + +```compile_fail,E0597 +struct Foo<'a> { + x: Option<&'a u32>, +} + +let mut x = Foo { x: None }; +{ + let y = 0; + x.x = Some(&y); // error: `y` does not live long enough +} +println!("{:?}", x.x); +``` + +In here, `y` is dropped at the end of the inner scope, but it is borrowed by +`x` until the `println`. To fix the previous example, just remove the scope +so that `y` isn't dropped until after the println + +``` +struct Foo<'a> { + x: Option<&'a u32>, +} + +let mut x = Foo { x: None }; + +let y = 0; +x.x = Some(&y); + +println!("{:?}", x.x); +``` +"##, + +E0626: r##" +This error occurs because a borrow in a generator persists across a +yield point. + +Erroneous code example: + +```compile_fail,E0626 +# #![feature(generators, generator_trait, pin)] +# use std::ops::Generator; +# use std::pin::Pin; +let mut b = || { + let a = &String::new(); // <-- This borrow... + yield (); // ...is still in scope here, when the yield occurs. + println!("{}", a); +}; +Pin::new(&mut b).resume(); +``` + +At present, it is not permitted to have a yield that occurs while a +borrow is still in scope. To resolve this error, the borrow must +either be "contained" to a smaller scope that does not overlap the +yield or else eliminated in another way. So, for example, we might +resolve the previous example by removing the borrow and just storing +the integer by value: + +``` +# #![feature(generators, generator_trait, pin)] +# use std::ops::Generator; +# use std::pin::Pin; +let mut b = || { + let a = 3; + yield (); + println!("{}", a); +}; +Pin::new(&mut b).resume(); +``` + +This is a very simple case, of course. In more complex cases, we may +wish to have more than one reference to the value that was borrowed -- +in those cases, something like the `Rc` or `Arc` types may be useful. + +This error also frequently arises with iteration: + +```compile_fail,E0626 +# #![feature(generators, generator_trait, pin)] +# use std::ops::Generator; +# use std::pin::Pin; +let mut b = || { + let v = vec![1,2,3]; + for &x in &v { // <-- borrow of `v` is still in scope... + yield x; // ...when this yield occurs. + } +}; +Pin::new(&mut b).resume(); +``` + +Such cases can sometimes be resolved by iterating "by value" (or using +`into_iter()`) to avoid borrowing: + +``` +# #![feature(generators, generator_trait, pin)] +# use std::ops::Generator; +# use std::pin::Pin; +let mut b = || { + let v = vec![1,2,3]; + for x in v { // <-- Take ownership of the values instead! + yield x; // <-- Now yield is OK. + } +}; +Pin::new(&mut b).resume(); +``` + +If taking ownership is not an option, using indices can work too: + +``` +# #![feature(generators, generator_trait, pin)] +# use std::ops::Generator; +# use std::pin::Pin; +let mut b = || { + let v = vec![1,2,3]; + let len = v.len(); // (*) + for i in 0..len { + let x = v[i]; // (*) + yield x; // <-- Now yield is OK. + } +}; +Pin::new(&mut b).resume(); + +// (*) -- Unfortunately, these temporaries are currently required. +// See . +``` +"##, + +E0712: r##" +This error occurs because a borrow of a thread-local variable was made inside a +function which outlived the lifetime of the function. + +Erroneous code example: + +```compile_fail,E0712 +#![feature(thread_local)] + +#[thread_local] +static FOO: u8 = 3; + +fn main() { + let a = &FOO; // error: thread-local variable borrowed past end of function + + std::thread::spawn(move || { + println!("{}", a); + }); +} +``` +"##, + +E0713: r##" +This error occurs when an attempt is made to borrow state past the end of the +lifetime of a type that implements the `Drop` trait. + +Erroneous code example: + +```compile_fail,E0713 +#![feature(nll)] + +pub struct S<'a> { data: &'a mut String } + +impl<'a> Drop for S<'a> { + fn drop(&mut self) { self.data.push_str("being dropped"); } +} + +fn demo<'a>(s: S<'a>) -> &'a mut String { let p = &mut *s.data; p } +``` + +Here, `demo` tries to borrow the string data held within its +argument `s` and then return that borrow. However, `S` is +declared as implementing `Drop`. + +Structs implementing the `Drop` trait have an implicit destructor that +gets called when they go out of scope. This destructor gets exclusive +access to the fields of the struct when it runs. + +This means that when `s` reaches the end of `demo`, its destructor +gets exclusive access to its `&mut`-borrowed string data. allowing +another borrow of that string data (`p`), to exist across the drop of +`s` would be a violation of the principle that `&mut`-borrows have +exclusive, unaliased access to their referenced data. + +This error can be fixed by changing `demo` so that the destructor does +not run while the string-data is borrowed; for example by taking `S` +by reference: + +``` +pub struct S<'a> { data: &'a mut String } + +impl<'a> Drop for S<'a> { + fn drop(&mut self) { self.data.push_str("being dropped"); } +} + +fn demo<'a>(s: &'a mut S<'a>) -> &'a mut String { let p = &mut *(*s).data; p } +``` + +Note that this approach needs a reference to S with lifetime `'a`. +Nothing shorter than `'a` will suffice: a shorter lifetime would imply +that after `demo` finishes executing, something else (such as the +destructor!) could access `s.data` after the end of that shorter +lifetime, which would again violate the `&mut`-borrow's exclusive +access. +"##, + +E0716: r##" +This error indicates that a temporary value is being dropped +while a borrow is still in active use. + +Erroneous code example: + +```compile_fail,E0716 +fn foo() -> i32 { 22 } +fn bar(x: &i32) -> &i32 { x } +let p = bar(&foo()); + // ------ creates a temporary +let q = *p; +``` + +Here, the expression `&foo()` is borrowing the expression +`foo()`. As `foo()` is a call to a function, and not the name of +a variable, this creates a **temporary** -- that temporary stores +the return value from `foo()` so that it can be borrowed. +You could imagine that `let p = bar(&foo());` is equivalent +to this: + +```compile_fail,E0597 +# fn foo() -> i32 { 22 } +# fn bar(x: &i32) -> &i32 { x } +let p = { + let tmp = foo(); // the temporary + bar(&tmp) +}; // <-- tmp is freed as we exit this block +let q = p; +``` + +Whenever a temporary is created, it is automatically dropped (freed) +according to fixed rules. Ordinarily, the temporary is dropped +at the end of the enclosing statement -- in this case, after the `let`. +This is illustrated in the example above by showing that `tmp` would +be freed as we exit the block. + +To fix this problem, you need to create a local variable +to store the value in rather than relying on a temporary. +For example, you might change the original program to +the following: + +``` +fn foo() -> i32 { 22 } +fn bar(x: &i32) -> &i32 { x } +let value = foo(); // dropped at the end of the enclosing block +let p = bar(&value); +let q = *p; +``` + +By introducing the explicit `let value`, we allocate storage +that will last until the end of the enclosing block (when `value` +goes out of scope). When we borrow `&value`, we are borrowing a +local variable that already exists, and hence no temporary is created. + +Temporaries are not always dropped at the end of the enclosing +statement. In simple cases where the `&` expression is immediately +stored into a variable, the compiler will automatically extend +the lifetime of the temporary until the end of the enclosing +block. Therefore, an alternative way to fix the original +program is to write `let tmp = &foo()` and not `let tmp = foo()`: + +``` +fn foo() -> i32 { 22 } +fn bar(x: &i32) -> &i32 { x } +let value = &foo(); +let p = bar(value); +let q = *p; +``` + +Here, we are still borrowing `foo()`, but as the borrow is assigned +directly into a variable, the temporary will not be dropped until +the end of the enclosing block. Similar rules apply when temporaries +are stored into aggregate structures like a tuple or struct: + +``` +// Here, two temporaries are created, but +// as they are stored directly into `value`, +// they are not dropped until the end of the +// enclosing block. +fn foo() -> i32 { 22 } +let value = (&foo(), &foo()); +``` +"##, + +E0723: r##" +An feature unstable in `const` contexts was used. + +Erroneous code example: + +```compile_fail,E0723 +trait T {} + +impl T for () {} + +const fn foo() -> impl T { // error: `impl Trait` in const fn is unstable + () +} +``` + +To enable this feature on a nightly version of rustc, add the `const_fn` +feature flag: + +``` +#![feature(const_fn)] + +trait T {} + +impl T for () {} + +const fn foo() -> impl T { + () +} +``` +"##, + +E0729: r##" +Support for Non-Lexical Lifetimes (NLL) has been included in the Rust compiler +since 1.31, and has been enabled on the 2015 edition since 1.36. The new borrow +checker for NLL uncovered some bugs in the old borrow checker, which in some +cases allowed unsound code to compile, resulting in memory safety issues. + +### What do I do? + +Change your code so the warning does no longer trigger. For backwards +compatibility, this unsound code may still compile (with a warning) right now. +However, at some point in the future, the compiler will no longer accept this +code and will throw a hard error. + +### Shouldn't you fix the old borrow checker? + +The old borrow checker has known soundness issues that are basically impossible +to fix. The new NLL-based borrow checker is the fix. + +### Can I turn these warnings into errors by denying a lint? + +No. + +### When are these warnings going to turn into errors? + +No formal timeline for turning the warnings into errors has been set. See +[GitHub issue 58781](https://github.com/rust-lang/rust/issues/58781) for more +information. + +### Why do I get this message with code that doesn't involve borrowing? + +There are some known bugs that trigger this message. +"##, + +; + +// E0008, // cannot bind by-move into a pattern guard +// E0298, // cannot compare constants +// E0299, // mismatched types between arms +// E0471, // constant evaluation error (in pattern) +// E0385, // {} in an aliasable location + E0521, // borrowed data escapes outside of closure +// E0526, // shuffle indices are not constant +// E0598, // lifetime of {} is too short to guarantee its contents can be... + E0625, // thread-local statics cannot be accessed at compile-time +} From cd13335ae23c115275d2c99728f3e66efc25993d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 6 Nov 2019 13:58:44 +0100 Subject: [PATCH 19/28] Update ui tests --- src/test/ui/borrowck/borrow-immutable-upvar-mutation.stderr | 3 ++- .../borrowck/borrowck-assign-to-andmut-in-aliasable-loc.stderr | 1 + src/test/ui/borrowck/borrowck-assign-to-constants.stderr | 1 + .../borrowck-borrow-mut-base-ptr-in-aliasable-loc.stderr | 2 +- .../ui/borrowck/borrowck-borrow-overloaded-auto-deref.stderr | 3 ++- src/test/ui/borrowck/borrowck-borrow-overloaded-deref.stderr | 3 ++- src/test/ui/borrowck/borrowck-closures-unique.stderr | 2 +- src/test/ui/borrowck/borrowck-issue-14498.stderr | 3 ++- .../ui/borrowck/borrowck-overloaded-index-ref-index.stderr | 3 ++- src/test/ui/borrowck/index-mut-help.stderr | 3 ++- src/test/ui/borrowck/issue-45983.nll.stderr | 1 + .../ui/borrowck/issue-54499-field-mutation-of-moved-out.stderr | 3 ++- .../issue-55492-borrowck-migrate-scans-parents.migrate.stderr | 3 ++- .../issue-55492-borrowck-migrate-scans-parents.nll.stderr | 3 ++- src/test/ui/borrowck/mutability-errors.stderr | 3 ++- .../borrowck/reassignment_immutable_fields_overlapping.stderr | 3 ++- .../ui/borrowck/reassignment_immutable_fields_twice.stderr | 3 ++- src/test/ui/cannot-mutate-captured-non-mut-var.stderr | 3 ++- src/test/ui/closures/closure-immutable-outer-variable.stderr | 1 + src/test/ui/consts/miri_unleashed/mutable_references.stderr | 1 + src/test/ui/did_you_mean/issue-35937.stderr | 3 ++- src/test/ui/did_you_mean/issue-39544.stderr | 3 ++- src/test/ui/error-codes/E0389.stderr | 1 + src/test/ui/error-codes/E0594.stderr | 1 + src/test/ui/fn/fn-closure-mutable-capture.stderr | 1 + src/test/ui/immut-function-arguments.stderr | 1 + src/test/ui/issues/issue-46023.stderr | 1 + src/test/ui/issues/issue-46604.stderr | 3 ++- src/test/ui/issues/issue-51244.stderr | 1 + src/test/ui/issues/issue-51515.stderr | 1 + src/test/ui/mut/mutable-class-fields-2.stderr | 1 + src/test/ui/mut/mutable-class-fields.stderr | 1 + src/test/ui/nll/closure-captures.stderr | 3 ++- src/test/ui/nll/constant-thread-locals-issue-47053.stderr | 1 + src/test/ui/nll/generator-upvar-mutability.stderr | 1 + src/test/ui/nll/issue-47388.stderr | 1 + src/test/ui/nll/issue-51244.stderr | 1 + src/test/ui/nll/issue-57989.stderr | 3 ++- src/test/ui/rfc-2005-default-binding-mode/enum.stderr | 1 + src/test/ui/rfc-2005-default-binding-mode/explicit-mut.stderr | 1 + src/test/ui/suggestions/suggest-ref-mut.stderr | 1 + src/test/ui/thread-local-mutation.stderr | 1 + .../unboxed-closures/unboxed-closure-immutable-capture.stderr | 3 ++- .../ui/unboxed-closures/unboxed-closures-mutate-upvar.stderr | 1 + .../unboxed-closures-mutated-upvar-from-fn-closure.stderr | 1 + 45 files changed, 64 insertions(+), 21 deletions(-) diff --git a/src/test/ui/borrowck/borrow-immutable-upvar-mutation.stderr b/src/test/ui/borrowck/borrow-immutable-upvar-mutation.stderr index 17969137a9881..097e4c75065c9 100644 --- a/src/test/ui/borrowck/borrow-immutable-upvar-mutation.stderr +++ b/src/test/ui/borrowck/borrow-immutable-upvar-mutation.stderr @@ -72,4 +72,5 @@ LL | let _h = to_fn_mut(move || { set(&mut z); to_fn(move || z = 42); }) error: aborting due to 6 previous errors -For more information about this error, try `rustc --explain E0596`. +Some errors have detailed explanations: E0594, E0596. +For more information about an error, try `rustc --explain E0594`. diff --git a/src/test/ui/borrowck/borrowck-assign-to-andmut-in-aliasable-loc.stderr b/src/test/ui/borrowck/borrowck-assign-to-andmut-in-aliasable-loc.stderr index 38fcfbfc2a026..d8ccf36852a51 100644 --- a/src/test/ui/borrowck/borrowck-assign-to-andmut-in-aliasable-loc.stderr +++ b/src/test/ui/borrowck/borrowck-assign-to-andmut-in-aliasable-loc.stderr @@ -16,3 +16,4 @@ LL | *s.pointer += 1; error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/borrowck/borrowck-assign-to-constants.stderr b/src/test/ui/borrowck/borrowck-assign-to-constants.stderr index 800003caa0f34..864d933da127f 100644 --- a/src/test/ui/borrowck/borrowck-assign-to-constants.stderr +++ b/src/test/ui/borrowck/borrowck-assign-to-constants.stderr @@ -6,3 +6,4 @@ LL | foo = 6; error: aborting due to previous error +For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.stderr b/src/test/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.stderr index 8115e3150fbce..1fdeb812bf8bb 100644 --- a/src/test/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.stderr +++ b/src/test/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.stderr @@ -27,5 +27,5 @@ LL | let x: &mut isize = &mut **t0; error: aborting due to 3 previous errors -Some errors have detailed explanations: E0502, E0596. +Some errors have detailed explanations: E0502, E0594, E0596. For more information about an error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/borrowck-borrow-overloaded-auto-deref.stderr b/src/test/ui/borrowck/borrowck-borrow-overloaded-auto-deref.stderr index d262c578843a0..6f2b20285b931 100644 --- a/src/test/ui/borrowck/borrowck-borrow-overloaded-auto-deref.stderr +++ b/src/test/ui/borrowck/borrowck-borrow-overloaded-auto-deref.stderr @@ -112,4 +112,5 @@ LL | *x.y_mut() = 3; error: aborting due to 14 previous errors -For more information about this error, try `rustc --explain E0596`. +Some errors have detailed explanations: E0594, E0596. +For more information about an error, try `rustc --explain E0594`. diff --git a/src/test/ui/borrowck/borrowck-borrow-overloaded-deref.stderr b/src/test/ui/borrowck/borrowck-borrow-overloaded-deref.stderr index 8cacc29414d75..246a7981ae3c8 100644 --- a/src/test/ui/borrowck/borrowck-borrow-overloaded-deref.stderr +++ b/src/test/ui/borrowck/borrowck-borrow-overloaded-deref.stderr @@ -56,4 +56,5 @@ LL | **x = 3; error: aborting due to 7 previous errors -For more information about this error, try `rustc --explain E0596`. +Some errors have detailed explanations: E0594, E0596. +For more information about an error, try `rustc --explain E0594`. diff --git a/src/test/ui/borrowck/borrowck-closures-unique.stderr b/src/test/ui/borrowck/borrowck-closures-unique.stderr index 2ed08b83c58b9..64c2f419ffa65 100644 --- a/src/test/ui/borrowck/borrowck-closures-unique.stderr +++ b/src/test/ui/borrowck/borrowck-closures-unique.stderr @@ -50,5 +50,5 @@ LL | let c1 = |y: &'static mut isize| x = y; error: aborting due to 4 previous errors -Some errors have detailed explanations: E0500, E0524. +Some errors have detailed explanations: E0500, E0524, E0594. For more information about an error, try `rustc --explain E0500`. diff --git a/src/test/ui/borrowck/borrowck-issue-14498.stderr b/src/test/ui/borrowck/borrowck-issue-14498.stderr index fec4c27520cf3..ae9167757a0ae 100644 --- a/src/test/ui/borrowck/borrowck-issue-14498.stderr +++ b/src/test/ui/borrowck/borrowck-issue-14498.stderr @@ -96,4 +96,5 @@ LL | drop(p); error: aborting due to 9 previous errors -For more information about this error, try `rustc --explain E0506`. +Some errors have detailed explanations: E0506, E0594. +For more information about an error, try `rustc --explain E0506`. diff --git a/src/test/ui/borrowck/borrowck-overloaded-index-ref-index.stderr b/src/test/ui/borrowck/borrowck-overloaded-index-ref-index.stderr index 84fe17d85448e..2f92c1ebe5e18 100644 --- a/src/test/ui/borrowck/borrowck-overloaded-index-ref-index.stderr +++ b/src/test/ui/borrowck/borrowck-overloaded-index-ref-index.stderr @@ -31,4 +31,5 @@ LL | s[2] = 20; error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0502`. +Some errors have detailed explanations: E0502, E0594. +For more information about an error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/index-mut-help.stderr b/src/test/ui/borrowck/index-mut-help.stderr index 47f2171f88c86..baf649f9127a5 100644 --- a/src/test/ui/borrowck/index-mut-help.stderr +++ b/src/test/ui/borrowck/index-mut-help.stderr @@ -24,4 +24,5 @@ LL | let _ = &mut map["peter"]; error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0596`. +Some errors have detailed explanations: E0594, E0596. +For more information about an error, try `rustc --explain E0594`. diff --git a/src/test/ui/borrowck/issue-45983.nll.stderr b/src/test/ui/borrowck/issue-45983.nll.stderr index dff0b4cebace9..49d6c2473f6a3 100644 --- a/src/test/ui/borrowck/issue-45983.nll.stderr +++ b/src/test/ui/borrowck/issue-45983.nll.stderr @@ -18,3 +18,4 @@ LL | give_any(|y| x = Some(y)); error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out.stderr b/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out.stderr index 7dfd71c81c30d..b7623a54056d8 100644 --- a/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out.stderr +++ b/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out.stderr @@ -84,4 +84,5 @@ LL | v.y = 2; error: aborting due to 9 previous errors -For more information about this error, try `rustc --explain E0382`. +Some errors have detailed explanations: E0382, E0594. +For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.migrate.stderr b/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.migrate.stderr index f1d28eed922af..1cdcc18632c62 100644 --- a/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.migrate.stderr +++ b/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.migrate.stderr @@ -50,4 +50,5 @@ LL | || { &mut x.0; }; error: aborting due to 6 previous errors -For more information about this error, try `rustc --explain E0596`. +Some errors have detailed explanations: E0594, E0596. +For more information about an error, try `rustc --explain E0594`. diff --git a/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.nll.stderr b/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.nll.stderr index f1d28eed922af..1cdcc18632c62 100644 --- a/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.nll.stderr +++ b/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.nll.stderr @@ -50,4 +50,5 @@ LL | || { &mut x.0; }; error: aborting due to 6 previous errors -For more information about this error, try `rustc --explain E0596`. +Some errors have detailed explanations: E0594, E0596. +For more information about an error, try `rustc --explain E0594`. diff --git a/src/test/ui/borrowck/mutability-errors.stderr b/src/test/ui/borrowck/mutability-errors.stderr index 545de5d0e75bf..72547a40352c9 100644 --- a/src/test/ui/borrowck/mutability-errors.stderr +++ b/src/test/ui/borrowck/mutability-errors.stderr @@ -375,4 +375,5 @@ LL | &mut X.0; error: aborting due to 38 previous errors -For more information about this error, try `rustc --explain E0596`. +Some errors have detailed explanations: E0594, E0596. +For more information about an error, try `rustc --explain E0594`. diff --git a/src/test/ui/borrowck/reassignment_immutable_fields_overlapping.stderr b/src/test/ui/borrowck/reassignment_immutable_fields_overlapping.stderr index 5f346708eb610..0eae2c71e4a19 100644 --- a/src/test/ui/borrowck/reassignment_immutable_fields_overlapping.stderr +++ b/src/test/ui/borrowck/reassignment_immutable_fields_overlapping.stderr @@ -15,4 +15,5 @@ LL | x.b = 22; error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0381`. +Some errors have detailed explanations: E0381, E0594. +For more information about an error, try `rustc --explain E0381`. diff --git a/src/test/ui/borrowck/reassignment_immutable_fields_twice.stderr b/src/test/ui/borrowck/reassignment_immutable_fields_twice.stderr index 14f0fee84c9aa..f55e1a27f475e 100644 --- a/src/test/ui/borrowck/reassignment_immutable_fields_twice.stderr +++ b/src/test/ui/borrowck/reassignment_immutable_fields_twice.stderr @@ -15,4 +15,5 @@ LL | x.0 = 1; error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0381`. +Some errors have detailed explanations: E0381, E0594. +For more information about an error, try `rustc --explain E0381`. diff --git a/src/test/ui/cannot-mutate-captured-non-mut-var.stderr b/src/test/ui/cannot-mutate-captured-non-mut-var.stderr index 2961497ef9f5c..2d6e83c9e82f9 100644 --- a/src/test/ui/cannot-mutate-captured-non-mut-var.stderr +++ b/src/test/ui/cannot-mutate-captured-non-mut-var.stderr @@ -16,4 +16,5 @@ LL | to_fn_once(move|| { s.read_to_end(&mut Vec::new()); }); error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0596`. +Some errors have detailed explanations: E0594, E0596. +For more information about an error, try `rustc --explain E0594`. diff --git a/src/test/ui/closures/closure-immutable-outer-variable.stderr b/src/test/ui/closures/closure-immutable-outer-variable.stderr index 558c9caeff336..7e60f3cd8ffa4 100644 --- a/src/test/ui/closures/closure-immutable-outer-variable.stderr +++ b/src/test/ui/closures/closure-immutable-outer-variable.stderr @@ -8,3 +8,4 @@ LL | foo(Box::new(move || y = false) as Box<_>); error: aborting due to previous error +For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/consts/miri_unleashed/mutable_references.stderr b/src/test/ui/consts/miri_unleashed/mutable_references.stderr index e8a867307ce19..b9c0af33c39cd 100644 --- a/src/test/ui/consts/miri_unleashed/mutable_references.stderr +++ b/src/test/ui/consts/miri_unleashed/mutable_references.stderr @@ -36,3 +36,4 @@ LL | *OH_YES = 99; error: aborting due to previous error +For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/did_you_mean/issue-35937.stderr b/src/test/ui/did_you_mean/issue-35937.stderr index 4f9b6a6134dc8..1f578d18a1ce5 100644 --- a/src/test/ui/did_you_mean/issue-35937.stderr +++ b/src/test/ui/did_you_mean/issue-35937.stderr @@ -24,4 +24,5 @@ LL | s.x += 1; error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0596`. +Some errors have detailed explanations: E0594, E0596. +For more information about an error, try `rustc --explain E0594`. diff --git a/src/test/ui/did_you_mean/issue-39544.stderr b/src/test/ui/did_you_mean/issue-39544.stderr index dfaaf6b17dc31..ce0d697238c6b 100644 --- a/src/test/ui/did_you_mean/issue-39544.stderr +++ b/src/test/ui/did_you_mean/issue-39544.stderr @@ -98,4 +98,5 @@ LL | *x.0 = 1; error: aborting due to 12 previous errors -For more information about this error, try `rustc --explain E0596`. +Some errors have detailed explanations: E0594, E0596. +For more information about an error, try `rustc --explain E0594`. diff --git a/src/test/ui/error-codes/E0389.stderr b/src/test/ui/error-codes/E0389.stderr index 5310367d51a55..c47750b6f4e69 100644 --- a/src/test/ui/error-codes/E0389.stderr +++ b/src/test/ui/error-codes/E0389.stderr @@ -8,3 +8,4 @@ LL | fancy_ref.num = 6; error: aborting due to previous error +For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/error-codes/E0594.stderr b/src/test/ui/error-codes/E0594.stderr index c00ec4250a70b..f4d96f4e45a56 100644 --- a/src/test/ui/error-codes/E0594.stderr +++ b/src/test/ui/error-codes/E0594.stderr @@ -6,3 +6,4 @@ LL | NUM = 20; error: aborting due to previous error +For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/fn/fn-closure-mutable-capture.stderr b/src/test/ui/fn/fn-closure-mutable-capture.stderr index 8dfae0cbdf294..f7ab56da8de97 100644 --- a/src/test/ui/fn/fn-closure-mutable-capture.stderr +++ b/src/test/ui/fn/fn-closure-mutable-capture.stderr @@ -12,3 +12,4 @@ LL | bar(move || x = 1); error: aborting due to previous error +For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/immut-function-arguments.stderr b/src/test/ui/immut-function-arguments.stderr index 7871ba52db9c9..7238dd14433ce 100644 --- a/src/test/ui/immut-function-arguments.stderr +++ b/src/test/ui/immut-function-arguments.stderr @@ -16,3 +16,4 @@ LL | let _frob = |q: Box| { *q = 2; }; error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/issues/issue-46023.stderr b/src/test/ui/issues/issue-46023.stderr index fac696c6fdcbf..ca19c2501205d 100644 --- a/src/test/ui/issues/issue-46023.stderr +++ b/src/test/ui/issues/issue-46023.stderr @@ -9,3 +9,4 @@ LL | x = 1; error: aborting due to previous error +For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/issues/issue-46604.stderr b/src/test/ui/issues/issue-46604.stderr index 961b249daeb0c..c72f580f24391 100644 --- a/src/test/ui/issues/issue-46604.stderr +++ b/src/test/ui/issues/issue-46604.stderr @@ -12,4 +12,5 @@ LL | buf[0]=2; error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0017`. +Some errors have detailed explanations: E0017, E0594. +For more information about an error, try `rustc --explain E0017`. diff --git a/src/test/ui/issues/issue-51244.stderr b/src/test/ui/issues/issue-51244.stderr index 8a7e71e0326a0..c91083955b820 100644 --- a/src/test/ui/issues/issue-51244.stderr +++ b/src/test/ui/issues/issue-51244.stderr @@ -8,3 +8,4 @@ LL | *my_ref = 0; error: aborting due to previous error +For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/issues/issue-51515.stderr b/src/test/ui/issues/issue-51515.stderr index 827bb8fe2b892..3c208935f31f6 100644 --- a/src/test/ui/issues/issue-51515.stderr +++ b/src/test/ui/issues/issue-51515.stderr @@ -18,3 +18,4 @@ LL | *bar = 64; error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/mut/mutable-class-fields-2.stderr b/src/test/ui/mut/mutable-class-fields-2.stderr index a27a82ffe4642..15323ce9a9755 100644 --- a/src/test/ui/mut/mutable-class-fields-2.stderr +++ b/src/test/ui/mut/mutable-class-fields-2.stderr @@ -8,3 +8,4 @@ LL | self.how_hungry -= 5; error: aborting due to previous error +For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/mut/mutable-class-fields.stderr b/src/test/ui/mut/mutable-class-fields.stderr index 5391ccc80c5f9..40a0dc9b29c23 100644 --- a/src/test/ui/mut/mutable-class-fields.stderr +++ b/src/test/ui/mut/mutable-class-fields.stderr @@ -8,3 +8,4 @@ LL | nyan.how_hungry = 0; error: aborting due to previous error +For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/nll/closure-captures.stderr b/src/test/ui/nll/closure-captures.stderr index 77f7d815eeb4c..b8f5cc86500c5 100644 --- a/src/test/ui/nll/closure-captures.stderr +++ b/src/test/ui/nll/closure-captures.stderr @@ -156,4 +156,5 @@ LL | | *x = 1;}); error: aborting due to 12 previous errors -For more information about this error, try `rustc --explain E0596`. +Some errors have detailed explanations: E0594, E0596. +For more information about an error, try `rustc --explain E0594`. diff --git a/src/test/ui/nll/constant-thread-locals-issue-47053.stderr b/src/test/ui/nll/constant-thread-locals-issue-47053.stderr index 8afb42d66a61a..a44acfb5fc354 100644 --- a/src/test/ui/nll/constant-thread-locals-issue-47053.stderr +++ b/src/test/ui/nll/constant-thread-locals-issue-47053.stderr @@ -6,3 +6,4 @@ LL | FOO = 6; error: aborting due to previous error +For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/nll/generator-upvar-mutability.stderr b/src/test/ui/nll/generator-upvar-mutability.stderr index 1b4e5b89984e7..31b061b61d19d 100644 --- a/src/test/ui/nll/generator-upvar-mutability.stderr +++ b/src/test/ui/nll/generator-upvar-mutability.stderr @@ -9,3 +9,4 @@ LL | x = 1; error: aborting due to previous error +For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/nll/issue-47388.stderr b/src/test/ui/nll/issue-47388.stderr index d4064b3f50a34..8d48b00f8d1f1 100644 --- a/src/test/ui/nll/issue-47388.stderr +++ b/src/test/ui/nll/issue-47388.stderr @@ -8,3 +8,4 @@ LL | fancy_ref.num = 6; error: aborting due to previous error +For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/nll/issue-51244.stderr b/src/test/ui/nll/issue-51244.stderr index 8a7e71e0326a0..c91083955b820 100644 --- a/src/test/ui/nll/issue-51244.stderr +++ b/src/test/ui/nll/issue-51244.stderr @@ -8,3 +8,4 @@ LL | *my_ref = 0; error: aborting due to previous error +For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/nll/issue-57989.stderr b/src/test/ui/nll/issue-57989.stderr index 00a9bab486855..4c416105035d7 100644 --- a/src/test/ui/nll/issue-57989.stderr +++ b/src/test/ui/nll/issue-57989.stderr @@ -20,4 +20,5 @@ LL | g; error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0506`. +Some errors have detailed explanations: E0506, E0594. +For more information about an error, try `rustc --explain E0506`. diff --git a/src/test/ui/rfc-2005-default-binding-mode/enum.stderr b/src/test/ui/rfc-2005-default-binding-mode/enum.stderr index 9d53e6d7887df..d6a89006bc0fb 100644 --- a/src/test/ui/rfc-2005-default-binding-mode/enum.stderr +++ b/src/test/ui/rfc-2005-default-binding-mode/enum.stderr @@ -18,3 +18,4 @@ LL | *x += 1; error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/rfc-2005-default-binding-mode/explicit-mut.stderr b/src/test/ui/rfc-2005-default-binding-mode/explicit-mut.stderr index 5eace3d263d46..a6f2f3ec30968 100644 --- a/src/test/ui/rfc-2005-default-binding-mode/explicit-mut.stderr +++ b/src/test/ui/rfc-2005-default-binding-mode/explicit-mut.stderr @@ -18,3 +18,4 @@ LL | *n += 1; error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/suggestions/suggest-ref-mut.stderr b/src/test/ui/suggestions/suggest-ref-mut.stderr index 2414367875718..b4981279a238b 100644 --- a/src/test/ui/suggestions/suggest-ref-mut.stderr +++ b/src/test/ui/suggestions/suggest-ref-mut.stderr @@ -35,3 +35,4 @@ LL | ref quo => { *quo = 32; }, error: aborting due to 4 previous errors +For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/thread-local-mutation.stderr b/src/test/ui/thread-local-mutation.stderr index 7f7738b5d6509..e5dc0e72edfc7 100644 --- a/src/test/ui/thread-local-mutation.stderr +++ b/src/test/ui/thread-local-mutation.stderr @@ -6,3 +6,4 @@ LL | S = "after"; error: aborting due to previous error +For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/unboxed-closures/unboxed-closure-immutable-capture.stderr b/src/test/ui/unboxed-closures/unboxed-closure-immutable-capture.stderr index 9fd8aa562f4e4..ad5451ced55d0 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-immutable-capture.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-immutable-capture.stderr @@ -71,4 +71,5 @@ LL | || set(&mut x); error: aborting due to 8 previous errors -For more information about this error, try `rustc --explain E0596`. +Some errors have detailed explanations: E0594, E0596. +For more information about an error, try `rustc --explain E0594`. diff --git a/src/test/ui/unboxed-closures/unboxed-closures-mutate-upvar.stderr b/src/test/ui/unboxed-closures/unboxed-closures-mutate-upvar.stderr index fef6c23a50130..6bba38510b676 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-mutate-upvar.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-mutate-upvar.stderr @@ -42,3 +42,4 @@ LL | | }); error: aborting due to 4 previous errors +For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/unboxed-closures/unboxed-closures-mutated-upvar-from-fn-closure.stderr b/src/test/ui/unboxed-closures/unboxed-closures-mutated-upvar-from-fn-closure.stderr index 2bc1f01af9815..a38c612e1dea9 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-mutated-upvar-from-fn-closure.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-mutated-upvar-from-fn-closure.stderr @@ -16,3 +16,4 @@ LL | | }); error: aborting due to previous error +For more information about this error, try `rustc --explain E0594`. From 0e2ccaaa3e70d85d1243c07e6ac0ef3829115a8d Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Thu, 14 Nov 2019 20:19:34 -0500 Subject: [PATCH 20/28] Fix 'type annotations needed' error with opaque types Related: #66426 This commit adds handling for opaque types during inference variable fallback. Type variables generated from the instantiatino of opaque types now fallback to the opque type itself. Normally, the type variable for an instantiated opaque type is either unified with the concrete type, or with the opaque type itself (e.g when a function returns an opaque type by calling another function). However, it's possible for the type variable to be left completely unconstrained. This can occur in code like this: ```rust pub type Foo = impl Copy; fn produce() -> Option { None } ``` Here, we'll instantatiate the `Foo` in `Option` to a fresh type variable, but we will never unify it with anything due to the fact that we return a `None`. This results in the error message: `type annotations needed: cannot resolve `_: std::marker::Copy`` pointing at `pub type Foo = impl Copy`. This message is not only confusing, it's incorrect. When an opaque type inference variable is completely unconstrained, we can always fall back to using the opaque type itself. This effectively turns that particular use of the opaque type into a non-defining use, even if it appears in a defining scope. --- src/librustc/infer/opaque_types/mod.rs | 5 + src/librustc_typeck/check/mod.rs | 101 +++++++++++++++++- src/test/ui/impl-trait/where-allowed-2.rs | 9 ++ src/test/ui/impl-trait/where-allowed-2.stderr | 11 ++ src/test/ui/impl-trait/where-allowed.rs | 5 - src/test/ui/type-alias-impl-trait/fallback.rs | 22 ++++ 6 files changed, 144 insertions(+), 9 deletions(-) create mode 100644 src/test/ui/impl-trait/where-allowed-2.rs create mode 100644 src/test/ui/impl-trait/where-allowed-2.stderr create mode 100644 src/test/ui/type-alias-impl-trait/fallback.rs diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs index 9ed60b1f0c112..500122ce8c49e 100644 --- a/src/librustc/infer/opaque_types/mod.rs +++ b/src/librustc/infer/opaque_types/mod.rs @@ -24,6 +24,10 @@ pub type OpaqueTypeMap<'tcx> = DefIdMap>; /// appear in the return type). #[derive(Copy, Clone, Debug)] pub struct OpaqueTypeDecl<'tcx> { + + /// The opaque type (`ty::Opaque`) for this declaration + pub opaque_type: Ty<'tcx>, + /// The substitutions that we apply to the opaque type that this /// `impl Trait` desugars to. e.g., if: /// @@ -1150,6 +1154,7 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { self.opaque_types.insert( def_id, OpaqueTypeDecl { + opaque_type: ty, substs, definition_span, concrete_ty: ty_var, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index a8418c5f3499b..6c2f6e4fb3eea 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -147,7 +147,7 @@ use crate::TypeAndSubsts; use crate::lint; use crate::util::captures::Captures; use crate::util::common::{ErrorReported, indenter}; -use crate::util::nodemap::{DefIdMap, DefIdSet, FxHashSet, HirIdMap}; +use crate::util::nodemap::{DefIdMap, DefIdSet, FxHashMap, FxHashSet, HirIdMap}; pub use self::Expectation::*; use self::autoderef::Autoderef; @@ -231,6 +231,13 @@ pub struct Inherited<'a, 'tcx> { // 'de-opaque' OpaqueTypeDecl, after typeck is done with all functions. opaque_types: RefCell>>, + /// A map from inference variables created from opaque + /// type instantiations (ty::Infer) to the actual opaque + /// type (`ty::Opaque`). Used during fallback to map unconstrained + /// opaque type inference variables to their corresponding + /// opaque type. + opaque_types_vars: RefCell, Ty<'tcx>>>, + /// Each type parameter has an implicit region bound that /// indicates it must outlive at least the function body (the user /// may specify stronger requirements). This field indicates the @@ -696,6 +703,7 @@ impl Inherited<'a, 'tcx> { deferred_cast_checks: RefCell::new(Vec::new()), deferred_generator_interiors: RefCell::new(Vec::new()), opaque_types: RefCell::new(Default::default()), + opaque_types_vars: RefCell::new(Default::default()), implicit_region_bound, body_id, } @@ -937,9 +945,46 @@ fn typeck_tables_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::TypeckTables<'_> { // All type checking constraints were added, try to fallback unsolved variables. fcx.select_obligations_where_possible(false, |_| {}); let mut fallback_has_occurred = false; + + // We do fallback in two passes, to try to generate + // better error messages. + // The first time, we do *not* replace opaque types. + for ty in &fcx.unsolved_variables() { + fallback_has_occurred |= fcx.fallback_if_possible(ty, false /* opaque_fallback */); + } + // We now see if we can make progress. This might + // cause us to unify inference variables for opaque types, + // since we may have unified some other type variables + // during the first phase of fallback. + // This means that we only replace inference variables with their underlying + // opaque types as a last resort. + // + // In code like this: + // + // ```rust + // type MyType = impl Copy; + // fn produce() -> MyType { true } + // fn bad_produce() -> MyType { panic!() } + // ``` + // + // we want to unify the opaque inference variable in `bad_produce` + // with the diverging fallback for `panic!` (e.g. `()` or `!`), + // This will produce a nice error message about conflicting concrete + // types for `MyType`. + // + // If we had tried to fallback the opaque inference variable to `MyType`, + // we will generate a confusing type-check error that does not explicitly + // refer to opaque types. + fcx.select_obligations_where_possible(fallback_has_occurred, |_| {}); + + // We now run fallback again, but this time we allow it to replace + // unconstrained opaque type variables, in addition to performing + // other kinds of fallback. for ty in &fcx.unsolved_variables() { - fallback_has_occurred |= fcx.fallback_if_possible(ty); + fallback_has_occurred |= fcx.fallback_if_possible(ty, true /* opaque_fallback */); } + + // See if we can make any more progress fcx.select_obligations_where_possible(fallback_has_occurred, |_| {}); // Even though coercion casts provide type hints, we check casts after fallback for @@ -2864,8 +2909,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); let mut opaque_types = self.opaque_types.borrow_mut(); + let mut opaque_types_vars = self.opaque_types_vars.borrow_mut(); for (ty, decl) in opaque_type_map { let _ = opaque_types.insert(ty, decl); + let _ = opaque_types_vars.insert(decl.concrete_ty, decl.opaque_type); } value @@ -3078,7 +3125,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Fallback becomes very dubious if we have encountered type-checking errors. // In that case, fallback to Error. // The return value indicates whether fallback has occurred. - fn fallback_if_possible(&self, ty: Ty<'tcx>) -> bool { + fn fallback_if_possible(&self, ty: Ty<'tcx>, opaque_fallback: bool) -> bool { use rustc::ty::error::UnconstrainedNumeric::Neither; use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; @@ -3088,7 +3135,53 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { UnconstrainedInt => self.tcx.types.i32, UnconstrainedFloat => self.tcx.types.f64, Neither if self.type_var_diverges(ty) => self.tcx.mk_diverging_default(), - Neither => return false, + Neither => { + // This type variable was created from the instantiation of an opaque + // type. The fact that we're attempting to perform fallback for it + // means that the function neither constrained it to a concrete + // type, nor to the opaque type itself. + // + // For example, in this code: + // + //``` + // type MyType = impl Copy; + // fn defining_use() -> MyType { true } + // fn other_use() -> MyType { defining_use() } + // ``` + // + // `defining_use` will constrain the instantiated inference + // variable to `bool`, while `other_use` will constrain + // the instantiated inference variable to `MyType`. + // + // When we process opaque types during writeback, we + // will handle cases like `other_use`, and not count + // them as defining usages + // + // However, we also need to handle cases like this: + // + // ```rust + // pub type Foo = impl Copy; + // fn produce() -> Option { + // None + // } + // ``` + // + // In the above snippet, the inference varaible created by + // instantiating `Option` will be completely unconstrained. + // We treat this as a non-defining use by making the inference + // variable fall back to the opaque type itself. + if opaque_fallback { + if let Some(opaque_ty) = self.opaque_types_vars.borrow().get(ty) { + debug!("fallback_if_possible: falling back opaque type var {:?} to {:?}", + ty, opaque_ty); + *opaque_ty + } else { + return false; + } + } else { + return false; + } + }, }; debug!("fallback_if_possible: defaulting `{:?}` to `{:?}`", ty, fallback); self.demand_eqtype(syntax_pos::DUMMY_SP, ty, fallback); diff --git a/src/test/ui/impl-trait/where-allowed-2.rs b/src/test/ui/impl-trait/where-allowed-2.rs new file mode 100644 index 0000000000000..f7744ef1b3eae --- /dev/null +++ b/src/test/ui/impl-trait/where-allowed-2.rs @@ -0,0 +1,9 @@ +//! Ideally, these tests would go in `where-allowed.rs`, but we bail out +//! too early to display them. +use std::fmt::Debug; + +// Disallowed +fn in_adt_in_return() -> Vec { panic!() } +//~^ ERROR opaque type expands to a recursive type + +fn main() {} diff --git a/src/test/ui/impl-trait/where-allowed-2.stderr b/src/test/ui/impl-trait/where-allowed-2.stderr new file mode 100644 index 0000000000000..1de15014c1f8d --- /dev/null +++ b/src/test/ui/impl-trait/where-allowed-2.stderr @@ -0,0 +1,11 @@ +error[E0720]: opaque type expands to a recursive type + --> $DIR/where-allowed-2.rs:6:30 + | +LL | fn in_adt_in_return() -> Vec { panic!() } + | ^^^^^^^^^^ expands to a recursive type + | + = note: type resolves to itself + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0720`. diff --git a/src/test/ui/impl-trait/where-allowed.rs b/src/test/ui/impl-trait/where-allowed.rs index 5ab74e02e0e40..211a14ed4dd99 100644 --- a/src/test/ui/impl-trait/where-allowed.rs +++ b/src/test/ui/impl-trait/where-allowed.rs @@ -11,10 +11,6 @@ fn in_return() -> impl Debug { panic!() } // Allowed fn in_adt_in_parameters(_: Vec) { panic!() } -// Disallowed -fn in_adt_in_return() -> Vec { panic!() } -//~^ ERROR type annotations needed - // Disallowed fn in_fn_parameter_in_parameters(_: fn(impl Debug)) { panic!() } //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types @@ -60,7 +56,6 @@ fn in_impl_Fn_return_in_parameters(_: &impl Fn() -> impl Debug) { panic!() } fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() } //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types //~| ERROR nested `impl Trait` is not allowed -//~| ERROR type annotations needed // Disallowed fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { panic!() } diff --git a/src/test/ui/type-alias-impl-trait/fallback.rs b/src/test/ui/type-alias-impl-trait/fallback.rs new file mode 100644 index 0000000000000..c59c1e3b7d01e --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/fallback.rs @@ -0,0 +1,22 @@ +// Tests that we correctly handle the instantiated +// inference variable being completely unconstrained. +// +// check-pass +#![feature(type_alias_impl_trait)] + +type Foo = impl Copy; + +enum Wrapper { + First(T), + Second +} + +fn _make_iter() -> Foo { + true +} + +fn _produce() -> Wrapper { + Wrapper::Second +} + +fn main() {} From 61c75bdb11e782ee50ff1e4de6d29fd5ff4f0e31 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Fri, 15 Nov 2019 10:47:47 -0500 Subject: [PATCH 21/28] Add explanation of unconstrained opaque type --- src/test/ui/type-alias-impl-trait/fallback.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/test/ui/type-alias-impl-trait/fallback.rs b/src/test/ui/type-alias-impl-trait/fallback.rs index c59c1e3b7d01e..fe1ca2230daca 100644 --- a/src/test/ui/type-alias-impl-trait/fallback.rs +++ b/src/test/ui/type-alias-impl-trait/fallback.rs @@ -11,11 +11,17 @@ enum Wrapper { Second } -fn _make_iter() -> Foo { +// This method constrains `Foo` to be `bool` +fn constrained_foo() -> Foo { true } -fn _produce() -> Wrapper { + +// This method does not constrain `Foo`. +// Per RFC 2071, function bodies may either +// fully constrain an opaque type, or place no +// constraints on it. +fn unconstrained_foo() -> Wrapper { Wrapper::Second } From f87177b1c5df80d98e8f9c4645ecfc68edbae931 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Fri, 15 Nov 2019 16:24:51 -0500 Subject: [PATCH 22/28] Replace bool with new `FallbackMode` enum --- src/librustc/infer/opaque_types/mod.rs | 2 +- src/librustc_typeck/check/mod.rs | 24 +++++++++++++++++------- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs index 500122ce8c49e..9b197c1ecb140 100644 --- a/src/librustc/infer/opaque_types/mod.rs +++ b/src/librustc/infer/opaque_types/mod.rs @@ -25,7 +25,7 @@ pub type OpaqueTypeMap<'tcx> = DefIdMap>; #[derive(Copy, Clone, Debug)] pub struct OpaqueTypeDecl<'tcx> { - /// The opaque type (`ty::Opaque`) for this declaration + /// The opaque type (`ty::Opaque`) for this declaration. pub opaque_type: Ty<'tcx>, /// The substitutions that we apply to the opaque type that this diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 6c2f6e4fb3eea..50c1a74fe911b 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -232,7 +232,7 @@ pub struct Inherited<'a, 'tcx> { opaque_types: RefCell>>, /// A map from inference variables created from opaque - /// type instantiations (ty::Infer) to the actual opaque + /// type instantiations (`ty::Infer`) to the actual opaque /// type (`ty::Opaque`). Used during fallback to map unconstrained /// opaque type inference variables to their corresponding /// opaque type. @@ -950,7 +950,7 @@ fn typeck_tables_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::TypeckTables<'_> { // better error messages. // The first time, we do *not* replace opaque types. for ty in &fcx.unsolved_variables() { - fallback_has_occurred |= fcx.fallback_if_possible(ty, false /* opaque_fallback */); + fallback_has_occurred |= fcx.fallback_if_possible(ty, FallbackMode::NoOpaque); } // We now see if we can make progress. This might // cause us to unify inference variables for opaque types, @@ -968,7 +968,7 @@ fn typeck_tables_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::TypeckTables<'_> { // ``` // // we want to unify the opaque inference variable in `bad_produce` - // with the diverging fallback for `panic!` (e.g. `()` or `!`), + // with the diverging fallback for `panic!` (e.g. `()` or `!`). // This will produce a nice error message about conflicting concrete // types for `MyType`. // @@ -981,10 +981,10 @@ fn typeck_tables_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::TypeckTables<'_> { // unconstrained opaque type variables, in addition to performing // other kinds of fallback. for ty in &fcx.unsolved_variables() { - fallback_has_occurred |= fcx.fallback_if_possible(ty, true /* opaque_fallback */); + fallback_has_occurred |= fcx.fallback_if_possible(ty, FallbackMode::All); } - // See if we can make any more progress + // See if we can make any more progress. fcx.select_obligations_where_possible(fallback_has_occurred, |_| {}); // Even though coercion casts provide type hints, we check casts after fallback for @@ -2544,6 +2544,16 @@ enum TupleArgumentsFlag { TupleArguments, } +/// Controls how we perform fallback for unconstrained +/// type variables. +enum FallbackMode { + /// Do not fallback type variables to opaque types. + NoOpaque, + /// Perform all possible kinds of fallback, including + /// turning type variables to opaque types. + All, +} + impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn new( inh: &'a Inherited<'a, 'tcx>, @@ -3125,7 +3135,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Fallback becomes very dubious if we have encountered type-checking errors. // In that case, fallback to Error. // The return value indicates whether fallback has occurred. - fn fallback_if_possible(&self, ty: Ty<'tcx>, opaque_fallback: bool) -> bool { + fn fallback_if_possible(&self, ty: Ty<'tcx>, mode: FallbackMode) -> bool { use rustc::ty::error::UnconstrainedNumeric::Neither; use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; @@ -3170,7 +3180,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // instantiating `Option` will be completely unconstrained. // We treat this as a non-defining use by making the inference // variable fall back to the opaque type itself. - if opaque_fallback { + if let FallbackMode::All = mode { if let Some(opaque_ty) = self.opaque_types_vars.borrow().get(ty) { debug!("fallback_if_possible: falling back opaque type var {:?} to {:?}", ty, opaque_ty); From a11abe0d6b0f1a7a7bb4bdfde1dedfd89b357732 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Fri, 15 Nov 2019 16:50:57 -0500 Subject: [PATCH 23/28] Update test output --- src/test/ui/impl-trait/where-allowed.stderr | 102 +++++++++----------- 1 file changed, 45 insertions(+), 57 deletions(-) diff --git a/src/test/ui/impl-trait/where-allowed.stderr b/src/test/ui/impl-trait/where-allowed.stderr index fcd4c357afdbe..e5d2feff51cc4 100644 --- a/src/test/ui/impl-trait/where-allowed.stderr +++ b/src/test/ui/impl-trait/where-allowed.stderr @@ -1,5 +1,5 @@ error[E0666]: nested `impl Trait` is not allowed - --> $DIR/where-allowed.rs:51:51 + --> $DIR/where-allowed.rs:47:51 | LL | fn in_impl_Fn_parameter_in_parameters(_: &impl Fn(impl Debug)) { panic!() } | --------^^^^^^^^^^- @@ -8,7 +8,7 @@ LL | fn in_impl_Fn_parameter_in_parameters(_: &impl Fn(impl Debug)) { panic!() } | outer `impl Trait` error[E0666]: nested `impl Trait` is not allowed - --> $DIR/where-allowed.rs:60:57 + --> $DIR/where-allowed.rs:56:57 | LL | fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() } | --------^^^^^^^^^^- @@ -17,7 +17,7 @@ LL | fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic | outer `impl Trait` error[E0658]: `impl Trait` in type aliases is unstable - --> $DIR/where-allowed.rs:124:16 + --> $DIR/where-allowed.rs:119:16 | LL | type Out = impl Debug; | ^^^^^^^^^^ @@ -26,7 +26,7 @@ LL | type Out = impl Debug; = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable error[E0658]: `impl Trait` in type aliases is unstable - --> $DIR/where-allowed.rs:160:23 + --> $DIR/where-allowed.rs:155:23 | LL | type InTypeAlias = impl Debug; | ^^^^^^^^^^ @@ -35,7 +35,7 @@ LL | type InTypeAlias = impl Debug; = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable error[E0658]: `impl Trait` in type aliases is unstable - --> $DIR/where-allowed.rs:164:39 + --> $DIR/where-allowed.rs:159:39 | LL | type InReturnInTypeAlias = fn() -> impl Debug; | ^^^^^^^^^^ @@ -44,205 +44,205 @@ LL | type InReturnInTypeAlias = fn() -> impl Debug; = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:19:40 + --> $DIR/where-allowed.rs:15:40 | LL | fn in_fn_parameter_in_parameters(_: fn(impl Debug)) { panic!() } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:23:42 + --> $DIR/where-allowed.rs:19:42 | LL | fn in_fn_return_in_parameters(_: fn() -> impl Debug) { panic!() } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:27:38 + --> $DIR/where-allowed.rs:23:38 | LL | fn in_fn_parameter_in_return() -> fn(impl Debug) { panic!() } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:31:40 + --> $DIR/where-allowed.rs:27:40 | LL | fn in_fn_return_in_return() -> fn() -> impl Debug { panic!() } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:35:49 + --> $DIR/where-allowed.rs:31:49 | LL | fn in_dyn_Fn_parameter_in_parameters(_: &dyn Fn(impl Debug)) { panic!() } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:39:51 + --> $DIR/where-allowed.rs:35:51 | LL | fn in_dyn_Fn_return_in_parameters(_: &dyn Fn() -> impl Debug) { panic!() } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:43:55 + --> $DIR/where-allowed.rs:39:55 | LL | fn in_dyn_Fn_parameter_in_return() -> &'static dyn Fn(impl Debug) { panic!() } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:47:57 + --> $DIR/where-allowed.rs:43:57 | LL | fn in_dyn_Fn_return_in_return() -> &'static dyn Fn() -> impl Debug { panic!() } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:51:51 + --> $DIR/where-allowed.rs:47:51 | LL | fn in_impl_Fn_parameter_in_parameters(_: &impl Fn(impl Debug)) { panic!() } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:56:53 + --> $DIR/where-allowed.rs:52:53 | LL | fn in_impl_Fn_return_in_parameters(_: &impl Fn() -> impl Debug) { panic!() } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:60:57 + --> $DIR/where-allowed.rs:56:57 | LL | fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:66:59 + --> $DIR/where-allowed.rs:61:59 | LL | fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { panic!() } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:70:38 + --> $DIR/where-allowed.rs:65:38 | LL | fn in_Fn_parameter_in_generics (_: F) { panic!() } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:74:40 + --> $DIR/where-allowed.rs:69:40 | LL | fn in_Fn_return_in_generics impl Debug> (_: F) { panic!() } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:87:32 + --> $DIR/where-allowed.rs:82:32 | LL | struct InBraceStructField { x: impl Debug } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:91:41 + --> $DIR/where-allowed.rs:86:41 | LL | struct InAdtInBraceStructField { x: Vec } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:95:27 + --> $DIR/where-allowed.rs:90:27 | LL | struct InTupleStructField(impl Debug); | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:100:25 + --> $DIR/where-allowed.rs:95:25 | LL | InBraceVariant { x: impl Debug }, | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:102:20 + --> $DIR/where-allowed.rs:97:20 | LL | InTupleVariant(impl Debug), | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:113:23 + --> $DIR/where-allowed.rs:108:23 | LL | fn in_return() -> impl Debug; | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:131:34 + --> $DIR/where-allowed.rs:126:34 | LL | fn in_trait_impl_return() -> impl Debug { () } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:144:33 + --> $DIR/where-allowed.rs:139:33 | LL | fn in_foreign_parameters(_: impl Debug); | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:147:31 + --> $DIR/where-allowed.rs:142:31 | LL | fn in_foreign_return() -> impl Debug; | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:164:39 + --> $DIR/where-allowed.rs:159:39 | LL | type InReturnInTypeAlias = fn() -> impl Debug; | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:169:16 + --> $DIR/where-allowed.rs:164:16 | LL | impl PartialEq for () { | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:174:24 + --> $DIR/where-allowed.rs:169:24 | LL | impl PartialEq<()> for impl Debug { | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:179:6 + --> $DIR/where-allowed.rs:174:6 | LL | impl impl Debug { | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:185:24 + --> $DIR/where-allowed.rs:180:24 | LL | impl InInherentImplAdt { | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:191:11 + --> $DIR/where-allowed.rs:186:11 | LL | where impl Debug: Debug | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:198:15 + --> $DIR/where-allowed.rs:193:15 | LL | where Vec: Debug | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:205:24 + --> $DIR/where-allowed.rs:200:24 | LL | where T: PartialEq | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:212:17 + --> $DIR/where-allowed.rs:207:17 | LL | where T: Fn(impl Debug) | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:219:22 + --> $DIR/where-allowed.rs:214:22 | LL | where T: Fn() -> impl Debug | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:225:29 + --> $DIR/where-allowed.rs:220:29 | LL | let _in_local_variable: impl Fn() = || {}; | ^^^^^^^^^ @@ -250,36 +250,24 @@ LL | let _in_local_variable: impl Fn() = || {}; = help: add `#![feature(impl_trait_in_bindings)]` to the crate attributes to enable error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:227:46 + --> $DIR/where-allowed.rs:222:46 | LL | let _in_return_in_local_variable = || -> impl Fn() { || {} }; | ^^^^^^^^^ -error[E0282]: type annotations needed - --> $DIR/where-allowed.rs:15:30 - | -LL | fn in_adt_in_return() -> Vec { panic!() } - | ^^^^^^^^^^ cannot infer type - -error[E0282]: type annotations needed - --> $DIR/where-allowed.rs:60:49 - | -LL | fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() } - | ^^^^^^^^^^^^^^^^^^^ cannot infer type - error: could not find defining uses - --> $DIR/where-allowed.rs:160:1 + --> $DIR/where-allowed.rs:155:1 | LL | type InTypeAlias = impl Debug; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: could not find defining uses - --> $DIR/where-allowed.rs:124:5 + --> $DIR/where-allowed.rs:119:5 | LL | type Out = impl Debug; | ^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 44 previous errors +error: aborting due to 42 previous errors -Some errors have detailed explanations: E0282, E0562, E0658, E0666. -For more information about an error, try `rustc --explain E0282`. +Some errors have detailed explanations: E0562, E0658, E0666. +For more information about an error, try `rustc --explain E0562`. From 614da98454984921142eb2059db7be953d2c855c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 17 Nov 2019 11:27:48 -0800 Subject: [PATCH 24/28] review comments --- src/librustc/traits/error_reporting.rs | 78 +++++++++++++++----------- 1 file changed, 45 insertions(+), 33 deletions(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index b1652f58772d0..18f083e154a86 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -1244,6 +1244,42 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { Obligation::new(cause, param_env, new_trait_ref.to_predicate()) } + /// Given a closure's `DefId`, return the given name of the closure. + /// + /// This doesn't account for reassignments, but it's only used for suggestions. + fn get_closure_name( + &self, + def_id: DefId, + err: &mut DiagnosticBuilder<'_>, + msg: &str, + ) -> Option { + let get_name = |err: &mut DiagnosticBuilder<'_>, kind: &hir::PatKind| -> Option { + // Get the local name of this closure. This can be inaccurate because + // of the possibility of reassignment, but this should be good enough. + match &kind { + hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, name, None) => { + Some(format!("{}", name)) + } + _ => { + err.note(&msg); + None + } + } + }; + + let hir = self.tcx.hir(); + let hir_id = hir.as_local_hir_id(def_id)?; + let parent_node = hir.get_parent_node(hir_id); + match hir.find(parent_node) { + Some(hir::Node::Stmt(hir::Stmt { + kind: hir::StmtKind::Local(local), .. + })) => get_name(err, &local.pat.kind), + // Different to previous arm because one is `&hir::Local` and the other + // is `P`. + Some(hir::Node::Local(local)) => get_name(err, &local.pat.kind), + _ => return None, + } + } /// We tried to apply the bound to an `fn` or closure. Check whether calling it would /// evaluate to a type that *would* satisfy the trait binding. If it would, suggest calling @@ -1274,19 +1310,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { obligation.param_env, ); - let get_name = |err: &mut DiagnosticBuilder<'_>, kind: &hir::PatKind| -> Option { - // Get the local name of this closure. This can be inaccurate because - // of the possibility of reassignment, but this should be good enough. - match &kind { - hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, name, None) => { - Some(format!("{}", name)) - } - _ => { - err.note(&msg); - None - } - } - }; match self.evaluate_obligation(&obligation) { Ok(EvaluationResult::EvaluatedToOk) | Ok(EvaluationResult::EvaluatedToOkModuloRegions) | @@ -1301,29 +1324,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { .. })) => { err.span_label(*span, "consider calling this closure"); - let hir_id = match hir.as_local_hir_id(def_id) { - Some(hir_id) => hir_id, + let name = match self.get_closure_name(def_id, err, &msg) { + Some(name) => name, None => return, }; - let parent_node = hir.get_parent_node(hir_id); - let name = match hir.find(parent_node) { - Some(hir::Node::Stmt(hir::Stmt { - kind: hir::StmtKind::Local(local), .. - })) => match get_name(err, &local.pat.kind) { - Some(name) => name, - None => return, - }, - // Different to previous arm because one is `&hir::Local` and the other - // is `P`. - Some(hir::Node::Local(local)) => match get_name(err, &local.pat.kind) { - Some(name) => name, - None => return, - }, - _ => return, - }; let args = decl.inputs.iter() .map(|_| "_") - .collect::>().join(", "); + .collect::>() + .join(", "); format!("{}({})", name, args) } Some(hir::Node::Item(hir::Item { @@ -1336,9 +1344,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let args = body.params.iter() .map(|arg| match &arg.pat.kind { hir::PatKind::Binding(_, _, ident, None) + // FIXME: provide a better suggestion when encountering `SelfLower`, it + // should suggest a method call. if ident.name != kw::SelfLower => ident.to_string(), _ => "_".to_string(), - }).collect::>().join(", "); + }) + .collect::>() + .join(", "); format!("{}({})", ident, args) } _ => return, From f74fe812fe802c71bd9f909cbce8a703a20ba479 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 18 Nov 2019 23:22:58 +0300 Subject: [PATCH 25/28] resolve: Give derive helpers highest priority during resolution --- src/librustc_resolve/macros.rs | 25 +++++++----- .../auxiliary/derive-helper-shadowing-2.rs | 12 ++++++ .../proc-macro/derive-helper-shadowing-2.rs | 16 ++++++++ .../ui/proc-macro/derive-helper-shadowing.rs | 4 +- .../proc-macro/derive-helper-shadowing.stderr | 38 +------------------ 5 files changed, 47 insertions(+), 48 deletions(-) create mode 100644 src/test/ui/proc-macro/auxiliary/derive-helper-shadowing-2.rs create mode 100644 src/test/ui/proc-macro/derive-helper-shadowing-2.rs diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 4f687b5ba9200..8dc0fb9bd77f5 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -466,11 +466,12 @@ impl<'a> Resolver<'a> { ) -> Result<&'a NameBinding<'a>, Determinacy> { bitflags::bitflags! { struct Flags: u8 { - const MACRO_RULES = 1 << 0; - const MODULE = 1 << 1; - const MISC_SUGGEST_CRATE = 1 << 2; - const MISC_SUGGEST_SELF = 1 << 3; - const MISC_FROM_PRELUDE = 1 << 4; + const MACRO_RULES = 1 << 0; + const MODULE = 1 << 1; + const DERIVE_HELPER_COMPAT = 1 << 2; + const MISC_SUGGEST_CRATE = 1 << 3; + const MISC_SUGGEST_SELF = 1 << 4; + const MISC_FROM_PRELUDE = 1 << 5; } } @@ -528,8 +529,10 @@ impl<'a> Resolver<'a> { match this.resolve_macro_path(derive, Some(MacroKind::Derive), parent_scope, true, force) { Ok((Some(ext), _)) => if ext.helper_attrs.contains(&ident.name) { - let res = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper); - result = ok(res, derive.span, this.arenas); + let binding = (Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper), + ty::Visibility::Public, derive.span, ExpnId::root()) + .to_name_binding(this.arenas); + result = Ok((binding, Flags::DERIVE_HELPER_COMPAT)); break; } Ok(_) | Err(Determinacy::Determined) => {} @@ -659,13 +662,17 @@ impl<'a> Resolver<'a> { let (res, innermost_res) = (binding.res(), innermost_binding.res()); if res != innermost_res { let builtin = Res::NonMacroAttr(NonMacroAttrKind::Builtin); - let derive_helper = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper); + let is_derive_helper_compat = |res, flags: Flags| { + res == Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper) && + flags.contains(Flags::DERIVE_HELPER_COMPAT) + }; let ambiguity_error_kind = if is_import { Some(AmbiguityKind::Import) } else if innermost_res == builtin || res == builtin { Some(AmbiguityKind::BuiltinAttr) - } else if innermost_res == derive_helper || res == derive_helper { + } else if is_derive_helper_compat(innermost_res, innermost_flags) || + is_derive_helper_compat(res, flags) { Some(AmbiguityKind::DeriveHelper) } else if innermost_flags.contains(Flags::MACRO_RULES) && flags.contains(Flags::MODULE) && diff --git a/src/test/ui/proc-macro/auxiliary/derive-helper-shadowing-2.rs b/src/test/ui/proc-macro/auxiliary/derive-helper-shadowing-2.rs new file mode 100644 index 0000000000000..370a1a2794dcf --- /dev/null +++ b/src/test/ui/proc-macro/auxiliary/derive-helper-shadowing-2.rs @@ -0,0 +1,12 @@ +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] + +extern crate proc_macro; +use proc_macro::*; + +#[proc_macro_derive(same_name, attributes(same_name))] +pub fn derive_a(_: TokenStream) -> TokenStream { + TokenStream::new() +} diff --git a/src/test/ui/proc-macro/derive-helper-shadowing-2.rs b/src/test/ui/proc-macro/derive-helper-shadowing-2.rs new file mode 100644 index 0000000000000..5204d72b980c1 --- /dev/null +++ b/src/test/ui/proc-macro/derive-helper-shadowing-2.rs @@ -0,0 +1,16 @@ +// If a derive macro introduces a helper attribute with the same name as that macro, +// then make sure that it's usable without ambiguities. + +// check-pass +// aux-build:derive-helper-shadowing-2.rs + +#[macro_use] +extern crate derive_helper_shadowing_2; + +#[derive(same_name)] +struct S { + #[same_name] // OK, no ambiguity, derive helpers have highest priority + field: u8, +} + +fn main() {} diff --git a/src/test/ui/proc-macro/derive-helper-shadowing.rs b/src/test/ui/proc-macro/derive-helper-shadowing.rs index f0ca34db414d4..6147e96a74bf1 100644 --- a/src/test/ui/proc-macro/derive-helper-shadowing.rs +++ b/src/test/ui/proc-macro/derive-helper-shadowing.rs @@ -19,11 +19,11 @@ macro_rules! gen_helper_use { #[empty_helper] //~ ERROR `empty_helper` is ambiguous #[derive(Empty)] struct S { - #[empty_helper] //~ ERROR `empty_helper` is ambiguous + #[empty_helper] // OK, no ambiguity, derive helpers have highest priority field: [u8; { use empty_helper; //~ ERROR `empty_helper` is ambiguous - #[empty_helper] //~ ERROR `empty_helper` is ambiguous + #[empty_helper] // OK, no ambiguity, derive helpers have highest priority struct U; mod inner { diff --git a/src/test/ui/proc-macro/derive-helper-shadowing.stderr b/src/test/ui/proc-macro/derive-helper-shadowing.stderr index 9048830bee24d..76434860a4956 100644 --- a/src/test/ui/proc-macro/derive-helper-shadowing.stderr +++ b/src/test/ui/proc-macro/derive-helper-shadowing.stderr @@ -61,42 +61,6 @@ LL | use test_macros::empty_attr as empty_helper; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: use `crate::empty_helper` to refer to this attribute macro unambiguously -error[E0659]: `empty_helper` is ambiguous (derive helper attribute vs any other name) - --> $DIR/derive-helper-shadowing.rs:22:7 - | -LL | #[empty_helper] - | ^^^^^^^^^^^^ ambiguous name - | -note: `empty_helper` could refer to the derive helper attribute defined here - --> $DIR/derive-helper-shadowing.rs:20:10 - | -LL | #[derive(Empty)] - | ^^^^^ -note: `empty_helper` could also refer to the attribute macro imported here - --> $DIR/derive-helper-shadowing.rs:10:5 - | -LL | use test_macros::empty_attr as empty_helper; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: use `crate::empty_helper` to refer to this attribute macro unambiguously - -error[E0659]: `empty_helper` is ambiguous (derive helper attribute vs any other name) - --> $DIR/derive-helper-shadowing.rs:26:11 - | -LL | #[empty_helper] - | ^^^^^^^^^^^^ ambiguous name - | -note: `empty_helper` could refer to the derive helper attribute defined here - --> $DIR/derive-helper-shadowing.rs:20:10 - | -LL | #[derive(Empty)] - | ^^^^^ -note: `empty_helper` could also refer to the attribute macro imported here - --> $DIR/derive-helper-shadowing.rs:10:5 - | -LL | use test_macros::empty_attr as empty_helper; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: use `crate::empty_helper` to refer to this attribute macro unambiguously - -error: aborting due to 7 previous errors +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0659`. From c981c994d44801df0a68566467b0bf059f714c3d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 18 Nov 2019 19:03:20 +0100 Subject: [PATCH 26/28] Move E0594 to new error code system --- src/librustc_error_codes/error_codes.rs | 2 +- src/librustc_error_codes/error_codes/E0594.md | 23 + src/librustc_mir/error_codes.rs | 2577 ----------------- 3 files changed, 24 insertions(+), 2578 deletions(-) create mode 100644 src/librustc_error_codes/error_codes/E0594.md delete mode 100644 src/librustc_mir/error_codes.rs diff --git a/src/librustc_error_codes/error_codes.rs b/src/librustc_error_codes/error_codes.rs index 428cecf13a3b0..9fc375cc7b044 100644 --- a/src/librustc_error_codes/error_codes.rs +++ b/src/librustc_error_codes/error_codes.rs @@ -318,6 +318,7 @@ E0590: include_str!("./error_codes/E0590.md"), E0591: include_str!("./error_codes/E0591.md"), E0592: include_str!("./error_codes/E0592.md"), E0593: include_str!("./error_codes/E0593.md"), +E0594: include_str!("./error_codes/E0594.md"), E0595: include_str!("./error_codes/E0595.md"), E0596: include_str!("./error_codes/E0596.md"), E0597: include_str!("./error_codes/E0597.md"), @@ -566,7 +567,6 @@ E0744: include_str!("./error_codes/E0744.md"), // E0563, // cannot determine a type for this `impl Trait` removed in 6383de15 // E0564, // only named lifetimes are allowed in `impl Trait`, // but `{}` was found in the type `{}` - E0594, // cannot assign to {} // E0598, // lifetime of {} is too short to guarantee its contents can be... // E0611, // merged into E0616 // E0612, // merged into E0609 diff --git a/src/librustc_error_codes/error_codes/E0594.md b/src/librustc_error_codes/error_codes/E0594.md new file mode 100644 index 0000000000000..ad8eb631e63b1 --- /dev/null +++ b/src/librustc_error_codes/error_codes/E0594.md @@ -0,0 +1,23 @@ +A non-mutable value was assigned a value. + +Erroneous code example: + +```compile_fail,E0594 +struct SolarSystem { + earth: i32, +} + +let ss = SolarSystem { earth: 3 }; +ss.earth = 2; // error! +``` + +To fix this error, declare `ss` as mutable by using the `mut` keyword: + +``` +struct SolarSystem { + earth: i32, +} + +let mut ss = SolarSystem { earth: 3 }; // declaring `ss` as mutable +ss.earth = 2; // ok! +``` diff --git a/src/librustc_mir/error_codes.rs b/src/librustc_mir/error_codes.rs deleted file mode 100644 index 5e9bf4be75ead..0000000000000 --- a/src/librustc_mir/error_codes.rs +++ /dev/null @@ -1,2577 +0,0 @@ -syntax::register_diagnostics! { - - -E0001: r##" -#### Note: this error code is no longer emitted by the compiler. - -This error suggests that the expression arm corresponding to the noted pattern -will never be reached as for all possible values of the expression being -matched, one of the preceding patterns will match. - -This means that perhaps some of the preceding patterns are too general, this -one is too specific or the ordering is incorrect. - -For example, the following `match` block has too many arms: - -``` -match Some(0) { - Some(bar) => {/* ... */} - x => {/* ... */} // This handles the `None` case - _ => {/* ... */} // All possible cases have already been handled -} -``` - -`match` blocks have their patterns matched in order, so, for example, putting -a wildcard arm above a more specific arm will make the latter arm irrelevant. - -Ensure the ordering of the match arm is correct and remove any superfluous -arms. -"##, - -E0002: r##" -#### Note: this error code is no longer emitted by the compiler. - -This error indicates that an empty match expression is invalid because the type -it is matching on is non-empty (there exist values of this type). In safe code -it is impossible to create an instance of an empty type, so empty match -expressions are almost never desired. This error is typically fixed by adding -one or more cases to the match expression. - -An example of an empty type is `enum Empty { }`. So, the following will work: - -``` -enum Empty {} - -fn foo(x: Empty) { - match x { - // empty - } -} -``` - -However, this won't: - -```compile_fail -fn foo(x: Option) { - match x { - // empty - } -} -``` -"##, - -E0004: r##" -This error indicates that the compiler cannot guarantee a matching pattern for -one or more possible inputs to a match expression. Guaranteed matches are -required in order to assign values to match expressions, or alternatively, -determine the flow of execution. - -Erroneous code example: - -```compile_fail,E0004 -enum Terminator { - HastaLaVistaBaby, - TalkToMyHand, -} - -let x = Terminator::HastaLaVistaBaby; - -match x { // error: non-exhaustive patterns: `HastaLaVistaBaby` not covered - Terminator::TalkToMyHand => {} -} -``` - -If you encounter this error you must alter your patterns so that every possible -value of the input type is matched. For types with a small number of variants -(like enums) you should probably cover all cases explicitly. Alternatively, the -underscore `_` wildcard pattern can be added after all other patterns to match -"anything else". Example: - -``` -enum Terminator { - HastaLaVistaBaby, - TalkToMyHand, -} - -let x = Terminator::HastaLaVistaBaby; - -match x { - Terminator::TalkToMyHand => {} - Terminator::HastaLaVistaBaby => {} -} - -// or: - -match x { - Terminator::TalkToMyHand => {} - _ => {} -} -``` -"##, - -E0005: r##" -Patterns used to bind names must be irrefutable, that is, they must guarantee -that a name will be extracted in all cases. - -Erroneous code example: - -```compile_fail,E0005 -let x = Some(1); -let Some(y) = x; -// error: refutable pattern in local binding: `None` not covered -``` - -If you encounter this error you probably need to use a `match` or `if let` to -deal with the possibility of failure. Example: - -``` -let x = Some(1); - -match x { - Some(y) => { - // do something - }, - None => {} -} - -// or: - -if let Some(y) = x { - // do something -} -``` -"##, - -E0007: r##" -This error indicates that the bindings in a match arm would require a value to -be moved into more than one location, thus violating unique ownership. Code -like the following is invalid as it requires the entire `Option` to be -moved into a variable called `op_string` while simultaneously requiring the -inner `String` to be moved into a variable called `s`. - -Erroneous code example: - -```compile_fail,E0007 -let x = Some("s".to_string()); - -match x { - op_string @ Some(s) => {}, // error: cannot bind by-move with sub-bindings - None => {}, -} -``` - -See also the error E0303. -"##, - -E0009: r##" -In a pattern, all values that don't implement the `Copy` trait have to be bound -the same way. The goal here is to avoid binding simultaneously by-move and -by-ref. - -This limitation may be removed in a future version of Rust. - -Erroneous code example: - -```compile_fail,E0009 -struct X { x: (), } - -let x = Some((X { x: () }, X { x: () })); -match x { - Some((y, ref z)) => {}, // error: cannot bind by-move and by-ref in the - // same pattern - None => panic!() -} -``` - -You have two solutions: - -Solution #1: Bind the pattern's values the same way. - -``` -struct X { x: (), } - -let x = Some((X { x: () }, X { x: () })); -match x { - Some((ref y, ref z)) => {}, - // or Some((y, z)) => {} - None => panic!() -} -``` - -Solution #2: Implement the `Copy` trait for the `X` structure. - -However, please keep in mind that the first solution should be preferred. - -``` -#[derive(Clone, Copy)] -struct X { x: (), } - -let x = Some((X { x: () }, X { x: () })); -match x { - Some((y, ref z)) => {}, - None => panic!() -} -``` -"##, - -E0010: r##" -The value of statics and constants must be known at compile time, and they live -for the entire lifetime of a program. Creating a boxed value allocates memory on -the heap at runtime, and therefore cannot be done at compile time. - -Erroneous code example: - -```compile_fail,E0010 -#![feature(box_syntax)] - -const CON : Box = box 0; -``` -"##, - -E0013: r##" -Static and const variables can refer to other const variables. But a const -variable cannot refer to a static variable. - -Erroneous code example: - -```compile_fail,E0013 -static X: i32 = 42; -const Y: i32 = X; -``` - -In this example, `Y` cannot refer to `X` here. To fix this, the value can be -extracted as a const and then used: - -``` -const A: i32 = 42; -static X: i32 = A; -const Y: i32 = A; -``` -"##, - -// FIXME(#57563) Change the language here when const fn stabilizes -E0015: r##" -The only functions that can be called in static or constant expressions are -`const` functions, and struct/enum constructors. `const` functions are only -available on a nightly compiler. Rust currently does not support more general -compile-time function execution. - -``` -const FOO: Option = Some(1); // enum constructor -struct Bar {x: u8} -const BAR: Bar = Bar {x: 1}; // struct constructor -``` - -See [RFC 911] for more details on the design of `const fn`s. - -[RFC 911]: https://github.com/rust-lang/rfcs/blob/master/text/0911-const-fn.md -"##, - -E0017: r##" -References in statics and constants may only refer to immutable values. - -Erroneous code example: - -```compile_fail,E0017 -static X: i32 = 1; -const C: i32 = 2; - -// these three are not allowed: -const CR: &mut i32 = &mut C; -static STATIC_REF: &'static mut i32 = &mut X; -static CONST_REF: &'static mut i32 = &mut C; -``` - -Statics are shared everywhere, and if they refer to mutable data one might -violate memory safety since holding multiple mutable references to shared data -is not allowed. - -If you really want global mutable state, try using `static mut` or a global -`UnsafeCell`. -"##, - -E0019: r##" -A function call isn't allowed in the const's initialization expression -because the expression's value must be known at compile-time. - -Erroneous code example: - -```compile_fail,E0019 -#![feature(box_syntax)] - -fn main() { - struct MyOwned; - - static STATIC11: Box = box MyOwned; // error! -} -``` - -Remember: you can't use a function call inside a const's initialization -expression! However, you can totally use it anywhere else: - -``` -enum Test { - V1 -} - -impl Test { - fn func(&self) -> i32 { - 12 - } -} - -fn main() { - const FOO: Test = Test::V1; - - FOO.func(); // here is good - let x = FOO.func(); // or even here! -} -``` -"##, - -E0030: r##" -When matching against a range, the compiler verifies that the range is -non-empty. Range patterns include both end-points, so this is equivalent to -requiring the start of the range to be less than or equal to the end of the -range. - -Erroneous code example: - -```compile_fail,E0030 -match 5u32 { - // This range is ok, albeit pointless. - 1 ..= 1 => {} - // This range is empty, and the compiler can tell. - 1000 ..= 5 => {} -} -``` -"##, - -E0133: r##" -Unsafe code was used outside of an unsafe function or block. - -Erroneous code example: - -```compile_fail,E0133 -unsafe fn f() { return; } // This is the unsafe code - -fn main() { - f(); // error: call to unsafe function requires unsafe function or block -} -``` - -Using unsafe functionality is potentially dangerous and disallowed by safety -checks. Examples: - -* Dereferencing raw pointers -* Calling functions via FFI -* Calling functions marked unsafe - -These safety checks can be relaxed for a section of the code by wrapping the -unsafe instructions with an `unsafe` block. For instance: - -``` -unsafe fn f() { return; } - -fn main() { - unsafe { f(); } // ok! -} -``` - -See also https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html -"##, - -E0158: r##" -An associated const has been referenced in a pattern. - -Erroneous code example: - -```compile_fail,E0158 -enum EFoo { A, B, C, D } - -trait Foo { - const X: EFoo; -} - -fn test(arg: EFoo) { - match arg { - A::X => { // error! - println!("A::X"); - } - } -} -``` - -`const` and `static` mean different things. A `const` is a compile-time -constant, an alias for a literal value. This property means you can match it -directly within a pattern. - -The `static` keyword, on the other hand, guarantees a fixed location in memory. -This does not always mean that the value is constant. For example, a global -mutex can be declared `static` as well. - -If you want to match against a `static`, consider using a guard instead: - -``` -static FORTY_TWO: i32 = 42; - -match Some(42) { - Some(x) if x == FORTY_TWO => {} - _ => {} -} -``` -"##, - -E0161: r##" -A value was moved. However, its size was not known at compile time, and only -values of a known size can be moved. - -Erroneous code example: - -```compile_fail,E0161 -#![feature(box_syntax)] - -fn main() { - let array: &[isize] = &[1, 2, 3]; - let _x: Box<[isize]> = box *array; - // error: cannot move a value of type [isize]: the size of [isize] cannot - // be statically determined -} -``` - -In Rust, you can only move a value when its size is known at compile time. - -To work around this restriction, consider "hiding" the value behind a reference: -either `&x` or `&mut x`. Since a reference has a fixed size, this lets you move -it around as usual. Example: - -``` -#![feature(box_syntax)] - -fn main() { - let array: &[isize] = &[1, 2, 3]; - let _x: Box<&[isize]> = box array; // ok! -} -``` -"##, - -E0162: r##" -#### Note: this error code is no longer emitted by the compiler. - -An if-let pattern attempts to match the pattern, and enters the body if the -match was successful. If the match is irrefutable (when it cannot fail to -match), use a regular `let`-binding instead. For instance: - -``` -struct Irrefutable(i32); -let irr = Irrefutable(0); - -// This fails to compile because the match is irrefutable. -if let Irrefutable(x) = irr { - // This body will always be executed. - // ... -} -``` - -Try this instead: - -``` -struct Irrefutable(i32); -let irr = Irrefutable(0); - -let Irrefutable(x) = irr; -println!("{}", x); -``` -"##, - -E0165: r##" -#### Note: this error code is no longer emitted by the compiler. - -A while-let pattern attempts to match the pattern, and enters the body if the -match was successful. If the match is irrefutable (when it cannot fail to -match), use a regular `let`-binding inside a `loop` instead. For instance: - -```no_run -struct Irrefutable(i32); -let irr = Irrefutable(0); - -// This fails to compile because the match is irrefutable. -while let Irrefutable(x) = irr { - // ... -} -``` - -Try this instead: - -```no_run -struct Irrefutable(i32); -let irr = Irrefutable(0); - -loop { - let Irrefutable(x) = irr; - // ... -} -``` -"##, - -E0170: r##" -Enum variants are qualified by default. For example, given this type: - -``` -enum Method { - GET, - POST, -} -``` - -You would match it using: - -``` -enum Method { - GET, - POST, -} - -let m = Method::GET; - -match m { - Method::GET => {}, - Method::POST => {}, -} -``` - -If you don't qualify the names, the code will bind new variables named "GET" and -"POST" instead. This behavior is likely not what you want, so `rustc` warns when -that happens. - -Qualified names are good practice, and most code works well with them. But if -you prefer them unqualified, you can import the variants into scope: - -``` -use Method::*; -enum Method { GET, POST } -# fn main() {} -``` - -If you want others to be able to import variants from your module directly, use -`pub use`: - -``` -pub use Method::*; -pub enum Method { GET, POST } -# fn main() {} -``` -"##, - - -E0297: r##" -#### Note: this error code is no longer emitted by the compiler. - -Patterns used to bind names must be irrefutable. That is, they must guarantee -that a name will be extracted in all cases. Instead of pattern matching the -loop variable, consider using a `match` or `if let` inside the loop body. For -instance: - -```compile_fail,E0005 -let xs : Vec> = vec![Some(1), None]; - -// This fails because `None` is not covered. -for Some(x) in xs { - // ... -} -``` - -Match inside the loop instead: - -``` -let xs : Vec> = vec![Some(1), None]; - -for item in xs { - match item { - Some(x) => {}, - None => {}, - } -} -``` - -Or use `if let`: - -``` -let xs : Vec> = vec![Some(1), None]; - -for item in xs { - if let Some(x) = item { - // ... - } -} -``` -"##, - -E0301: r##" -#### Note: this error code is no longer emitted by the compiler. - -Mutable borrows are not allowed in pattern guards, because matching cannot have -side effects. Side effects could alter the matched object or the environment -on which the match depends in such a way, that the match would not be -exhaustive. For instance, the following would not match any arm if mutable -borrows were allowed: - -```compile_fail,E0596 -match Some(()) { - None => { }, - option if option.take().is_none() => { - /* impossible, option is `Some` */ - }, - Some(_) => { } // When the previous match failed, the option became `None`. -} -``` -"##, - -E0302: r##" -#### Note: this error code is no longer emitted by the compiler. - -Assignments are not allowed in pattern guards, because matching cannot have -side effects. Side effects could alter the matched object or the environment -on which the match depends in such a way, that the match would not be -exhaustive. For instance, the following would not match any arm if assignments -were allowed: - -```compile_fail,E0594 -match Some(()) { - None => { }, - option if { option = None; false } => { }, - Some(_) => { } // When the previous match failed, the option became `None`. -} -``` -"##, - -E0303: r##" -In certain cases it is possible for sub-bindings to violate memory safety. -Updates to the borrow checker in a future version of Rust may remove this -restriction, but for now patterns must be rewritten without sub-bindings. - -Before: - -```compile_fail,E0303 -match Some("hi".to_string()) { - ref op_string_ref @ Some(s) => {}, - None => {}, -} -``` - -After: - -``` -match Some("hi".to_string()) { - Some(ref s) => { - let op_string_ref = &Some(s); - // ... - }, - None => {}, -} -``` - -The `op_string_ref` binding has type `&Option<&String>` in both cases. - -See also https://github.com/rust-lang/rust/issues/14587 -"##, - -E0373: r##" -This error occurs when an attempt is made to use data captured by a closure, -when that data may no longer exist. It's most commonly seen when attempting to -return a closure: - -```compile_fail,E0373 -fn foo() -> Box u32> { - let x = 0u32; - Box::new(|y| x + y) -} -``` - -Notice that `x` is stack-allocated by `foo()`. By default, Rust captures -closed-over data by reference. This means that once `foo()` returns, `x` no -longer exists. An attempt to access `x` within the closure would thus be -unsafe. - -Another situation where this might be encountered is when spawning threads: - -```compile_fail,E0373 -fn foo() { - let x = 0u32; - let y = 1u32; - - let thr = std::thread::spawn(|| { - x + y - }); -} -``` - -Since our new thread runs in parallel, the stack frame containing `x` and `y` -may well have disappeared by the time we try to use them. Even if we call -`thr.join()` within foo (which blocks until `thr` has completed, ensuring the -stack frame won't disappear), we will not succeed: the compiler cannot prove -that this behaviour is safe, and so won't let us do it. - -The solution to this problem is usually to switch to using a `move` closure. -This approach moves (or copies, where possible) data into the closure, rather -than taking references to it. For example: - -``` -fn foo() -> Box u32> { - let x = 0u32; - Box::new(move |y| x + y) -} -``` - -Now that the closure has its own copy of the data, there's no need to worry -about safety. -"##, - -E0381: r##" -It is not allowed to use or capture an uninitialized variable. - -Erroneous code example: - -```compile_fail,E0381 -fn main() { - let x: i32; - let y = x; // error, use of possibly-uninitialized variable -} -``` - -To fix this, ensure that any declared variables are initialized before being -used. Example: - -``` -fn main() { - let x: i32 = 0; - let y = x; // ok! -} -``` -"##, - -E0382: r##" -This error occurs when an attempt is made to use a variable after its contents -have been moved elsewhere. - -Erroneous code example: - -```compile_fail,E0382 -struct MyStruct { s: u32 } - -fn main() { - let mut x = MyStruct{ s: 5u32 }; - let y = x; - x.s = 6; - println!("{}", x.s); -} -``` - -Since `MyStruct` is a type that is not marked `Copy`, the data gets moved out -of `x` when we set `y`. This is fundamental to Rust's ownership system: outside -of workarounds like `Rc`, a value cannot be owned by more than one variable. - -Sometimes we don't need to move the value. Using a reference, we can let another -function borrow the value without changing its ownership. In the example below, -we don't actually have to move our string to `calculate_length`, we can give it -a reference to it with `&` instead. - -``` -fn main() { - let s1 = String::from("hello"); - - let len = calculate_length(&s1); - - println!("The length of '{}' is {}.", s1, len); -} - -fn calculate_length(s: &String) -> usize { - s.len() -} -``` - -A mutable reference can be created with `&mut`. - -Sometimes we don't want a reference, but a duplicate. All types marked `Clone` -can be duplicated by calling `.clone()`. Subsequent changes to a clone do not -affect the original variable. - -Most types in the standard library are marked `Clone`. The example below -demonstrates using `clone()` on a string. `s1` is first set to "many", and then -copied to `s2`. Then the first character of `s1` is removed, without affecting -`s2`. "any many" is printed to the console. - -``` -fn main() { - let mut s1 = String::from("many"); - let s2 = s1.clone(); - s1.remove(0); - println!("{} {}", s1, s2); -} -``` - -If we control the definition of a type, we can implement `Clone` on it ourselves -with `#[derive(Clone)]`. - -Some types have no ownership semantics at all and are trivial to duplicate. An -example is `i32` and the other number types. We don't have to call `.clone()` to -clone them, because they are marked `Copy` in addition to `Clone`. Implicit -cloning is more convenient in this case. We can mark our own types `Copy` if -all their members also are marked `Copy`. - -In the example below, we implement a `Point` type. Because it only stores two -integers, we opt-out of ownership semantics with `Copy`. Then we can -`let p2 = p1` without `p1` being moved. - -``` -#[derive(Copy, Clone)] -struct Point { x: i32, y: i32 } - -fn main() { - let mut p1 = Point{ x: -1, y: 2 }; - let p2 = p1; - p1.x = 1; - println!("p1: {}, {}", p1.x, p1.y); - println!("p2: {}, {}", p2.x, p2.y); -} -``` - -Alternatively, if we don't control the struct's definition, or mutable shared -ownership is truly required, we can use `Rc` and `RefCell`: - -``` -use std::cell::RefCell; -use std::rc::Rc; - -struct MyStruct { s: u32 } - -fn main() { - let mut x = Rc::new(RefCell::new(MyStruct{ s: 5u32 })); - let y = x.clone(); - x.borrow_mut().s = 6; - println!("{}", x.borrow().s); -} -``` - -With this approach, x and y share ownership of the data via the `Rc` (reference -count type). `RefCell` essentially performs runtime borrow checking: ensuring -that at most one writer or multiple readers can access the data at any one time. - -If you wish to learn more about ownership in Rust, start with the chapter in the -Book: - -https://doc.rust-lang.org/book/ch04-00-understanding-ownership.html -"##, - -E0383: r##" -#### Note: this error code is no longer emitted by the compiler. - -This error occurs when an attempt is made to partially reinitialize a -structure that is currently uninitialized. - -For example, this can happen when a drop has taken place: - -```compile_fail -struct Foo { - a: u32, -} -impl Drop for Foo { - fn drop(&mut self) { /* ... */ } -} - -let mut x = Foo { a: 1 }; -drop(x); // `x` is now uninitialized -x.a = 2; // error, partial reinitialization of uninitialized structure `t` -``` - -This error can be fixed by fully reinitializing the structure in question: - -``` -struct Foo { - a: u32, -} -impl Drop for Foo { - fn drop(&mut self) { /* ... */ } -} - -let mut x = Foo { a: 1 }; -drop(x); -x = Foo { a: 2 }; -``` -"##, - -E0384: r##" -This error occurs when an attempt is made to reassign an immutable variable. - -Erroneous code example: - -```compile_fail,E0384 -fn main() { - let x = 3; - x = 5; // error, reassignment of immutable variable -} -``` - -By default, variables in Rust are immutable. To fix this error, add the keyword -`mut` after the keyword `let` when declaring the variable. For example: - -``` -fn main() { - let mut x = 3; - x = 5; -} -``` -"##, - -E0386: r##" -#### Note: this error code is no longer emitted by the compiler. - -This error occurs when an attempt is made to mutate the target of a mutable -reference stored inside an immutable container. - -For example, this can happen when storing a `&mut` inside an immutable `Box`: - -``` -let mut x: i64 = 1; -let y: Box<_> = Box::new(&mut x); -**y = 2; // error, cannot assign to data in an immutable container -``` - -This error can be fixed by making the container mutable: - -``` -let mut x: i64 = 1; -let mut y: Box<_> = Box::new(&mut x); -**y = 2; -``` - -It can also be fixed by using a type with interior mutability, such as `Cell` -or `RefCell`: - -``` -use std::cell::Cell; - -let x: i64 = 1; -let y: Box> = Box::new(Cell::new(x)); -y.set(2); -``` -"##, - -E0387: r##" -#### Note: this error code is no longer emitted by the compiler. - -This error occurs when an attempt is made to mutate or mutably reference data -that a closure has captured immutably. - -Erroneous code example: - -```compile_fail -// Accepts a function or a closure that captures its environment immutably. -// Closures passed to foo will not be able to mutate their closed-over state. -fn foo(f: F) { } - -// Attempts to mutate closed-over data. Error message reads: -// `cannot assign to data in a captured outer variable...` -fn mutable() { - let mut x = 0u32; - foo(|| x = 2); -} - -// Attempts to take a mutable reference to closed-over data. Error message -// reads: `cannot borrow data mutably in a captured outer variable...` -fn mut_addr() { - let mut x = 0u32; - foo(|| { let y = &mut x; }); -} -``` - -The problem here is that foo is defined as accepting a parameter of type `Fn`. -Closures passed into foo will thus be inferred to be of type `Fn`, meaning that -they capture their context immutably. - -If the definition of `foo` is under your control, the simplest solution is to -capture the data mutably. This can be done by defining `foo` to take FnMut -rather than Fn: - -``` -fn foo(f: F) { } -``` - -Alternatively, we can consider using the `Cell` and `RefCell` types to achieve -interior mutability through a shared reference. Our example's `mutable` -function could be redefined as below: - -``` -use std::cell::Cell; - -fn foo(f: F) { } - -fn mutable() { - let x = Cell::new(0u32); - foo(|| x.set(2)); -} -``` - -You can read more about cell types in the API documentation: - -https://doc.rust-lang.org/std/cell/ -"##, - -E0388: r##" -#### Note: this error code is no longer emitted by the compiler. -"##, - -E0389: r##" -#### Note: this error code is no longer emitted by the compiler. - -An attempt was made to mutate data using a non-mutable reference. This -commonly occurs when attempting to assign to a non-mutable reference of a -mutable reference (`&(&mut T)`). - -Erroneous code example: - -```compile_fail -struct FancyNum { - num: u8, -} - -fn main() { - let mut fancy = FancyNum{ num: 5 }; - let fancy_ref = &(&mut fancy); - fancy_ref.num = 6; // error: cannot assign to data in a `&` reference - println!("{}", fancy_ref.num); -} -``` - -Here, `&mut fancy` is mutable, but `&(&mut fancy)` is not. Creating an -immutable reference to a value borrows it immutably. There can be multiple -references of type `&(&mut T)` that point to the same value, so they must be -immutable to prevent multiple mutable references to the same value. - -To fix this, either remove the outer reference: - -``` -struct FancyNum { - num: u8, -} - -fn main() { - let mut fancy = FancyNum{ num: 5 }; - - let fancy_ref = &mut fancy; - // `fancy_ref` is now &mut FancyNum, rather than &(&mut FancyNum) - - fancy_ref.num = 6; // No error! - - println!("{}", fancy_ref.num); -} -``` - -Or make the outer reference mutable: - -``` -struct FancyNum { - num: u8 -} - -fn main() { - let mut fancy = FancyNum{ num: 5 }; - - let fancy_ref = &mut (&mut fancy); - // `fancy_ref` is now &mut(&mut FancyNum), rather than &(&mut FancyNum) - - fancy_ref.num = 6; // No error! - - println!("{}", fancy_ref.num); -} -``` -"##, - -E0492: r##" -A borrow of a constant containing interior mutability was attempted. - -Erroneous code example: - -```compile_fail,E0492 -use std::sync::atomic::AtomicUsize; - -const A: AtomicUsize = AtomicUsize::new(0); -static B: &'static AtomicUsize = &A; -// error: cannot borrow a constant which may contain interior mutability, -// create a static instead -``` - -A `const` represents a constant value that should never change. If one takes -a `&` reference to the constant, then one is taking a pointer to some memory -location containing the value. Normally this is perfectly fine: most values -can't be changed via a shared `&` pointer, but interior mutability would allow -it. That is, a constant value could be mutated. On the other hand, a `static` is -explicitly a single memory location, which can be mutated at will. - -So, in order to solve this error, either use statics which are `Sync`: - -``` -use std::sync::atomic::AtomicUsize; - -static A: AtomicUsize = AtomicUsize::new(0); -static B: &'static AtomicUsize = &A; // ok! -``` - -You can also have this error while using a cell type: - -```compile_fail,E0492 -use std::cell::Cell; - -const A: Cell = Cell::new(1); -const B: &Cell = &A; -// error: cannot borrow a constant which may contain interior mutability, -// create a static instead - -// or: -struct C { a: Cell } - -const D: C = C { a: Cell::new(1) }; -const E: &Cell = &D.a; // error - -// or: -const F: &C = &D; // error -``` - -This is because cell types do operations that are not thread-safe. Due to this, -they don't implement Sync and thus can't be placed in statics. - -However, if you still wish to use these types, you can achieve this by an unsafe -wrapper: - -``` -use std::cell::Cell; -use std::marker::Sync; - -struct NotThreadSafe { - value: Cell, -} - -unsafe impl Sync for NotThreadSafe {} - -static A: NotThreadSafe = NotThreadSafe { value : Cell::new(1) }; -static B: &'static NotThreadSafe = &A; // ok! -``` - -Remember this solution is unsafe! You will have to ensure that accesses to the -cell are synchronized. -"##, - -E0493: r##" -A type with a `Drop` implementation was destructured when trying to initialize -a static item. - -Erroneous code example: - -```compile_fail,E0493 -enum DropType { - A, -} - -impl Drop for DropType { - fn drop(&mut self) {} -} - -struct Foo { - field1: DropType, -} - -static FOO: Foo = Foo { ..Foo { field1: DropType::A } }; // error! -``` - -The problem here is that if the given type or one of its fields implements the -`Drop` trait, this `Drop` implementation cannot be called during the static -type initialization which might cause a memory leak. To prevent this issue, -you need to instantiate all the static type's fields by hand. - -``` -enum DropType { - A, -} - -impl Drop for DropType { - fn drop(&mut self) {} -} - -struct Foo { - field1: DropType, -} - -static FOO: Foo = Foo { field1: DropType::A }; // We initialize all fields - // by hand. -``` -"##, - -E0499: r##" -A variable was borrowed as mutable more than once. - -Erroneous code example: - -```compile_fail,E0499 -let mut i = 0; -let mut x = &mut i; -let mut a = &mut i; -x; -// error: cannot borrow `i` as mutable more than once at a time -``` - -Please note that in rust, you can either have many immutable references, or one -mutable reference. Take a look at -https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html for more -information. Example: - - -``` -let mut i = 0; -let mut x = &mut i; // ok! - -// or: -let mut i = 0; -let a = &i; // ok! -let b = &i; // still ok! -let c = &i; // still ok! -b; -a; -``` -"##, - -E0500: r##" -A borrowed variable was used by a closure. - -Erroneous code example: - -```compile_fail,E0500 -fn you_know_nothing(jon_snow: &mut i32) { - let nights_watch = &jon_snow; - let starks = || { - *jon_snow = 3; // error: closure requires unique access to `jon_snow` - // but it is already borrowed - }; - println!("{}", nights_watch); -} -``` - -In here, `jon_snow` is already borrowed by the `nights_watch` reference, so it -cannot be borrowed by the `starks` closure at the same time. To fix this issue, -you can create the closure after the borrow has ended: - -``` -fn you_know_nothing(jon_snow: &mut i32) { - let nights_watch = &jon_snow; - println!("{}", nights_watch); - let starks = || { - *jon_snow = 3; - }; -} -``` - -Or, if the type implements the `Clone` trait, you can clone it between -closures: - -``` -fn you_know_nothing(jon_snow: &mut i32) { - let mut jon_copy = jon_snow.clone(); - let starks = || { - *jon_snow = 3; - }; - println!("{}", jon_copy); -} -``` -"##, - -E0501: r##" -This error indicates that a mutable variable is being used while it is still -captured by a closure. Because the closure has borrowed the variable, it is not -available for use until the closure goes out of scope. - -Note that a capture will either move or borrow a variable, but in this -situation, the closure is borrowing the variable. Take a look at -http://rustbyexample.com/fn/closures/capture.html for more information about -capturing. - -Erroneous code example: - -```compile_fail,E0501 -fn inside_closure(x: &mut i32) { - // Actions which require unique access -} - -fn outside_closure(x: &mut i32) { - // Actions which require unique access -} - -fn foo(a: &mut i32) { - let mut bar = || { - inside_closure(a) - }; - outside_closure(a); // error: cannot borrow `*a` as mutable because previous - // closure requires unique access. - bar(); -} -``` - -To fix this error, you can finish using the closure before using the captured -variable: - -``` -fn inside_closure(x: &mut i32) {} -fn outside_closure(x: &mut i32) {} - -fn foo(a: &mut i32) { - let mut bar = || { - inside_closure(a) - }; - bar(); - // borrow on `a` ends. - outside_closure(a); // ok! -} -``` - -Or you can pass the variable as a parameter to the closure: - -``` -fn inside_closure(x: &mut i32) {} -fn outside_closure(x: &mut i32) {} - -fn foo(a: &mut i32) { - let mut bar = |s: &mut i32| { - inside_closure(s) - }; - outside_closure(a); - bar(a); -} -``` - -It may be possible to define the closure later: - -``` -fn inside_closure(x: &mut i32) {} -fn outside_closure(x: &mut i32) {} - -fn foo(a: &mut i32) { - outside_closure(a); - let mut bar = || { - inside_closure(a) - }; - bar(); -} -``` -"##, - -E0502: r##" -This error indicates that you are trying to borrow a variable as mutable when it -has already been borrowed as immutable. - -Erroneous code example: - -```compile_fail,E0502 -fn bar(x: &mut i32) {} -fn foo(a: &mut i32) { - let ref y = a; // a is borrowed as immutable. - bar(a); // error: cannot borrow `*a` as mutable because `a` is also borrowed - // as immutable - println!("{}", y); -} -``` - -To fix this error, ensure that you don't have any other references to the -variable before trying to access it mutably: - -``` -fn bar(x: &mut i32) {} -fn foo(a: &mut i32) { - bar(a); - let ref y = a; // ok! - println!("{}", y); -} -``` - -For more information on the rust ownership system, take a look at -https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html. -"##, - -E0503: r##" -A value was used after it was mutably borrowed. - -Erroneous code example: - -```compile_fail,E0503 -fn main() { - let mut value = 3; - // Create a mutable borrow of `value`. - let borrow = &mut value; - let _sum = value + 1; // error: cannot use `value` because - // it was mutably borrowed - println!("{}", borrow); -} -``` - -In this example, `value` is mutably borrowed by `borrow` and cannot be -used to calculate `sum`. This is not possible because this would violate -Rust's mutability rules. - -You can fix this error by finishing using the borrow before the next use of -the value: - -``` -fn main() { - let mut value = 3; - let borrow = &mut value; - println!("{}", borrow); - // The block has ended and with it the borrow. - // You can now use `value` again. - let _sum = value + 1; -} -``` - -Or by cloning `value` before borrowing it: - -``` -fn main() { - let mut value = 3; - // We clone `value`, creating a copy. - let value_cloned = value.clone(); - // The mutable borrow is a reference to `value` and - // not to `value_cloned`... - let borrow = &mut value; - // ... which means we can still use `value_cloned`, - let _sum = value_cloned + 1; - // even though the borrow only ends here. - println!("{}", borrow); -} -``` - -You can find more information about borrowing in the rust-book: -http://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html -"##, - -E0504: r##" -#### Note: this error code is no longer emitted by the compiler. - -This error occurs when an attempt is made to move a borrowed variable into a -closure. - -Erroneous code example: - -```compile_fail -struct FancyNum { - num: u8, -} - -fn main() { - let fancy_num = FancyNum { num: 5 }; - let fancy_ref = &fancy_num; - - let x = move || { - println!("child function: {}", fancy_num.num); - // error: cannot move `fancy_num` into closure because it is borrowed - }; - - x(); - println!("main function: {}", fancy_ref.num); -} -``` - -Here, `fancy_num` is borrowed by `fancy_ref` and so cannot be moved into -the closure `x`. There is no way to move a value into a closure while it is -borrowed, as that would invalidate the borrow. - -If the closure can't outlive the value being moved, try using a reference -rather than moving: - -``` -struct FancyNum { - num: u8, -} - -fn main() { - let fancy_num = FancyNum { num: 5 }; - let fancy_ref = &fancy_num; - - let x = move || { - // fancy_ref is usable here because it doesn't move `fancy_num` - println!("child function: {}", fancy_ref.num); - }; - - x(); - - println!("main function: {}", fancy_num.num); -} -``` - -If the value has to be borrowed and then moved, try limiting the lifetime of -the borrow using a scoped block: - -``` -struct FancyNum { - num: u8, -} - -fn main() { - let fancy_num = FancyNum { num: 5 }; - - { - let fancy_ref = &fancy_num; - println!("main function: {}", fancy_ref.num); - // `fancy_ref` goes out of scope here - } - - let x = move || { - // `fancy_num` can be moved now (no more references exist) - println!("child function: {}", fancy_num.num); - }; - - x(); -} -``` - -If the lifetime of a reference isn't enough, such as in the case of threading, -consider using an `Arc` to create a reference-counted value: - -``` -use std::sync::Arc; -use std::thread; - -struct FancyNum { - num: u8, -} - -fn main() { - let fancy_ref1 = Arc::new(FancyNum { num: 5 }); - let fancy_ref2 = fancy_ref1.clone(); - - let x = thread::spawn(move || { - // `fancy_ref1` can be moved and has a `'static` lifetime - println!("child thread: {}", fancy_ref1.num); - }); - - x.join().expect("child thread should finish"); - println!("main thread: {}", fancy_ref2.num); -} -``` -"##, - -E0505: r##" -A value was moved out while it was still borrowed. - -Erroneous code example: - -```compile_fail,E0505 -struct Value {} - -fn borrow(val: &Value) {} - -fn eat(val: Value) {} - -fn main() { - let x = Value{}; - let _ref_to_val: &Value = &x; - eat(x); - borrow(_ref_to_val); -} -``` - -Here, the function `eat` takes ownership of `x`. However, -`x` cannot be moved because the borrow to `_ref_to_val` -needs to last till the function `borrow`. -To fix that you can do a few different things: - -* Try to avoid moving the variable. -* Release borrow before move. -* Implement the `Copy` trait on the type. - -Examples: - -``` -struct Value {} - -fn borrow(val: &Value) {} - -fn eat(val: &Value) {} - -fn main() { - let x = Value{}; - - let ref_to_val: &Value = &x; - eat(&x); // pass by reference, if it's possible - borrow(ref_to_val); -} -``` - -Or: - -``` -struct Value {} - -fn borrow(val: &Value) {} - -fn eat(val: Value) {} - -fn main() { - let x = Value{}; - - let ref_to_val: &Value = &x; - borrow(ref_to_val); - // ref_to_val is no longer used. - eat(x); -} -``` - -Or: - -``` -#[derive(Clone, Copy)] // implement Copy trait -struct Value {} - -fn borrow(val: &Value) {} - -fn eat(val: Value) {} - -fn main() { - let x = Value{}; - let ref_to_val: &Value = &x; - eat(x); // it will be copied here. - borrow(ref_to_val); -} -``` - -You can find more information about borrowing in the rust-book: -http://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html -"##, - -E0506: r##" -This error occurs when an attempt is made to assign to a borrowed value. - -Erroneous code example: - -```compile_fail,E0506 -struct FancyNum { - num: u8, -} - -fn main() { - let mut fancy_num = FancyNum { num: 5 }; - let fancy_ref = &fancy_num; - fancy_num = FancyNum { num: 6 }; - // error: cannot assign to `fancy_num` because it is borrowed - - println!("Num: {}, Ref: {}", fancy_num.num, fancy_ref.num); -} -``` - -Because `fancy_ref` still holds a reference to `fancy_num`, `fancy_num` can't -be assigned to a new value as it would invalidate the reference. - -Alternatively, we can move out of `fancy_num` into a second `fancy_num`: - -``` -struct FancyNum { - num: u8, -} - -fn main() { - let mut fancy_num = FancyNum { num: 5 }; - let moved_num = fancy_num; - fancy_num = FancyNum { num: 6 }; - - println!("Num: {}, Moved num: {}", fancy_num.num, moved_num.num); -} -``` - -If the value has to be borrowed, try limiting the lifetime of the borrow using -a scoped block: - -``` -struct FancyNum { - num: u8, -} - -fn main() { - let mut fancy_num = FancyNum { num: 5 }; - - { - let fancy_ref = &fancy_num; - println!("Ref: {}", fancy_ref.num); - } - - // Works because `fancy_ref` is no longer in scope - fancy_num = FancyNum { num: 6 }; - println!("Num: {}", fancy_num.num); -} -``` - -Or by moving the reference into a function: - -``` -struct FancyNum { - num: u8, -} - -fn main() { - let mut fancy_num = FancyNum { num: 5 }; - - print_fancy_ref(&fancy_num); - - // Works because function borrow has ended - fancy_num = FancyNum { num: 6 }; - println!("Num: {}", fancy_num.num); -} - -fn print_fancy_ref(fancy_ref: &FancyNum){ - println!("Ref: {}", fancy_ref.num); -} -``` -"##, - -E0507: r##" -You tried to move out of a value which was borrowed. - -This can also happen when using a type implementing `Fn` or `FnMut`, as neither -allows moving out of them (they usually represent closures which can be called -more than once). Much of the text following applies equally well to non-`FnOnce` -closure bodies. - -Erroneous code example: - -```compile_fail,E0507 -use std::cell::RefCell; - -struct TheDarkKnight; - -impl TheDarkKnight { - fn nothing_is_true(self) {} -} - -fn main() { - let x = RefCell::new(TheDarkKnight); - - x.borrow().nothing_is_true(); // error: cannot move out of borrowed content -} -``` - -Here, the `nothing_is_true` method takes the ownership of `self`. However, -`self` cannot be moved because `.borrow()` only provides an `&TheDarkKnight`, -which is a borrow of the content owned by the `RefCell`. To fix this error, -you have three choices: - -* Try to avoid moving the variable. -* Somehow reclaim the ownership. -* Implement the `Copy` trait on the type. - -Examples: - -``` -use std::cell::RefCell; - -struct TheDarkKnight; - -impl TheDarkKnight { - fn nothing_is_true(&self) {} // First case, we don't take ownership -} - -fn main() { - let x = RefCell::new(TheDarkKnight); - - x.borrow().nothing_is_true(); // ok! -} -``` - -Or: - -``` -use std::cell::RefCell; - -struct TheDarkKnight; - -impl TheDarkKnight { - fn nothing_is_true(self) {} -} - -fn main() { - let x = RefCell::new(TheDarkKnight); - let x = x.into_inner(); // we get back ownership - - x.nothing_is_true(); // ok! -} -``` - -Or: - -``` -use std::cell::RefCell; - -#[derive(Clone, Copy)] // we implement the Copy trait -struct TheDarkKnight; - -impl TheDarkKnight { - fn nothing_is_true(self) {} -} - -fn main() { - let x = RefCell::new(TheDarkKnight); - - x.borrow().nothing_is_true(); // ok! -} -``` - -Moving a member out of a mutably borrowed struct will also cause E0507 error: - -```compile_fail,E0507 -struct TheDarkKnight; - -impl TheDarkKnight { - fn nothing_is_true(self) {} -} - -struct Batcave { - knight: TheDarkKnight -} - -fn main() { - let mut cave = Batcave { - knight: TheDarkKnight - }; - let borrowed = &mut cave; - - borrowed.knight.nothing_is_true(); // E0507 -} -``` - -It is fine only if you put something back. `mem::replace` can be used for that: - -``` -# struct TheDarkKnight; -# impl TheDarkKnight { fn nothing_is_true(self) {} } -# struct Batcave { knight: TheDarkKnight } -use std::mem; - -let mut cave = Batcave { - knight: TheDarkKnight -}; -let borrowed = &mut cave; - -mem::replace(&mut borrowed.knight, TheDarkKnight).nothing_is_true(); // ok! -``` - -You can find more information about borrowing in the rust-book: -http://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html -"##, - -E0508: r##" -A value was moved out of a non-copy fixed-size array. - -Erroneous code example: - -```compile_fail,E0508 -struct NonCopy; - -fn main() { - let array = [NonCopy; 1]; - let _value = array[0]; // error: cannot move out of type `[NonCopy; 1]`, - // a non-copy fixed-size array -} -``` - -The first element was moved out of the array, but this is not -possible because `NonCopy` does not implement the `Copy` trait. - -Consider borrowing the element instead of moving it: - -``` -struct NonCopy; - -fn main() { - let array = [NonCopy; 1]; - let _value = &array[0]; // Borrowing is allowed, unlike moving. -} -``` - -Alternatively, if your type implements `Clone` and you need to own the value, -consider borrowing and then cloning: - -``` -#[derive(Clone)] -struct NonCopy; - -fn main() { - let array = [NonCopy; 1]; - // Now you can clone the array element. - let _value = array[0].clone(); -} -``` -"##, - -E0509: r##" -This error occurs when an attempt is made to move out of a value whose type -implements the `Drop` trait. - -Erroneous code example: - -```compile_fail,E0509 -struct FancyNum { - num: usize -} - -struct DropStruct { - fancy: FancyNum -} - -impl Drop for DropStruct { - fn drop(&mut self) { - // Destruct DropStruct, possibly using FancyNum - } -} - -fn main() { - let drop_struct = DropStruct{fancy: FancyNum{num: 5}}; - let fancy_field = drop_struct.fancy; // Error E0509 - println!("Fancy: {}", fancy_field.num); - // implicit call to `drop_struct.drop()` as drop_struct goes out of scope -} -``` - -Here, we tried to move a field out of a struct of type `DropStruct` which -implements the `Drop` trait. However, a struct cannot be dropped if one or -more of its fields have been moved. - -Structs implementing the `Drop` trait have an implicit destructor that gets -called when they go out of scope. This destructor may use the fields of the -struct, so moving out of the struct could make it impossible to run the -destructor. Therefore, we must think of all values whose type implements the -`Drop` trait as single units whose fields cannot be moved. - -This error can be fixed by creating a reference to the fields of a struct, -enum, or tuple using the `ref` keyword: - -``` -struct FancyNum { - num: usize -} - -struct DropStruct { - fancy: FancyNum -} - -impl Drop for DropStruct { - fn drop(&mut self) { - // Destruct DropStruct, possibly using FancyNum - } -} - -fn main() { - let drop_struct = DropStruct{fancy: FancyNum{num: 5}}; - let ref fancy_field = drop_struct.fancy; // No more errors! - println!("Fancy: {}", fancy_field.num); - // implicit call to `drop_struct.drop()` as drop_struct goes out of scope -} -``` - -Note that this technique can also be used in the arms of a match expression: - -``` -struct FancyNum { - num: usize -} - -enum DropEnum { - Fancy(FancyNum) -} - -impl Drop for DropEnum { - fn drop(&mut self) { - // Destruct DropEnum, possibly using FancyNum - } -} - -fn main() { - // Creates and enum of type `DropEnum`, which implements `Drop` - let drop_enum = DropEnum::Fancy(FancyNum{num: 10}); - match drop_enum { - // Creates a reference to the inside of `DropEnum::Fancy` - DropEnum::Fancy(ref fancy_field) => // No error! - println!("It was fancy-- {}!", fancy_field.num), - } - // implicit call to `drop_enum.drop()` as drop_enum goes out of scope -} -``` -"##, - -E0510: r##" -Cannot mutate place in this match guard. - -When matching on a variable it cannot be mutated in the match guards, as this -could cause the match to be non-exhaustive: - -```compile_fail,E0510 -let mut x = Some(0); -match x { - None => (), - Some(_) if { x = None; false } => (), - Some(v) => (), // No longer matches -} -``` - -Here executing `x = None` would modify the value being matched and require us -to go "back in time" to the `None` arm. -"##, - -E0515: r##" -Cannot return value that references local variable - -Local variables, function parameters and temporaries are all dropped before the -end of the function body. So a reference to them cannot be returned. - -Erroneous code example: - -```compile_fail,E0515 -fn get_dangling_reference() -> &'static i32 { - let x = 0; - &x -} -``` - -```compile_fail,E0515 -use std::slice::Iter; -fn get_dangling_iterator<'a>() -> Iter<'a, i32> { - let v = vec![1, 2, 3]; - v.iter() -} -``` - -Consider returning an owned value instead: - -``` -use std::vec::IntoIter; - -fn get_integer() -> i32 { - let x = 0; - x -} - -fn get_owned_iterator() -> IntoIter { - let v = vec![1, 2, 3]; - v.into_iter() -} -``` -"##, - -E0524: r##" -A variable which requires unique access is being used in more than one closure -at the same time. - -Erroneous code example: - -```compile_fail,E0524 -fn set(x: &mut isize) { - *x += 4; -} - -fn dragoooon(x: &mut isize) { - let mut c1 = || set(x); - let mut c2 = || set(x); // error! - - c2(); - c1(); -} -``` - -To solve this issue, multiple solutions are available. First, is it required -for this variable to be used in more than one closure at a time? If it is the -case, use reference counted types such as `Rc` (or `Arc` if it runs -concurrently): - -``` -use std::rc::Rc; -use std::cell::RefCell; - -fn set(x: &mut isize) { - *x += 4; -} - -fn dragoooon(x: &mut isize) { - let x = Rc::new(RefCell::new(x)); - let y = Rc::clone(&x); - let mut c1 = || { let mut x2 = x.borrow_mut(); set(&mut x2); }; - let mut c2 = || { let mut x2 = y.borrow_mut(); set(&mut x2); }; // ok! - - c2(); - c1(); -} -``` - -If not, just run closures one at a time: - -``` -fn set(x: &mut isize) { - *x += 4; -} - -fn dragoooon(x: &mut isize) { - { // This block isn't necessary since non-lexical lifetimes, it's just to - // make it more clear. - let mut c1 = || set(&mut *x); - c1(); - } // `c1` has been dropped here so we're free to use `x` again! - let mut c2 = || set(&mut *x); - c2(); -} -``` -"##, - -E0579: r##" -When matching against an exclusive range, the compiler verifies that the range -is non-empty. Exclusive range patterns include the start point but not the end -point, so this is equivalent to requiring the start of the range to be less -than the end of the range. - -Erroneous code example: - -```compile_fail,E0579 -#![feature(exclusive_range_pattern)] - -fn main() { - match 5u32 { - // This range is ok, albeit pointless. - 1 .. 2 => {} - // This range is empty, and the compiler can tell. - 5 .. 5 => {} // error! - } -} -``` -"##, - -E0594: r##" -A non-mutable value was assigned a value. - -Erroneous code example: - -```compile_fail,E0594 -struct SolarSystem { - earth: i32, -} - -let ss = SolarSystem { earth: 3 }; -ss.earth = 2; // error! -``` - -To fix this error, just declare `ss` as mutable by using the `mut` keyword: - -``` -struct SolarSystem { - earth: i32, -} - -let mut ss = SolarSystem { earth: 3 }; // declaring `ss` as mutable -ss.earth = 2; // ok! -``` -"##, - -E0595: r##" -#### Note: this error code is no longer emitted by the compiler. - -Closures cannot mutate immutable captured variables. - -Erroneous code example: - -```compile_fail,E0594 -let x = 3; // error: closure cannot assign to immutable local variable `x` -let mut c = || { x += 1 }; -``` - -Make the variable binding mutable: - -``` -let mut x = 3; // ok! -let mut c = || { x += 1 }; -``` -"##, - -E0596: r##" -This error occurs because you tried to mutably borrow a non-mutable variable. - -Erroneous code example: - -```compile_fail,E0596 -let x = 1; -let y = &mut x; // error: cannot borrow mutably -``` - -In here, `x` isn't mutable, so when we try to mutably borrow it in `y`, it -fails. To fix this error, you need to make `x` mutable: - -``` -let mut x = 1; -let y = &mut x; // ok! -``` -"##, - -E0597: r##" -This error occurs because a value was dropped while it was still borrowed - -Erroneous code example: - -```compile_fail,E0597 -struct Foo<'a> { - x: Option<&'a u32>, -} - -let mut x = Foo { x: None }; -{ - let y = 0; - x.x = Some(&y); // error: `y` does not live long enough -} -println!("{:?}", x.x); -``` - -In here, `y` is dropped at the end of the inner scope, but it is borrowed by -`x` until the `println`. To fix the previous example, just remove the scope -so that `y` isn't dropped until after the println - -``` -struct Foo<'a> { - x: Option<&'a u32>, -} - -let mut x = Foo { x: None }; - -let y = 0; -x.x = Some(&y); - -println!("{:?}", x.x); -``` -"##, - -E0626: r##" -This error occurs because a borrow in a generator persists across a -yield point. - -Erroneous code example: - -```compile_fail,E0626 -# #![feature(generators, generator_trait, pin)] -# use std::ops::Generator; -# use std::pin::Pin; -let mut b = || { - let a = &String::new(); // <-- This borrow... - yield (); // ...is still in scope here, when the yield occurs. - println!("{}", a); -}; -Pin::new(&mut b).resume(); -``` - -At present, it is not permitted to have a yield that occurs while a -borrow is still in scope. To resolve this error, the borrow must -either be "contained" to a smaller scope that does not overlap the -yield or else eliminated in another way. So, for example, we might -resolve the previous example by removing the borrow and just storing -the integer by value: - -``` -# #![feature(generators, generator_trait, pin)] -# use std::ops::Generator; -# use std::pin::Pin; -let mut b = || { - let a = 3; - yield (); - println!("{}", a); -}; -Pin::new(&mut b).resume(); -``` - -This is a very simple case, of course. In more complex cases, we may -wish to have more than one reference to the value that was borrowed -- -in those cases, something like the `Rc` or `Arc` types may be useful. - -This error also frequently arises with iteration: - -```compile_fail,E0626 -# #![feature(generators, generator_trait, pin)] -# use std::ops::Generator; -# use std::pin::Pin; -let mut b = || { - let v = vec![1,2,3]; - for &x in &v { // <-- borrow of `v` is still in scope... - yield x; // ...when this yield occurs. - } -}; -Pin::new(&mut b).resume(); -``` - -Such cases can sometimes be resolved by iterating "by value" (or using -`into_iter()`) to avoid borrowing: - -``` -# #![feature(generators, generator_trait, pin)] -# use std::ops::Generator; -# use std::pin::Pin; -let mut b = || { - let v = vec![1,2,3]; - for x in v { // <-- Take ownership of the values instead! - yield x; // <-- Now yield is OK. - } -}; -Pin::new(&mut b).resume(); -``` - -If taking ownership is not an option, using indices can work too: - -``` -# #![feature(generators, generator_trait, pin)] -# use std::ops::Generator; -# use std::pin::Pin; -let mut b = || { - let v = vec![1,2,3]; - let len = v.len(); // (*) - for i in 0..len { - let x = v[i]; // (*) - yield x; // <-- Now yield is OK. - } -}; -Pin::new(&mut b).resume(); - -// (*) -- Unfortunately, these temporaries are currently required. -// See . -``` -"##, - -E0712: r##" -This error occurs because a borrow of a thread-local variable was made inside a -function which outlived the lifetime of the function. - -Erroneous code example: - -```compile_fail,E0712 -#![feature(thread_local)] - -#[thread_local] -static FOO: u8 = 3; - -fn main() { - let a = &FOO; // error: thread-local variable borrowed past end of function - - std::thread::spawn(move || { - println!("{}", a); - }); -} -``` -"##, - -E0713: r##" -This error occurs when an attempt is made to borrow state past the end of the -lifetime of a type that implements the `Drop` trait. - -Erroneous code example: - -```compile_fail,E0713 -#![feature(nll)] - -pub struct S<'a> { data: &'a mut String } - -impl<'a> Drop for S<'a> { - fn drop(&mut self) { self.data.push_str("being dropped"); } -} - -fn demo<'a>(s: S<'a>) -> &'a mut String { let p = &mut *s.data; p } -``` - -Here, `demo` tries to borrow the string data held within its -argument `s` and then return that borrow. However, `S` is -declared as implementing `Drop`. - -Structs implementing the `Drop` trait have an implicit destructor that -gets called when they go out of scope. This destructor gets exclusive -access to the fields of the struct when it runs. - -This means that when `s` reaches the end of `demo`, its destructor -gets exclusive access to its `&mut`-borrowed string data. allowing -another borrow of that string data (`p`), to exist across the drop of -`s` would be a violation of the principle that `&mut`-borrows have -exclusive, unaliased access to their referenced data. - -This error can be fixed by changing `demo` so that the destructor does -not run while the string-data is borrowed; for example by taking `S` -by reference: - -``` -pub struct S<'a> { data: &'a mut String } - -impl<'a> Drop for S<'a> { - fn drop(&mut self) { self.data.push_str("being dropped"); } -} - -fn demo<'a>(s: &'a mut S<'a>) -> &'a mut String { let p = &mut *(*s).data; p } -``` - -Note that this approach needs a reference to S with lifetime `'a`. -Nothing shorter than `'a` will suffice: a shorter lifetime would imply -that after `demo` finishes executing, something else (such as the -destructor!) could access `s.data` after the end of that shorter -lifetime, which would again violate the `&mut`-borrow's exclusive -access. -"##, - -E0716: r##" -This error indicates that a temporary value is being dropped -while a borrow is still in active use. - -Erroneous code example: - -```compile_fail,E0716 -fn foo() -> i32 { 22 } -fn bar(x: &i32) -> &i32 { x } -let p = bar(&foo()); - // ------ creates a temporary -let q = *p; -``` - -Here, the expression `&foo()` is borrowing the expression -`foo()`. As `foo()` is a call to a function, and not the name of -a variable, this creates a **temporary** -- that temporary stores -the return value from `foo()` so that it can be borrowed. -You could imagine that `let p = bar(&foo());` is equivalent -to this: - -```compile_fail,E0597 -# fn foo() -> i32 { 22 } -# fn bar(x: &i32) -> &i32 { x } -let p = { - let tmp = foo(); // the temporary - bar(&tmp) -}; // <-- tmp is freed as we exit this block -let q = p; -``` - -Whenever a temporary is created, it is automatically dropped (freed) -according to fixed rules. Ordinarily, the temporary is dropped -at the end of the enclosing statement -- in this case, after the `let`. -This is illustrated in the example above by showing that `tmp` would -be freed as we exit the block. - -To fix this problem, you need to create a local variable -to store the value in rather than relying on a temporary. -For example, you might change the original program to -the following: - -``` -fn foo() -> i32 { 22 } -fn bar(x: &i32) -> &i32 { x } -let value = foo(); // dropped at the end of the enclosing block -let p = bar(&value); -let q = *p; -``` - -By introducing the explicit `let value`, we allocate storage -that will last until the end of the enclosing block (when `value` -goes out of scope). When we borrow `&value`, we are borrowing a -local variable that already exists, and hence no temporary is created. - -Temporaries are not always dropped at the end of the enclosing -statement. In simple cases where the `&` expression is immediately -stored into a variable, the compiler will automatically extend -the lifetime of the temporary until the end of the enclosing -block. Therefore, an alternative way to fix the original -program is to write `let tmp = &foo()` and not `let tmp = foo()`: - -``` -fn foo() -> i32 { 22 } -fn bar(x: &i32) -> &i32 { x } -let value = &foo(); -let p = bar(value); -let q = *p; -``` - -Here, we are still borrowing `foo()`, but as the borrow is assigned -directly into a variable, the temporary will not be dropped until -the end of the enclosing block. Similar rules apply when temporaries -are stored into aggregate structures like a tuple or struct: - -``` -// Here, two temporaries are created, but -// as they are stored directly into `value`, -// they are not dropped until the end of the -// enclosing block. -fn foo() -> i32 { 22 } -let value = (&foo(), &foo()); -``` -"##, - -E0723: r##" -An feature unstable in `const` contexts was used. - -Erroneous code example: - -```compile_fail,E0723 -trait T {} - -impl T for () {} - -const fn foo() -> impl T { // error: `impl Trait` in const fn is unstable - () -} -``` - -To enable this feature on a nightly version of rustc, add the `const_fn` -feature flag: - -``` -#![feature(const_fn)] - -trait T {} - -impl T for () {} - -const fn foo() -> impl T { - () -} -``` -"##, - -E0729: r##" -Support for Non-Lexical Lifetimes (NLL) has been included in the Rust compiler -since 1.31, and has been enabled on the 2015 edition since 1.36. The new borrow -checker for NLL uncovered some bugs in the old borrow checker, which in some -cases allowed unsound code to compile, resulting in memory safety issues. - -### What do I do? - -Change your code so the warning does no longer trigger. For backwards -compatibility, this unsound code may still compile (with a warning) right now. -However, at some point in the future, the compiler will no longer accept this -code and will throw a hard error. - -### Shouldn't you fix the old borrow checker? - -The old borrow checker has known soundness issues that are basically impossible -to fix. The new NLL-based borrow checker is the fix. - -### Can I turn these warnings into errors by denying a lint? - -No. - -### When are these warnings going to turn into errors? - -No formal timeline for turning the warnings into errors has been set. See -[GitHub issue 58781](https://github.com/rust-lang/rust/issues/58781) for more -information. - -### Why do I get this message with code that doesn't involve borrowing? - -There are some known bugs that trigger this message. -"##, - -; - -// E0008, // cannot bind by-move into a pattern guard -// E0298, // cannot compare constants -// E0299, // mismatched types between arms -// E0471, // constant evaluation error (in pattern) -// E0385, // {} in an aliasable location - E0521, // borrowed data escapes outside of closure -// E0526, // shuffle indices are not constant -// E0598, // lifetime of {} is too short to guarantee its contents can be... - E0625, // thread-local statics cannot be accessed at compile-time -} From f6b327baa67c6d9d05315c9206d67de2ecaf2eda Mon Sep 17 00:00:00 2001 From: Yu Ding Date: Mon, 18 Nov 2019 19:43:24 -0800 Subject: [PATCH 27/28] Remove compiler_builtins_lib feature from libstd --- src/libstd/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 72d998de9c4b7..32023a5b75bfb 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -244,7 +244,6 @@ #![feature(cfg_target_thread_local)] #![feature(char_error_internals)] #![feature(clamp)] -#![feature(compiler_builtins_lib)] #![feature(concat_idents)] #![feature(const_cstr_unchecked)] #![feature(const_raw_ptr_deref)] From c84fae13e5eb5a475dcb214b170aaf77a8c3783d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 1 Nov 2019 15:16:52 +1100 Subject: [PATCH 28/28] Move the definition of `QueryResult` into `plumbing.rs`. Because it's the only file that uses it, and removes the need for importing it. --- src/librustc/ty/query/job.rs | 10 ---------- src/librustc/ty/query/plumbing.rs | 14 +++++++++++--- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/librustc/ty/query/job.rs b/src/librustc/ty/query/job.rs index 391ea762a083b..e5f4e793132f4 100644 --- a/src/librustc/ty/query/job.rs +++ b/src/librustc/ty/query/job.rs @@ -22,16 +22,6 @@ use { std::iter::FromIterator, }; -/// Indicates the state of a query for a given key in a query map. -pub(super) enum QueryResult<'tcx> { - /// An already executing query. The query job can be used to await for its completion. - Started(Lrc>), - - /// The query panicked. Queries trying to wait on this will raise a fatal error or - /// silently panic. - Poisoned, -} - /// Represents a span and a query key. #[derive(Clone, Debug)] pub struct QueryInfo<'tcx> { diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs index 52a784d3fc0be..fc55b665c1d0e 100644 --- a/src/librustc/ty/query/plumbing.rs +++ b/src/librustc/ty/query/plumbing.rs @@ -7,7 +7,7 @@ use crate::ty::tls; use crate::ty::{self, TyCtxt}; use crate::ty::query::Query; use crate::ty::query::config::{QueryConfig, QueryDescription}; -use crate::ty::query::job::{QueryJob, QueryResult, QueryInfo}; +use crate::ty::query::job::{QueryJob, QueryInfo}; use errors::DiagnosticBuilder; use errors::Level; @@ -52,6 +52,16 @@ impl QueryValue { } } +/// Indicates the state of a query for a given key in a query map. +pub(super) enum QueryResult<'tcx> { + /// An already executing query. The query job can be used to await for its completion. + Started(Lrc>), + + /// The query panicked. Queries trying to wait on this will raise a fatal error or + /// silently panic. + Poisoned, +} + impl<'tcx, M: QueryConfig<'tcx>> Default for QueryCache<'tcx, M> { fn default() -> QueryCache<'tcx, M> { QueryCache { @@ -676,8 +686,6 @@ macro_rules! define_queries_inner { [$($modifiers:tt)*] fn $name:ident: $node:ident($K:ty) -> $V:ty,)*) => { use std::mem; - #[cfg(parallel_compiler)] - use ty::query::job::QueryResult; use rustc_data_structures::sharded::Sharded; use crate::{ rustc_data_structures::stable_hasher::HashStable,