Fix merge conflicts

This commit is contained in:
Christian Poveda 2019-07-04 01:45:29 -05:00
commit e45bbaf48c
1131 changed files with 6685 additions and 3696 deletions

View file

@ -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.
#

View file

@ -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

View file

@ -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>

View file

@ -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

View file

@ -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"

View file

@ -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/

View file

@ -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:

View file

@ -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);

View file

@ -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> {

View file

@ -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);
}

View file

@ -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

View file

@ -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)

View file

@ -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.

View 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

View file

@ -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
Heres an example of documenting a macro:

View file

@ -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.

View file

@ -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
------------------------

View file

@ -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 } => {}
}
}
```

View file

@ -16,7 +16,7 @@
set -ex
bucket=rust-lang-ci-evalazure
bucket=rust-lang-ci2
commit=$1
builder=$2

View file

@ -1,2 +1,3 @@
import gdb
import gdb_rust_pretty_printing
gdb_rust_pretty_printing.register_printers(gdb.current_objfile())

View file

@ -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> {

View file

@ -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")]

View file

@ -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> {

View file

@ -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")]

View file

@ -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")]

View file

@ -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")]

View file

@ -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

View file

@ -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) }
}

View file

@ -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")]

View file

@ -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());
}

View file

@ -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> {

View file

@ -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 {

View file

@ -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());

View file

@ -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.

View file

@ -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()

View file

@ -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)]

View file

@ -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

View file

@ -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

View file

@ -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,

View file

@ -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.

View file

@ -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,

View file

@ -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")]

View file

@ -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")]

View file

@ -151,7 +151,7 @@ macro_rules! assert_none {
stringify!($what), b);
}
}
)*
)+
}};
($what:ident, $($str:tt),+,) => (assert_none!($what,$($str),+))
}

View file

@ -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 = "";

View file

@ -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);
}
}

View file

@ -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 doesnt 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.

View file

@ -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);

View file

@ -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]) {

View file

@ -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())
}
}

View file

@ -25,6 +25,7 @@
#![feature(extern_types)]
#![feature(in_band_lifetimes)]
#![feature(optin_builtin_traits)]
#![feature(mem_take)]
#![feature(non_exhaustive)]
#![feature(specialization)]

View file

@ -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);

View file

@ -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)
}

View file

@ -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 {
$(

View file

@ -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.
}
}
}
}

View file

@ -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()

View file

@ -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,

View file

@ -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());

View file

@ -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) {

View file

@ -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,

View file

@ -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
View 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);
}
}

View file

@ -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>;

View file

@ -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() }
}

View file

@ -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
}

View file

@ -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))
}
}
}
}

View file

@ -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);
}
}

View file

@ -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);

View file

@ -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<&region::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);

View file

@ -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()
}

View file

@ -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

View file

@ -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()
}
}

View file

@ -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
}

View file

@ -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"]

View file

@ -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),

View file

@ -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];
}

View file

@ -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);

View file

@ -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

View file

@ -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;

View file

@ -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()

View file

@ -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

View file

@ -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(),

View file

@ -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)
}

View file

@ -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);

View file

@ -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);

View file

@ -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,

View file

@ -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,

View file

@ -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>,

View file

@ -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()
}
}

View file

@ -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) }
}

View file

@ -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);

View file

@ -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();

View file

@ -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 \

View file

@ -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

View file

@ -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),

View file

@ -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
}
}
}

View file

@ -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)
}
})
}

View file

@ -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()
}

View file

@ -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> {

View file

@ -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