Fix merge conflicts
This commit is contained in:
commit
e45bbaf48c
1131 changed files with 6685 additions and 3696 deletions
|
|
@ -138,9 +138,8 @@ jobs:
|
|||
IMAGE: x86_64-gnu-full-bootstrap
|
||||
x86_64-gnu-aux:
|
||||
IMAGE: x86_64-gnu-aux
|
||||
# FIXME: needs reenabling here rather than Travis
|
||||
# x86_64-gnu-tools:
|
||||
# IMAGE: x86_64-gnu-tools
|
||||
x86_64-gnu-tools:
|
||||
IMAGE: x86_64-gnu-tools
|
||||
x86_64-gnu-debug:
|
||||
IMAGE: x86_64-gnu-debug
|
||||
x86_64-gnu-nopt:
|
||||
|
|
@ -252,12 +251,10 @@ jobs:
|
|||
RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc
|
||||
VCVARS_BAT: vcvars64.bat
|
||||
# MSVC tools tests
|
||||
# FIXME: broken on azure right now, need to figure out a cause and
|
||||
# reenable
|
||||
# x86_64-msvc-tools:
|
||||
# MSYS_BITS: 64
|
||||
# SCRIPT: src/ci/docker/x86_64-gnu-tools/checktools.sh x.py /tmp/toolstates.json windows
|
||||
# RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --save-toolstates=/tmp/toolstates.json --enable-test-miri
|
||||
x86_64-msvc-tools:
|
||||
MSYS_BITS: 64
|
||||
SCRIPT: src/ci/docker/x86_64-gnu-tools/checktools.sh x.py /tmp/toolstates.json windows
|
||||
RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --save-toolstates=/tmp/toolstates.json --enable-test-miri
|
||||
|
||||
# 32/64-bit MinGW builds.
|
||||
#
|
||||
|
|
|
|||
|
|
@ -8,6 +8,13 @@
|
|||
|
||||
steps:
|
||||
|
||||
# Disable automatic line ending conversion, which is enabled by default on
|
||||
# Azure's Windows image. Having the conversion enabled caused regressions both
|
||||
# in our test suite (it broke miri tests) and in the ecosystem, since we
|
||||
# started shipping install scripts with CRLF endings instead of the old LF.
|
||||
- bash: git config --global core.autocrlf false
|
||||
displayName: "Disable git automatic line ending conversion"
|
||||
|
||||
- checkout: self
|
||||
fetchDepth: 2
|
||||
|
||||
|
|
|
|||
2
.mailmap
2
.mailmap
|
|
@ -167,6 +167,8 @@ Matthijs Hofstra <thiezz@gmail.com>
|
|||
Melody Horn <melody@boringcactus.com> <mathphreak@gmail.com>
|
||||
Michael Williams <m.t.williams@live.com>
|
||||
Michael Woerister <michaelwoerister@posteo> <michaelwoerister@gmail>
|
||||
Michael Woerister <michaelwoerister@posteo> <michaelwoerister@users.noreply.github.com>
|
||||
Michael Woerister <michaelwoerister@posteo> <michaelwoerister@posteo.net>
|
||||
Mickaël Raybaud-Roig <raybaudroigm@gmail.com> m-r-r <raybaudroigm@gmail.com>
|
||||
Ms2ger <ms2ger@gmail.com> <Ms2ger@gmail.com>
|
||||
Mukilan Thiagarajan <mukilanthiagarajan@gmail.com>
|
||||
|
|
|
|||
164
.travis.yml
164
.travis.yml
|
|
@ -1,164 +1,10 @@
|
|||
language: shell
|
||||
sudo: required
|
||||
dist: xenial
|
||||
services:
|
||||
- docker
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gdb
|
||||
script: echo Travis CI is not used anymore
|
||||
|
||||
git:
|
||||
depth: 2
|
||||
submodules: false
|
||||
|
||||
env:
|
||||
global:
|
||||
- CI_JOB_NAME=$TRAVIS_JOB_NAME
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
include:
|
||||
- env: IMAGE=x86_64-gnu-tools
|
||||
name: x86_64-gnu-tools
|
||||
if: branch = auto OR (type = pull_request AND commit_message =~ /(?i:^update.*\b(rls|rustfmt|clippy|miri|cargo)\b)/)
|
||||
|
||||
before_install:
|
||||
# We'll use the AWS cli to download/upload cached docker layers as well as
|
||||
# push our deployments, so download that here.
|
||||
- pip install --user awscli; export PATH=$PATH:$HOME/.local/bin:$HOME/Library/Python/2.7/bin/
|
||||
- mkdir -p $HOME/rustsrc
|
||||
# FIXME(#46924): these two commands are required to enable IPv6,
|
||||
# they shouldn't exist, please revert once more official solutions appeared.
|
||||
# see https://github.com/travis-ci/travis-ci/issues/8891#issuecomment-353403729
|
||||
- if [ "$TRAVIS_OS_NAME" = linux ]; then
|
||||
echo '{"ipv6":true,"fixed-cidr-v6":"fd9a:8454:6789:13f7::/64"}' | sudo tee /etc/docker/daemon.json;
|
||||
sudo service docker restart;
|
||||
fi
|
||||
|
||||
install:
|
||||
- case "$TRAVIS_OS_NAME" in
|
||||
linux)
|
||||
travis_retry curl -fo $HOME/stamp https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/2017-03-17-stamp-x86_64-unknown-linux-musl &&
|
||||
chmod +x $HOME/stamp &&
|
||||
export PATH=$PATH:$HOME
|
||||
;;
|
||||
osx)
|
||||
if [[ "$SCRIPT" == "./x.py dist" ]]; then
|
||||
travis_retry brew update &&
|
||||
travis_retry brew install xz &&
|
||||
travis_retry brew install swig@3 &&
|
||||
brew link --force swig@3;
|
||||
fi &&
|
||||
travis_retry curl -fo /usr/local/bin/sccache https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/2018-04-02-sccache-x86_64-apple-darwin &&
|
||||
chmod +x /usr/local/bin/sccache &&
|
||||
travis_retry curl -fo /usr/local/bin/stamp https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/2017-03-17-stamp-x86_64-apple-darwin &&
|
||||
chmod +x /usr/local/bin/stamp &&
|
||||
travis_retry curl -f http://releases.llvm.org/7.0.0/clang+llvm-7.0.0-x86_64-apple-darwin.tar.xz | tar xJf - &&
|
||||
export CC=`pwd`/clang+llvm-7.0.0-x86_64-apple-darwin/bin/clang &&
|
||||
export CXX=`pwd`/clang+llvm-7.0.0-x86_64-apple-darwin/bin/clang++ &&
|
||||
export AR=ar
|
||||
;;
|
||||
esac
|
||||
|
||||
before_script:
|
||||
- >
|
||||
echo "#### Disk usage before running script:";
|
||||
df -h;
|
||||
du . | sort -nr | head -n100
|
||||
- >
|
||||
RUN_SCRIPT="src/ci/init_repo.sh . $HOME/rustsrc";
|
||||
if [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
export RUN_SCRIPT="$RUN_SCRIPT && src/ci/run.sh";
|
||||
else
|
||||
export RUN_SCRIPT="$RUN_SCRIPT && src/ci/docker/run.sh $IMAGE";
|
||||
# Enable core dump on Linux.
|
||||
sudo sh -c 'echo "/checkout/obj/cores/core.%p.%E" > /proc/sys/kernel/core_pattern';
|
||||
fi
|
||||
- >
|
||||
if [ "$IMAGE" = mingw-check ]; then
|
||||
# verify the publish_toolstate script works.
|
||||
git clone --depth=1 https://github.com/rust-lang-nursery/rust-toolstate.git;
|
||||
cd rust-toolstate;
|
||||
python2.7 "$TRAVIS_BUILD_DIR/src/tools/publish_toolstate.py" "$(git rev-parse HEAD)" "$(git log --format=%s -n1 HEAD)" "" "";
|
||||
cd ..;
|
||||
rm -rf rust-toolstate;
|
||||
fi
|
||||
|
||||
# Log time information from this machine and an external machine for insight into possible
|
||||
# clock drift. Timezones don't matter since relative deltas give all the necessary info.
|
||||
script:
|
||||
- >
|
||||
date && (curl -fs --head https://google.com | grep ^Date: | sed 's/Date: //g' || true)
|
||||
- stamp sh -x -c "$RUN_SCRIPT"
|
||||
- >
|
||||
date && (curl -fs --head https://google.com | grep ^Date: | sed 's/Date: //g' || true)
|
||||
|
||||
after_success:
|
||||
- >
|
||||
echo "#### Build successful; Disk usage after running script:";
|
||||
df -h;
|
||||
du . | sort -nr | head -n100
|
||||
- >
|
||||
if [ "$DEPLOY$DEPLOY_ALT" == "1" ]; then
|
||||
mkdir -p deploy/$TRAVIS_COMMIT;
|
||||
if [ "$TRAVIS_OS_NAME" == "osx" ]; then
|
||||
rm -rf build/dist/doc &&
|
||||
cp -r build/dist/* deploy/$TRAVIS_COMMIT;
|
||||
else
|
||||
rm -rf obj/build/dist/doc &&
|
||||
cp -r obj/build/dist/* deploy/$TRAVIS_COMMIT;
|
||||
fi;
|
||||
ls -la deploy/$TRAVIS_COMMIT;
|
||||
deploy_dir=rustc-builds;
|
||||
if [ "$DEPLOY_ALT" == "1" ]; then
|
||||
deploy_dir=rustc-builds-alt;
|
||||
fi;
|
||||
travis_retry aws s3 cp --no-progress --recursive --acl public-read ./deploy s3://rust-lang-ci2/$deploy_dir
|
||||
fi
|
||||
|
||||
after_failure:
|
||||
- >
|
||||
echo "#### Build failed; Disk usage after running script:";
|
||||
df -h;
|
||||
du . | sort -nr | head -n100
|
||||
|
||||
# Random attempt at debugging currently. Just poking around in here to see if
|
||||
# anything shows up.
|
||||
|
||||
# Dump backtrace for macOS
|
||||
- ls -lat $HOME/Library/Logs/DiagnosticReports/
|
||||
- find $HOME/Library/Logs/DiagnosticReports
|
||||
-type f
|
||||
-name '*.crash'
|
||||
-not -name '*.stage2-*.crash'
|
||||
-not -name 'com.apple.CoreSimulator.CoreSimulatorService-*.crash'
|
||||
-exec printf travis_fold":start:crashlog\n\033[31;1m%s\033[0m\n" {} \;
|
||||
-exec head -750 {} \;
|
||||
-exec echo travis_fold":"end:crashlog \; || true
|
||||
|
||||
# Dump backtrace for Linux
|
||||
- ln -s . checkout &&
|
||||
for CORE in obj/cores/core.*; do
|
||||
EXE=$(echo $CORE | sed 's|obj/cores/core\.[0-9]*\.!checkout!\(.*\)|\1|;y|!|/|');
|
||||
if [ -f "$EXE" ]; then
|
||||
printf travis_fold":start:crashlog\n\033[31;1m%s\033[0m\n" "$CORE";
|
||||
gdb --batch -q -c "$CORE" "$EXE"
|
||||
-iex 'set auto-load off'
|
||||
-iex 'dir src/'
|
||||
-iex 'set sysroot .'
|
||||
-ex bt
|
||||
-ex q;
|
||||
echo travis_fold":"end:crashlog;
|
||||
fi;
|
||||
done || true
|
||||
|
||||
# see #50887
|
||||
- cat ./obj/build/x86_64-unknown-linux-gnu/native/asan/build/lib/asan/clang_rt.asan-dynamic-i386.vers || true
|
||||
|
||||
# attempt to debug anything killed by the oom killer on linux, just to see if
|
||||
# it happened
|
||||
- dmesg | grep -i kill
|
||||
branches:
|
||||
only:
|
||||
- auto
|
||||
- try
|
||||
|
||||
notifications:
|
||||
email: false
|
||||
|
|
|
|||
26
Cargo.lock
26
Cargo.lock
|
|
@ -1030,7 +1030,7 @@ version = "0.1.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"new_debug_unreachable 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"new_debug_unreachable 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1760,11 +1760,8 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "new_debug_unreachable"
|
||||
version = "1.0.1"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nodrop"
|
||||
|
|
@ -3450,7 +3447,7 @@ version = "0.7.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"new_debug_unreachable 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"new_debug_unreachable 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"phf_shared 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
|
@ -4038,14 +4035,6 @@ name = "unicode_categories"
|
|||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unreachable"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unstable-book-gen"
|
||||
version = "0.1.0"
|
||||
|
|
@ -4124,11 +4113,6 @@ name = "version_check"
|
|||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "void"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "vte"
|
||||
version = "0.3.3"
|
||||
|
|
@ -4388,7 +4372,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
|
||||
"checksum miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "396aa0f2003d7df8395cb93e09871561ccc3e785f0acb369170e8cc74ddf9226"
|
||||
"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88"
|
||||
"checksum new_debug_unreachable 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0cdc457076c78ab54d5e0d6fa7c47981757f1e34dc39ff92787f217dede586c4"
|
||||
"checksum new_debug_unreachable 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f40f005c60db6e03bae699e414c58bf9aa7ea02a2d0b9bfbcf19286cc4c82b30"
|
||||
"checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2"
|
||||
"checksum num-derive 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8af1847c907c2f04d7bfd572fb25bbb4385c637fe5be163cf2f8c5d778fe1e7d"
|
||||
"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea"
|
||||
|
|
@ -4552,7 +4536,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc"
|
||||
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
|
||||
"checksum unicode_categories 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
|
||||
"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
|
||||
"checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a"
|
||||
"checksum url_serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "74e7d099f1ee52f823d4bdd60c93c3602043c728f5db3b97bdb548467f7bddea"
|
||||
"checksum utf-8 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f1262dfab4c30d5cb7c07026be00ee343a6cf5027fdc0104a9160f354e5db75c"
|
||||
|
|
@ -4562,7 +4545,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
|
||||
"checksum vergen 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6aba5e34f93dc7051dfad05b98a18e9156f27e7b431fe1d2398cb6061c0a1dba"
|
||||
"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
|
||||
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||
"checksum vte 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4f42f536e22f7fcbb407639765c8fd78707a33109301f834a594758bedd6e8cf"
|
||||
"checksum walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d9d7ed3431229a144296213105a390676cc49c9b6a72bd19f3176c98e129fa1"
|
||||
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||
|
|
|
|||
|
|
@ -309,9 +309,9 @@ Misc
|
|||
|
||||
Compatibility Notes
|
||||
-------------------
|
||||
- [`Command::before_exec` is now deprecated in favor of the
|
||||
unsafe method `Command::pre_exec`.][58059]
|
||||
- [Use of `ATOMIC_{BOOL, ISIZE, USIZE}_INIT` is now deprecated.][57425] As you
|
||||
- [`Command::before_exec` is being replaced by the unsafe method
|
||||
`Command::pre_exec`][58059] and will be deprecated with Rust 1.37.0.
|
||||
- [Use of `ATOMIC_{BOOL, ISIZE, USIZE}_INIT` is now deprecated][57425] as you
|
||||
can now use `const` functions in `static` variables.
|
||||
|
||||
[58370]: https://github.com/rust-lang/rust/pull/58370/
|
||||
|
|
|
|||
109
appveyor.yml
109
appveyor.yml
|
|
@ -1,113 +1,8 @@
|
|||
environment:
|
||||
# This is required for at least an AArch64 compiler in one image, and is also
|
||||
# going to soon be required for compiling LLVM.
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 Preview
|
||||
|
||||
# By default schannel checks revocation of certificates unlike some other SSL
|
||||
# backends, but we've historically had problems on CI where a revocation
|
||||
# server goes down presumably. See #43333 for more info
|
||||
CARGO_HTTP_CHECK_REVOKE: false
|
||||
|
||||
matrix:
|
||||
# MSVC tools tests
|
||||
- CI_JOB_NAME: x86_64-msvc-tools
|
||||
MSYS_BITS: 64
|
||||
SCRIPT: src/ci/docker/x86_64-gnu-tools/checktools.sh x.py /tmp/toolstates.json windows
|
||||
RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --save-toolstates=/tmp/toolstates.json --enable-test-miri
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
|
||||
clone_depth: 2
|
||||
clone_depth: 1
|
||||
build: false
|
||||
|
||||
install:
|
||||
# Print which AppVeyor agent version we're running on.
|
||||
- appveyor version
|
||||
# If we need to download a custom MinGW, do so here and set the path
|
||||
# appropriately.
|
||||
#
|
||||
# Note that this *also* means that we're not using what is typically
|
||||
# /mingw32/bin/python2.7.exe, which is a "correct" python interpreter where
|
||||
# /usr/bin/python2.7.exe is not. To ensure we use the right interpreter we
|
||||
# move `C:\Python27` ahead in PATH and then also make sure the `python2.7.exe`
|
||||
# file exists in there (which it doesn't by default).
|
||||
- if defined MINGW_URL appveyor-retry appveyor DownloadFile %MINGW_URL%/%MINGW_ARCHIVE%
|
||||
- if defined MINGW_URL 7z x -y %MINGW_ARCHIVE% > nul
|
||||
- if defined MINGW_URL set PATH=%CD%\%MINGW_DIR%\bin;C:\msys64\usr\bin;%PATH%
|
||||
|
||||
# If we're compiling for MSVC then we, like most other distribution builders,
|
||||
# switch to clang as the compiler. This'll allow us eventually to enable LTO
|
||||
# amongst LLVM and rustc. Note that we only do this on MSVC as I don't think
|
||||
# clang has an output mode compatible with MinGW that we need. If it does we
|
||||
# should switch to clang for MinGW as well!
|
||||
#
|
||||
# Note that the LLVM installer is an NSIS installer
|
||||
#
|
||||
# Original downloaded here came from
|
||||
# http://releases.llvm.org/8.0.0/LLVM-8.0.0-win64.exe
|
||||
- if NOT defined MINGW_URL appveyor-retry appveyor DownloadFile https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/LLVM-8.0.0-win64.exe
|
||||
- if NOT defined MINGW_URL .\LLVM-8.0.0-win64.exe /S /NCRC /D=C:\clang-rust
|
||||
- if NOT defined MINGW_URL set RUST_CONFIGURE_ARGS=%RUST_CONFIGURE_ARGS% --set llvm.clang-cl=C:\clang-rust\bin\clang-cl.exe
|
||||
|
||||
# Here we do a pretty heinous thing which is to mangle the MinGW installation
|
||||
# we just had above. Currently, as of this writing, we're using MinGW-w64
|
||||
# builds of gcc, and that's currently at 6.3.0. We use 6.3.0 as it appears to
|
||||
# be the first version which contains a fix for #40546, builds randomly
|
||||
# failing during LLVM due to ar.exe/ranlib.exe failures.
|
||||
#
|
||||
# Unfortunately, though, 6.3.0 *also* is the first version of MinGW-w64 builds
|
||||
# to contain a regression in gdb (#40184). As a result if we were to use the
|
||||
# gdb provided (7.11.1) then we would fail all debuginfo tests.
|
||||
#
|
||||
# In order to fix spurious failures (pretty high priority) we use 6.3.0. To
|
||||
# avoid disabling gdb tests we download an *old* version of gdb, specifically
|
||||
# that found inside the 6.2.0 distribution. We then overwrite the 6.3.0 gdb
|
||||
# with the 6.2.0 gdb to get tests passing.
|
||||
#
|
||||
# Note that we don't literally overwrite the gdb.exe binary because it appears
|
||||
# to just use gdborig.exe, so that's the binary we deal with instead.
|
||||
- if defined MINGW_URL appveyor-retry appveyor DownloadFile %MINGW_URL%/2017-04-20-%MSYS_BITS%bit-gdborig.exe
|
||||
- if defined MINGW_URL mv 2017-04-20-%MSYS_BITS%bit-gdborig.exe %MINGW_DIR%\bin\gdborig.exe
|
||||
|
||||
# Otherwise pull in the MinGW installed on appveyor
|
||||
- if NOT defined MINGW_URL set PATH=C:\msys64\mingw%MSYS_BITS%\bin;C:\msys64\usr\bin;%PATH%
|
||||
|
||||
# Prefer the "native" Python as LLVM has trouble building with MSYS sometimes
|
||||
- copy C:\Python27\python.exe C:\Python27\python2.7.exe
|
||||
- set PATH=C:\Python27;%PATH%
|
||||
|
||||
# Download and install sccache
|
||||
- appveyor-retry appveyor DownloadFile https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/2018-04-26-sccache-x86_64-pc-windows-msvc
|
||||
- mv 2018-04-26-sccache-x86_64-pc-windows-msvc sccache.exe
|
||||
- set PATH=%PATH%;%CD%
|
||||
|
||||
# Download and install ninja
|
||||
#
|
||||
# Note that this is originally from the github releases patch of Ninja
|
||||
- appveyor-retry appveyor DownloadFile https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/2017-03-15-ninja-win.zip
|
||||
- 7z x 2017-03-15-ninja-win.zip
|
||||
- set RUST_CONFIGURE_ARGS=%RUST_CONFIGURE_ARGS% --enable-ninja
|
||||
# - set PATH=%PATH%;%CD% -- this already happens above for sccache
|
||||
|
||||
# Install InnoSetup to get `iscc` used to produce installers
|
||||
- appveyor-retry appveyor DownloadFile https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/2017-08-22-is.exe
|
||||
- 2017-08-22-is.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP-
|
||||
- set PATH="C:\Program Files (x86)\Inno Setup 5";%PATH%
|
||||
|
||||
# Help debug some handle issues on AppVeyor
|
||||
- appveyor-retry appveyor DownloadFile https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/2017-05-15-Handle.zip
|
||||
- mkdir handle
|
||||
- 7z x -ohandle 2017-05-15-Handle.zip
|
||||
- set PATH=%PATH%;%CD%\handle
|
||||
- handle.exe -accepteula -help
|
||||
|
||||
test_script:
|
||||
- if not exist C:\cache\rustsrc\NUL mkdir C:\cache\rustsrc
|
||||
- sh src/ci/init_repo.sh . /c/cache/rustsrc
|
||||
- set SRC=.
|
||||
- set NO_CCACHE=1
|
||||
- sh src/ci/run.sh
|
||||
- echo AppVeyor is not used anymore
|
||||
|
||||
branches:
|
||||
only:
|
||||
|
|
|
|||
|
|
@ -598,6 +598,7 @@ fn test_with_no_doc_stage0() {
|
|||
bless: false,
|
||||
compare_mode: None,
|
||||
rustfix_coverage: false,
|
||||
pass: None,
|
||||
};
|
||||
|
||||
let build = Build::new(config);
|
||||
|
|
@ -640,6 +641,7 @@ fn test_exclude() {
|
|||
bless: false,
|
||||
compare_mode: None,
|
||||
rustfix_coverage: false,
|
||||
pass: None,
|
||||
};
|
||||
|
||||
let build = Build::new(config);
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ pub enum Subcommand {
|
|||
/// Whether to automatically update stderr/stdout files
|
||||
bless: bool,
|
||||
compare_mode: Option<String>,
|
||||
pass: Option<String>,
|
||||
test_args: Vec<String>,
|
||||
rustc_args: Vec<String>,
|
||||
fail_fast: bool,
|
||||
|
|
@ -199,6 +200,12 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`"
|
|||
"mode describing what file the actual ui output will be compared to",
|
||||
"COMPARE MODE",
|
||||
);
|
||||
opts.optopt(
|
||||
"",
|
||||
"pass",
|
||||
"force {check,build,run}-pass tests to this mode.",
|
||||
"check | build | run"
|
||||
);
|
||||
opts.optflag(
|
||||
"",
|
||||
"rustfix-coverage",
|
||||
|
|
@ -401,6 +408,7 @@ Arguments:
|
|||
paths,
|
||||
bless: matches.opt_present("bless"),
|
||||
compare_mode: matches.opt_str("compare-mode"),
|
||||
pass: matches.opt_str("pass"),
|
||||
test_args: matches.opt_strs("test-args"),
|
||||
rustc_args: matches.opt_strs("rustc-args"),
|
||||
fail_fast: !matches.opt_present("no-fail-fast"),
|
||||
|
|
@ -524,6 +532,15 @@ impl Subcommand {
|
|||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pass(&self) -> Option<&str> {
|
||||
match *self {
|
||||
Subcommand::Test {
|
||||
ref pass, ..
|
||||
} => pass.as_ref().map(|s| &s[..]),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn split(s: &[String]) -> Vec<String> {
|
||||
|
|
|
|||
|
|
@ -1065,6 +1065,11 @@ impl Step for Compiletest {
|
|||
}
|
||||
});
|
||||
|
||||
if let Some(ref pass) = builder.config.cmd.pass() {
|
||||
cmd.arg("--pass");
|
||||
cmd.arg(pass);
|
||||
}
|
||||
|
||||
if let Some(ref nodejs) = builder.config.nodejs {
|
||||
cmd.arg("--nodejs").arg(nodejs);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ shift
|
|||
|
||||
export CFLAGS="-fPIC $CFLAGS"
|
||||
|
||||
MUSL=musl-1.1.20
|
||||
MUSL=musl-1.1.22
|
||||
|
||||
# may have been downloaded in a previous run
|
||||
if [ ! -d $MUSL ]; then
|
||||
|
|
|
|||
|
|
@ -13,5 +13,6 @@
|
|||
- [Targets](targets/index.md)
|
||||
- [Built-in Targets](targets/built-in.md)
|
||||
- [Custom Targets](targets/custom.md)
|
||||
- [Profile-guided Optimization](profile-guided-optimization.md)
|
||||
- [Linker-plugin based LTO](linker-plugin-lto.md)
|
||||
- [Contributing to `rustc`](contributing.md)
|
||||
|
|
|
|||
|
|
@ -214,3 +214,20 @@ This option lets you control what happens when the code panics.
|
|||
## incremental
|
||||
|
||||
This flag allows you to enable incremental compilation.
|
||||
|
||||
## profile-generate
|
||||
|
||||
This flag allows for creating instrumented binaries that will collect
|
||||
profiling data for use with profile-guided optimization (PGO). The flag takes
|
||||
an optional argument which is the path to a directory into which the
|
||||
instrumented binary will emit the collected data. See the chapter on
|
||||
[profile-guided optimization](profile-guided-optimization.html) for more
|
||||
information.
|
||||
|
||||
## profile-use
|
||||
|
||||
This flag specifies the profiling data file to be used for profile-guided
|
||||
optimization (PGO). The flag takes a mandatory argument which is the path
|
||||
to a valid `.profdata` file. See the chapter on
|
||||
[profile-guided optimization](profile-guided-optimization.html) for more
|
||||
information.
|
||||
|
|
|
|||
136
src/doc/rustc/src/profile-guided-optimization.md
Normal file
136
src/doc/rustc/src/profile-guided-optimization.md
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
# Profile Guided Optimization
|
||||
|
||||
`rustc` supports doing profile-guided optimization (PGO).
|
||||
This chapter describes what PGO is, what it is good for, and how it can be used.
|
||||
|
||||
## What Is Profiled-Guided Optimization?
|
||||
|
||||
The basic concept of PGO is to collect data about the typical execution of
|
||||
a program (e.g. which branches it is likely to take) and then use this data
|
||||
to inform optimizations such as inlining, machine-code layout,
|
||||
register allocation, etc.
|
||||
|
||||
There are different ways of collecting data about a program's execution.
|
||||
One is to run the program inside a profiler (such as `perf`) and another
|
||||
is to create an instrumented binary, that is, a binary that has data
|
||||
collection built into it, and run that.
|
||||
The latter usually provides more accurate data and it is also what is
|
||||
supported by `rustc`.
|
||||
|
||||
## Usage
|
||||
|
||||
Generating a PGO-optimized program involves following a workflow with four steps:
|
||||
|
||||
1. Compile the program with instrumentation enabled
|
||||
(e.g. `rustc -Cprofile-generate=/tmp/pgo-data main.rs`)
|
||||
2. Run the instrumented program (e.g. `./main`) which generates a
|
||||
`default_<id>.profraw` file
|
||||
3. Convert the `.profraw` file into a `.profdata` file using
|
||||
LLVM's `llvm-profdata` tool
|
||||
4. Compile the program again, this time making use of the profiling data
|
||||
(for example `rustc -Cprofile-use=merged.profdata main.rs`)
|
||||
|
||||
An instrumented program will create one or more `.profraw` files, one for each
|
||||
instrumented binary. E.g. an instrumented executable that loads two instrumented
|
||||
dynamic libraries at runtime will generate three `.profraw` files. Running an
|
||||
instrumented binary multiple times, on the other hand, will re-use the
|
||||
respective `.profraw` files, updating them in place.
|
||||
|
||||
These `.profraw` files have to be post-processed before they can be fed back
|
||||
into the compiler. This is done by the `llvm-profdata` tool. This tool
|
||||
is most easily installed via
|
||||
|
||||
```bash
|
||||
rustup component add llvm-tools-preview
|
||||
```
|
||||
|
||||
Note that installing the `llvm-tools-preview` component won't add
|
||||
`llvm-profdata` to the `PATH`. Rather, the tool can be found in:
|
||||
|
||||
```bash
|
||||
~/.rustup/toolchains/<toolchain>/lib/rustlib/<target-triple>/bin/
|
||||
```
|
||||
|
||||
Alternatively, an `llvm-profdata` coming with a recent LLVM or Clang
|
||||
version usually works too.
|
||||
|
||||
The `llvm-profdata` tool merges multiple `.profraw` files into a single
|
||||
`.profdata` file that can then be fed back into the compiler via
|
||||
`-Cprofile-use`:
|
||||
|
||||
```bash
|
||||
# STEP 1: Compile the binary with instrumentation
|
||||
rustc -Cprofile-generate=/tmp/pgo-data -O ./main.rs
|
||||
|
||||
# STEP 2: Run the binary a few times, maybe with common sets of args.
|
||||
# Each run will create or update `.profraw` files in /tmp/pgo-data
|
||||
./main mydata1.csv
|
||||
./main mydata2.csv
|
||||
./main mydata3.csv
|
||||
|
||||
# STEP 3: Merge and post-process all the `.profraw` files in /tmp/pgo-data
|
||||
llvm-profdata merge -o ./merged.profdata /tmp/pgo-data
|
||||
|
||||
# STEP 4: Use the merged `.profdata` file during optimization. All `rustc`
|
||||
# flags have to be the same.
|
||||
rustc -Cprofile-use=./merged.profdata -O ./main.rs
|
||||
```
|
||||
|
||||
### A Complete Cargo Workflow
|
||||
|
||||
Using this feature with Cargo works very similar to using it with `rustc`
|
||||
directly. Again, we generate an instrumented binary, run it to produce data,
|
||||
merge the data, and feed it back into the compiler. Some things of note:
|
||||
|
||||
- We use the `RUSTFLAGS` environment variable in order to pass the PGO compiler
|
||||
flags to the compilation of all crates in the program.
|
||||
|
||||
- We pass the `--target` flag to Cargo, which prevents the `RUSTFLAGS`
|
||||
arguments to be passed to Cargo build scripts. We don't want the build
|
||||
scripts to generate a bunch of `.profraw` files.
|
||||
|
||||
- We pass `--release` to Cargo because that's where PGO makes the most sense.
|
||||
In theory, PGO can also be done on debug builds but there is little reason
|
||||
to do so.
|
||||
|
||||
- It is recommended to use *absolute paths* for the argument of
|
||||
`-Cprofile-generate` and `-Cprofile-use`. Cargo can invoke `rustc` with
|
||||
varying working directories, meaning that `rustc` will not be able to find
|
||||
the supplied `.profdata` file. With absolute paths this is not an issue.
|
||||
|
||||
- It is good practice to make sure that there is no left-over profiling data
|
||||
from previous compilation sessions. Just deleting the directory is a simple
|
||||
way of doing so (see `STEP 0` below).
|
||||
|
||||
This is what the entire workflow looks like:
|
||||
|
||||
```bash
|
||||
# STEP 0: Make sure there is no left-over profiling data from previous runs
|
||||
rm -rf /tmp/pgo-data
|
||||
|
||||
# STEP 1: Build the instrumented binaries
|
||||
RUSTFLAGS="-Cprofile-generate=/tmp/pgo-data" \
|
||||
cargo build --release --target=x86_64-unknown-linux-gnu
|
||||
|
||||
# STEP 2: Run the instrumented binaries with some typical data
|
||||
./target/x86_64-unknown-linux-gnu/release/myprogram mydata1.csv
|
||||
./target/x86_64-unknown-linux-gnu/release/myprogram mydata2.csv
|
||||
./target/x86_64-unknown-linux-gnu/release/myprogram mydata3.csv
|
||||
|
||||
# STEP 3: Merge the `.profraw` files into a `.profdata` file
|
||||
llvm-profdata merge -o /tmp/pgo-data/merged.profdata /tmp/pgo-data
|
||||
|
||||
# STEP 4: Use the `.profdata` file for guiding optimizations
|
||||
RUSTFLAGS="-Cprofile-use=/tmp/pgo-data/merged.profdata" \
|
||||
cargo build --release --target=x86_64-unknown-linux-gnu
|
||||
```
|
||||
|
||||
## Further Reading
|
||||
|
||||
`rustc`'s PGO support relies entirely on LLVM's implementation of the feature
|
||||
and is equivalent to what Clang offers via the `-fprofile-generate` /
|
||||
`-fprofile-use` flags. The [Profile Guided Optimization][clang-pgo] section
|
||||
in Clang's documentation is therefore an interesting read for anyone who wants
|
||||
to use PGO with Rust.
|
||||
|
||||
[clang-pgo]: https://clang.llvm.org/docs/UsersManual.html#profile-guided-optimization
|
||||
|
|
@ -253,19 +253,6 @@ conversion, so type inference fails because the type is not unique. Please note
|
|||
that you must write the `(())` in one sequence without intermediate whitespace
|
||||
so that rustdoc understands you want an implicit `Result`-returning function.
|
||||
|
||||
As of version 1.37.0, this simplification also works with `Option`s, which can
|
||||
be handy to test e.g. iterators or checked arithmetic, for example:
|
||||
|
||||
```ignore
|
||||
/// ```
|
||||
/// let _ = &[].iter().next()?;
|
||||
///# Some(())
|
||||
/// ```
|
||||
```
|
||||
|
||||
Note that the result must be a `Some(())` and this has to be written in one go.
|
||||
In this case disambiguating the result isn't required.
|
||||
|
||||
## Documenting macros
|
||||
|
||||
Here’s an example of documenting a macro:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
# `member_constraints`
|
||||
|
||||
The tracking issue for this feature is: [#61977]
|
||||
|
||||
[#61977]: https://github.com/rust-lang/rust/issues/61977
|
||||
|
||||
------------------------
|
||||
|
||||
The `member_constraints` feature gate lets you use `impl Trait` syntax with
|
||||
multiple unrelated lifetime parameters.
|
||||
|
||||
A simple example is:
|
||||
|
||||
```rust
|
||||
#![feature(member_constraints)]
|
||||
|
||||
trait Trait<'a, 'b> { }
|
||||
impl<T> Trait<'_, '_> for T {}
|
||||
|
||||
fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Trait<'a, 'b> {
|
||||
(x, y)
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
```
|
||||
|
||||
Without the `member_constraints` feature gate, the above example is an
|
||||
error because both `'a` and `'b` appear in the impl Trait bounds, but
|
||||
neither outlives the other.
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
# `slice_patterns`
|
||||
|
||||
The tracking issue for this feature is: [#23121]
|
||||
The tracking issue for this feature is: [#62254]
|
||||
|
||||
[#23121]: https://github.com/rust-lang/rust/issues/23121
|
||||
[#62254]: https://github.com/rust-lang/rust/issues/62254
|
||||
|
||||
------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -1,36 +0,0 @@
|
|||
# `type_alias_enum_variants`
|
||||
|
||||
The tracking issue for this feature is: [#49683]
|
||||
|
||||
[#49683]: https://github.com/rust-lang/rust/issues/49683
|
||||
|
||||
------------------------
|
||||
|
||||
The `type_alias_enum_variants` feature enables the use of variants on type
|
||||
aliases that refer to enums, as both a constructor and a pattern. That is,
|
||||
it allows for the syntax `EnumAlias::Variant`, which behaves exactly the same
|
||||
as `Enum::Variant` (assuming that `EnumAlias` is an alias for some enum type
|
||||
`Enum`).
|
||||
|
||||
Note that since `Self` exists as a type alias, this feature also enables the
|
||||
use of the syntax `Self::Variant` within an impl block for an enum type.
|
||||
|
||||
```rust
|
||||
#![feature(type_alias_enum_variants)]
|
||||
|
||||
enum Foo {
|
||||
Bar(i32),
|
||||
Baz { i: i32 },
|
||||
}
|
||||
|
||||
type Alias = Foo;
|
||||
|
||||
fn main() {
|
||||
let t = Alias::Bar(0);
|
||||
let t = Alias::Baz { i: 0 };
|
||||
match t {
|
||||
Alias::Bar(_i) => {}
|
||||
Alias::Baz { i: _i } => {}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
set -ex
|
||||
|
||||
bucket=rust-lang-ci-evalazure
|
||||
bucket=rust-lang-ci2
|
||||
commit=$1
|
||||
builder=$2
|
||||
|
||||
|
|
|
|||
|
|
@ -1,2 +1,3 @@
|
|||
import gdb
|
||||
import gdb_rust_pretty_printing
|
||||
gdb_rust_pretty_printing.register_printers(gdb.current_objfile())
|
||||
|
|
|
|||
|
|
@ -367,12 +367,19 @@ impl<T: Clone> Clone for Box<T> {
|
|||
/// ```
|
||||
/// let x = Box::new(5);
|
||||
/// let y = x.clone();
|
||||
///
|
||||
/// // The value is the same
|
||||
/// assert_eq!(x, y);
|
||||
///
|
||||
/// // But they are unique objects
|
||||
/// assert_ne!(&*x as *const i32, &*y as *const i32);
|
||||
/// ```
|
||||
#[rustfmt::skip]
|
||||
#[inline]
|
||||
fn clone(&self) -> Box<T> {
|
||||
box { (**self).clone() }
|
||||
}
|
||||
|
||||
/// Copies `source`'s contents into `self` without creating a new allocation.
|
||||
///
|
||||
/// # Examples
|
||||
|
|
@ -380,10 +387,15 @@ impl<T: Clone> Clone for Box<T> {
|
|||
/// ```
|
||||
/// let x = Box::new(5);
|
||||
/// let mut y = Box::new(10);
|
||||
/// let yp: *const i32 = &*y;
|
||||
///
|
||||
/// y.clone_from(&x);
|
||||
///
|
||||
/// assert_eq!(*y, 5);
|
||||
/// // The value is the same
|
||||
/// assert_eq!(x, y);
|
||||
///
|
||||
/// // And no allocation occurred
|
||||
/// assert_eq!(yp, &*y);
|
||||
/// ```
|
||||
#[inline]
|
||||
fn clone_from(&mut self, source: &Box<T>) {
|
||||
|
|
@ -716,6 +728,14 @@ impl<I: Iterator + ?Sized> Iterator for Box<I> {
|
|||
(**self).nth(n)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<I: Iterator + Sized> Iterator for Box<I> {
|
||||
fn last(self) -> Option<I::Item> where I: Sized {
|
||||
(*self).last()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<I: DoubleEndedIterator + ?Sized> DoubleEndedIterator for Box<I> {
|
||||
fn next_back(&mut self) -> Option<I::Item> {
|
||||
|
|
|
|||
|
|
@ -1035,6 +1035,11 @@ impl<'a, T> Iterator for Iter<'a, T> {
|
|||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.iter.size_hint()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn last(self) -> Option<&'a T> {
|
||||
self.iter.last()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
|
|||
|
|
@ -770,8 +770,8 @@ impl<K: Ord, V> BTreeMap<K, V> {
|
|||
}
|
||||
|
||||
// First, we merge `self` and `other` into a sorted sequence in linear time.
|
||||
let self_iter = mem::replace(self, BTreeMap::new()).into_iter();
|
||||
let other_iter = mem::replace(other, BTreeMap::new()).into_iter();
|
||||
let self_iter = mem::take(self).into_iter();
|
||||
let other_iter = mem::take(other).into_iter();
|
||||
let iter = MergeIter {
|
||||
left: self_iter.peekable(),
|
||||
right: other_iter.peekable(),
|
||||
|
|
@ -1193,6 +1193,10 @@ impl<'a, K: 'a, V: 'a> Iterator for Iter<'a, K, V> {
|
|||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
(self.length, Some(self.length))
|
||||
}
|
||||
|
||||
fn last(mut self) -> Option<(&'a K, &'a V)> {
|
||||
self.next_back()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "fused", since = "1.26.0")]
|
||||
|
|
@ -1253,6 +1257,10 @@ impl<'a, K: 'a, V: 'a> Iterator for IterMut<'a, K, V> {
|
|||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
(self.length, Some(self.length))
|
||||
}
|
||||
|
||||
fn last(mut self) -> Option<(&'a K, &'a mut V)> {
|
||||
self.next_back()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -1421,6 +1429,10 @@ impl<'a, K, V> Iterator for Keys<'a, K, V> {
|
|||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.inner.size_hint()
|
||||
}
|
||||
|
||||
fn last(mut self) -> Option<&'a K> {
|
||||
self.next_back()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -1458,6 +1470,10 @@ impl<'a, K, V> Iterator for Values<'a, K, V> {
|
|||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.inner.size_hint()
|
||||
}
|
||||
|
||||
fn last(mut self) -> Option<&'a V> {
|
||||
self.next_back()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -1495,6 +1511,10 @@ impl<'a, K, V> Iterator for Range<'a, K, V> {
|
|||
unsafe { Some(self.next_unchecked()) }
|
||||
}
|
||||
}
|
||||
|
||||
fn last(mut self) -> Option<(&'a K, &'a V)> {
|
||||
self.next_back()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "map_values_mut", since = "1.10.0")]
|
||||
|
|
@ -1508,6 +1528,10 @@ impl<'a, K, V> Iterator for ValuesMut<'a, K, V> {
|
|||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.inner.size_hint()
|
||||
}
|
||||
|
||||
fn last(mut self) -> Option<&'a mut V> {
|
||||
self.next_back()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "map_values_mut", since = "1.10.0")]
|
||||
|
|
@ -1626,6 +1650,10 @@ impl<'a, K, V> Iterator for RangeMut<'a, K, V> {
|
|||
unsafe { Some(self.next_unchecked()) }
|
||||
}
|
||||
}
|
||||
|
||||
fn last(mut self) -> Option<(&'a K, &'a mut V)> {
|
||||
self.next_back()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, V> RangeMut<'a, K, V> {
|
||||
|
|
|
|||
|
|
@ -1019,6 +1019,9 @@ impl<'a, T> Iterator for Iter<'a, T> {
|
|||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.iter.size_hint()
|
||||
}
|
||||
fn last(mut self) -> Option<&'a T> {
|
||||
self.next_back()
|
||||
}
|
||||
}
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, T> DoubleEndedIterator for Iter<'a, T> {
|
||||
|
|
@ -1073,6 +1076,10 @@ impl<'a, T> Iterator for Range<'a, T> {
|
|||
fn next(&mut self) -> Option<&'a T> {
|
||||
self.iter.next().map(|(k, _)| k)
|
||||
}
|
||||
|
||||
fn last(mut self) -> Option<&'a T> {
|
||||
self.next_back()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "btree_range", since = "1.17.0")]
|
||||
|
|
|
|||
|
|
@ -708,7 +708,7 @@ impl<T> LinkedList<T> {
|
|||
let len = self.len();
|
||||
assert!(at <= len, "Cannot split off at a nonexistent index");
|
||||
if at == 0 {
|
||||
return mem::replace(self, Self::new());
|
||||
return mem::take(self);
|
||||
} else if at == len {
|
||||
return Self::new();
|
||||
}
|
||||
|
|
@ -832,6 +832,11 @@ impl<'a, T> Iterator for Iter<'a, T> {
|
|||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
(self.len, Some(self.len))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn last(mut self) -> Option<&'a T> {
|
||||
self.next_back()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -881,6 +886,11 @@ impl<'a, T> Iterator for IterMut<'a, T> {
|
|||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
(self.len, Some(self.len))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn last(mut self) -> Option<&'a mut T> {
|
||||
self.next_back()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
|
|||
|
|
@ -2206,6 +2206,11 @@ impl<'a, T> Iterator for Iter<'a, T> {
|
|||
self.tail = self.head - iter.len();
|
||||
final_res
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn last(mut self) -> Option<&'a T> {
|
||||
self.next_back()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -2319,6 +2324,11 @@ impl<'a, T> Iterator for IterMut<'a, T> {
|
|||
accum = front.iter_mut().fold(accum, &mut f);
|
||||
back.iter_mut().fold(accum, &mut f)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn last(mut self) -> Option<&'a mut T> {
|
||||
self.next_back()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
|
|||
|
|
@ -112,6 +112,7 @@
|
|||
#![feature(maybe_uninit_extra, maybe_uninit_slice, maybe_uninit_array)]
|
||||
#![feature(alloc_layout_extra)]
|
||||
#![feature(try_trait)]
|
||||
#![feature(mem_take)]
|
||||
|
||||
// Allow testing this library
|
||||
|
||||
|
|
|
|||
|
|
@ -203,7 +203,7 @@ impl ToOwned for str {
|
|||
}
|
||||
|
||||
fn clone_into(&self, target: &mut String) {
|
||||
let mut b = mem::replace(target, String::new()).into_bytes();
|
||||
let mut b = mem::take(target).into_bytes();
|
||||
self.as_bytes().clone_into(&mut b);
|
||||
*target = unsafe { String::from_utf8_unchecked(b) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2385,6 +2385,11 @@ impl Iterator for Drain<'_> {
|
|||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.iter.size_hint()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn last(mut self) -> Option<char> {
|
||||
self.next_back()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "drain", since = "1.6.0")]
|
||||
|
|
|
|||
|
|
@ -761,7 +761,6 @@ fn from_into_inner() {
|
|||
it.next().unwrap();
|
||||
let vec = it.collect::<Vec<_>>();
|
||||
assert_eq!(vec, [2, 3]);
|
||||
#[cfg(not(miri))] // Miri does not support comparing dangling pointers
|
||||
assert!(ptr != vec.as_ptr());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1367,6 +1367,40 @@ impl<T> Vec<T> {
|
|||
self.truncate(new_len);
|
||||
}
|
||||
}
|
||||
|
||||
/// Consumes and leaks the `Vec`, returning a mutable reference to the contents,
|
||||
/// `&'a mut [T]`. Note that the type `T` must outlive the chosen lifetime
|
||||
/// `'a`. If the type has only static references, or none at all, then this
|
||||
/// may be chosen to be `'static`.
|
||||
///
|
||||
/// This function is similar to the `leak` function on `Box`.
|
||||
///
|
||||
/// This function is mainly useful for data that lives for the remainder of
|
||||
/// the program's life. Dropping the returned reference will cause a memory
|
||||
/// leak.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Simple usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(vec_leak)]
|
||||
///
|
||||
/// fn main() {
|
||||
/// let x = vec![1, 2, 3];
|
||||
/// let static_ref: &'static mut [usize] = Vec::leak(x);
|
||||
/// static_ref[0] += 1;
|
||||
/// assert_eq!(static_ref, &[2, 2, 3]);
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "vec_leak", issue = "62195")]
|
||||
#[inline]
|
||||
pub fn leak<'a>(vec: Vec<T>) -> &'a mut [T]
|
||||
where
|
||||
T: 'a // Technically not needed, but kept to be explicit.
|
||||
{
|
||||
Box::leak(vec.into_boxed_slice())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone> Vec<T> {
|
||||
|
|
|
|||
|
|
@ -117,6 +117,7 @@ impl Iterator for EscapeDefault {
|
|||
type Item = u8;
|
||||
fn next(&mut self) -> Option<u8> { self.range.next().map(|i| self.data[i]) }
|
||||
fn size_hint(&self) -> (usize, Option<usize>) { self.range.size_hint() }
|
||||
fn last(mut self) -> Option<u8> { self.next_back() }
|
||||
}
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl DoubleEndedIterator for EscapeDefault {
|
||||
|
|
|
|||
|
|
@ -337,16 +337,16 @@ impl char {
|
|||
/// ```
|
||||
/// // as chars
|
||||
/// let eastern = '東';
|
||||
/// let capitol = '京';
|
||||
/// let capital = '京';
|
||||
///
|
||||
/// // both can be represented as three bytes
|
||||
/// assert_eq!(3, eastern.len_utf8());
|
||||
/// assert_eq!(3, capitol.len_utf8());
|
||||
/// assert_eq!(3, capital.len_utf8());
|
||||
///
|
||||
/// // as a &str, these two are encoded in UTF-8
|
||||
/// let tokyo = "東京";
|
||||
///
|
||||
/// let len = eastern.len_utf8() + capitol.len_utf8();
|
||||
/// let len = eastern.len_utf8() + capital.len_utf8();
|
||||
///
|
||||
/// // we can see that they take six bytes total...
|
||||
/// assert_eq!(6, tokyo.len());
|
||||
|
|
|
|||
|
|
@ -251,12 +251,12 @@ pub trait AsMut<T: ?Sized> {
|
|||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// [`String`] implements `Into<Vec<u8>>`:
|
||||
/// [`String`] implements [`Into`]`<`[`Vec`]`<`[`u8`]`>>`:
|
||||
///
|
||||
/// In order to express that we want a generic function to take all arguments that can be
|
||||
/// converted to a specified type `T`, we can use a trait bound of [`Into`]`<T>`.
|
||||
/// For example: The function `is_hello` takes all arguments that can be converted into a
|
||||
/// `Vec<u8>`.
|
||||
/// [`Vec`]`<`[`u8`]`>`.
|
||||
///
|
||||
/// ```
|
||||
/// fn is_hello<T: Into<Vec<u8>>>(s: T) {
|
||||
|
|
@ -274,6 +274,7 @@ pub trait AsMut<T: ?Sized> {
|
|||
/// [`String`]: ../../std/string/struct.String.html
|
||||
/// [`From`]: trait.From.html
|
||||
/// [`Into`]: trait.Into.html
|
||||
/// [`Vec`]: ../../std/vec/struct.Vec.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait Into<T>: Sized {
|
||||
/// Performs the conversion.
|
||||
|
|
@ -410,12 +411,12 @@ pub trait TryInto<T>: Sized {
|
|||
///
|
||||
/// This is useful when you are doing a type conversion that may
|
||||
/// trivially succeed but may also need special handling.
|
||||
/// For example, there is no way to convert an `i64` into an `i32`
|
||||
/// using the [`From`] trait, because an `i64` may contain a value
|
||||
/// that an `i32` cannot represent and so the conversion would lose data.
|
||||
/// This might be handled by truncating the `i64` to an `i32` (essentially
|
||||
/// giving the `i64`'s value modulo `i32::MAX`) or by simply returning
|
||||
/// `i32::MAX`, or by some other method. The `From` trait is intended
|
||||
/// For example, there is no way to convert an [`i64`] into an [`i32`]
|
||||
/// using the [`From`] trait, because an [`i64`] may contain a value
|
||||
/// that an [`i32`] cannot represent and so the conversion would lose data.
|
||||
/// This might be handled by truncating the [`i64`] to an [`i32`] (essentially
|
||||
/// giving the [`i64`]'s value modulo [`i32::MAX`]) or by simply returning
|
||||
/// [`i32::MAX`], or by some other method. The [`From`] trait is intended
|
||||
/// for perfect conversions, so the `TryFrom` trait informs the
|
||||
/// programmer when a type conversion could go bad and lets them
|
||||
/// decide how to handle it.
|
||||
|
|
@ -425,8 +426,8 @@ pub trait TryInto<T>: Sized {
|
|||
/// - `TryFrom<T> for U` implies [`TryInto`]`<U> for T`
|
||||
/// - [`try_from`] is reflexive, which means that `TryFrom<T> for T`
|
||||
/// is implemented and cannot fail -- the associated `Error` type for
|
||||
/// calling `T::try_from()` on a value of type `T` is `Infallible`.
|
||||
/// When the `!` type is stablized `Infallible` and `!` will be
|
||||
/// calling `T::try_from()` on a value of type `T` is [`Infallible`].
|
||||
/// When the [`!`] type is stablized [`Infallible`] and [`!`] will be
|
||||
/// equivalent.
|
||||
///
|
||||
/// `TryFrom<T>` can be implemented as follows:
|
||||
|
|
@ -451,7 +452,7 @@ pub trait TryInto<T>: Sized {
|
|||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// As described, [`i32`] implements `TryFrom<i64>`:
|
||||
/// As described, [`i32`] implements `TryFrom<`[`i64`]`>`:
|
||||
///
|
||||
/// ```
|
||||
/// use std::convert::TryFrom;
|
||||
|
|
@ -474,6 +475,8 @@ pub trait TryInto<T>: Sized {
|
|||
///
|
||||
/// [`try_from`]: trait.TryFrom.html#tymethod.try_from
|
||||
/// [`TryInto`]: trait.TryInto.html
|
||||
/// [`i32::MAX`]: ../../std/i32/constant.MAX.html
|
||||
/// [`!`]: ../../std/primitive.never.html
|
||||
#[stable(feature = "try_from", since = "1.34.0")]
|
||||
pub trait TryFrom<T>: Sized {
|
||||
/// The type returned in the event of a conversion error.
|
||||
|
|
|
|||
|
|
@ -196,7 +196,7 @@ pub trait FromIterator<A>: Sized {
|
|||
/// ```rust
|
||||
/// fn collect_as_strings<T>(collection: T) -> Vec<String>
|
||||
/// where T: IntoIterator,
|
||||
/// T::Item : std::fmt::Debug,
|
||||
/// T::Item: std::fmt::Debug,
|
||||
/// {
|
||||
/// collection
|
||||
/// .into_iter()
|
||||
|
|
|
|||
|
|
@ -126,6 +126,7 @@
|
|||
#![feature(adx_target_feature)]
|
||||
#![feature(maybe_uninit_slice, maybe_uninit_array)]
|
||||
#![feature(external_doc)]
|
||||
#![feature(mem_take)]
|
||||
|
||||
#[prelude_import]
|
||||
#[allow(unused)]
|
||||
|
|
|
|||
|
|
@ -73,9 +73,9 @@ impl<T: ?Sized> !Send for *mut T { }
|
|||
/// impl Foo for Impl { }
|
||||
/// impl Bar for Impl { }
|
||||
///
|
||||
/// let x: &Foo = &Impl; // OK
|
||||
/// // let y: &Bar = &Impl; // error: the trait `Bar` cannot
|
||||
/// // be made into an object
|
||||
/// let x: &dyn Foo = &Impl; // OK
|
||||
/// // let y: &dyn Bar = &Impl; // error: the trait `Bar` cannot
|
||||
/// // be made into an object
|
||||
/// ```
|
||||
///
|
||||
/// [trait object]: ../../book/ch17-02-trait-objects.html
|
||||
|
|
|
|||
|
|
@ -510,6 +510,8 @@ pub fn swap<T>(x: &mut T, y: &mut T) {
|
|||
/// A simple example:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(mem_take)]
|
||||
///
|
||||
/// use std::mem;
|
||||
///
|
||||
/// let mut v: Vec<i32> = vec![1, 2];
|
||||
|
|
@ -540,7 +542,8 @@ pub fn swap<T>(x: &mut T, y: &mut T) {
|
|||
/// `self`, allowing it to be returned:
|
||||
///
|
||||
/// ```
|
||||
/// # #![allow(dead_code)]
|
||||
/// #![feature(mem_take)]
|
||||
///
|
||||
/// use std::mem;
|
||||
///
|
||||
/// # struct Buffer<T> { buf: Vec<T> }
|
||||
|
|
@ -549,6 +552,12 @@ pub fn swap<T>(x: &mut T, y: &mut T) {
|
|||
/// mem::take(&mut self.buf)
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// let mut buffer = Buffer { buf: vec![0, 1] };
|
||||
/// assert_eq!(buffer.buf.len(), 2);
|
||||
///
|
||||
/// assert_eq!(buffer.get_and_reset(), vec![0, 1]);
|
||||
/// assert_eq!(buffer.buf.len(), 0);
|
||||
/// ```
|
||||
///
|
||||
/// [`Clone`]: ../../std/clone/trait.Clone.html
|
||||
|
|
@ -583,17 +592,17 @@ pub fn take<T: Default>(dest: &mut T) -> T {
|
|||
/// struct Buffer<T> { buf: Vec<T> }
|
||||
///
|
||||
/// impl<T> Buffer<T> {
|
||||
/// fn get_and_reset(&mut self) -> Vec<T> {
|
||||
/// fn replace_index(&mut self, i: usize, v: T) -> T {
|
||||
/// // error: cannot move out of dereference of `&mut`-pointer
|
||||
/// let buf = self.buf;
|
||||
/// self.buf = Vec::new();
|
||||
/// buf
|
||||
/// let t = self.buf[i];
|
||||
/// self.buf[i] = v;
|
||||
/// t
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Note that `T` does not necessarily implement [`Clone`], so it can't even clone and reset
|
||||
/// `self.buf`. But `replace` can be used to disassociate the original value of `self.buf` from
|
||||
/// Note that `T` does not necessarily implement [`Clone`], so we can't even clone `self.buf[i]` to
|
||||
/// avoid the move. But `replace` can be used to disassociate the original value at that index from
|
||||
/// `self`, allowing it to be returned:
|
||||
///
|
||||
/// ```
|
||||
|
|
@ -602,10 +611,16 @@ pub fn take<T: Default>(dest: &mut T) -> T {
|
|||
///
|
||||
/// # struct Buffer<T> { buf: Vec<T> }
|
||||
/// impl<T> Buffer<T> {
|
||||
/// fn get_and_reset(&mut self) -> Vec<T> {
|
||||
/// mem::replace(&mut self.buf, Vec::new())
|
||||
/// fn replace_index(&mut self, i: usize, v: T) -> T {
|
||||
/// mem::replace(&mut self.buf[i], v)
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// let mut buffer = Buffer { buf: vec![0, 1] };
|
||||
/// assert_eq!(buffer.buf[0], 0);
|
||||
///
|
||||
/// assert_eq!(buffer.replace_index(0, 2), 0);
|
||||
/// assert_eq!(buffer.buf[0], 2);
|
||||
/// ```
|
||||
///
|
||||
/// [`Clone`]: ../../std/clone/trait.Clone.html
|
||||
|
|
|
|||
|
|
@ -777,15 +777,7 @@ impl<T> Option<T> {
|
|||
#[inline]
|
||||
#[stable(feature = "option_entry", since = "1.20.0")]
|
||||
pub fn get_or_insert(&mut self, v: T) -> &mut T {
|
||||
match *self {
|
||||
None => *self = Some(v),
|
||||
_ => (),
|
||||
}
|
||||
|
||||
match *self {
|
||||
Some(ref mut v) => v,
|
||||
None => unsafe { hint::unreachable_unchecked() },
|
||||
}
|
||||
self.get_or_insert_with(|| v)
|
||||
}
|
||||
|
||||
/// Inserts a value computed from `f` into the option if it is [`None`], then
|
||||
|
|
@ -845,7 +837,7 @@ impl<T> Option<T> {
|
|||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn take(&mut self) -> Option<T> {
|
||||
mem::replace(self, None)
|
||||
mem::take(self)
|
||||
}
|
||||
|
||||
/// Replaces the actual value in the option by the value given in parameter,
|
||||
|
|
|
|||
|
|
@ -100,7 +100,11 @@ pub use unique::Unique;
|
|||
/// as the compiler doesn't need to prove that it's sound to elide the
|
||||
/// copy.
|
||||
///
|
||||
/// Unaligned values cannot be dropped in place, they must be copied to an aligned
|
||||
/// location first using [`ptr::read_unaligned`].
|
||||
///
|
||||
/// [`ptr::read`]: ../ptr/fn.read.html
|
||||
/// [`ptr::read_unaligned`]: ../ptr/fn.read_unaligned.html
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
|
|
@ -108,8 +112,7 @@ pub use unique::Unique;
|
|||
///
|
||||
/// * `to_drop` must be [valid] for reads.
|
||||
///
|
||||
/// * `to_drop` must be properly aligned. See the example below for how to drop
|
||||
/// an unaligned pointer.
|
||||
/// * `to_drop` must be properly aligned.
|
||||
///
|
||||
/// Additionally, if `T` is not [`Copy`], using the pointed-to value after
|
||||
/// calling `drop_in_place` can cause undefined behavior. Note that `*to_drop =
|
||||
|
|
@ -153,31 +156,6 @@ pub use unique::Unique;
|
|||
/// assert!(weak.upgrade().is_none());
|
||||
/// ```
|
||||
///
|
||||
/// Unaligned values cannot be dropped in place, they must be copied to an aligned
|
||||
/// location first:
|
||||
/// ```
|
||||
/// use std::ptr;
|
||||
/// use std::mem::{self, MaybeUninit};
|
||||
///
|
||||
/// unsafe fn drop_after_copy<T>(to_drop: *mut T) {
|
||||
/// let mut copy: MaybeUninit<T> = MaybeUninit::uninit();
|
||||
/// ptr::copy(to_drop, copy.as_mut_ptr(), 1);
|
||||
/// drop(copy.assume_init());
|
||||
/// }
|
||||
///
|
||||
/// #[repr(packed, C)]
|
||||
/// struct Packed {
|
||||
/// _padding: u8,
|
||||
/// unaligned: Vec<i32>,
|
||||
/// }
|
||||
///
|
||||
/// let mut p = Packed { _padding: 0, unaligned: vec![42] };
|
||||
/// unsafe {
|
||||
/// drop_after_copy(&mut p.unaligned as *mut _);
|
||||
/// mem::forget(p);
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Notice that the compiler performs this copy automatically when dropping packed structs,
|
||||
/// i.e., you do not usually have to worry about such issues unless you call `drop_in_place`
|
||||
/// manually.
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@
|
|||
/// let value: i32 = 123;
|
||||
///
|
||||
/// // let the compiler make a trait object
|
||||
/// let object: &Foo = &value;
|
||||
/// let object: &dyn Foo = &value;
|
||||
///
|
||||
/// // look at the raw representation
|
||||
/// let raw_object: raw::TraitObject = unsafe { mem::transmute(object) };
|
||||
|
|
@ -65,7 +65,7 @@
|
|||
///
|
||||
/// // construct a new object, pointing to a different `i32`, being
|
||||
/// // careful to use the `i32` vtable from `object`
|
||||
/// let synthesized: &Foo = unsafe {
|
||||
/// let synthesized: &dyn Foo = unsafe {
|
||||
/// mem::transmute(raw::TraitObject {
|
||||
/// data: &other_value as *const _ as *mut (),
|
||||
/// vtable: raw_object.vtable,
|
||||
|
|
|
|||
|
|
@ -4453,6 +4453,21 @@ impl<'a, T> DoubleEndedIterator for ChunksExact<'a, T> {
|
|||
Some(snd)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
|
||||
let len = self.len();
|
||||
if n >= len {
|
||||
self.v = &[];
|
||||
None
|
||||
} else {
|
||||
let start = (len - 1 - n) * self.chunk_size;
|
||||
let end = start + self.chunk_size;
|
||||
let nth_back = &self.v[start..end];
|
||||
self.v = &self.v[..start];
|
||||
Some(nth_back)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "chunks_exact", since = "1.31.0")]
|
||||
|
|
|
|||
|
|
@ -1333,6 +1333,11 @@ impl<'a> Iterator for Lines<'a> {
|
|||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.0.size_hint()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn last(mut self) -> Option<&'a str> {
|
||||
self.next_back()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -3716,10 +3721,10 @@ impl str {
|
|||
///
|
||||
/// # Text directionality
|
||||
///
|
||||
/// A string is a sequence of bytes. 'Left' in this context means the first
|
||||
/// position of that byte string; for a language like Arabic or Hebrew
|
||||
/// which are 'right to left' rather than 'left to right', this will be
|
||||
/// the _right_ side, not the left.
|
||||
/// A string is a sequence of bytes. `start` in this context means the first
|
||||
/// position of that byte string; for a left-to-right language like English or
|
||||
/// Russian, this will be left side, and for right-to-left languages like
|
||||
/// like Arabic or Hebrew, this will be the right side.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -3755,10 +3760,10 @@ impl str {
|
|||
///
|
||||
/// # Text directionality
|
||||
///
|
||||
/// A string is a sequence of bytes. 'Right' in this context means the last
|
||||
/// position of that byte string; for a language like Arabic or Hebrew
|
||||
/// which are 'right to left' rather than 'left to right', this will be
|
||||
/// the _left_ side, not the right.
|
||||
/// A string is a sequence of bytes. `end` in this context means the last
|
||||
/// position of that byte string; for a left-to-right language like English or
|
||||
/// Russian, this will be right side, and for right-to-left languages like
|
||||
/// like Arabic or Hebrew, this will be the left side.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -3804,10 +3809,10 @@ impl str {
|
|||
///
|
||||
/// # Text directionality
|
||||
///
|
||||
/// A string is a sequence of bytes. `start` in this context means the first
|
||||
/// position of that byte string; for a left-to-right language like English or
|
||||
/// Russian, this will be left side, and for right-to-left languages like
|
||||
/// like Arabic or Hebrew, this will be the right side.
|
||||
/// A string is a sequence of bytes. 'Left' in this context means the first
|
||||
/// position of that byte string; for a language like Arabic or Hebrew
|
||||
/// which are 'right to left' rather than 'left to right', this will be
|
||||
/// the _right_ side, not the left.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -3840,10 +3845,10 @@ impl str {
|
|||
///
|
||||
/// # Text directionality
|
||||
///
|
||||
/// A string is a sequence of bytes. `end` in this context means the last
|
||||
/// position of that byte string; for a left-to-right language like English or
|
||||
/// Russian, this will be right side, and for right-to-left languages like
|
||||
/// like Arabic or Hebrew, this will be the left side.
|
||||
/// A string is a sequence of bytes. 'Right' in this context means the last
|
||||
/// position of that byte string; for a language like Arabic or Hebrew
|
||||
/// which are 'right to left' rather than 'left to right', this will be
|
||||
/// the _left_ side, not the right.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -4241,6 +4246,11 @@ impl<'a> Iterator for SplitWhitespace<'a> {
|
|||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.inner.size_hint()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn last(mut self) -> Option<&'a str> {
|
||||
self.next_back()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "split_whitespace", since = "1.1.0")]
|
||||
|
|
@ -4267,6 +4277,11 @@ impl<'a> Iterator for SplitAsciiWhitespace<'a> {
|
|||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.inner.size_hint()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn last(mut self) -> Option<&'a str> {
|
||||
self.next_back()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "split_ascii_whitespace", since = "1.34.0")]
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@ macro_rules! assert_none {
|
|||
stringify!($what), b);
|
||||
}
|
||||
}
|
||||
)*
|
||||
)+
|
||||
}};
|
||||
($what:ident, $($str:tt),+,) => (assert_none!($what,$($str),+))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ mod float;
|
|||
mod num;
|
||||
|
||||
#[test]
|
||||
#[cfg(not(miri))] // Miri cannot print pointers
|
||||
fn test_format_flags() {
|
||||
// No residual flags left by pointer formatting
|
||||
let p = "".as_ptr();
|
||||
|
|
@ -13,7 +12,6 @@ fn test_format_flags() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(miri))] // Miri cannot print pointers
|
||||
fn test_pointer_formats_data_pointer() {
|
||||
let b: &[u8] = b"";
|
||||
let s: &str = "";
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use std::str::pattern::*;
|
|||
macro_rules! search_asserts {
|
||||
($haystack:expr, $needle:expr, $testname:expr, [$($func:ident),*], $result:expr) => {
|
||||
let mut searcher = $needle.into_searcher($haystack);
|
||||
let arr = [$( Step::from(searcher.$func()) ),+];
|
||||
let arr = [$( Step::from(searcher.$func()) ),*];
|
||||
assert_eq!(&arr[..], &$result, $testname);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -253,7 +253,6 @@ fn test_unsized_nonnull() {
|
|||
|
||||
#[test]
|
||||
#[allow(warnings)]
|
||||
#[cfg(not(miri))] // Miri cannot hash pointers
|
||||
// Have a symbol for the test below. It doesn’t need to be an actual variadic function, match the
|
||||
// ABI, or even point to an actual executable code, because the function itself is never invoked.
|
||||
#[no_mangle]
|
||||
|
|
@ -293,7 +292,7 @@ fn write_unaligned_drop() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(miri))] // Miri cannot compute actual alignment of an allocation
|
||||
#[cfg(not(miri))] // Miri does not compute a maximal `mid` for `align_offset`
|
||||
fn align_offset_zst() {
|
||||
// For pointers of stride = 0, the pointer is already aligned or it cannot be aligned at
|
||||
// all, because no amount of elements will align the pointer.
|
||||
|
|
@ -308,7 +307,7 @@ fn align_offset_zst() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(miri))] // Miri cannot compute actual alignment of an allocation
|
||||
#[cfg(not(miri))] // Miri does not compute a maximal `mid` for `align_offset`
|
||||
fn align_offset_stride1() {
|
||||
// For pointers of stride = 1, the pointer can always be aligned. The offset is equal to
|
||||
// number of bytes.
|
||||
|
|
|
|||
|
|
@ -275,6 +275,25 @@ fn test_chunks_exact_nth() {
|
|||
assert_eq!(c2.next(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_chunks_exact_nth_back() {
|
||||
let v: &[i32] = &[0, 1, 2, 3, 4, 5];
|
||||
let mut c = v.chunks_exact(2);
|
||||
assert_eq!(c.nth_back(1).unwrap(), &[2, 3]);
|
||||
assert_eq!(c.next().unwrap(), &[0, 1]);
|
||||
assert_eq!(c.next(), None);
|
||||
|
||||
let v2: &[i32] = &[0, 1, 2, 3, 4];
|
||||
let mut c2 = v2.chunks_exact(3);
|
||||
assert_eq!(c2.nth_back(0).unwrap(), &[0, 1, 2]);
|
||||
assert_eq!(c2.next(), None);
|
||||
assert_eq!(c2.next_back(), None);
|
||||
|
||||
let v3: &[i32] = &[0, 1, 2, 3, 4];
|
||||
let mut c3 = v3.chunks_exact(10);
|
||||
assert_eq!(c3.nth_back(0), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_chunks_exact_last() {
|
||||
let v: &[i32] = &[0, 1, 2, 3, 4, 5];
|
||||
|
|
@ -1396,7 +1415,7 @@ pub mod memchr {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(miri))] // Miri cannot compute actual alignment of an allocation
|
||||
#[cfg(not(miri))] // Miri does not compute a maximal `mid` for `align_offset`
|
||||
fn test_align_to_simple() {
|
||||
let bytes = [1u8, 2, 3, 4, 5, 6, 7];
|
||||
let (prefix, aligned, suffix) = unsafe { bytes.align_to::<u16>() };
|
||||
|
|
@ -1420,7 +1439,7 @@ fn test_align_to_zst() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(miri))] // Miri cannot compute actual alignment of an allocation
|
||||
#[cfg(not(miri))] // Miri does not compute a maximal `mid` for `align_offset`
|
||||
fn test_align_to_non_trivial() {
|
||||
#[repr(align(8))] struct U64(u64, u64);
|
||||
#[repr(align(8))] struct U64U64U32(u64, u64, u32);
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ impl<T: Copy> Buffer<T> {
|
|||
}
|
||||
|
||||
pub(super) fn take(&mut self) -> Self {
|
||||
mem::replace(self, Self::default())
|
||||
mem::take(self)
|
||||
}
|
||||
|
||||
pub(super) fn extend_from_slice(&mut self, xs: &[T]) {
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ impl<T: LambdaL> ScopedCell<T> {
|
|||
}
|
||||
|
||||
/// Sets the value in `self` to `value` while running `f`.
|
||||
pub fn set<'a, R>(&self, value: <T as ApplyL<'a>>::Out, f: impl FnOnce() -> R) -> R {
|
||||
pub fn set<R>(&self, value: <T as ApplyL<'_>>::Out, f: impl FnOnce() -> R) -> R {
|
||||
self.replace(value, |_| f())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#![feature(extern_types)]
|
||||
#![feature(in_band_lifetimes)]
|
||||
#![feature(optin_builtin_traits)]
|
||||
#![feature(mem_take)]
|
||||
#![feature(non_exhaustive)]
|
||||
#![feature(specialization)]
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
use crate::cfg::*;
|
||||
use crate::middle::region;
|
||||
use rustc_data_structures::graph::implementation as graph;
|
||||
use syntax::ptr::P;
|
||||
use crate::ty::{self, TyCtxt};
|
||||
|
||||
use crate::hir::{self, PatKind};
|
||||
use crate::hir::def_id::DefId;
|
||||
use crate::hir::ptr::P;
|
||||
|
||||
struct CFGBuilder<'a, 'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
|
|
@ -30,7 +30,7 @@ struct LoopScope {
|
|||
break_index: CFGIndex, // where to go on a `break`
|
||||
}
|
||||
|
||||
pub fn construct<'tcx>(tcx: TyCtxt<'tcx>, body: &hir::Body) -> CFG {
|
||||
pub fn construct(tcx: TyCtxt<'_>, body: &hir::Body) -> CFG {
|
||||
let mut graph = graph::Graph::new();
|
||||
let entry = graph.add_node(CFGNodeData::Entry);
|
||||
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ pub type CFGNode = graph::Node<CFGNodeData>;
|
|||
pub type CFGEdge = graph::Edge<CFGEdgeData>;
|
||||
|
||||
impl CFG {
|
||||
pub fn new<'tcx>(tcx: TyCtxt<'tcx>, body: &hir::Body) -> CFG {
|
||||
pub fn new(tcx: TyCtxt<'_>, body: &hir::Body) -> CFG {
|
||||
construct::construct(tcx, body)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -142,9 +142,6 @@ macro_rules! define_dep_nodes {
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME: Make `is_anon`, `is_eval_always` and `has_params` properties
|
||||
// of queries
|
||||
#[inline(always)]
|
||||
pub fn is_anon(&self) -> bool {
|
||||
match *self {
|
||||
$(
|
||||
|
|
@ -163,7 +160,6 @@ macro_rules! define_dep_nodes {
|
|||
}
|
||||
|
||||
#[allow(unreachable_code)]
|
||||
#[inline(always)]
|
||||
pub fn has_params(&self) -> bool {
|
||||
match *self {
|
||||
$(
|
||||
|
|
|
|||
|
|
@ -841,32 +841,21 @@ impl DepGraph {
|
|||
//
|
||||
// This method will only load queries that will end up in the disk cache.
|
||||
// Other queries will not be executed.
|
||||
pub fn exec_cache_promotions<'tcx>(&self, tcx: TyCtxt<'tcx>) {
|
||||
let green_nodes: Vec<DepNode> = {
|
||||
let data = self.data.as_ref().unwrap();
|
||||
data.colors.values.indices().filter_map(|prev_index| {
|
||||
match data.colors.get(prev_index) {
|
||||
Some(DepNodeColor::Green(_)) => {
|
||||
let dep_node = data.previous.index_to_node(prev_index);
|
||||
if dep_node.cache_on_disk(tcx) {
|
||||
Some(dep_node)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
None |
|
||||
Some(DepNodeColor::Red) => {
|
||||
// We can skip red nodes because a node can only be marked
|
||||
// as red if the query result was recomputed and thus is
|
||||
// already in memory.
|
||||
None
|
||||
}
|
||||
pub fn exec_cache_promotions(&self, tcx: TyCtxt<'_>) {
|
||||
let data = self.data.as_ref().unwrap();
|
||||
for prev_index in data.colors.values.indices() {
|
||||
match data.colors.get(prev_index) {
|
||||
Some(DepNodeColor::Green(_)) => {
|
||||
let dep_node = data.previous.index_to_node(prev_index);
|
||||
dep_node.try_load_from_on_disk_cache(tcx);
|
||||
}
|
||||
}).collect()
|
||||
};
|
||||
|
||||
for dep_node in green_nodes {
|
||||
dep_node.load_from_on_disk_cache(tcx);
|
||||
None |
|
||||
Some(DepNodeColor::Red) => {
|
||||
// We can skip red nodes because a node can only be marked
|
||||
// as red if the query result was recomputed and thus is
|
||||
// already in memory.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -347,7 +347,7 @@ fn is_c_like_enum(item: &hir::Item) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_mod_attrs<'tcx>(tcx: TyCtxt<'tcx>, module_def_id: DefId) {
|
||||
fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: DefId) {
|
||||
tcx.hir().visit_item_likes_in_module(
|
||||
module_def_id,
|
||||
&mut CheckAttrVisitor { tcx }.as_deep_visitor()
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ use crate::hir::map::{DefKey, DefPathData, Definitions};
|
|||
use crate::hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX};
|
||||
use crate::hir::def::{Res, DefKind, PartialRes, PerNS};
|
||||
use crate::hir::{GenericArg, ConstArg};
|
||||
use crate::hir::ptr::P;
|
||||
use crate::lint::builtin::{self, PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES,
|
||||
ELIDED_LIFETIMES_IN_PATHS};
|
||||
use crate::middle::cstore::CrateStore;
|
||||
|
|
@ -61,7 +62,6 @@ use syntax::ast::*;
|
|||
use syntax::errors;
|
||||
use syntax::ext::hygiene::{Mark, SyntaxContext};
|
||||
use syntax::print::pprust;
|
||||
use syntax::ptr::P;
|
||||
use syntax::source_map::{self, respan, ExpnInfo, CompilerDesugaringKind, Spanned};
|
||||
use syntax::source_map::CompilerDesugaringKind::IfTemporary;
|
||||
use syntax::std_inject;
|
||||
|
|
@ -1111,7 +1111,7 @@ impl<'a> LoweringContext<'a> {
|
|||
},
|
||||
);
|
||||
|
||||
lowered_generics.params = lowered_generics
|
||||
let mut lowered_params: Vec<_> = lowered_generics
|
||||
.params
|
||||
.into_iter()
|
||||
.chain(in_band_defs)
|
||||
|
|
@ -1121,7 +1121,7 @@ impl<'a> LoweringContext<'a> {
|
|||
// unsorted generic parameters at the moment, so we make sure
|
||||
// that they're ordered correctly here for now. (When we chain
|
||||
// the `in_band_defs`, we might make the order unsorted.)
|
||||
lowered_generics.params.sort_by_key(|param| {
|
||||
lowered_params.sort_by_key(|param| {
|
||||
match param.kind {
|
||||
hir::GenericParamKind::Lifetime { .. } => ParamKindOrd::Lifetime,
|
||||
hir::GenericParamKind::Type { .. } => ParamKindOrd::Type,
|
||||
|
|
@ -1129,6 +1129,8 @@ impl<'a> LoweringContext<'a> {
|
|||
}
|
||||
});
|
||||
|
||||
lowered_generics.params = lowered_params.into();
|
||||
|
||||
(lowered_generics, res)
|
||||
}
|
||||
|
||||
|
|
@ -1155,13 +1157,13 @@ impl<'a> LoweringContext<'a> {
|
|||
&mut self,
|
||||
capture_clause: CaptureBy,
|
||||
closure_node_id: NodeId,
|
||||
ret_ty: Option<&Ty>,
|
||||
ret_ty: Option<syntax::ptr::P<Ty>>,
|
||||
span: Span,
|
||||
body: impl FnOnce(&mut LoweringContext<'_>) -> hir::Expr,
|
||||
) -> hir::ExprKind {
|
||||
let capture_clause = self.lower_capture_clause(capture_clause);
|
||||
let output = match ret_ty {
|
||||
Some(ty) => FunctionRetTy::Ty(P(ty.clone())),
|
||||
Some(ty) => FunctionRetTy::Ty(ty),
|
||||
None => FunctionRetTy::Default(span),
|
||||
};
|
||||
let ast_decl = FnDecl {
|
||||
|
|
@ -1278,8 +1280,8 @@ impl<'a> LoweringContext<'a> {
|
|||
let was_in_loop_condition = self.is_in_loop_condition;
|
||||
self.is_in_loop_condition = false;
|
||||
|
||||
let catch_scopes = mem::replace(&mut self.catch_scopes, Vec::new());
|
||||
let loop_scopes = mem::replace(&mut self.loop_scopes, Vec::new());
|
||||
let catch_scopes = mem::take(&mut self.catch_scopes);
|
||||
let loop_scopes = mem::take(&mut self.loop_scopes);
|
||||
let ret = f(self);
|
||||
self.catch_scopes = catch_scopes;
|
||||
self.loop_scopes = loop_scopes;
|
||||
|
|
@ -2725,7 +2727,7 @@ impl<'a> LoweringContext<'a> {
|
|||
|
||||
// ::std::future::Future<future_params>
|
||||
let future_path =
|
||||
self.std_path(span, &[sym::future, sym::Future], Some(future_params), false);
|
||||
P(self.std_path(span, &[sym::future, sym::Future], Some(future_params), false));
|
||||
|
||||
hir::GenericBound::Trait(
|
||||
hir::PolyTraitRef {
|
||||
|
|
@ -3094,7 +3096,7 @@ impl<'a> LoweringContext<'a> {
|
|||
|
||||
fn lower_trait_ref(&mut self, p: &TraitRef, itctx: ImplTraitContext<'_>) -> hir::TraitRef {
|
||||
let path = match self.lower_qpath(p.ref_id, &None, &p.path, ParamMode::Explicit, itctx) {
|
||||
hir::QPath::Resolved(None, path) => path.and_then(|path| path),
|
||||
hir::QPath::Resolved(None, path) => path,
|
||||
qpath => bug!("lower_trait_ref: unexpected QPath `{:?}`", qpath),
|
||||
};
|
||||
hir::TraitRef {
|
||||
|
|
@ -3620,7 +3622,7 @@ impl<'a> LoweringContext<'a> {
|
|||
hir::Item {
|
||||
hir_id: new_id,
|
||||
ident,
|
||||
attrs: attrs.clone(),
|
||||
attrs: attrs.into_iter().cloned().collect(),
|
||||
node: item,
|
||||
vis,
|
||||
span,
|
||||
|
|
@ -3705,7 +3707,7 @@ impl<'a> LoweringContext<'a> {
|
|||
hir::Item {
|
||||
hir_id: new_hir_id,
|
||||
ident,
|
||||
attrs: attrs.clone(),
|
||||
attrs: attrs.into_iter().cloned().collect(),
|
||||
node: item,
|
||||
vis,
|
||||
span: use_tree.span,
|
||||
|
|
@ -4567,7 +4569,7 @@ impl<'a> LoweringContext<'a> {
|
|||
// `|x: u8| future_from_generator(|| -> X { ... })`.
|
||||
let body_id = this.lower_fn_body(&outer_decl, |this| {
|
||||
let async_ret_ty = if let FunctionRetTy::Ty(ty) = &decl.output {
|
||||
Some(&**ty)
|
||||
Some(ty.clone())
|
||||
} else { None };
|
||||
let async_body = this.make_async_expr(
|
||||
capture_clause, closure_id, async_ret_ty, body.span,
|
||||
|
|
@ -5577,7 +5579,7 @@ impl<'a> LoweringContext<'a> {
|
|||
let principal = hir::PolyTraitRef {
|
||||
bound_generic_params: hir::HirVec::new(),
|
||||
trait_ref: hir::TraitRef {
|
||||
path: path.and_then(|path| path),
|
||||
path,
|
||||
hir_ref_id: hir_id,
|
||||
},
|
||||
span,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use crate::hir::itemlikevisit::ItemLikeVisitor;
|
|||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::sync::{Lock, ParallelIterator, par_iter};
|
||||
|
||||
pub fn check_crate<'hir>(hir_map: &hir::map::Map<'hir>) {
|
||||
pub fn check_crate(hir_map: &hir::map::Map<'_>) {
|
||||
hir_map.dep_graph.assert_ignored();
|
||||
|
||||
let errors = Lock::new(Vec::new());
|
||||
|
|
|
|||
|
|
@ -147,7 +147,7 @@ impl Forest {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn krate<'hir>(&'hir self) -> &'hir Crate {
|
||||
pub fn krate(&self) -> &Crate {
|
||||
self.dep_graph.read(DepNode::new_no_params(DepKind::Krate));
|
||||
&self.krate
|
||||
}
|
||||
|
|
@ -155,7 +155,7 @@ impl Forest {
|
|||
/// This is used internally in the dependency tracking system.
|
||||
/// Use the `krate` method to ensure your dependency on the
|
||||
/// crate is tracked.
|
||||
pub fn untracked_krate<'hir>(&'hir self) -> &'hir Crate {
|
||||
pub fn untracked_krate(&self) -> &Crate {
|
||||
&self.krate
|
||||
}
|
||||
}
|
||||
|
|
@ -1085,7 +1085,7 @@ impl<'a> NodesMatchingSuffix<'a> {
|
|||
// If `id` itself is a mod named `m` with parent `p`, then
|
||||
// returns `Some(id, m, p)`. If `id` has no mod in its parent
|
||||
// chain, then returns `None`.
|
||||
fn find_first_mod_parent<'a>(map: &'a Map<'_>, mut id: HirId) -> Option<(HirId, Name)> {
|
||||
fn find_first_mod_parent(map: &Map<'_>, mut id: HirId) -> Option<(HirId, Name)> {
|
||||
loop {
|
||||
if let Node::Item(item) = map.find(id)? {
|
||||
if item_is_mod(&item) {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ pub use self::UnsafeSource::*;
|
|||
|
||||
use crate::hir::def::{Res, DefKind};
|
||||
use crate::hir::def_id::{DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX};
|
||||
use crate::hir::ptr::P;
|
||||
use crate::util::nodemap::{NodeMap, FxHashSet};
|
||||
use crate::mir::mono::Linkage;
|
||||
|
||||
|
|
@ -23,7 +24,6 @@ use syntax::ast::{self, CrateSugar, Ident, Name, NodeId, AsmDialect};
|
|||
use syntax::ast::{Attribute, Label, LitKind, StrStyle, FloatTy, IntTy, UintTy};
|
||||
use syntax::attr::{InlineAttr, OptimizeAttr};
|
||||
use syntax::ext::hygiene::SyntaxContext;
|
||||
use syntax::ptr::P;
|
||||
use syntax::symbol::{Symbol, kw};
|
||||
use syntax::tokenstream::TokenStream;
|
||||
use syntax::util::parser::ExprPrecedence;
|
||||
|
|
@ -63,6 +63,7 @@ pub mod lowering;
|
|||
pub mod map;
|
||||
pub mod pat_util;
|
||||
pub mod print;
|
||||
pub mod ptr;
|
||||
pub mod upvars;
|
||||
|
||||
/// Uniquely identifies a node in the HIR of the current crate. It is
|
||||
|
|
@ -1979,13 +1980,15 @@ pub struct InlineAsmOutput {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
// NOTE(eddyb) This is used within MIR as well, so unlike the rest of the HIR,
|
||||
// it needs to be `Clone` and use plain `Vec<T>` instead of `HirVec<T>`.
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
|
||||
pub struct InlineAsm {
|
||||
pub asm: Symbol,
|
||||
pub asm_str_style: StrStyle,
|
||||
pub outputs: HirVec<InlineAsmOutput>,
|
||||
pub inputs: HirVec<Symbol>,
|
||||
pub clobbers: HirVec<Symbol>,
|
||||
pub outputs: Vec<InlineAsmOutput>,
|
||||
pub inputs: Vec<Symbol>,
|
||||
pub clobbers: Vec<Symbol>,
|
||||
pub volatile: bool,
|
||||
pub alignstack: bool,
|
||||
pub dialect: AsmDialect,
|
||||
|
|
@ -2217,7 +2220,7 @@ pub enum UseKind {
|
|||
/// within the resolution map.
|
||||
#[derive(RustcEncodable, RustcDecodable, Debug, HashStable)]
|
||||
pub struct TraitRef {
|
||||
pub path: Path,
|
||||
pub path: P<Path>,
|
||||
// Don't hash the ref_id. It is tracked via the thing it is used to access
|
||||
#[stable_hasher(ignore)]
|
||||
pub hir_ref_id: HirId,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ use syntax::parse::lexer::comments;
|
|||
use syntax::print::pp::{self, Breaks};
|
||||
use syntax::print::pp::Breaks::{Consistent, Inconsistent};
|
||||
use syntax::print::pprust::{self, PrintState};
|
||||
use syntax::ptr::P;
|
||||
use syntax::symbol::kw;
|
||||
use syntax::util::parser::{self, AssocOp, Fixity};
|
||||
use syntax_pos::{self, BytePos, FileName};
|
||||
|
|
@ -14,6 +13,7 @@ use syntax_pos::{self, BytePos, FileName};
|
|||
use crate::hir;
|
||||
use crate::hir::{PatKind, GenericBound, TraitBoundModifier, RangeEnd};
|
||||
use crate::hir::{GenericParam, GenericParamKind, GenericArg};
|
||||
use crate::hir::ptr::P;
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::cell::Cell;
|
||||
|
|
|
|||
141
src/librustc/hir/ptr.rs
Normal file
141
src/librustc/hir/ptr.rs
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
// HACK(eddyb) this is a copy of `syntax::ptr`, minus the mutation (the HIR is
|
||||
// frozen anyway). The only reason for doing this instead of replacing `P<T>`
|
||||
// with `Box<T>` in HIR, is that `&Box<[T]>` doesn't implement `IntoIterator`.
|
||||
|
||||
use std::fmt::{self, Display, Debug};
|
||||
use std::iter::FromIterator;
|
||||
use std::ops::Deref;
|
||||
use std::{slice, vec};
|
||||
|
||||
use serialize::{Encodable, Decodable, Encoder, Decoder};
|
||||
|
||||
use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult,
|
||||
HashStable};
|
||||
/// An owned smart pointer.
|
||||
#[derive(Hash, PartialEq, Eq)]
|
||||
pub struct P<T: ?Sized> {
|
||||
ptr: Box<T>
|
||||
}
|
||||
|
||||
/// Construct a `P<T>` from a `T` value.
|
||||
#[allow(non_snake_case)]
|
||||
pub fn P<T: 'static>(value: T) -> P<T> {
|
||||
P {
|
||||
ptr: box value
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: 'static> P<T> {
|
||||
// HACK(eddyb) used by HIR lowering in a few places still.
|
||||
// NOTE: do not make this more public than `pub(super)`.
|
||||
pub(super) fn into_inner(self) -> T {
|
||||
*self.ptr
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> Deref for P<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &T {
|
||||
&self.ptr
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + Debug> Debug for P<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
Debug::fmt(&self.ptr, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Display> Display for P<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
Display::fmt(&**self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: 'static + Decodable> Decodable for P<T> {
|
||||
fn decode<D: Decoder>(d: &mut D) -> Result<P<T>, D::Error> {
|
||||
Decodable::decode(d).map(P)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Encodable> Encodable for P<T> {
|
||||
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
|
||||
(**self).encode(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> P<[T]> {
|
||||
pub const fn new() -> P<[T]> {
|
||||
// HACK(eddyb) bypass the lack of a `const fn` to create an empty `Box<[T]>`
|
||||
// (as trait methods, `default` in this case, can't be `const fn` yet).
|
||||
P {
|
||||
ptr: unsafe {
|
||||
use std::ptr::NonNull;
|
||||
std::mem::transmute(NonNull::<[T; 0]>::dangling() as NonNull<[T]>)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
pub fn from_vec(v: Vec<T>) -> P<[T]> {
|
||||
P { ptr: v.into_boxed_slice() }
|
||||
}
|
||||
|
||||
// HACK(eddyb) used by HIR lowering in a few places still.
|
||||
// NOTE: do not make this more public than `pub(super)`,
|
||||
// and do not make this into an `IntoIterator` impl.
|
||||
pub(super) fn into_iter(self) -> vec::IntoIter<T> {
|
||||
self.ptr.into_vec().into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<T> Default for P<[T]> {
|
||||
/// Creates an empty `P<[T]>`.
|
||||
fn default() -> P<[T]> {
|
||||
P::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<Vec<T>> for P<[T]> {
|
||||
fn from(v: Vec<T>) -> Self {
|
||||
P::from_vec(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> FromIterator<T> for P<[T]> {
|
||||
fn from_iter<I: IntoIterator<Item=T>>(iter: I) -> P<[T]> {
|
||||
P::from_vec(iter.into_iter().collect())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> IntoIterator for &'a P<[T]> {
|
||||
type Item = &'a T;
|
||||
type IntoIter = slice::Iter<'a, T>;
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.ptr.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Encodable> Encodable for P<[T]> {
|
||||
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
|
||||
Encodable::encode(&**self, s)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Decodable> Decodable for P<[T]> {
|
||||
fn decode<D: Decoder>(d: &mut D) -> Result<P<[T]>, D::Error> {
|
||||
Ok(P::from_vec(Decodable::decode(d)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl<CTX, T> HashStable<CTX> for P<T>
|
||||
where T: ?Sized + HashStable<CTX>
|
||||
{
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut CTX,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
(**self).hash_stable(hcx, hasher);
|
||||
}
|
||||
}
|
||||
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
use crate::infer::{InferCtxt, RegionVariableOrigin, TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use crate::infer::{ConstVariableOrigin, ConstVariableOriginKind};
|
||||
use crate::infer::region_constraints::MemberConstraint;
|
||||
use crate::mir::interpret::ConstValue;
|
||||
use rustc_data_structures::indexed_vec::IndexVec;
|
||||
use rustc_macros::HashStable;
|
||||
|
|
@ -189,11 +190,25 @@ pub enum CanonicalTyVarKind {
|
|||
#[derive(Clone, Debug, HashStable)]
|
||||
pub struct QueryResponse<'tcx, R> {
|
||||
pub var_values: CanonicalVarValues<'tcx>,
|
||||
pub region_constraints: Vec<QueryRegionConstraint<'tcx>>,
|
||||
pub region_constraints: QueryRegionConstraints<'tcx>,
|
||||
pub certainty: Certainty,
|
||||
pub value: R,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, HashStable)]
|
||||
pub struct QueryRegionConstraints<'tcx> {
|
||||
pub outlives: Vec<QueryOutlivesConstraint<'tcx>>,
|
||||
pub member_constraints: Vec<MemberConstraint<'tcx>>,
|
||||
}
|
||||
|
||||
impl QueryRegionConstraints<'_> {
|
||||
/// Represents an empty (trivially true) set of region
|
||||
/// constraints.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.outlives.is_empty() && self.member_constraints.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
pub type Canonicalized<'tcx, V> = Canonical<'tcx, V>;
|
||||
|
||||
pub type CanonicalizedQueryResponse<'tcx, T> =
|
||||
|
|
@ -292,7 +307,8 @@ impl<'tcx, V> Canonical<'tcx, V> {
|
|||
}
|
||||
}
|
||||
|
||||
pub type QueryRegionConstraint<'tcx> = ty::Binder<ty::OutlivesPredicate<Kind<'tcx>, Region<'tcx>>>;
|
||||
pub type QueryOutlivesConstraint<'tcx> =
|
||||
ty::Binder<ty::OutlivesPredicate<Kind<'tcx>, Region<'tcx>>>;
|
||||
|
||||
impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
||||
/// Creates a substitution S for the canonical value with fresh
|
||||
|
|
@ -540,6 +556,19 @@ BraceStructLiftImpl! {
|
|||
} where R: Lift<'tcx>
|
||||
}
|
||||
|
||||
BraceStructTypeFoldableImpl! {
|
||||
impl<'tcx> TypeFoldable<'tcx> for QueryRegionConstraints<'tcx> {
|
||||
outlives, member_constraints
|
||||
}
|
||||
}
|
||||
|
||||
BraceStructLiftImpl! {
|
||||
impl<'a, 'tcx> Lift<'tcx> for QueryRegionConstraints<'a> {
|
||||
type Lifted = QueryRegionConstraints<'tcx>;
|
||||
outlives, member_constraints
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Index<BoundVar> for CanonicalVarValues<'tcx> {
|
||||
type Output = Kind<'tcx>;
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use crate::arena::ArenaAllocatable;
|
|||
use crate::infer::canonical::substitute::substitute_value;
|
||||
use crate::infer::canonical::{
|
||||
Canonical, CanonicalVarValues, CanonicalizedQueryResponse, Certainty,
|
||||
OriginalQueryValues, QueryRegionConstraint, QueryResponse,
|
||||
OriginalQueryValues, QueryRegionConstraints, QueryOutlivesConstraint, QueryResponse,
|
||||
};
|
||||
use crate::infer::region_constraints::{Constraint, RegionConstraintData};
|
||||
use crate::infer::InferCtxtBuilder;
|
||||
|
|
@ -132,7 +132,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
|||
{
|
||||
self.canonicalize_response(&QueryResponse {
|
||||
var_values: inference_vars,
|
||||
region_constraints: vec![],
|
||||
region_constraints: QueryRegionConstraints::default(),
|
||||
certainty: Certainty::Proven, // Ambiguities are OK!
|
||||
value: answer,
|
||||
})
|
||||
|
|
@ -174,7 +174,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
|||
|
||||
let region_obligations = self.take_registered_region_obligations();
|
||||
let region_constraints = self.with_region_constraints(|region_constraints| {
|
||||
make_query_outlives(
|
||||
make_query_region_constraints(
|
||||
tcx,
|
||||
region_obligations
|
||||
.iter()
|
||||
|
|
@ -222,10 +222,10 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
|||
mut obligations,
|
||||
} = self.query_response_substitution(cause, param_env, original_values, query_response)?;
|
||||
|
||||
obligations.extend(self.query_region_constraints_into_obligations(
|
||||
obligations.extend(self.query_outlives_constraints_into_obligations(
|
||||
cause,
|
||||
param_env,
|
||||
&query_response.value.region_constraints,
|
||||
&query_response.value.region_constraints.outlives,
|
||||
&result_subst,
|
||||
));
|
||||
|
||||
|
|
@ -248,9 +248,9 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
|||
/// that come out of these queries, which it wants to convert into
|
||||
/// MIR-based constraints and solve. Therefore, it is most
|
||||
/// convenient for the NLL Type Checker to **directly consume**
|
||||
/// the `QueryRegionConstraint` values that arise from doing a
|
||||
/// the `QueryOutlivesConstraint` values that arise from doing a
|
||||
/// query. This is contrast to other parts of the compiler, which
|
||||
/// would prefer for those `QueryRegionConstraint` to be converted
|
||||
/// would prefer for those `QueryOutlivesConstraint` to be converted
|
||||
/// into the older infcx-style constraints (e.g., calls to
|
||||
/// `sub_regions` or `register_region_obligation`).
|
||||
///
|
||||
|
|
@ -263,7 +263,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
|||
/// result. If any errors arise, they are propagated back as an
|
||||
/// `Err` result.
|
||||
/// - In the case of a successful substitution, we will append
|
||||
/// `QueryRegionConstraint` values onto the
|
||||
/// `QueryOutlivesConstraint` values onto the
|
||||
/// `output_query_region_constraints` vector for the solver to
|
||||
/// use (if an error arises, some values may also be pushed, but
|
||||
/// they should be ignored).
|
||||
|
|
@ -279,7 +279,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
|||
param_env: ty::ParamEnv<'tcx>,
|
||||
original_values: &OriginalQueryValues<'tcx>,
|
||||
query_response: &Canonical<'tcx, QueryResponse<'tcx, R>>,
|
||||
output_query_region_constraints: &mut Vec<QueryRegionConstraint<'tcx>>,
|
||||
output_query_region_constraints: &mut QueryRegionConstraints<'tcx>,
|
||||
) -> InferResult<'tcx, R>
|
||||
where
|
||||
R: Debug + TypeFoldable<'tcx>,
|
||||
|
|
@ -287,7 +287,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
|||
let result_subst =
|
||||
self.query_response_substitution_guess(cause, original_values, query_response);
|
||||
|
||||
// Compute `QueryRegionConstraint` values that unify each of
|
||||
// Compute `QueryOutlivesConstraint` values that unify each of
|
||||
// the original values `v_o` that was canonicalized into a
|
||||
// variable...
|
||||
let mut obligations = vec![];
|
||||
|
|
@ -306,8 +306,10 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
|||
// To make `v_o = v_r`, we emit `v_o: v_r` and `v_r: v_o`.
|
||||
if v_o != v_r {
|
||||
output_query_region_constraints
|
||||
.outlives
|
||||
.push(ty::Binder::dummy(ty::OutlivesPredicate(v_o.into(), v_r)));
|
||||
output_query_region_constraints
|
||||
.outlives
|
||||
.push(ty::Binder::dummy(ty::OutlivesPredicate(v_r.into(), v_o)));
|
||||
}
|
||||
}
|
||||
|
|
@ -333,12 +335,12 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
|||
}
|
||||
|
||||
// ...also include the other query region constraints from the query.
|
||||
output_query_region_constraints.extend(
|
||||
query_response.value.region_constraints.iter().filter_map(|r_c| {
|
||||
output_query_region_constraints.outlives.extend(
|
||||
query_response.value.region_constraints.outlives.iter().filter_map(|r_c| {
|
||||
let r_c = substitute_value(self.tcx, &result_subst, r_c);
|
||||
|
||||
// Screen out `'a: 'a` cases -- we skip the binder here but
|
||||
// only care the inner values to one another, so they are still at
|
||||
// only compare the inner values to one another, so they are still at
|
||||
// consistent binding levels.
|
||||
let &ty::OutlivesPredicate(k1, r2) = r_c.skip_binder();
|
||||
if k1 != r2.into() {
|
||||
|
|
@ -349,6 +351,13 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
|||
})
|
||||
);
|
||||
|
||||
// ...also include the query member constraints.
|
||||
output_query_region_constraints.member_constraints.extend(
|
||||
query_response.value.region_constraints.member_constraints.iter().map(|p_c| {
|
||||
substitute_value(self.tcx, &result_subst, p_c)
|
||||
})
|
||||
);
|
||||
|
||||
let user_result: R =
|
||||
query_response.substitute_projected(self.tcx, &result_subst, |q_r| &q_r.value);
|
||||
|
||||
|
|
@ -560,11 +569,11 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
|||
|
||||
/// Converts the region constraints resulting from a query into an
|
||||
/// iterator of obligations.
|
||||
fn query_region_constraints_into_obligations<'a>(
|
||||
fn query_outlives_constraints_into_obligations<'a>(
|
||||
&'a self,
|
||||
cause: &'a ObligationCause<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
unsubstituted_region_constraints: &'a [QueryRegionConstraint<'tcx>],
|
||||
unsubstituted_region_constraints: &'a [QueryOutlivesConstraint<'tcx>],
|
||||
result_subst: &'a CanonicalVarValues<'tcx>,
|
||||
) -> impl Iterator<Item = PredicateObligation<'tcx>> + 'a + Captures<'tcx> {
|
||||
unsubstituted_region_constraints
|
||||
|
|
@ -645,15 +654,16 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
|||
|
||||
/// Given the region obligations and constraints scraped from the infcx,
|
||||
/// creates query region constraints.
|
||||
pub fn make_query_outlives<'tcx>(
|
||||
pub fn make_query_region_constraints<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
outlives_obligations: impl Iterator<Item = (Ty<'tcx>, ty::Region<'tcx>)>,
|
||||
region_constraints: &RegionConstraintData<'tcx>,
|
||||
) -> Vec<QueryRegionConstraint<'tcx>> {
|
||||
) -> QueryRegionConstraints<'tcx> {
|
||||
let RegionConstraintData {
|
||||
constraints,
|
||||
verifys,
|
||||
givens,
|
||||
member_constraints,
|
||||
} = region_constraints;
|
||||
|
||||
assert!(verifys.is_empty());
|
||||
|
|
@ -684,5 +694,5 @@ pub fn make_query_outlives<'tcx>(
|
|||
)
|
||||
.collect();
|
||||
|
||||
outlives
|
||||
QueryRegionConstraints { outlives, member_constraints: member_constraints.clone() }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ use crate::infer::{self, SuppressRegionErrors};
|
|||
use crate::hir;
|
||||
use crate::hir::def_id::DefId;
|
||||
use crate::hir::Node;
|
||||
use crate::infer::opaque_types;
|
||||
use crate::middle::region;
|
||||
use crate::traits::{ObligationCause, ObligationCauseCode};
|
||||
use crate::ty::error::TypeError;
|
||||
|
|
@ -375,6 +376,23 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
RegionResolutionError::MemberConstraintFailure {
|
||||
opaque_type_def_id,
|
||||
hidden_ty,
|
||||
member_region,
|
||||
span: _,
|
||||
choice_regions: _,
|
||||
} => {
|
||||
let hidden_ty = self.resolve_vars_if_possible(&hidden_ty);
|
||||
opaque_types::unexpected_hidden_region_diagnostic(
|
||||
self.tcx,
|
||||
Some(region_scope_tree),
|
||||
opaque_type_def_id,
|
||||
hidden_ty,
|
||||
member_region,
|
||||
).emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -411,7 +429,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
let is_bound_failure = |e: &RegionResolutionError<'tcx>| match *e {
|
||||
RegionResolutionError::GenericBoundFailure(..) => true,
|
||||
RegionResolutionError::ConcreteFailure(..)
|
||||
| RegionResolutionError::SubSupConflict(..) => false,
|
||||
| RegionResolutionError::SubSupConflict(..)
|
||||
| RegionResolutionError::MemberConstraintFailure { .. } => false,
|
||||
};
|
||||
|
||||
let mut errors = if errors.iter().all(|e| is_bound_failure(e)) {
|
||||
|
|
@ -429,6 +448,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
RegionResolutionError::ConcreteFailure(ref sro, _, _) => sro.span(),
|
||||
RegionResolutionError::GenericBoundFailure(ref sro, _, _) => sro.span(),
|
||||
RegionResolutionError::SubSupConflict(_, ref rvo, _, _, _, _) => rvo.span(),
|
||||
RegionResolutionError::MemberConstraintFailure { span, .. } => span,
|
||||
});
|
||||
errors
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,20 @@
|
|||
//! Lexical region resolution.
|
||||
|
||||
use crate::hir::def_id::DefId;
|
||||
use crate::infer::region_constraints::Constraint;
|
||||
use crate::infer::region_constraints::GenericKind;
|
||||
use crate::infer::region_constraints::MemberConstraint;
|
||||
use crate::infer::region_constraints::RegionConstraintData;
|
||||
use crate::infer::region_constraints::VarInfos;
|
||||
use crate::infer::region_constraints::VerifyBound;
|
||||
use crate::infer::RegionVariableOrigin;
|
||||
use crate::infer::SubregionOrigin;
|
||||
use crate::middle::free_region::RegionRelations;
|
||||
use crate::ty::fold::TypeFoldable;
|
||||
use crate::ty::{self, Ty, TyCtxt};
|
||||
use crate::ty::{ReEarlyBound, ReEmpty, ReErased, ReFree, ReStatic};
|
||||
use crate::ty::{ReLateBound, RePlaceholder, ReScope, ReVar};
|
||||
use crate::ty::{Region, RegionVid};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::graph::implementation::{
|
||||
Direction, Graph, NodeIndex, INCOMING, OUTGOING,
|
||||
|
|
@ -15,12 +22,7 @@ use rustc_data_structures::graph::implementation::{
|
|||
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
|
||||
use smallvec::SmallVec;
|
||||
use std::fmt;
|
||||
use std::u32;
|
||||
use crate::ty::fold::TypeFoldable;
|
||||
use crate::ty::{self, Ty, TyCtxt};
|
||||
use crate::ty::{ReEarlyBound, ReEmpty, ReErased, ReFree, ReStatic};
|
||||
use crate::ty::{ReLateBound, ReScope, RePlaceholder, ReVar};
|
||||
use crate::ty::{Region, RegionVid};
|
||||
use syntax_pos::Span;
|
||||
|
||||
mod graphviz;
|
||||
|
||||
|
|
@ -36,11 +38,7 @@ pub fn resolve<'tcx>(
|
|||
) -> (LexicalRegionResolutions<'tcx>, Vec<RegionResolutionError<'tcx>>) {
|
||||
debug!("RegionConstraintData: resolve_regions()");
|
||||
let mut errors = vec![];
|
||||
let mut resolver = LexicalResolver {
|
||||
region_rels,
|
||||
var_infos,
|
||||
data,
|
||||
};
|
||||
let mut resolver = LexicalResolver { region_rels, var_infos, data };
|
||||
let values = resolver.infer_variable_values(&mut errors);
|
||||
(values, errors)
|
||||
}
|
||||
|
|
@ -84,6 +82,17 @@ pub enum RegionResolutionError<'tcx> {
|
|||
SubregionOrigin<'tcx>,
|
||||
Region<'tcx>,
|
||||
),
|
||||
|
||||
/// Indicates a failure of a `MemberConstraint`. These arise during
|
||||
/// impl trait processing explicitly -- basically, the impl trait's hidden type
|
||||
/// included some region that it was not supposed to.
|
||||
MemberConstraintFailure {
|
||||
span: Span,
|
||||
opaque_type_def_id: DefId,
|
||||
hidden_ty: Ty<'tcx>,
|
||||
member_region: Region<'tcx>,
|
||||
choice_regions: Vec<Region<'tcx>>,
|
||||
},
|
||||
}
|
||||
|
||||
struct RegionAndOrigin<'tcx> {
|
||||
|
|
@ -121,7 +130,12 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
|||
|
||||
let graph = self.construct_graph();
|
||||
self.expand_givens(&graph);
|
||||
self.expansion(&mut var_data);
|
||||
loop {
|
||||
self.expansion(&mut var_data);
|
||||
if !self.enforce_member_constraints(&graph, &mut var_data) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
self.collect_errors(&mut var_data, errors);
|
||||
self.collect_var_errors(&var_data, &graph, errors);
|
||||
var_data
|
||||
|
|
@ -136,7 +150,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
|||
fn construct_var_data(&self, tcx: TyCtxt<'tcx>) -> LexicalRegionResolutions<'tcx> {
|
||||
LexicalRegionResolutions {
|
||||
error_region: tcx.lifetimes.re_static,
|
||||
values: IndexVec::from_elem_n(VarValue::Value(tcx.lifetimes.re_empty), self.num_vars())
|
||||
values: IndexVec::from_elem_n(VarValue::Value(tcx.lifetimes.re_empty), self.num_vars()),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -182,6 +196,113 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Enforce all member constraints and return true if anything
|
||||
/// changed. See `enforce_member_constraint` for more details.
|
||||
fn enforce_member_constraints(
|
||||
&self,
|
||||
graph: &RegionGraph<'tcx>,
|
||||
var_values: &mut LexicalRegionResolutions<'tcx>,
|
||||
) -> bool {
|
||||
// Note: we don't use the `any` combinator because we don't
|
||||
// want to stop at the first constraint that makes a change.
|
||||
let mut any_changed = false;
|
||||
for member_constraint in &self.data.member_constraints {
|
||||
if self.enforce_member_constraint(graph, member_constraint, var_values) {
|
||||
any_changed = true;
|
||||
}
|
||||
}
|
||||
any_changed
|
||||
}
|
||||
|
||||
/// Enforce a constraint like
|
||||
///
|
||||
/// ```
|
||||
/// 'r member of ['c...]
|
||||
/// ```
|
||||
///
|
||||
/// We look for all choice regions from the list `'c...` that:
|
||||
///
|
||||
/// (a) are greater than the current value of `'r` (which is a lower bound)
|
||||
///
|
||||
/// and
|
||||
///
|
||||
/// (b) are compatible with the upper bounds of `'r` that we can
|
||||
/// find by traversing the graph.
|
||||
///
|
||||
/// From that list, we look for a *minimal* option `'c_min`. If we
|
||||
/// find one, then we can enforce that `'r: 'c_min`.
|
||||
fn enforce_member_constraint(
|
||||
&self,
|
||||
graph: &RegionGraph<'tcx>,
|
||||
member_constraint: &MemberConstraint<'tcx>,
|
||||
var_values: &mut LexicalRegionResolutions<'tcx>,
|
||||
) -> bool {
|
||||
debug!("enforce_member_constraint(member_constraint={:#?})", member_constraint);
|
||||
|
||||
// The constraint is some inference variable (`vid`) which
|
||||
// must be equal to one of the options.
|
||||
let member_vid = match member_constraint.member_region {
|
||||
ty::ReVar(vid) => *vid,
|
||||
_ => return false,
|
||||
};
|
||||
|
||||
// The current value of `vid` is a lower bound LB -- i.e., we
|
||||
// know that `LB <= vid` must be true.
|
||||
let member_lower_bound: ty::Region<'tcx> = match var_values.value(member_vid) {
|
||||
VarValue::ErrorValue => return false,
|
||||
VarValue::Value(r) => r,
|
||||
};
|
||||
|
||||
// Find all the "upper bounds" -- that is, each region `b` such that
|
||||
// `r0 <= b` must hold.
|
||||
let (member_upper_bounds, _) = self.collect_concrete_regions(
|
||||
graph,
|
||||
member_vid,
|
||||
OUTGOING,
|
||||
None,
|
||||
);
|
||||
|
||||
// Get an iterator over the *available choice* -- that is,
|
||||
// each choice region `c` where `lb <= c` and `c <= ub` for all the
|
||||
// upper bounds `ub`.
|
||||
debug!("enforce_member_constraint: upper_bounds={:#?}", member_upper_bounds);
|
||||
let mut options = member_constraint.choice_regions.iter().filter(|option| {
|
||||
self.sub_concrete_regions(member_lower_bound, option)
|
||||
&& member_upper_bounds
|
||||
.iter()
|
||||
.all(|upper_bound| self.sub_concrete_regions(option, upper_bound.region))
|
||||
});
|
||||
|
||||
// If there is more than one option, we only make a choice if
|
||||
// there is a single *least* choice -- i.e., some available
|
||||
// region that is `<=` all the others.
|
||||
let mut least_choice: ty::Region<'tcx> = match options.next() {
|
||||
Some(&r) => r,
|
||||
None => return false,
|
||||
};
|
||||
debug!("enforce_member_constraint: least_choice={:?}", least_choice);
|
||||
for &option in options {
|
||||
debug!("enforce_member_constraint: option={:?}", option);
|
||||
if !self.sub_concrete_regions(least_choice, option) {
|
||||
if self.sub_concrete_regions(option, least_choice) {
|
||||
debug!("enforce_member_constraint: new least choice");
|
||||
least_choice = option;
|
||||
} else {
|
||||
debug!("enforce_member_constraint: no least choice");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
debug!("enforce_member_constraint: final least choice = {:?}", least_choice);
|
||||
if least_choice != member_lower_bound {
|
||||
*var_values.value_mut(member_vid) = VarValue::Value(least_choice);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn expansion(&self, var_values: &mut LexicalRegionResolutions<'tcx>) {
|
||||
self.iterate_until_fixed_point("Expansion", |constraint| {
|
||||
debug!("expansion: constraint={:?}", constraint);
|
||||
|
|
@ -196,7 +317,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
|||
let b_data = var_values.value_mut(b_vid);
|
||||
let retain = match *b_data {
|
||||
VarValue::Value(ReStatic) | VarValue::ErrorValue => false,
|
||||
_ => true
|
||||
_ => true,
|
||||
};
|
||||
(a_region, b_vid, b_data, retain)
|
||||
}
|
||||
|
|
@ -204,7 +325,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
|||
Constraint::RegSubReg(..) | Constraint::VarSubReg(..) => {
|
||||
// These constraints are checked after expansion
|
||||
// is done, in `collect_errors`.
|
||||
return (false, false)
|
||||
return (false, false);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -226,16 +347,16 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
|||
|
||||
match *a_region {
|
||||
// Check if this relationship is implied by a given.
|
||||
ty::ReEarlyBound(_) | ty::ReFree(_) => if self.data.givens.contains(&(a_region, b_vid))
|
||||
{
|
||||
debug!("given");
|
||||
return false;
|
||||
},
|
||||
ty::ReEarlyBound(_) | ty::ReFree(_) => {
|
||||
if self.data.givens.contains(&(a_region, b_vid)) {
|
||||
debug!("given");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
|
||||
|
||||
match *b_data {
|
||||
VarValue::Value(cur_region) => {
|
||||
// Identical scopes can show up quite often, if the fixed point
|
||||
|
|
@ -267,10 +388,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
debug!(
|
||||
"Expanding value of {:?} from {:?} to {:?}",
|
||||
b_vid, cur_region, lub
|
||||
);
|
||||
debug!("Expanding value of {:?} from {:?} to {:?}", b_vid, cur_region, lub);
|
||||
|
||||
*b_data = VarValue::Value(lub);
|
||||
return true;
|
||||
|
|
@ -282,6 +400,12 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// True if `a <= b`, but not defined over inference variables.
|
||||
fn sub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> bool {
|
||||
self.lub_concrete_regions(a, b) == b
|
||||
}
|
||||
|
||||
/// Returns the smallest region `c` such that `a <= c` and `b <= c`.
|
||||
fn lub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> Region<'tcx> {
|
||||
let tcx = self.tcx();
|
||||
|
||||
|
|
@ -321,17 +445,16 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
|||
// at least as big as fr.scope". So, we can
|
||||
// reasonably compare free regions and scopes:
|
||||
let fr_scope = match (a, b) {
|
||||
(&ReEarlyBound(ref br), _) | (_, &ReEarlyBound(ref br)) => self.region_rels
|
||||
.region_scope_tree
|
||||
.early_free_scope(self.tcx(), br),
|
||||
(&ReFree(ref fr), _) | (_, &ReFree(ref fr)) => self.region_rels
|
||||
.region_scope_tree
|
||||
.free_scope(self.tcx(), fr),
|
||||
(&ReEarlyBound(ref br), _) | (_, &ReEarlyBound(ref br)) => {
|
||||
self.region_rels.region_scope_tree.early_free_scope(self.tcx(), br)
|
||||
}
|
||||
(&ReFree(ref fr), _) | (_, &ReFree(ref fr)) => {
|
||||
self.region_rels.region_scope_tree.free_scope(self.tcx(), fr)
|
||||
}
|
||||
_ => bug!(),
|
||||
};
|
||||
let r_id = self.region_rels
|
||||
.region_scope_tree
|
||||
.nearest_common_ancestor(fr_scope, s_id);
|
||||
let r_id =
|
||||
self.region_rels.region_scope_tree.nearest_common_ancestor(fr_scope, s_id);
|
||||
if r_id == fr_scope {
|
||||
// if the free region's scope `fr.scope` is bigger than
|
||||
// the scope region `s_id`, then the LUB is the free
|
||||
|
|
@ -352,9 +475,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
|||
// The region corresponding to an outer block is a
|
||||
// subtype of the region corresponding to an inner
|
||||
// block.
|
||||
let lub = self.region_rels
|
||||
.region_scope_tree
|
||||
.nearest_common_ancestor(a_id, b_id);
|
||||
let lub = self.region_rels.region_scope_tree.nearest_common_ancestor(a_id, b_id);
|
||||
tcx.mk_region(ReScope(lub))
|
||||
}
|
||||
|
||||
|
|
@ -365,11 +486,13 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
|||
|
||||
// For these types, we cannot define any additional
|
||||
// relationship:
|
||||
(&RePlaceholder(..), _) | (_, &RePlaceholder(..)) => if a == b {
|
||||
a
|
||||
} else {
|
||||
tcx.lifetimes.re_static
|
||||
},
|
||||
(&RePlaceholder(..), _) | (_, &RePlaceholder(..)) => {
|
||||
if a == b {
|
||||
a
|
||||
} else {
|
||||
tcx.lifetimes.re_static
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -382,10 +505,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
|||
errors: &mut Vec<RegionResolutionError<'tcx>>,
|
||||
) {
|
||||
for (constraint, origin) in &self.data.constraints {
|
||||
debug!(
|
||||
"collect_errors: constraint={:?} origin={:?}",
|
||||
constraint, origin
|
||||
);
|
||||
debug!("collect_errors: constraint={:?} origin={:?}", constraint, origin);
|
||||
match *constraint {
|
||||
Constraint::RegSubVar(..) | Constraint::VarSubVar(..) => {
|
||||
// Expansion will ensure that these constraints hold. Ignore.
|
||||
|
|
@ -433,6 +553,25 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
// Check that all member constraints are satisfied.
|
||||
for member_constraint in &self.data.member_constraints {
|
||||
let member_region = var_data.normalize(self.tcx(), member_constraint.member_region);
|
||||
let choice_regions = member_constraint
|
||||
.choice_regions
|
||||
.iter()
|
||||
.map(|&choice_region| var_data.normalize(self.tcx(), choice_region));
|
||||
if !choice_regions.clone().any(|choice_region| member_region == choice_region) {
|
||||
let span = self.tcx().def_span(member_constraint.opaque_type_def_id);
|
||||
errors.push(RegionResolutionError::MemberConstraintFailure {
|
||||
span,
|
||||
opaque_type_def_id: member_constraint.opaque_type_def_id,
|
||||
hidden_ty: member_constraint.hidden_ty,
|
||||
member_region,
|
||||
choice_regions: choice_regions.collect(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
for verify in &self.data.verifys {
|
||||
debug!("collect_errors: verify={:?}", verify);
|
||||
let sub = var_data.normalize(self.tcx(), verify.region);
|
||||
|
|
@ -483,34 +622,35 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
|||
// idea is to report errors that derive from independent
|
||||
// regions of the graph, but not those that derive from
|
||||
// overlapping locations.
|
||||
let mut dup_vec = vec![u32::MAX; self.num_vars()];
|
||||
let mut dup_vec = IndexVec::from_elem_n(None, self.num_vars());
|
||||
|
||||
for (node_vid, value) in var_data.values.iter_enumerated() {
|
||||
match *value {
|
||||
VarValue::Value(_) => { /* Inference successful */ }
|
||||
VarValue::ErrorValue => {
|
||||
/* Inference impossible: this value contains
|
||||
inconsistent constraints.
|
||||
|
||||
I think that in this case we should report an
|
||||
error now -- unlike the case above, we can't
|
||||
wait to see whether the user needs the result
|
||||
of this variable. The reason is that the mere
|
||||
existence of this variable implies that the
|
||||
region graph is inconsistent, whether or not it
|
||||
is used.
|
||||
|
||||
For example, we may have created a region
|
||||
variable that is the GLB of two other regions
|
||||
which do not have a GLB. Even if that variable
|
||||
is not used, it implies that those two regions
|
||||
*should* have a GLB.
|
||||
|
||||
At least I think this is true. It may be that
|
||||
the mere existence of a conflict in a region variable
|
||||
that is not used is not a problem, so if this rule
|
||||
starts to create problems we'll have to revisit
|
||||
this portion of the code and think hard about it. =) */
|
||||
// Inference impossible: this value contains
|
||||
// inconsistent constraints.
|
||||
//
|
||||
// I think that in this case we should report an
|
||||
// error now -- unlike the case above, we can't
|
||||
// wait to see whether the user needs the result
|
||||
// of this variable. The reason is that the mere
|
||||
// existence of this variable implies that the
|
||||
// region graph is inconsistent, whether or not it
|
||||
// is used.
|
||||
//
|
||||
// For example, we may have created a region
|
||||
// variable that is the GLB of two other regions
|
||||
// which do not have a GLB. Even if that variable
|
||||
// is not used, it implies that those two regions
|
||||
// *should* have a GLB.
|
||||
//
|
||||
// At least I think this is true. It may be that
|
||||
// the mere existence of a conflict in a region
|
||||
// variable that is not used is not a problem, so
|
||||
// if this rule starts to create problems we'll
|
||||
// have to revisit this portion of the code and
|
||||
// think hard about it. =) -- nikomatsakis
|
||||
self.collect_error_for_expanding_node(graph, &mut dup_vec, node_vid, errors);
|
||||
}
|
||||
}
|
||||
|
|
@ -562,16 +702,16 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
|||
fn collect_error_for_expanding_node(
|
||||
&self,
|
||||
graph: &RegionGraph<'tcx>,
|
||||
dup_vec: &mut [u32],
|
||||
dup_vec: &mut IndexVec<RegionVid, Option<RegionVid>>,
|
||||
node_idx: RegionVid,
|
||||
errors: &mut Vec<RegionResolutionError<'tcx>>,
|
||||
) {
|
||||
// Errors in expanding nodes result from a lower-bound that is
|
||||
// not contained by an upper-bound.
|
||||
let (mut lower_bounds, lower_dup) =
|
||||
self.collect_concrete_regions(graph, node_idx, INCOMING, dup_vec);
|
||||
self.collect_concrete_regions(graph, node_idx, INCOMING, Some(dup_vec));
|
||||
let (mut upper_bounds, upper_dup) =
|
||||
self.collect_concrete_regions(graph, node_idx, OUTGOING, dup_vec);
|
||||
self.collect_concrete_regions(graph, node_idx, OUTGOING, Some(dup_vec));
|
||||
|
||||
if lower_dup || upper_dup {
|
||||
return;
|
||||
|
|
@ -604,9 +744,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
|||
};
|
||||
|
||||
for upper_bound in &upper_bounds {
|
||||
if !self.region_rels
|
||||
.is_subregion_of(effective_lower_bound, upper_bound.region)
|
||||
{
|
||||
if !self.region_rels.is_subregion_of(effective_lower_bound, upper_bound.region) {
|
||||
let origin = self.var_infos[node_idx].origin.clone();
|
||||
debug!(
|
||||
"region inference error at {:?} for {:?}: SubSupConflict sub: {:?} \
|
||||
|
|
@ -643,7 +781,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
|||
graph: &RegionGraph<'tcx>,
|
||||
orig_node_idx: RegionVid,
|
||||
dir: Direction,
|
||||
dup_vec: &mut [u32],
|
||||
mut dup_vec: Option<&mut IndexVec<RegionVid, Option<RegionVid>>>,
|
||||
) -> (Vec<RegionAndOrigin<'tcx>>, bool) {
|
||||
struct WalkState<'tcx> {
|
||||
set: FxHashSet<RegionVid>,
|
||||
|
|
@ -667,23 +805,23 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
|||
let node_idx = state.stack.pop().unwrap();
|
||||
|
||||
// check whether we've visited this node on some previous walk
|
||||
if dup_vec[node_idx.index() as usize] == u32::MAX {
|
||||
dup_vec[node_idx.index() as usize] = orig_node_idx.index() as u32;
|
||||
} else if dup_vec[node_idx.index() as usize] != orig_node_idx.index() as u32 {
|
||||
state.dup_found = true;
|
||||
}
|
||||
if let Some(dup_vec) = &mut dup_vec {
|
||||
if dup_vec[node_idx].is_none() {
|
||||
dup_vec[node_idx] = Some(orig_node_idx);
|
||||
} else if dup_vec[node_idx] != Some(orig_node_idx) {
|
||||
state.dup_found = true;
|
||||
}
|
||||
|
||||
debug!(
|
||||
"collect_concrete_regions(orig_node_idx={:?}, node_idx={:?})",
|
||||
orig_node_idx, node_idx
|
||||
);
|
||||
debug!(
|
||||
"collect_concrete_regions(orig_node_idx={:?}, node_idx={:?})",
|
||||
orig_node_idx, node_idx
|
||||
);
|
||||
}
|
||||
|
||||
process_edges(&self.data, &mut state, graph, node_idx, dir);
|
||||
}
|
||||
|
||||
let WalkState {
|
||||
result, dup_found, ..
|
||||
} = state;
|
||||
let WalkState { result, dup_found, .. } = state;
|
||||
return (result, dup_found);
|
||||
|
||||
fn process_edges<'tcx>(
|
||||
|
|
@ -699,11 +837,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
|||
for (_, edge) in graph.adjacent_edges(source_node_index, dir) {
|
||||
match edge.data {
|
||||
Constraint::VarSubVar(from_vid, to_vid) => {
|
||||
let opp_vid = if from_vid == source_vid {
|
||||
to_vid
|
||||
} else {
|
||||
from_vid
|
||||
};
|
||||
let opp_vid = if from_vid == source_vid { to_vid } else { from_vid };
|
||||
if state.set.insert(opp_vid) {
|
||||
state.stack.push(opp_vid);
|
||||
}
|
||||
|
|
@ -726,7 +860,8 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
|||
}
|
||||
|
||||
fn iterate_until_fixed_point<F>(&self, tag: &str, mut body: F)
|
||||
where F: FnMut(&Constraint<'tcx>) -> (bool, bool),
|
||||
where
|
||||
F: FnMut(&Constraint<'tcx>) -> (bool, bool),
|
||||
{
|
||||
let mut constraints: SmallVec<[_; 16]> = self.data.constraints.keys().collect();
|
||||
let mut iteration = 0;
|
||||
|
|
@ -760,17 +895,17 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
|||
&& self.bound_is_met(b, var_values, generic_ty, min)
|
||||
}
|
||||
|
||||
VerifyBound::OutlivedBy(r) =>
|
||||
self.region_rels.is_subregion_of(
|
||||
min,
|
||||
var_values.normalize(self.tcx(), r),
|
||||
),
|
||||
VerifyBound::OutlivedBy(r) => {
|
||||
self.region_rels.is_subregion_of(min, var_values.normalize(self.tcx(), r))
|
||||
}
|
||||
|
||||
VerifyBound::AnyBound(bs) => bs.iter()
|
||||
.any(|b| self.bound_is_met(b, var_values, generic_ty, min)),
|
||||
VerifyBound::AnyBound(bs) => {
|
||||
bs.iter().any(|b| self.bound_is_met(b, var_values, generic_ty, min))
|
||||
}
|
||||
|
||||
VerifyBound::AllBounds(bs) => bs.iter()
|
||||
.all(|b| self.bound_is_met(b, var_values, generic_ty, min)),
|
||||
VerifyBound::AllBounds(bs) => {
|
||||
bs.iter().all(|b| self.bound_is_met(b, var_values, generic_ty, min))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ use crate::ty::{FloatVid, IntVid, TyVid, ConstVid};
|
|||
use crate::util::nodemap::FxHashMap;
|
||||
|
||||
use errors::DiagnosticBuilder;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_data_structures::unify as ut;
|
||||
use std::cell::{Cell, Ref, RefCell, RefMut};
|
||||
use std::collections::BTreeMap;
|
||||
|
|
@ -904,6 +905,21 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
.make_subregion(origin, a, b);
|
||||
}
|
||||
|
||||
/// Require that the region `r` be equal to one of the regions in
|
||||
/// the set `regions`.
|
||||
pub fn member_constraint(
|
||||
&self,
|
||||
opaque_type_def_id: DefId,
|
||||
definition_span: Span,
|
||||
hidden_ty: Ty<'tcx>,
|
||||
region: ty::Region<'tcx>,
|
||||
in_regions: &Lrc<Vec<ty::Region<'tcx>>>,
|
||||
) {
|
||||
debug!("member_constraint({:?} <: {:?})", region, in_regions);
|
||||
self.borrow_region_constraints()
|
||||
.member_constraint(opaque_type_def_id, definition_span, hidden_ty, region, in_regions);
|
||||
}
|
||||
|
||||
pub fn subtype_predicate(
|
||||
&self,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
|
|
@ -1456,7 +1472,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
// Even if the type may have no inference variables, during
|
||||
// type-checking closure types are in local tables only.
|
||||
if !self.in_progress_tables.is_some() || !ty.has_closure_types() {
|
||||
if let Some((param_env, ty)) = self.tcx.lift_to_global(&(param_env, ty)) {
|
||||
if !(param_env, ty).has_local_value() {
|
||||
return ty.is_copy_modulo_regions(self.tcx.global_tcx(), param_env, span);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -364,7 +364,7 @@ where
|
|||
// been fully instantiated and hence the set of scopes we have
|
||||
// doesn't matter -- just to be sure, put an empty vector
|
||||
// in there.
|
||||
let old_a_scopes = ::std::mem::replace(pair.vid_scopes(self), vec![]);
|
||||
let old_a_scopes = ::std::mem::take(pair.vid_scopes(self));
|
||||
|
||||
// Relate the generalized kind to the original one.
|
||||
let result = pair.relate_generalized_ty(self, generalized_ty);
|
||||
|
|
|
|||
|
|
@ -1,16 +1,19 @@
|
|||
use rustc_data_structures::fx::FxHashMap;
|
||||
use syntax_pos::Span;
|
||||
|
||||
use crate::hir::def_id::DefId;
|
||||
use crate::hir;
|
||||
use crate::hir::def_id::DefId;
|
||||
use crate::hir::Node;
|
||||
use crate::infer::{self, InferCtxt, InferOk, TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use crate::infer::outlives::free_region_map::FreeRegionRelations;
|
||||
use crate::infer::{self, InferCtxt, InferOk, TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use crate::middle::region;
|
||||
use crate::traits::{self, PredicateObligation};
|
||||
use crate::ty::{self, Ty, TyCtxt, GenericParamDefKind};
|
||||
use crate::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder, TypeVisitor};
|
||||
use crate::ty::subst::{Kind, InternalSubsts, SubstsRef, UnpackedKind};
|
||||
use crate::ty::subst::{InternalSubsts, Kind, SubstsRef, UnpackedKind};
|
||||
use crate::ty::{self, GenericParamDefKind, Ty, TyCtxt};
|
||||
use crate::util::nodemap::DefIdMap;
|
||||
use errors::DiagnosticBuilder;
|
||||
use rustc::session::config::nightly_options;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use syntax_pos::Span;
|
||||
|
||||
pub type OpaqueTypeMap<'tcx> = DefIdMap<OpaqueTypeDecl<'tcx>>;
|
||||
|
||||
|
|
@ -32,6 +35,20 @@ pub struct OpaqueTypeDecl<'tcx> {
|
|||
/// then `substs` would be `['a, T]`.
|
||||
pub substs: SubstsRef<'tcx>,
|
||||
|
||||
/// The span of this particular definition of the opaque type. So
|
||||
/// for example:
|
||||
///
|
||||
/// ```
|
||||
/// existential type Foo;
|
||||
/// fn bar() -> Foo {
|
||||
/// ^^^ This is the span we are looking for!
|
||||
/// ```
|
||||
///
|
||||
/// In cases where the fn returns `(impl Trait, impl Trait)` or
|
||||
/// other such combinations, the result is currently
|
||||
/// over-approximated, but better than nothing.
|
||||
pub definition_span: Span,
|
||||
|
||||
/// The type variable that represents the value of the abstract type
|
||||
/// that we require. In other words, after we compile this function,
|
||||
/// we will be created a constraint like:
|
||||
|
|
@ -98,30 +115,31 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
/// - `param_env` -- the in-scope parameter environment to be used for
|
||||
/// obligations
|
||||
/// - `value` -- the value within which we are instantiating opaque types
|
||||
/// - `value_span` -- the span where the value came from, used in error reporting
|
||||
pub fn instantiate_opaque_types<T: TypeFoldable<'tcx>>(
|
||||
&self,
|
||||
parent_def_id: DefId,
|
||||
body_id: hir::HirId,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
value: &T,
|
||||
value_span: Span,
|
||||
) -> InferOk<'tcx, (T, OpaqueTypeMap<'tcx>)> {
|
||||
debug!("instantiate_opaque_types(value={:?}, parent_def_id={:?}, body_id={:?}, \
|
||||
param_env={:?})",
|
||||
value, parent_def_id, body_id, param_env,
|
||||
debug!(
|
||||
"instantiate_opaque_types(value={:?}, parent_def_id={:?}, body_id={:?}, \
|
||||
param_env={:?})",
|
||||
value, parent_def_id, body_id, param_env,
|
||||
);
|
||||
let mut instantiator = Instantiator {
|
||||
infcx: self,
|
||||
parent_def_id,
|
||||
body_id,
|
||||
param_env,
|
||||
value_span,
|
||||
opaque_types: Default::default(),
|
||||
obligations: vec![],
|
||||
};
|
||||
let value = instantiator.instantiate_opaque_types_in_map(value);
|
||||
InferOk {
|
||||
value: (value, instantiator.opaque_types),
|
||||
obligations: instantiator.obligations,
|
||||
}
|
||||
InferOk { value: (value, instantiator.opaque_types), obligations: instantiator.obligations }
|
||||
}
|
||||
|
||||
/// Given the map `opaque_types` containing the existential `impl
|
||||
|
|
@ -216,13 +234,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
///
|
||||
/// # The Solution
|
||||
///
|
||||
/// We make use of the constraint that we *do* have in the `<=`
|
||||
/// relation. To do that, we find the "minimum" of all the
|
||||
/// arguments that appear in the substs: that is, some region
|
||||
/// which is less than all the others. In the case of `Foo1<'a>`,
|
||||
/// that would be `'a` (it's the only choice, after all). Then we
|
||||
/// apply that as a least bound to the variables (e.g., `'a <=
|
||||
/// '0`).
|
||||
/// We generally prefer to make `<=` constraints, since they
|
||||
/// integrate best into the region solver. To do that, we find the
|
||||
/// "minimum" of all the arguments that appear in the substs: that
|
||||
/// is, some region which is less than all the others. In the case
|
||||
/// of `Foo1<'a>`, that would be `'a` (it's the only choice, after
|
||||
/// all). Then we apply that as a least bound to the variables
|
||||
/// (e.g., `'a <= '0`).
|
||||
///
|
||||
/// In some cases, there is no minimum. Consider this example:
|
||||
///
|
||||
|
|
@ -230,8 +248,32 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
/// fn baz<'a, 'b>() -> impl Trait<'a, 'b> { ... }
|
||||
/// ```
|
||||
///
|
||||
/// Here we would report an error, because `'a` and `'b` have no
|
||||
/// relation to one another.
|
||||
/// Here we would report a more complex "in constraint", like `'r
|
||||
/// in ['a, 'b, 'static]` (where `'r` is some regon appearing in
|
||||
/// the hidden type).
|
||||
///
|
||||
/// # Constrain regions, not the hidden concrete type
|
||||
///
|
||||
/// Note that generating constraints on each region `Rc` is *not*
|
||||
/// the same as generating an outlives constraint on `Tc` iself.
|
||||
/// For example, if we had a function like this:
|
||||
///
|
||||
/// ```rust
|
||||
/// fn foo<'a, T>(x: &'a u32, y: T) -> impl Foo<'a> {
|
||||
/// (x, y)
|
||||
/// }
|
||||
///
|
||||
/// // Equivalent to:
|
||||
/// existential type FooReturn<'a, T>: Foo<'a>;
|
||||
/// fn foo<'a, T>(..) -> FooReturn<'a, T> { .. }
|
||||
/// ```
|
||||
///
|
||||
/// then the hidden type `Tc` would be `(&'0 u32, T)` (where `'0`
|
||||
/// is an inference variable). If we generated a constraint that
|
||||
/// `Tc: 'a`, then this would incorrectly require that `T: 'a` --
|
||||
/// but this is not necessary, because the existential type we
|
||||
/// create will be allowed to reference `T`. So we only generate a
|
||||
/// constraint that `'0: 'a`.
|
||||
///
|
||||
/// # The `free_region_relations` parameter
|
||||
///
|
||||
|
|
@ -274,6 +316,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// See `constrain_opaque_types` for documentation.
|
||||
pub fn constrain_opaque_type<FRR: FreeRegionRelations<'tcx>>(
|
||||
&self,
|
||||
def_id: DefId,
|
||||
|
|
@ -290,32 +333,25 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
|
||||
debug!("constrain_opaque_type: concrete_ty={:?}", concrete_ty);
|
||||
|
||||
let abstract_type_generics = tcx.generics_of(def_id);
|
||||
let opaque_type_generics = tcx.generics_of(def_id);
|
||||
|
||||
let span = tcx.def_span(def_id);
|
||||
|
||||
// If there are required region bounds, we can use them.
|
||||
if opaque_defn.has_required_region_bounds {
|
||||
let predicates_of = tcx.predicates_of(def_id);
|
||||
debug!(
|
||||
"constrain_opaque_type: predicates: {:#?}",
|
||||
predicates_of,
|
||||
);
|
||||
debug!("constrain_opaque_type: predicates: {:#?}", predicates_of,);
|
||||
let bounds = predicates_of.instantiate(tcx, opaque_defn.substs);
|
||||
debug!("constrain_opaque_type: bounds={:#?}", bounds);
|
||||
let opaque_type = tcx.mk_opaque(def_id, opaque_defn.substs);
|
||||
|
||||
let required_region_bounds = tcx.required_region_bounds(
|
||||
opaque_type,
|
||||
bounds.predicates,
|
||||
);
|
||||
let required_region_bounds = tcx.required_region_bounds(opaque_type, bounds.predicates);
|
||||
debug_assert!(!required_region_bounds.is_empty());
|
||||
|
||||
for region in required_region_bounds {
|
||||
concrete_ty.visit_with(&mut OpaqueTypeOutlivesVisitor {
|
||||
infcx: self,
|
||||
least_region: region,
|
||||
span,
|
||||
for required_region in required_region_bounds {
|
||||
concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
|
||||
tcx: self.tcx,
|
||||
op: |r| self.sub_regions(infer::CallReturn(span), required_region, r),
|
||||
});
|
||||
}
|
||||
return;
|
||||
|
|
@ -329,11 +365,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
// `['a]` for the first impl trait and `'b` for the
|
||||
// second.
|
||||
let mut least_region = None;
|
||||
for param in &abstract_type_generics.params {
|
||||
for param in &opaque_type_generics.params {
|
||||
match param.kind {
|
||||
GenericParamDefKind::Lifetime => {}
|
||||
_ => continue
|
||||
_ => continue,
|
||||
}
|
||||
|
||||
// Get the value supplied for this region from the substs.
|
||||
let subst_arg = opaque_defn.substs.region_at(param.index as usize);
|
||||
|
||||
|
|
@ -350,44 +387,21 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
least_region = Some(subst_arg);
|
||||
} else {
|
||||
// There are two regions (`lr` and
|
||||
// `subst_arg`) which are not relatable. We can't
|
||||
// find a best choice.
|
||||
let context_name = match opaque_defn.origin {
|
||||
hir::ExistTyOrigin::ExistentialType => "existential type",
|
||||
hir::ExistTyOrigin::ReturnImplTrait => "impl Trait",
|
||||
hir::ExistTyOrigin::AsyncFn => "async fn",
|
||||
};
|
||||
let msg = format!("ambiguous lifetime bound in `{}`", context_name);
|
||||
let mut err = self.tcx
|
||||
.sess
|
||||
.struct_span_err(span, &msg);
|
||||
|
||||
let lr_name = lr.to_string();
|
||||
let subst_arg_name = subst_arg.to_string();
|
||||
let label_owned;
|
||||
let label = match (&*lr_name, &*subst_arg_name) {
|
||||
("'_", "'_") => "the elided lifetimes here do not outlive one another",
|
||||
_ => {
|
||||
label_owned = format!(
|
||||
"neither `{}` nor `{}` outlives the other",
|
||||
lr_name,
|
||||
subst_arg_name,
|
||||
);
|
||||
&label_owned
|
||||
}
|
||||
};
|
||||
err.span_label(span, label);
|
||||
|
||||
if let hir::ExistTyOrigin::AsyncFn = opaque_defn.origin {
|
||||
err.note("multiple unrelated lifetimes are not allowed in \
|
||||
`async fn`.");
|
||||
err.note("if you're using argument-position elided lifetimes, consider \
|
||||
switching to a single named lifetime.");
|
||||
}
|
||||
err.emit();
|
||||
|
||||
least_region = Some(self.tcx.mk_region(ty::ReEmpty));
|
||||
break;
|
||||
// `subst_arg`) which are not relatable. We
|
||||
// can't find a best choice. Therefore,
|
||||
// instead of creating a single bound like
|
||||
// `'r: 'a` (which is our preferred choice),
|
||||
// we will create a "in bound" like `'r in
|
||||
// ['a, 'b, 'c]`, where `'a..'c` are the
|
||||
// regions that appear in the impl trait.
|
||||
return self.generate_member_constraint(
|
||||
concrete_ty,
|
||||
opaque_type_generics,
|
||||
opaque_defn,
|
||||
def_id,
|
||||
lr,
|
||||
subst_arg,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -396,13 +410,121 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
let least_region = least_region.unwrap_or(tcx.lifetimes.re_static);
|
||||
debug!("constrain_opaque_types: least_region={:?}", least_region);
|
||||
|
||||
concrete_ty.visit_with(&mut OpaqueTypeOutlivesVisitor {
|
||||
infcx: self,
|
||||
least_region,
|
||||
span,
|
||||
concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
|
||||
tcx: self.tcx,
|
||||
op: |r| self.sub_regions(infer::CallReturn(span), least_region, r),
|
||||
});
|
||||
}
|
||||
|
||||
/// As a fallback, we sometimes generate an "in constraint". For
|
||||
/// a case like `impl Foo<'a, 'b>`, where `'a` and `'b` cannot be
|
||||
/// related, we would generate a constraint `'r in ['a, 'b,
|
||||
/// 'static]` for each region `'r` that appears in the hidden type
|
||||
/// (i.e., it must be equal to `'a`, `'b`, or `'static`).
|
||||
///
|
||||
/// `conflict1` and `conflict2` are the two region bounds that we
|
||||
/// detected which were unrelated. They are used for diagnostics.
|
||||
fn generate_member_constraint(
|
||||
&self,
|
||||
concrete_ty: Ty<'tcx>,
|
||||
opaque_type_generics: &ty::Generics,
|
||||
opaque_defn: &OpaqueTypeDecl<'tcx>,
|
||||
opaque_type_def_id: DefId,
|
||||
conflict1: ty::Region<'tcx>,
|
||||
conflict2: ty::Region<'tcx>,
|
||||
) {
|
||||
// For now, enforce a feature gate outside of async functions.
|
||||
if self.member_constraint_feature_gate(
|
||||
opaque_defn,
|
||||
opaque_type_def_id,
|
||||
conflict1,
|
||||
conflict2,
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create the set of choice regions: each region in the hidden
|
||||
// type can be equal to any of the region parameters of the
|
||||
// opaque type definition.
|
||||
let choice_regions: Lrc<Vec<ty::Region<'tcx>>> = Lrc::new(
|
||||
opaque_type_generics
|
||||
.params
|
||||
.iter()
|
||||
.filter(|param| match param.kind {
|
||||
GenericParamDefKind::Lifetime => true,
|
||||
GenericParamDefKind::Type { .. } | GenericParamDefKind::Const => false,
|
||||
})
|
||||
.map(|param| opaque_defn.substs.region_at(param.index as usize))
|
||||
.chain(std::iter::once(self.tcx.lifetimes.re_static))
|
||||
.collect(),
|
||||
);
|
||||
|
||||
concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
|
||||
tcx: self.tcx,
|
||||
op: |r| self.member_constraint(
|
||||
opaque_type_def_id,
|
||||
opaque_defn.definition_span,
|
||||
concrete_ty,
|
||||
r,
|
||||
&choice_regions,
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
/// Member constraints are presently feature-gated except for
|
||||
/// async-await. We expect to lift this once we've had a bit more
|
||||
/// time.
|
||||
fn member_constraint_feature_gate(
|
||||
&self,
|
||||
opaque_defn: &OpaqueTypeDecl<'tcx>,
|
||||
opaque_type_def_id: DefId,
|
||||
conflict1: ty::Region<'tcx>,
|
||||
conflict2: ty::Region<'tcx>,
|
||||
) -> bool {
|
||||
// If we have `#![feature(member_constraints)]`, no problems.
|
||||
if self.tcx.features().member_constraints {
|
||||
return false;
|
||||
}
|
||||
|
||||
let span = self.tcx.def_span(opaque_type_def_id);
|
||||
|
||||
// Without a feature-gate, we only generate member-constraints for async-await.
|
||||
let context_name = match opaque_defn.origin {
|
||||
// No feature-gate required for `async fn`.
|
||||
hir::ExistTyOrigin::AsyncFn => return false,
|
||||
|
||||
// Otherwise, generate the label we'll use in the error message.
|
||||
hir::ExistTyOrigin::ExistentialType => "existential type",
|
||||
hir::ExistTyOrigin::ReturnImplTrait => "impl Trait",
|
||||
};
|
||||
let msg = format!("ambiguous lifetime bound in `{}`", context_name);
|
||||
let mut err = self.tcx.sess.struct_span_err(span, &msg);
|
||||
|
||||
let conflict1_name = conflict1.to_string();
|
||||
let conflict2_name = conflict2.to_string();
|
||||
let label_owned;
|
||||
let label = match (&*conflict1_name, &*conflict2_name) {
|
||||
("'_", "'_") => "the elided lifetimes here do not outlive one another",
|
||||
_ => {
|
||||
label_owned = format!(
|
||||
"neither `{}` nor `{}` outlives the other",
|
||||
conflict1_name, conflict2_name,
|
||||
);
|
||||
&label_owned
|
||||
}
|
||||
};
|
||||
err.span_label(span, label);
|
||||
|
||||
if nightly_options::is_nightly_build() {
|
||||
help!(err,
|
||||
"add #![feature(member_constraints)] to the crate attributes \
|
||||
to enable");
|
||||
}
|
||||
|
||||
err.emit();
|
||||
true
|
||||
}
|
||||
|
||||
/// Given the fully resolved, instantiated type for an opaque
|
||||
/// type, i.e., the value of an inference variable like C1 or C2
|
||||
/// (*), computes the "definition type" for an abstract type
|
||||
|
|
@ -456,23 +578,98 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
// Convert the type from the function into a type valid outside
|
||||
// the function, by replacing invalid regions with 'static,
|
||||
// after producing an error for each of them.
|
||||
let definition_ty =
|
||||
instantiated_ty.fold_with(&mut ReverseMapper::new(
|
||||
self.tcx,
|
||||
self.is_tainted_by_errors(),
|
||||
def_id,
|
||||
map,
|
||||
instantiated_ty,
|
||||
));
|
||||
debug!(
|
||||
"infer_opaque_definition_from_instantiation: definition_ty={:?}",
|
||||
definition_ty
|
||||
);
|
||||
let definition_ty = instantiated_ty.fold_with(&mut ReverseMapper::new(
|
||||
self.tcx,
|
||||
self.is_tainted_by_errors(),
|
||||
def_id,
|
||||
map,
|
||||
instantiated_ty,
|
||||
));
|
||||
debug!("infer_opaque_definition_from_instantiation: definition_ty={:?}", definition_ty);
|
||||
|
||||
definition_ty
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unexpected_hidden_region_diagnostic(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
region_scope_tree: Option<®ion::ScopeTree>,
|
||||
opaque_type_def_id: DefId,
|
||||
hidden_ty: Ty<'tcx>,
|
||||
hidden_region: ty::Region<'tcx>,
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
let span = tcx.def_span(opaque_type_def_id);
|
||||
let mut err = struct_span_err!(
|
||||
tcx.sess,
|
||||
span,
|
||||
E0700,
|
||||
"hidden type for `impl Trait` captures lifetime that does not appear in bounds",
|
||||
);
|
||||
|
||||
// Explain the region we are capturing.
|
||||
if let ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReStatic | ty::ReEmpty = hidden_region {
|
||||
// Assuming regionck succeeded (*), we ought to always be
|
||||
// capturing *some* region from the fn header, and hence it
|
||||
// ought to be free. So under normal circumstances, we will go
|
||||
// down this path which gives a decent human readable
|
||||
// explanation.
|
||||
//
|
||||
// (*) if not, the `tainted_by_errors` flag would be set to
|
||||
// true in any case, so we wouldn't be here at all.
|
||||
tcx.note_and_explain_free_region(
|
||||
&mut err,
|
||||
&format!("hidden type `{}` captures ", hidden_ty),
|
||||
hidden_region,
|
||||
"",
|
||||
);
|
||||
} else {
|
||||
// Ugh. This is a painful case: the hidden region is not one
|
||||
// that we can easily summarize or explain. This can happen
|
||||
// in a case like
|
||||
// `src/test/ui/multiple-lifetimes/ordinary-bounds-unsuited.rs`:
|
||||
//
|
||||
// ```
|
||||
// fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> {
|
||||
// if condition() { a } else { b }
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// Here the captured lifetime is the intersection of `'a` and
|
||||
// `'b`, which we can't quite express.
|
||||
|
||||
if let Some(region_scope_tree) = region_scope_tree {
|
||||
// If the `region_scope_tree` is available, this is being
|
||||
// invoked from the "region inferencer error". We can at
|
||||
// least report a really cryptic error for now.
|
||||
tcx.note_and_explain_region(
|
||||
region_scope_tree,
|
||||
&mut err,
|
||||
&format!("hidden type `{}` captures ", hidden_ty),
|
||||
hidden_region,
|
||||
"",
|
||||
);
|
||||
} else {
|
||||
// If the `region_scope_tree` is *unavailable*, this is
|
||||
// being invoked by the code that comes *after* region
|
||||
// inferencing. This is a bug, as the region inferencer
|
||||
// ought to have noticed the failed constraint and invoked
|
||||
// error reporting, which in turn should have prevented us
|
||||
// from getting trying to infer the hidden type
|
||||
// completely.
|
||||
tcx.sess.delay_span_bug(
|
||||
span,
|
||||
&format!(
|
||||
"hidden type captures unexpected lifetime `{:?}` \
|
||||
but no region inference failure",
|
||||
hidden_region,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
|
||||
// Visitor that requires that (almost) all regions in the type visited outlive
|
||||
// `least_region`. We cannot use `push_outlives_components` because regions in
|
||||
// closure signatures are not included in their outlives components. We need to
|
||||
|
|
@ -486,13 +683,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
//
|
||||
// We ignore any type parameters because impl trait values are assumed to
|
||||
// capture all the in-scope type parameters.
|
||||
struct OpaqueTypeOutlivesVisitor<'a, 'tcx> {
|
||||
infcx: &'a InferCtxt<'a, 'tcx>,
|
||||
least_region: ty::Region<'tcx>,
|
||||
span: Span,
|
||||
struct ConstrainOpaqueTypeRegionVisitor<'tcx, OP>
|
||||
where
|
||||
OP: FnMut(ty::Region<'tcx>),
|
||||
{
|
||||
tcx: TyCtxt<'tcx>,
|
||||
op: OP,
|
||||
}
|
||||
|
||||
impl<'tcx> TypeVisitor<'tcx> for OpaqueTypeOutlivesVisitor<'_, 'tcx> {
|
||||
impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor<'tcx, OP>
|
||||
where
|
||||
OP: FnMut(ty::Region<'tcx>),
|
||||
{
|
||||
fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> bool {
|
||||
t.skip_binder().visit_with(self);
|
||||
false // keep visiting
|
||||
|
|
@ -503,7 +705,7 @@ impl<'tcx> TypeVisitor<'tcx> for OpaqueTypeOutlivesVisitor<'_, 'tcx> {
|
|||
// ignore bound regions, keep visiting
|
||||
ty::ReLateBound(_, _) => false,
|
||||
_ => {
|
||||
self.infcx.sub_regions(infer::CallReturn(self.span), self.least_region, r);
|
||||
(self.op)(r);
|
||||
false
|
||||
}
|
||||
}
|
||||
|
|
@ -519,23 +721,23 @@ impl<'tcx> TypeVisitor<'tcx> for OpaqueTypeOutlivesVisitor<'_, 'tcx> {
|
|||
ty::Closure(def_id, ref substs) => {
|
||||
// Skip lifetime parameters of the enclosing item(s)
|
||||
|
||||
for upvar_ty in substs.upvar_tys(def_id, self.infcx.tcx) {
|
||||
for upvar_ty in substs.upvar_tys(def_id, self.tcx) {
|
||||
upvar_ty.visit_with(self);
|
||||
}
|
||||
|
||||
substs.closure_sig_ty(def_id, self.infcx.tcx).visit_with(self);
|
||||
substs.closure_sig_ty(def_id, self.tcx).visit_with(self);
|
||||
}
|
||||
|
||||
ty::Generator(def_id, ref substs, _) => {
|
||||
// Skip lifetime parameters of the enclosing item(s)
|
||||
// Also skip the witness type, because that has no free regions.
|
||||
|
||||
for upvar_ty in substs.upvar_tys(def_id, self.infcx.tcx) {
|
||||
for upvar_ty in substs.upvar_tys(def_id, self.tcx) {
|
||||
upvar_ty.visit_with(self);
|
||||
}
|
||||
|
||||
substs.return_ty(def_id, self.infcx.tcx).visit_with(self);
|
||||
substs.yield_ty(def_id, self.infcx.tcx).visit_with(self);
|
||||
substs.return_ty(def_id, self.tcx).visit_with(self);
|
||||
substs.yield_ty(def_id, self.tcx).visit_with(self);
|
||||
}
|
||||
_ => {
|
||||
ty.super_visit_with(self);
|
||||
|
|
@ -616,40 +818,17 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> {
|
|||
None => {
|
||||
if !self.map_missing_regions_to_empty && !self.tainted_by_errors {
|
||||
if let Some(hidden_ty) = self.hidden_ty.take() {
|
||||
let span = self.tcx.def_span(self.opaque_type_def_id);
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess,
|
||||
span,
|
||||
E0700,
|
||||
"hidden type for `impl Trait` captures lifetime that \
|
||||
does not appear in bounds",
|
||||
);
|
||||
|
||||
// Assuming regionck succeeded, then we must
|
||||
// be capturing *some* region from the fn
|
||||
// header, and hence it must be free, so it's
|
||||
// ok to invoke this fn (which doesn't accept
|
||||
// all regions, and would ICE if an
|
||||
// inappropriate region is given). We check
|
||||
// `is_tainted_by_errors` by errors above, so
|
||||
// we don't get in here unless regionck
|
||||
// succeeded. (Note also that if regionck
|
||||
// failed, then the regions we are attempting
|
||||
// to map here may well be giving errors
|
||||
// *because* the constraints were not
|
||||
// satisfiable.)
|
||||
self.tcx.note_and_explain_free_region(
|
||||
&mut err,
|
||||
&format!("hidden type `{}` captures ", hidden_ty),
|
||||
unexpected_hidden_region_diagnostic(
|
||||
self.tcx,
|
||||
None,
|
||||
self.opaque_type_def_id,
|
||||
hidden_ty,
|
||||
r,
|
||||
""
|
||||
);
|
||||
|
||||
err.emit();
|
||||
).emit();
|
||||
}
|
||||
}
|
||||
self.tcx.lifetimes.re_empty
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -681,8 +860,8 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> {
|
|||
// during codegen.
|
||||
|
||||
let generics = self.tcx.generics_of(def_id);
|
||||
let substs = self.tcx.mk_substs(substs.substs.iter().enumerate().map(
|
||||
|(index, &kind)| {
|
||||
let substs =
|
||||
self.tcx.mk_substs(substs.substs.iter().enumerate().map(|(index, &kind)| {
|
||||
if index < generics.parent_count {
|
||||
// Accommodate missing regions in the parent kinds...
|
||||
self.fold_kind_mapping_missing_regions_to_empty(kind)
|
||||
|
|
@ -690,16 +869,15 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> {
|
|||
// ...but not elsewhere.
|
||||
self.fold_kind_normally(kind)
|
||||
}
|
||||
},
|
||||
));
|
||||
}));
|
||||
|
||||
self.tcx.mk_closure(def_id, ty::ClosureSubsts { substs })
|
||||
}
|
||||
|
||||
ty::Generator(def_id, substs, movability) => {
|
||||
let generics = self.tcx.generics_of(def_id);
|
||||
let substs = self.tcx.mk_substs(substs.substs.iter().enumerate().map(
|
||||
|(index, &kind)| {
|
||||
let substs =
|
||||
self.tcx.mk_substs(substs.substs.iter().enumerate().map(|(index, &kind)| {
|
||||
if index < generics.parent_count {
|
||||
// Accommodate missing regions in the parent kinds...
|
||||
self.fold_kind_mapping_missing_regions_to_empty(kind)
|
||||
|
|
@ -707,8 +885,7 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> {
|
|||
// ...but not elsewhere.
|
||||
self.fold_kind_normally(kind)
|
||||
}
|
||||
},
|
||||
));
|
||||
}));
|
||||
|
||||
self.tcx.mk_generator(def_id, ty::GeneratorSubsts { substs }, movability)
|
||||
}
|
||||
|
|
@ -723,6 +900,7 @@ struct Instantiator<'a, 'tcx> {
|
|||
parent_def_id: DefId,
|
||||
body_id: hir::HirId,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
value_span: Span,
|
||||
opaque_types: OpaqueTypeMap<'tcx>,
|
||||
obligations: Vec<PredicateObligation<'tcx>>,
|
||||
}
|
||||
|
|
@ -773,12 +951,10 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
|
|||
let parent_def_id = self.parent_def_id;
|
||||
let def_scope_default = || {
|
||||
let opaque_parent_hir_id = tcx.hir().get_parent_item(opaque_hir_id);
|
||||
parent_def_id == tcx.hir()
|
||||
.local_def_id_from_hir_id(opaque_parent_hir_id)
|
||||
parent_def_id
|
||||
== tcx.hir().local_def_id_from_hir_id(opaque_parent_hir_id)
|
||||
};
|
||||
let (in_definition_scope, origin) =
|
||||
match tcx.hir().find(opaque_hir_id)
|
||||
{
|
||||
let (in_definition_scope, origin) = match tcx.hir().find(opaque_hir_id) {
|
||||
Some(Node::Item(item)) => match item.node {
|
||||
// Anonymous `impl Trait`
|
||||
hir::ItemKind::Existential(hir::ExistTy {
|
||||
|
|
@ -847,10 +1023,7 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
|
|||
let infcx = self.infcx;
|
||||
let tcx = infcx.tcx;
|
||||
|
||||
debug!(
|
||||
"instantiate_opaque_types: Opaque(def_id={:?}, substs={:?})",
|
||||
def_id, substs
|
||||
);
|
||||
debug!("instantiate_opaque_types: Opaque(def_id={:?}, substs={:?})", def_id, substs);
|
||||
|
||||
// Use the same type variable if the exact same opaque type appears more
|
||||
// than once in the return type (e.g., if it's passed to a type alias).
|
||||
|
|
@ -858,41 +1031,35 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
|
|||
return opaque_defn.concrete_ty;
|
||||
}
|
||||
let span = tcx.def_span(def_id);
|
||||
let ty_var = infcx.next_ty_var(TypeVariableOrigin {
|
||||
kind: TypeVariableOriginKind::TypeInference,
|
||||
span,
|
||||
});
|
||||
let ty_var = infcx
|
||||
.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span });
|
||||
|
||||
let predicates_of = tcx.predicates_of(def_id);
|
||||
debug!(
|
||||
"instantiate_opaque_types: predicates={:#?}",
|
||||
predicates_of,
|
||||
);
|
||||
debug!("instantiate_opaque_types: predicates={:#?}", predicates_of,);
|
||||
let bounds = predicates_of.instantiate(tcx, substs);
|
||||
debug!("instantiate_opaque_types: bounds={:?}", bounds);
|
||||
|
||||
let required_region_bounds = tcx.required_region_bounds(ty, bounds.predicates.clone());
|
||||
debug!(
|
||||
"instantiate_opaque_types: required_region_bounds={:?}",
|
||||
required_region_bounds
|
||||
);
|
||||
debug!("instantiate_opaque_types: required_region_bounds={:?}", required_region_bounds);
|
||||
|
||||
// Make sure that we are in fact defining the *entire* type
|
||||
// (e.g., `existential type Foo<T: Bound>: Bar;` needs to be
|
||||
// defined by a function like `fn foo<T: Bound>() -> Foo<T>`).
|
||||
debug!(
|
||||
"instantiate_opaque_types: param_env={:#?}",
|
||||
self.param_env,
|
||||
);
|
||||
debug!(
|
||||
"instantiate_opaque_types: generics={:#?}",
|
||||
tcx.generics_of(def_id),
|
||||
);
|
||||
debug!("instantiate_opaque_types: param_env={:#?}", self.param_env,);
|
||||
debug!("instantiate_opaque_types: generics={:#?}", tcx.generics_of(def_id),);
|
||||
|
||||
// Ideally, we'd get the span where *this specific `ty` came
|
||||
// from*, but right now we just use the span from the overall
|
||||
// value being folded. In simple cases like `-> impl Foo`,
|
||||
// these are the same span, but not in cases like `-> (impl
|
||||
// Foo, impl Bar)`.
|
||||
let definition_span = self.value_span;
|
||||
|
||||
self.opaque_types.insert(
|
||||
def_id,
|
||||
OpaqueTypeDecl {
|
||||
substs,
|
||||
definition_span,
|
||||
concrete_ty: ty_var,
|
||||
has_required_region_bounds: !required_region_bounds.is_empty(),
|
||||
origin,
|
||||
|
|
@ -911,8 +1078,7 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
|
|||
|
||||
// Require that the predicate holds for the concrete type.
|
||||
debug!("instantiate_opaque_types: predicate={:?}", predicate);
|
||||
self.obligations
|
||||
.push(traits::Obligation::new(cause, self.param_env, predicate));
|
||||
self.obligations.push(traits::Obligation::new(cause, self.param_env, predicate));
|
||||
}
|
||||
|
||||
ty_var
|
||||
|
|
@ -950,9 +1116,7 @@ pub fn may_define_existential_type(
|
|||
);
|
||||
|
||||
// Named existential types can be defined by any siblings or children of siblings.
|
||||
let scope = tcx.hir()
|
||||
.get_defining_scope(opaque_hir_id)
|
||||
.expect("could not get defining scope");
|
||||
let scope = tcx.hir().get_defining_scope(opaque_hir_id).expect("could not get defining scope");
|
||||
// We walk up the node tree until we hit the root or the scope of the opaque type.
|
||||
while hir_id != scope && hir_id != hir::CRATE_HIR_ID {
|
||||
hir_id = tcx.hir().get_parent_item(hir_id);
|
||||
|
|
|
|||
|
|
@ -11,6 +11,10 @@ pub struct FreeRegionMap<'tcx> {
|
|||
}
|
||||
|
||||
impl<'tcx> FreeRegionMap<'tcx> {
|
||||
pub fn elements(&self) -> impl Iterator<Item=&Region<'tcx>> {
|
||||
self.relation.elements()
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.relation.is_empty()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
|||
|
||||
/// Trait queries just want to pass back type obligations "as is"
|
||||
pub fn take_registered_region_obligations(&self) -> Vec<(hir::HirId, RegionObligation<'tcx>)> {
|
||||
::std::mem::replace(&mut *self.region_obligations.borrow_mut(), vec![])
|
||||
::std::mem::take(&mut *self.region_obligations.borrow_mut())
|
||||
}
|
||||
|
||||
/// Process the region obligations that must be proven (during
|
||||
|
|
|
|||
|
|
@ -8,11 +8,14 @@ use super::{MiscVariable, RegionVariableOrigin, SubregionOrigin};
|
|||
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::indexed_vec::IndexVec;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_data_structures::unify as ut;
|
||||
use crate::hir::def_id::DefId;
|
||||
use crate::ty::ReStatic;
|
||||
use crate::ty::{self, Ty, TyCtxt};
|
||||
use crate::ty::{ReLateBound, ReVar};
|
||||
use crate::ty::{Region, RegionVid};
|
||||
use syntax_pos::Span;
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::{cmp, fmt, mem};
|
||||
|
|
@ -78,6 +81,11 @@ pub struct RegionConstraintData<'tcx> {
|
|||
/// be a region variable (or neither, as it happens).
|
||||
pub constraints: BTreeMap<Constraint<'tcx>, SubregionOrigin<'tcx>>,
|
||||
|
||||
/// Constraints of the form `R0 member of [R1, ..., Rn]`, meaning that
|
||||
/// `R0` must be equal to one of the regions `R1..Rn`. These occur
|
||||
/// with `impl Trait` quite frequently.
|
||||
pub member_constraints: Vec<MemberConstraint<'tcx>>,
|
||||
|
||||
/// A "verify" is something that we need to verify after inference
|
||||
/// is done, but which does not directly affect inference in any
|
||||
/// way.
|
||||
|
|
@ -137,6 +145,43 @@ impl Constraint<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Requires that `region` must be equal to one of the regions in `choice_regions`.
|
||||
/// We often denote this using the syntax:
|
||||
///
|
||||
/// ```
|
||||
/// R0 member of [O1..On]
|
||||
/// ```
|
||||
#[derive(Debug, Clone, HashStable)]
|
||||
pub struct MemberConstraint<'tcx> {
|
||||
/// The `DefId` of the opaque type causing this constraint: used for error reporting.
|
||||
pub opaque_type_def_id: DefId,
|
||||
|
||||
/// The span where the hidden type was instantiated.
|
||||
pub definition_span: Span,
|
||||
|
||||
/// The hidden type in which `member_region` appears: used for error reporting.
|
||||
pub hidden_ty: Ty<'tcx>,
|
||||
|
||||
/// The region `R0`.
|
||||
pub member_region: Region<'tcx>,
|
||||
|
||||
/// The options `O1..On`.
|
||||
pub choice_regions: Lrc<Vec<Region<'tcx>>>,
|
||||
}
|
||||
|
||||
BraceStructTypeFoldableImpl! {
|
||||
impl<'tcx> TypeFoldable<'tcx> for MemberConstraint<'tcx> {
|
||||
opaque_type_def_id, definition_span, hidden_ty, member_region, choice_regions
|
||||
}
|
||||
}
|
||||
|
||||
BraceStructLiftImpl! {
|
||||
impl<'a, 'tcx> Lift<'tcx> for MemberConstraint<'a> {
|
||||
type Lifted = MemberConstraint<'tcx>;
|
||||
opaque_type_def_id, definition_span, hidden_ty, member_region, choice_regions
|
||||
}
|
||||
}
|
||||
|
||||
/// `VerifyGenericBound(T, _, R, RS)`: the parameter type `T` (or
|
||||
/// associated type) must outlive the region `R`. `T` is known to
|
||||
/// outlive `RS`. Therefore, verify that `R <= RS[i]` for some
|
||||
|
|
@ -410,7 +455,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
|
|||
*any_unifications = false;
|
||||
}
|
||||
|
||||
mem::replace(data, RegionConstraintData::default())
|
||||
mem::take(data)
|
||||
}
|
||||
|
||||
pub fn data(&self) -> &RegionConstraintData<'tcx> {
|
||||
|
|
@ -643,6 +688,30 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn member_constraint(
|
||||
&mut self,
|
||||
opaque_type_def_id: DefId,
|
||||
definition_span: Span,
|
||||
hidden_ty: Ty<'tcx>,
|
||||
member_region: ty::Region<'tcx>,
|
||||
choice_regions: &Lrc<Vec<ty::Region<'tcx>>>,
|
||||
) {
|
||||
debug!("member_constraint({:?} in {:#?})", member_region, choice_regions);
|
||||
|
||||
if choice_regions.iter().any(|&r| r == member_region) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.data.member_constraints.push(MemberConstraint {
|
||||
opaque_type_def_id,
|
||||
definition_span,
|
||||
hidden_ty,
|
||||
member_region,
|
||||
choice_regions: choice_regions.clone()
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
pub fn make_subregion(
|
||||
&mut self,
|
||||
origin: SubregionOrigin<'tcx>,
|
||||
|
|
@ -906,9 +975,13 @@ impl<'tcx> RegionConstraintData<'tcx> {
|
|||
pub fn is_empty(&self) -> bool {
|
||||
let RegionConstraintData {
|
||||
constraints,
|
||||
member_constraints,
|
||||
verifys,
|
||||
givens,
|
||||
} = self;
|
||||
constraints.is_empty() && verifys.is_empty() && givens.is_empty()
|
||||
constraints.is_empty() &&
|
||||
member_constraints.is_empty() &&
|
||||
verifys.is_empty() &&
|
||||
givens.is_empty()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ impl<'tcx> TypeVariableTable<'tcx> {
|
|||
///
|
||||
/// Note that this function does not return care whether
|
||||
/// `vid` has been unified with something else or not.
|
||||
pub fn var_diverges<'a>(&'a self, vid: ty::TyVid) -> bool {
|
||||
pub fn var_diverges(&self, vid: ty::TyVid) -> bool {
|
||||
self.values.get(vid.index as usize).diverging
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,8 @@
|
|||
#![feature(arbitrary_self_types)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(box_syntax)]
|
||||
#![feature(const_fn)]
|
||||
#![feature(const_transmute)]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(drain_filter)]
|
||||
#![feature(inner_deref)]
|
||||
|
|
@ -65,6 +67,7 @@
|
|||
#![feature(crate_visibility_modifier)]
|
||||
#![feature(proc_macro_hygiene)]
|
||||
#![feature(log_syntax)]
|
||||
#![feature(mem_take)]
|
||||
|
||||
#![recursion_limit="512"]
|
||||
|
||||
|
|
|
|||
|
|
@ -765,7 +765,7 @@ pub fn maybe_lint_level_root(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
|
|||
attrs.iter().any(|attr| Level::from_symbol(attr.name_or_empty()).is_some())
|
||||
}
|
||||
|
||||
fn lint_levels<'tcx>(tcx: TyCtxt<'tcx>, cnum: CrateNum) -> &'tcx LintLevelMap {
|
||||
fn lint_levels(tcx: TyCtxt<'_>, cnum: CrateNum) -> &LintLevelMap {
|
||||
assert_eq!(cnum, LOCAL_CRATE);
|
||||
let mut builder = LintLevelMapBuilder {
|
||||
levels: LintLevelSets::builder(tcx.sess),
|
||||
|
|
|
|||
|
|
@ -211,7 +211,7 @@ pub trait CrateStore {
|
|||
fn crates_untracked(&self) -> Vec<CrateNum>;
|
||||
|
||||
// utility functions
|
||||
fn encode_metadata<'tcx>(&self, tcx: TyCtxt<'tcx>) -> EncodedMetadata;
|
||||
fn encode_metadata(&self, tcx: TyCtxt<'_>) -> EncodedMetadata;
|
||||
fn metadata_encoding_version(&self) -> &[u8];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ use syntax_pos;
|
|||
// explored. For example, if it's a live Node::Item that is a
|
||||
// function, then we should explore its block to check for codes that
|
||||
// may need to be marked as live.
|
||||
fn should_explore<'tcx>(tcx: TyCtxt<'tcx>, hir_id: hir::HirId) -> bool {
|
||||
fn should_explore(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool {
|
||||
match tcx.hir().find(hir_id) {
|
||||
Some(Node::Item(..)) |
|
||||
Some(Node::ImplItem(..)) |
|
||||
|
|
@ -662,7 +662,7 @@ impl Visitor<'tcx> for DeadVisitor<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>) {
|
||||
pub fn check_crate(tcx: TyCtxt<'_>) {
|
||||
let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE);
|
||||
let krate = tcx.hir().krate();
|
||||
let live_symbols = find_live(tcx, access_levels, krate);
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ pub enum Linkage {
|
|||
Dynamic,
|
||||
}
|
||||
|
||||
pub fn calculate<'tcx>(tcx: TyCtxt<'tcx>) {
|
||||
pub fn calculate(tcx: TyCtxt<'_>) {
|
||||
let sess = &tcx.sess;
|
||||
let fmts = sess.crate_types.borrow().iter().map(|&ty| {
|
||||
let linkage = calculate_type(tcx, ty);
|
||||
|
|
@ -92,7 +92,7 @@ pub fn calculate<'tcx>(tcx: TyCtxt<'tcx>) {
|
|||
sess.dependency_formats.set(fmts);
|
||||
}
|
||||
|
||||
fn calculate_type<'tcx>(tcx: TyCtxt<'tcx>, ty: config::CrateType) -> DependencyList {
|
||||
fn calculate_type(tcx: TyCtxt<'_>, ty: config::CrateType) -> DependencyList {
|
||||
let sess = &tcx.sess;
|
||||
|
||||
if !sess.opts.output_types.should_codegen() {
|
||||
|
|
@ -267,7 +267,7 @@ fn add_library(
|
|||
}
|
||||
}
|
||||
|
||||
fn attempt_static<'tcx>(tcx: TyCtxt<'tcx>) -> Option<DependencyList> {
|
||||
fn attempt_static(tcx: TyCtxt<'_>) -> Option<DependencyList> {
|
||||
let sess = &tcx.sess;
|
||||
let crates = cstore::used_crates(tcx, RequireStatic);
|
||||
if !crates.iter().by_ref().all(|&(_, ref p)| p.is_some()) {
|
||||
|
|
@ -324,7 +324,7 @@ fn activate_injected_dep(injected: Option<CrateNum>,
|
|||
|
||||
// After the linkage for a crate has been determined we need to verify that
|
||||
// there's only going to be one allocator in the output.
|
||||
fn verify_ok<'tcx>(tcx: TyCtxt<'tcx>, list: &[Linkage]) {
|
||||
fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) {
|
||||
let sess = &tcx.sess;
|
||||
if list.len() == 0 {
|
||||
return
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ use self::OverloadedCallType::*;
|
|||
|
||||
use crate::hir::def::{CtorOf, Res, DefKind};
|
||||
use crate::hir::def_id::DefId;
|
||||
use crate::hir::ptr::P;
|
||||
use crate::infer::InferCtxt;
|
||||
use crate::middle::mem_categorization as mc;
|
||||
use crate::middle::region;
|
||||
|
|
@ -18,7 +19,6 @@ use crate::ty::{self, DefIdTree, TyCtxt, adjustment};
|
|||
|
||||
use crate::hir::{self, PatKind};
|
||||
use std::rc::Rc;
|
||||
use syntax::ptr::P;
|
||||
use syntax_pos::Span;
|
||||
use crate::util::nodemap::ItemLocalSet;
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use syntax_pos::{Span, sym};
|
|||
use crate::hir::intravisit::{self, Visitor, NestedVisitorMap};
|
||||
use crate::hir;
|
||||
|
||||
fn check_mod_intrinsics<'tcx>(tcx: TyCtxt<'tcx>, module_def_id: DefId) {
|
||||
fn check_mod_intrinsics(tcx: TyCtxt<'_>, module_def_id: DefId) {
|
||||
tcx.hir().visit_item_likes_in_module(
|
||||
module_def_id,
|
||||
&mut ItemVisitor { tcx }.as_deep_visitor()
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ impl Visitor<'tcx> for LibFeatureCollector<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn collect<'tcx>(tcx: TyCtxt<'tcx>) -> LibFeatures {
|
||||
pub fn collect(tcx: TyCtxt<'_>) -> LibFeatures {
|
||||
let mut collector = LibFeatureCollector::new(tcx);
|
||||
intravisit::walk_crate(&mut collector, tcx.hir().krate());
|
||||
collector.lib_features
|
||||
|
|
|
|||
|
|
@ -99,6 +99,7 @@ use self::VarKind::*;
|
|||
|
||||
use crate::hir::def::*;
|
||||
use crate::hir::Node;
|
||||
use crate::hir::ptr::P;
|
||||
use crate::ty::{self, TyCtxt};
|
||||
use crate::ty::query::Providers;
|
||||
use crate::lint;
|
||||
|
|
@ -111,7 +112,6 @@ use std::io::prelude::*;
|
|||
use std::io;
|
||||
use std::rc::Rc;
|
||||
use syntax::ast;
|
||||
use syntax::ptr::P;
|
||||
use syntax::symbol::{kw, sym};
|
||||
use syntax_pos::Span;
|
||||
|
||||
|
|
@ -181,7 +181,7 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
|
|||
fn visit_arm(&mut self, a: &'tcx hir::Arm) { visit_arm(self, a); }
|
||||
}
|
||||
|
||||
fn check_mod_liveness<'tcx>(tcx: TyCtxt<'tcx>, module_def_id: DefId) {
|
||||
fn check_mod_liveness(tcx: TyCtxt<'_>, module_def_id: DefId) {
|
||||
tcx.hir().visit_item_likes_in_module(
|
||||
module_def_id,
|
||||
&mut IrMaps::new(tcx, module_def_id).as_deep_visitor(),
|
||||
|
|
|
|||
|
|
@ -465,9 +465,11 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
|
|||
) -> bool {
|
||||
self.infcx.map(|infcx| infcx.type_is_copy_modulo_regions(param_env, ty, span))
|
||||
.or_else(|| {
|
||||
self.tcx.lift_to_global(&(param_env, ty)).map(|(param_env, ty)| {
|
||||
ty.is_copy_modulo_regions(self.tcx.global_tcx(), param_env, span)
|
||||
})
|
||||
if (param_env, ty).has_local_value() {
|
||||
None
|
||||
} else {
|
||||
Some(ty.is_copy_modulo_regions(self.tcx, param_env, span))
|
||||
}
|
||||
})
|
||||
.unwrap_or(true)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,8 +42,8 @@ fn item_might_be_inlined(tcx: TyCtxt<'tcx>, item: &hir::Item, attrs: CodegenFnAt
|
|||
}
|
||||
}
|
||||
|
||||
fn method_might_be_inlined<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
fn method_might_be_inlined(
|
||||
tcx: TyCtxt<'_>,
|
||||
impl_item: &hir::ImplItem,
|
||||
impl_src: DefId,
|
||||
) -> bool {
|
||||
|
|
@ -391,7 +391,7 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CollectPrivateImplItemsVisitor<'a, 'tcx
|
|||
#[derive(Clone, HashStable)]
|
||||
pub struct ReachableSet(pub Lrc<HirIdSet>);
|
||||
|
||||
fn reachable_set<'tcx>(tcx: TyCtxt<'tcx>, crate_num: CrateNum) -> ReachableSet {
|
||||
fn reachable_set(tcx: TyCtxt<'_>, crate_num: CrateNum) -> ReachableSet {
|
||||
debug_assert!(crate_num == LOCAL_CRATE);
|
||||
|
||||
let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE);
|
||||
|
|
|
|||
|
|
@ -1375,7 +1375,7 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> {
|
|||
|
||||
let outer_ec = mem::replace(&mut self.expr_and_pat_count, 0);
|
||||
let outer_cx = self.cx;
|
||||
let outer_ts = mem::replace(&mut self.terminating_scopes, FxHashSet::default());
|
||||
let outer_ts = mem::take(&mut self.terminating_scopes);
|
||||
self.terminating_scopes.insert(body.value.hir_id.local_id);
|
||||
|
||||
if let Some(root_id) = self.cx.root_id {
|
||||
|
|
@ -1446,7 +1446,7 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn region_scope_tree<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx ScopeTree {
|
||||
fn region_scope_tree(tcx: TyCtxt<'_>, def_id: DefId) -> &ScopeTree {
|
||||
let closure_base_def_id = tcx.closure_base_def_id(def_id);
|
||||
if closure_base_def_id != def_id {
|
||||
return tcx.region_scope_tree(closure_base_def_id);
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
use crate::hir::def::{Res, DefKind};
|
||||
use crate::hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
|
||||
use crate::hir::map::Map;
|
||||
use crate::hir::ptr::P;
|
||||
use crate::hir::{GenericArg, GenericParam, ItemLocalId, LifetimeName, Node, ParamName};
|
||||
use crate::ty::{self, DefIdTree, GenericParamDefKind, TyCtxt};
|
||||
|
||||
|
|
@ -18,10 +19,9 @@ use errors::{Applicability, DiagnosticBuilder};
|
|||
use rustc_macros::HashStable;
|
||||
use std::borrow::Cow;
|
||||
use std::cell::Cell;
|
||||
use std::mem::replace;
|
||||
use std::mem::{replace, take};
|
||||
use syntax::ast;
|
||||
use syntax::attr;
|
||||
use syntax::ptr::P;
|
||||
use syntax::symbol::{kw, sym};
|
||||
use syntax_pos::Span;
|
||||
|
||||
|
|
@ -368,7 +368,7 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
|
|||
/// entire crate. You should not read the result of this query
|
||||
/// directly, but rather use `named_region_map`, `is_late_bound_map`,
|
||||
/// etc.
|
||||
fn resolve_lifetimes<'tcx>(tcx: TyCtxt<'tcx>, for_krate: CrateNum) -> &'tcx ResolveLifetimes {
|
||||
fn resolve_lifetimes(tcx: TyCtxt<'_>, for_krate: CrateNum) -> &ResolveLifetimes {
|
||||
assert_eq!(for_krate, LOCAL_CRATE);
|
||||
|
||||
let named_region_map = krate(tcx);
|
||||
|
|
@ -395,7 +395,7 @@ fn resolve_lifetimes<'tcx>(tcx: TyCtxt<'tcx>, for_krate: CrateNum) -> &'tcx Reso
|
|||
tcx.arena.alloc(rl)
|
||||
}
|
||||
|
||||
fn krate<'tcx>(tcx: TyCtxt<'tcx>) -> NamedRegionMap {
|
||||
fn krate(tcx: TyCtxt<'_>) -> NamedRegionMap {
|
||||
let krate = tcx.hir().krate();
|
||||
let mut map = NamedRegionMap {
|
||||
defs: Default::default(),
|
||||
|
|
@ -441,7 +441,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
|
||||
fn visit_nested_body(&mut self, body: hir::BodyId) {
|
||||
// Each body has their own set of labels, save labels.
|
||||
let saved = replace(&mut self.labels_in_fn, vec![]);
|
||||
let saved = take(&mut self.labels_in_fn);
|
||||
let body = self.tcx.hir().body(body);
|
||||
extract_labels(self, body);
|
||||
self.with(
|
||||
|
|
@ -1405,9 +1405,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
lifetime_uses,
|
||||
..
|
||||
} = self;
|
||||
let labels_in_fn = replace(&mut self.labels_in_fn, vec![]);
|
||||
let xcrate_object_lifetime_defaults =
|
||||
replace(&mut self.xcrate_object_lifetime_defaults, DefIdMap::default());
|
||||
let labels_in_fn = take(&mut self.labels_in_fn);
|
||||
let xcrate_object_lifetime_defaults = take(&mut self.xcrate_object_lifetime_defaults);
|
||||
let mut this = LifetimeContext {
|
||||
tcx: *tcx,
|
||||
map: map,
|
||||
|
|
|
|||
|
|
@ -466,7 +466,7 @@ impl<'tcx> Index<'tcx> {
|
|||
|
||||
/// Cross-references the feature names of unstable APIs with enabled
|
||||
/// features and possibly prints errors.
|
||||
fn check_mod_unstable_api_usage<'tcx>(tcx: TyCtxt<'tcx>, module_def_id: DefId) {
|
||||
fn check_mod_unstable_api_usage(tcx: TyCtxt<'_>, module_def_id: DefId) {
|
||||
tcx.hir().visit_item_likes_in_module(module_def_id, &mut Checker { tcx }.as_deep_visitor());
|
||||
}
|
||||
|
||||
|
|
@ -836,7 +836,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
/// Given the list of enabled features that were not language features (i.e., that
|
||||
/// were expected to be library features), and the list of features used from
|
||||
/// libraries, identify activated features that don't exist and error about them.
|
||||
pub fn check_unused_or_stable_features<'tcx>(tcx: TyCtxt<'tcx>) {
|
||||
pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
|
||||
let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE);
|
||||
|
||||
if tcx.stability().staged_api[&LOCAL_CRATE] {
|
||||
|
|
@ -920,8 +920,8 @@ pub fn check_unused_or_stable_features<'tcx>(tcx: TyCtxt<'tcx>) {
|
|||
// don't lint about unused features. We should reenable this one day!
|
||||
}
|
||||
|
||||
fn unnecessary_stable_feature_lint<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
fn unnecessary_stable_feature_lint(
|
||||
tcx: TyCtxt<'_>,
|
||||
span: Span,
|
||||
feature: Symbol,
|
||||
since: Symbol,
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ use errors::DiagnosticBuilder;
|
|||
use syntax_pos::{Pos, Span};
|
||||
use syntax::symbol::Symbol;
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, RustcEncodable, RustcDecodable)]
|
||||
pub enum ErrorHandled {
|
||||
/// Already reported a lint or an error for this evaluation.
|
||||
Reported,
|
||||
|
|
@ -37,6 +37,10 @@ impl ErrorHandled {
|
|||
}
|
||||
}
|
||||
|
||||
CloneTypeFoldableImpls! {
|
||||
ErrorHandled,
|
||||
}
|
||||
|
||||
pub type ConstEvalRawResult<'tcx> = Result<RawConst<'tcx>, ErrorHandled>;
|
||||
pub type ConstEvalResult<'tcx> = Result<&'tcx ty::Const<'tcx>, ErrorHandled>;
|
||||
|
||||
|
|
@ -178,7 +182,7 @@ pub fn struct_error<'tcx>(tcx: TyCtxtAt<'tcx>, msg: &str) -> DiagnosticBuilder<'
|
|||
/// up with a Rust-level backtrace of where the error occured.
|
||||
/// Thsese should always be constructed by calling `.into()` on
|
||||
/// a `InterpError`. In `librustc_mir::interpret`, we have the `err!`
|
||||
/// macro for this
|
||||
/// macro for this.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct InterpErrorInfo<'tcx> {
|
||||
pub kind: InterpError<'tcx, u64>,
|
||||
|
|
|
|||
|
|
@ -2867,19 +2867,19 @@ impl<'tcx> graph::WithStartNode for Body<'tcx> {
|
|||
}
|
||||
|
||||
impl<'tcx> graph::WithPredecessors for Body<'tcx> {
|
||||
fn predecessors<'graph>(
|
||||
&'graph self,
|
||||
fn predecessors(
|
||||
&self,
|
||||
node: Self::Node,
|
||||
) -> <Self as GraphPredecessors<'graph>>::Iter {
|
||||
) -> <Self as GraphPredecessors<'_>>::Iter {
|
||||
self.predecessors_for(node).clone().into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> graph::WithSuccessors for Body<'tcx> {
|
||||
fn successors<'graph>(
|
||||
&'graph self,
|
||||
fn successors(
|
||||
&self,
|
||||
node: Self::Node,
|
||||
) -> <Self as GraphSuccessors<'graph>>::Iter {
|
||||
) -> <Self as GraphSuccessors<'_>>::Iter {
|
||||
self.basic_blocks[node].terminator().successors().cloned()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use crate::ty::query::QueryDescription;
|
|||
use crate::ty::query::queries;
|
||||
use crate::ty::{self, ParamEnvAnd, Ty, TyCtxt};
|
||||
use crate::ty::subst::SubstsRef;
|
||||
use crate::dep_graph::SerializedDepNodeIndex;
|
||||
use crate::dep_graph::{RecoverKey,DepKind, DepNode, SerializedDepNodeIndex};
|
||||
use crate::hir::def_id::{CrateNum, DefId, DefIndex};
|
||||
use crate::mir;
|
||||
use crate::mir::interpret::GlobalId;
|
||||
|
|
@ -33,13 +33,13 @@ rustc_queries! {
|
|||
Other {
|
||||
/// Records the type of every item.
|
||||
query type_of(key: DefId) -> Ty<'tcx> {
|
||||
cache { key.is_local() }
|
||||
cache_on_disk_if { key.is_local() }
|
||||
}
|
||||
|
||||
/// Maps from the `DefId` of an item (trait/struct/enum/fn) to its
|
||||
/// associated generics.
|
||||
query generics_of(key: DefId) -> &'tcx ty::Generics {
|
||||
cache { key.is_local() }
|
||||
cache_on_disk_if { key.is_local() }
|
||||
load_cached(tcx, id) {
|
||||
let generics: Option<ty::Generics> = tcx.queries.on_disk_cache
|
||||
.try_load_query_result(tcx, id);
|
||||
|
|
@ -62,7 +62,9 @@ rustc_queries! {
|
|||
/// predicate gets in the way of some checks, which are intended
|
||||
/// to operate over only the actual where-clauses written by the
|
||||
/// user.)
|
||||
query predicates_of(_: DefId) -> &'tcx ty::GenericPredicates<'tcx> {}
|
||||
query predicates_of(key: DefId) -> &'tcx ty::GenericPredicates<'tcx> {
|
||||
cache_on_disk_if { key.is_local() }
|
||||
}
|
||||
|
||||
query native_libraries(_: CrateNum) -> Lrc<Vec<NativeLibrary>> {
|
||||
desc { "looking up the native libraries of a linked crate" }
|
||||
|
|
@ -93,7 +95,7 @@ rustc_queries! {
|
|||
/// of the MIR qualify_consts pass. The actual meaning of
|
||||
/// the value isn't known except to the pass itself.
|
||||
query mir_const_qualif(key: DefId) -> (u8, &'tcx BitSet<mir::Local>) {
|
||||
cache { key.is_local() }
|
||||
cache_on_disk_if { key.is_local() }
|
||||
}
|
||||
|
||||
/// Fetch the MIR for a given `DefId` right after it's built - this includes
|
||||
|
|
@ -115,7 +117,7 @@ rustc_queries! {
|
|||
/// MIR after our optimization passes have run. This is MIR that is ready
|
||||
/// for codegen. This is also the only query that can fetch non-local MIR, at present.
|
||||
query optimized_mir(key: DefId) -> &'tcx mir::Body<'tcx> {
|
||||
cache { key.is_local() }
|
||||
cache_on_disk_if { key.is_local() }
|
||||
load_cached(tcx, id) {
|
||||
let mir: Option<crate::mir::Body<'tcx>> = tcx.queries.on_disk_cache
|
||||
.try_load_query_result(tcx, id);
|
||||
|
|
@ -285,7 +287,9 @@ rustc_queries! {
|
|||
|
||||
TypeChecking {
|
||||
/// The result of unsafety-checking this `DefId`.
|
||||
query unsafety_check_result(_: DefId) -> mir::UnsafetyCheckResult {}
|
||||
query unsafety_check_result(key: DefId) -> mir::UnsafetyCheckResult {
|
||||
cache_on_disk_if { key.is_local() }
|
||||
}
|
||||
|
||||
/// HACK: when evaluated, this reports a "unsafe derive on repr(packed)" error
|
||||
query unsafe_derive_on_repr_packed(_: DefId) -> () {}
|
||||
|
|
@ -348,7 +352,7 @@ rustc_queries! {
|
|||
}
|
||||
|
||||
query typeck_tables_of(key: DefId) -> &'tcx ty::TypeckTables<'tcx> {
|
||||
cache { key.is_local() }
|
||||
cache_on_disk_if { key.is_local() }
|
||||
load_cached(tcx, id) {
|
||||
let typeck_tables: Option<ty::TypeckTables<'tcx>> = tcx
|
||||
.queries.on_disk_cache
|
||||
|
|
@ -360,7 +364,9 @@ rustc_queries! {
|
|||
}
|
||||
|
||||
Other {
|
||||
query used_trait_imports(_: DefId) -> &'tcx DefIdSet {}
|
||||
query used_trait_imports(key: DefId) -> &'tcx DefIdSet {
|
||||
cache_on_disk_if { key.is_local() }
|
||||
}
|
||||
}
|
||||
|
||||
TypeChecking {
|
||||
|
|
@ -372,11 +378,15 @@ rustc_queries! {
|
|||
}
|
||||
|
||||
BorrowChecking {
|
||||
query borrowck(_: DefId) -> &'tcx BorrowCheckResult {}
|
||||
query borrowck(key: DefId) -> &'tcx BorrowCheckResult {
|
||||
cache_on_disk_if { key.is_local() }
|
||||
}
|
||||
|
||||
/// Borrow-checks the function body. If this is a closure, returns
|
||||
/// additional requirements that the closure's creator must verify.
|
||||
query mir_borrowck(_: DefId) -> mir::BorrowCheckResult<'tcx> {}
|
||||
query mir_borrowck(key: DefId) -> mir::BorrowCheckResult<'tcx> {
|
||||
cache_on_disk_if(tcx, _) { key.is_local() && tcx.is_closure(key) }
|
||||
}
|
||||
}
|
||||
|
||||
TypeChecking {
|
||||
|
|
@ -412,9 +422,10 @@ rustc_queries! {
|
|||
"const-evaluating `{}`",
|
||||
tcx.def_path_str(key.value.instance.def.def_id())
|
||||
}
|
||||
cache { true }
|
||||
load_cached(tcx, id) {
|
||||
tcx.queries.on_disk_cache.try_load_query_result(tcx, id).map(Ok)
|
||||
cache_on_disk_if(_, opt_result) {
|
||||
// Only store results without errors
|
||||
// FIXME: We never store these
|
||||
opt_result.map_or(true, |r| r.is_ok())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -427,9 +438,9 @@ rustc_queries! {
|
|||
"const-evaluating + checking `{}`",
|
||||
tcx.def_path_str(key.value.instance.def.def_id())
|
||||
}
|
||||
cache { true }
|
||||
load_cached(tcx, id) {
|
||||
tcx.queries.on_disk_cache.try_load_query_result(tcx, id).map(Ok)
|
||||
cache_on_disk_if(_, opt_result) {
|
||||
// Only store results without errors
|
||||
opt_result.map_or(true, |r| r.is_ok())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -453,7 +464,9 @@ rustc_queries! {
|
|||
}
|
||||
|
||||
TypeChecking {
|
||||
query check_match(_: DefId) -> () {}
|
||||
query check_match(key: DefId) -> () {
|
||||
cache_on_disk_if { key.is_local() }
|
||||
}
|
||||
|
||||
/// Performs part of the privacy check and computes "access levels".
|
||||
query privacy_access_levels(_: CrateNum) -> &'tcx AccessLevels {
|
||||
|
|
@ -483,7 +496,7 @@ rustc_queries! {
|
|||
query symbol_name(key: ty::Instance<'tcx>) -> ty::SymbolName {
|
||||
no_force
|
||||
desc { "computing the symbol for `{}`", key }
|
||||
cache { true }
|
||||
cache_on_disk_if { true }
|
||||
}
|
||||
|
||||
query def_kind(_: DefId) -> Option<DefKind> {}
|
||||
|
|
@ -501,7 +514,9 @@ rustc_queries! {
|
|||
}
|
||||
|
||||
Codegen {
|
||||
query codegen_fn_attrs(_: DefId) -> CodegenFnAttrs {}
|
||||
query codegen_fn_attrs(_: DefId) -> CodegenFnAttrs {
|
||||
cache_on_disk_if { true }
|
||||
}
|
||||
}
|
||||
|
||||
Other {
|
||||
|
|
@ -519,7 +534,7 @@ rustc_queries! {
|
|||
"const checking if rvalue is promotable to static `{}`",
|
||||
tcx.def_path_str(key)
|
||||
}
|
||||
cache { true }
|
||||
cache_on_disk_if { true }
|
||||
}
|
||||
query rvalue_promotable_map(key: DefId) -> &'tcx ItemLocalSet {
|
||||
desc { |tcx|
|
||||
|
|
@ -548,7 +563,7 @@ rustc_queries! {
|
|||
key: (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)
|
||||
) -> Vtable<'tcx, ()> {
|
||||
no_force
|
||||
cache { true }
|
||||
cache_on_disk_if { true }
|
||||
desc { |tcx|
|
||||
"checking if `{}` fulfills its obligations",
|
||||
tcx.def_path_str(key.1.def_id())
|
||||
|
|
@ -560,7 +575,9 @@ rustc_queries! {
|
|||
query trait_impls_of(key: DefId) -> &'tcx ty::trait_def::TraitImpls {
|
||||
desc { |tcx| "trait impls of `{}`", tcx.def_path_str(key) }
|
||||
}
|
||||
query specialization_graph_of(_: DefId) -> &'tcx specialization_graph::Graph {}
|
||||
query specialization_graph_of(_: DefId) -> &'tcx specialization_graph::Graph {
|
||||
cache_on_disk_if { true }
|
||||
}
|
||||
query is_object_safe(key: DefId) -> bool {
|
||||
desc { |tcx| "determine object safety of trait `{}`", tcx.def_path_str(key) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -269,11 +269,11 @@ impl OutputTypes {
|
|||
self.0.contains_key(key)
|
||||
}
|
||||
|
||||
pub fn keys<'a>(&'a self) -> BTreeMapKeysIter<'a, OutputType, Option<PathBuf>> {
|
||||
pub fn keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<PathBuf>> {
|
||||
self.0.keys()
|
||||
}
|
||||
|
||||
pub fn values<'a>(&'a self) -> BTreeMapValuesIter<'a, OutputType, Option<PathBuf>> {
|
||||
pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<PathBuf>> {
|
||||
self.0.values()
|
||||
}
|
||||
|
||||
|
|
@ -316,7 +316,7 @@ impl Externs {
|
|||
self.0.get(key)
|
||||
}
|
||||
|
||||
pub fn iter<'a>(&'a self) -> BTreeMapIter<'a, String, ExternEntry> {
|
||||
pub fn iter(&self) -> BTreeMapIter<'_, String, ExternEntry> {
|
||||
self.0.iter()
|
||||
}
|
||||
}
|
||||
|
|
@ -1207,7 +1207,11 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options,
|
|||
linker_plugin_lto: LinkerPluginLto = (LinkerPluginLto::Disabled,
|
||||
parse_linker_plugin_lto, [TRACKED],
|
||||
"generate build artifacts that are compatible with linker-based LTO."),
|
||||
|
||||
profile_generate: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
|
||||
parse_switch_with_opt_path, [TRACKED],
|
||||
"compile the program with profiling instrumentation"),
|
||||
profile_use: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
|
||||
"use the given `.profdata` file for profile-guided optimization"),
|
||||
}
|
||||
|
||||
options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
|
||||
|
|
@ -1379,11 +1383,6 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
|
|||
"extra arguments to prepend to the linker invocation (space separated)"),
|
||||
profile: bool = (false, parse_bool, [TRACKED],
|
||||
"insert profiling code"),
|
||||
pgo_gen: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
|
||||
parse_switch_with_opt_path, [TRACKED],
|
||||
"Generate PGO profile data, to a given file, or to the default location if it's empty."),
|
||||
pgo_use: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
|
||||
"Use PGO profile data from the given profile file."),
|
||||
disable_instrumentation_preinliner: bool = (false, parse_bool, [TRACKED],
|
||||
"Disable the instrumentation pre-inliner, useful for profiling / PGO."),
|
||||
relro_level: Option<RelroLevel> = (None, parse_relro_level, [TRACKED],
|
||||
|
|
@ -2036,13 +2035,6 @@ pub fn build_session_options_and_crate_config(
|
|||
}
|
||||
}
|
||||
|
||||
if debugging_opts.pgo_gen.enabled() && debugging_opts.pgo_use.is_some() {
|
||||
early_error(
|
||||
error_format,
|
||||
"options `-Z pgo-gen` and `-Z pgo-use` are exclusive",
|
||||
);
|
||||
}
|
||||
|
||||
let mut output_types = BTreeMap::new();
|
||||
if !debugging_opts.parse_only {
|
||||
for list in matches.opt_strs("emit") {
|
||||
|
|
@ -2154,6 +2146,13 @@ pub fn build_session_options_and_crate_config(
|
|||
);
|
||||
}
|
||||
|
||||
if cg.profile_generate.enabled() && cg.profile_use.is_some() {
|
||||
early_error(
|
||||
error_format,
|
||||
"options `-C profile-generate` and `-C profile-use` are exclusive",
|
||||
);
|
||||
}
|
||||
|
||||
let mut prints = Vec::<PrintRequest>::new();
|
||||
if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
|
||||
prints.push(PrintRequest::TargetCPUs);
|
||||
|
|
|
|||
|
|
@ -519,11 +519,11 @@ fn test_codegen_options_tracking_hash() {
|
|||
assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
|
||||
|
||||
opts = reference.clone();
|
||||
opts.debugging_opts.pgo_gen = SwitchWithOptPath::Enabled(None);
|
||||
opts.cg.profile_generate = SwitchWithOptPath::Enabled(None);
|
||||
assert_ne!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
|
||||
|
||||
opts = reference.clone();
|
||||
opts.debugging_opts.pgo_use = Some(PathBuf::from("abc"));
|
||||
opts.cg.profile_use = Some(PathBuf::from("abc"));
|
||||
assert_ne!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
|
||||
|
||||
opts = reference.clone();
|
||||
|
|
|
|||
|
|
@ -215,66 +215,66 @@ impl Session {
|
|||
*self.crate_disambiguator.get()
|
||||
}
|
||||
|
||||
pub fn struct_span_warn<'a, S: Into<MultiSpan>>(
|
||||
&'a self,
|
||||
pub fn struct_span_warn<S: Into<MultiSpan>>(
|
||||
&self,
|
||||
sp: S,
|
||||
msg: &str,
|
||||
) -> DiagnosticBuilder<'a> {
|
||||
) -> DiagnosticBuilder<'_> {
|
||||
self.diagnostic().struct_span_warn(sp, msg)
|
||||
}
|
||||
pub fn struct_span_warn_with_code<'a, S: Into<MultiSpan>>(
|
||||
&'a self,
|
||||
pub fn struct_span_warn_with_code<S: Into<MultiSpan>>(
|
||||
&self,
|
||||
sp: S,
|
||||
msg: &str,
|
||||
code: DiagnosticId,
|
||||
) -> DiagnosticBuilder<'a> {
|
||||
) -> DiagnosticBuilder<'_> {
|
||||
self.diagnostic().struct_span_warn_with_code(sp, msg, code)
|
||||
}
|
||||
pub fn struct_warn<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
|
||||
pub fn struct_warn(&self, msg: &str) -> DiagnosticBuilder<'_> {
|
||||
self.diagnostic().struct_warn(msg)
|
||||
}
|
||||
pub fn struct_span_err<'a, S: Into<MultiSpan>>(
|
||||
&'a self,
|
||||
pub fn struct_span_err<S: Into<MultiSpan>>(
|
||||
&self,
|
||||
sp: S,
|
||||
msg: &str,
|
||||
) -> DiagnosticBuilder<'a> {
|
||||
) -> DiagnosticBuilder<'_> {
|
||||
self.diagnostic().struct_span_err(sp, msg)
|
||||
}
|
||||
pub fn struct_span_err_with_code<'a, S: Into<MultiSpan>>(
|
||||
&'a self,
|
||||
pub fn struct_span_err_with_code<S: Into<MultiSpan>>(
|
||||
&self,
|
||||
sp: S,
|
||||
msg: &str,
|
||||
code: DiagnosticId,
|
||||
) -> DiagnosticBuilder<'a> {
|
||||
) -> DiagnosticBuilder<'_> {
|
||||
self.diagnostic().struct_span_err_with_code(sp, msg, code)
|
||||
}
|
||||
// FIXME: This method should be removed (every error should have an associated error code).
|
||||
pub fn struct_err<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
|
||||
pub fn struct_err(&self, msg: &str) -> DiagnosticBuilder<'_> {
|
||||
self.diagnostic().struct_err(msg)
|
||||
}
|
||||
pub fn struct_err_with_code<'a>(
|
||||
&'a self,
|
||||
pub fn struct_err_with_code(
|
||||
&self,
|
||||
msg: &str,
|
||||
code: DiagnosticId,
|
||||
) -> DiagnosticBuilder<'a> {
|
||||
) -> DiagnosticBuilder<'_> {
|
||||
self.diagnostic().struct_err_with_code(msg, code)
|
||||
}
|
||||
pub fn struct_span_fatal<'a, S: Into<MultiSpan>>(
|
||||
&'a self,
|
||||
pub fn struct_span_fatal<S: Into<MultiSpan>>(
|
||||
&self,
|
||||
sp: S,
|
||||
msg: &str,
|
||||
) -> DiagnosticBuilder<'a> {
|
||||
) -> DiagnosticBuilder<'_> {
|
||||
self.diagnostic().struct_span_fatal(sp, msg)
|
||||
}
|
||||
pub fn struct_span_fatal_with_code<'a, S: Into<MultiSpan>>(
|
||||
&'a self,
|
||||
pub fn struct_span_fatal_with_code<S: Into<MultiSpan>>(
|
||||
&self,
|
||||
sp: S,
|
||||
msg: &str,
|
||||
code: DiagnosticId,
|
||||
) -> DiagnosticBuilder<'a> {
|
||||
) -> DiagnosticBuilder<'_> {
|
||||
self.diagnostic().struct_span_fatal_with_code(sp, msg, code)
|
||||
}
|
||||
pub fn struct_fatal<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
|
||||
pub fn struct_fatal(&self, msg: &str) -> DiagnosticBuilder<'_> {
|
||||
self.diagnostic().struct_fatal(msg)
|
||||
}
|
||||
|
||||
|
|
@ -416,7 +416,7 @@ impl Session {
|
|||
pub fn next_node_id(&self) -> NodeId {
|
||||
self.reserve_node_ids(1)
|
||||
}
|
||||
pub fn diagnostic<'a>(&'a self) -> &'a errors::Handler {
|
||||
pub fn diagnostic(&self) -> &errors::Handler {
|
||||
&self.parse_sess.span_diagnostic
|
||||
}
|
||||
|
||||
|
|
@ -504,7 +504,7 @@ impl Session {
|
|||
);
|
||||
}
|
||||
|
||||
pub fn source_map<'a>(&'a self) -> &'a source_map::SourceMap {
|
||||
pub fn source_map(&self) -> &source_map::SourceMap {
|
||||
self.parse_sess.source_map()
|
||||
}
|
||||
pub fn verbose(&self) -> bool {
|
||||
|
|
@ -1295,9 +1295,9 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
|
|||
|
||||
// Make sure that any given profiling data actually exists so LLVM can't
|
||||
// decide to silently skip PGO.
|
||||
if let Some(ref path) = sess.opts.debugging_opts.pgo_use {
|
||||
if let Some(ref path) = sess.opts.cg.profile_use {
|
||||
if !path.exists() {
|
||||
sess.err(&format!("File `{}` passed to `-Zpgo-use` does not exist.",
|
||||
sess.err(&format!("File `{}` passed to `-C profile-use` does not exist.",
|
||||
path.display()));
|
||||
}
|
||||
}
|
||||
|
|
@ -1306,7 +1306,7 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
|
|||
// an error to combine the two for now. It always runs into an assertions
|
||||
// if LLVM is built with assertions, but without assertions it sometimes
|
||||
// does not crash and will probably generate a corrupted binary.
|
||||
if sess.opts.debugging_opts.pgo_gen.enabled() &&
|
||||
if sess.opts.cg.profile_generate.enabled() &&
|
||||
sess.target.target.options.is_like_msvc &&
|
||||
sess.panic_strategy() == PanicStrategy::Unwind {
|
||||
sess.err("Profile-guided optimization does not yet work in conjunction \
|
||||
|
|
|
|||
|
|
@ -48,8 +48,8 @@ pub fn add_placeholder_note(err: &mut errors::DiagnosticBuilder<'_>) {
|
|||
/// If there are types that satisfy both impls, invokes `on_overlap`
|
||||
/// with a suitably-freshened `ImplHeader` with those types
|
||||
/// substituted. Otherwise, invokes `no_overlap`.
|
||||
pub fn overlapping_impls<'tcx, F1, F2, R>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
pub fn overlapping_impls<F1, F2, R>(
|
||||
tcx: TyCtxt<'_>,
|
||||
impl1_def_id: DefId,
|
||||
impl2_def_id: DefId,
|
||||
intercrate_mode: IntercrateMode,
|
||||
|
|
@ -247,10 +247,10 @@ pub enum OrphanCheckErr<'tcx> {
|
|||
///
|
||||
/// 1. All type parameters in `Self` must be "covered" by some local type constructor.
|
||||
/// 2. Some local type must appear in `Self`.
|
||||
pub fn orphan_check<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
pub fn orphan_check(
|
||||
tcx: TyCtxt<'_>,
|
||||
impl_def_id: DefId,
|
||||
) -> Result<(), OrphanCheckErr<'tcx>> {
|
||||
) -> Result<(), OrphanCheckErr<'_>> {
|
||||
debug!("orphan_check({:?})", impl_def_id);
|
||||
|
||||
// We only except this routine to be invoked on implementations
|
||||
|
|
|
|||
|
|
@ -247,7 +247,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
fn fuzzy_match_tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
|
||||
/// returns the fuzzy category of a given type, or None
|
||||
/// if the type can be equated to any type.
|
||||
fn type_category<'tcx>(t: Ty<'tcx>) -> Option<u32> {
|
||||
fn type_category(t: Ty<'_>) -> Option<u32> {
|
||||
match t.sty {
|
||||
ty::Bool => Some(0),
|
||||
ty::Char => Some(1),
|
||||
|
|
|
|||
|
|
@ -461,41 +461,35 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
|
|||
}
|
||||
|
||||
ty::Predicate::ConstEvaluatable(def_id, substs) => {
|
||||
match self.selcx.tcx().lift_to_global(&obligation.param_env) {
|
||||
None => {
|
||||
if obligation.param_env.has_local_value() {
|
||||
ProcessResult::Unchanged
|
||||
}
|
||||
Some(param_env) => {
|
||||
match self.selcx.tcx().lift_to_global(&substs) {
|
||||
Some(substs) => {
|
||||
let instance = ty::Instance::resolve(
|
||||
self.selcx.tcx().global_tcx(),
|
||||
param_env,
|
||||
def_id,
|
||||
substs,
|
||||
);
|
||||
if let Some(instance) = instance {
|
||||
let cid = GlobalId {
|
||||
instance,
|
||||
promoted: None,
|
||||
};
|
||||
match self.selcx.tcx().at(obligation.cause.span)
|
||||
.const_eval(param_env.and(cid)) {
|
||||
Ok(_) => ProcessResult::Changed(vec![]),
|
||||
Err(err) => ProcessResult::Error(
|
||||
CodeSelectionError(ConstEvalFailure(err)))
|
||||
}
|
||||
} else {
|
||||
ProcessResult::Error(CodeSelectionError(
|
||||
ConstEvalFailure(ErrorHandled::TooGeneric)
|
||||
))
|
||||
}
|
||||
},
|
||||
None => {
|
||||
pending_obligation.stalled_on = substs.types().collect();
|
||||
ProcessResult::Unchanged
|
||||
} else {
|
||||
if !substs.has_local_value() {
|
||||
let instance = ty::Instance::resolve(
|
||||
self.selcx.tcx().global_tcx(),
|
||||
obligation.param_env,
|
||||
def_id,
|
||||
substs,
|
||||
);
|
||||
if let Some(instance) = instance {
|
||||
let cid = GlobalId {
|
||||
instance,
|
||||
promoted: None,
|
||||
};
|
||||
match self.selcx.tcx().at(obligation.cause.span)
|
||||
.const_eval(obligation.param_env.and(cid)) {
|
||||
Ok(_) => ProcessResult::Changed(vec![]),
|
||||
Err(err) => ProcessResult::Error(
|
||||
CodeSelectionError(ConstEvalFailure(err)))
|
||||
}
|
||||
} else {
|
||||
ProcessResult::Error(CodeSelectionError(
|
||||
ConstEvalFailure(ErrorHandled::TooGeneric)
|
||||
))
|
||||
}
|
||||
} else {
|
||||
pending_obligation.stalled_on = substs.types().collect();
|
||||
ProcessResult::Unchanged
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -457,6 +457,16 @@ pub enum SelectionError<'tcx> {
|
|||
Overflow,
|
||||
}
|
||||
|
||||
EnumTypeFoldableImpl! {
|
||||
impl<'tcx> TypeFoldable<'tcx> for SelectionError<'tcx> {
|
||||
(SelectionError::Unimplemented),
|
||||
(SelectionError::OutputTypeParameterMismatch)(a, b, c),
|
||||
(SelectionError::TraitNotObjectSafe)(a),
|
||||
(SelectionError::ConstEvalFailure)(a),
|
||||
(SelectionError::Overflow),
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FulfillmentError<'tcx> {
|
||||
pub obligation: PredicateObligation<'tcx>,
|
||||
pub code: FulfillmentErrorCode<'tcx>
|
||||
|
|
@ -782,13 +792,11 @@ fn do_normalize_predicates<'tcx>(
|
|||
return Err(ErrorReported)
|
||||
}
|
||||
};
|
||||
|
||||
match tcx.lift_to_global(&predicates) {
|
||||
Some(predicates) => Ok(predicates),
|
||||
None => {
|
||||
// FIXME: shouldn't we, you know, actually report an error here? or an ICE?
|
||||
Err(ErrorReported)
|
||||
}
|
||||
if predicates.has_local_value() {
|
||||
// FIXME: shouldn't we, you know, actually report an error here? or an ICE?
|
||||
Err(ErrorReported)
|
||||
} else {
|
||||
Ok(predicates)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -702,6 +702,6 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) fn is_object_safe_provider<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId) -> bool {
|
||||
pub(super) fn is_object_safe_provider(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
|
||||
tcx.object_safety_violations(trait_def_id).is_empty()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -399,7 +399,8 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
|
|||
fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
|
||||
if let ConstValue::Unevaluated(def_id, substs) = constant.val {
|
||||
let tcx = self.selcx.tcx().global_tcx();
|
||||
if let Some(param_env) = self.tcx().lift_to_global(&self.param_env) {
|
||||
let param_env = self.param_env;
|
||||
if !param_env.has_local_value() {
|
||||
if substs.needs_infer() || substs.has_placeholders() {
|
||||
let identity_substs = InternalSubsts::identity_for_item(tcx, def_id);
|
||||
let instance = ty::Instance::resolve(tcx, param_env, def_id, identity_substs);
|
||||
|
|
@ -414,7 +415,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
if let Some(substs) = self.tcx().lift_to_global(&substs) {
|
||||
if !substs.has_local_value() {
|
||||
let instance = ty::Instance::resolve(tcx, param_env, def_id, substs);
|
||||
if let Some(instance) = instance {
|
||||
let cid = GlobalId {
|
||||
|
|
@ -1508,8 +1509,8 @@ fn confirm_impl_candidate<'cx, 'tcx>(
|
|||
///
|
||||
/// Based on the "projection mode", this lookup may in fact only examine the
|
||||
/// topmost impl. See the comments for `Reveal` for more details.
|
||||
fn assoc_ty_def<'cx, 'tcx>(
|
||||
selcx: &SelectionContext<'cx, 'tcx>,
|
||||
fn assoc_ty_def(
|
||||
selcx: &SelectionContext<'_, '_>,
|
||||
impl_def_id: DefId,
|
||||
assoc_ty_def_id: DefId,
|
||||
) -> specialization_graph::NodeItem<ty::AssocItem> {
|
||||
|
|
|
|||
|
|
@ -193,7 +193,8 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
|
|||
fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
|
||||
if let ConstValue::Unevaluated(def_id, substs) = constant.val {
|
||||
let tcx = self.infcx.tcx.global_tcx();
|
||||
if let Some(param_env) = self.tcx().lift_to_global(&self.param_env) {
|
||||
let param_env = self.param_env;
|
||||
if !param_env.has_local_value() {
|
||||
if substs.needs_infer() || substs.has_placeholders() {
|
||||
let identity_substs = InternalSubsts::identity_for_item(tcx, def_id);
|
||||
let instance = ty::Instance::resolve(tcx, param_env, def_id, identity_substs);
|
||||
|
|
@ -208,7 +209,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
if let Some(substs) = self.tcx().lift_to_global(&substs) {
|
||||
if !substs.has_local_value() {
|
||||
let instance = ty::Instance::resolve(tcx, param_env, def_id, substs);
|
||||
if let Some(instance) = instance {
|
||||
let cid = GlobalId {
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue